Line data Source code
1 : /**
2 : Copyright (c) 2024 Stappler LLC <admin@stappler.dev>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #include "SPFontLibrary.h"
24 :
25 : #include "ft2build.h"
26 : #include FT_FREETYPE_H
27 : #include FT_GLYPH_H
28 : #include FT_MULTIPLE_MASTERS_H
29 : #include FT_SFNT_NAMES_H
30 : #include FT_ADVANCES_H
31 :
32 : #include "SPFontFace.h"
33 :
34 : namespace STAPPLER_VERSIONIZED stappler::font {
35 :
36 : #include "SPFont-RobotoMono-Italic-VariableFont_wght.ttf.cc"
37 : #include "SPFont-RobotoMono-VariableFont_wght.ttf.cc"
38 : #include "SPFont-RobotoFlex-VariableFont.ttf.cc"
39 : #include "SPFont-DejaVuSansStappler.cc"
40 :
41 8942 : FontFaceObjectHandle::~FontFaceObjectHandle() {
42 4471 : if (_onDestroy) {
43 4471 : _onDestroy(this);
44 4471 : _onDestroy = nullptr;
45 : }
46 4471 : _library = nullptr;
47 4471 : _face = nullptr;
48 8942 : }
49 :
50 4471 : bool FontFaceObjectHandle::init(const Rc<FontLibrary> &lib, Rc<FontFaceObject> &&obj, Function<void(const FontFaceObjectHandle *)> &&onDestroy) {
51 4471 : _face = move(obj);
52 4471 : _library = lib;
53 4471 : _onDestroy = move(onDestroy);
54 4471 : return true;
55 : }
56 :
57 149577 : bool FontFaceObjectHandle::acquireTexture(char16_t theChar, const Callback<void(const CharTexture &)> &cb) {
58 149577 : return _face->acquireTextureUnsafe(theChar, cb);
59 : }
60 :
61 198 : BytesView FontLibrary::getFont(DefaultFontName name) {
62 198 : switch (name) {
63 0 : case DefaultFontName::None: return BytesView(); break;
64 50 : case DefaultFontName::RobotoFlex_VariableFont:
65 50 : return BytesView(reinterpret_cast<const uint8_t *>(s_font_RobotoFlex_VariableFont), sizeof(s_font_RobotoFlex_VariableFont));
66 : break;
67 50 : case DefaultFontName::RobotoMono_VariableFont:
68 50 : return BytesView(reinterpret_cast<const uint8_t *>(s_font_RobotoMono_VariableFont), sizeof(s_font_RobotoMono_VariableFont));
69 : break;
70 50 : case DefaultFontName::RobotoMono_Italic_VariableFont:
71 50 : return BytesView(reinterpret_cast<const uint8_t *>(s_font_RobotoMono_Italic_VariableFont), sizeof(s_font_RobotoMono_Italic_VariableFont));
72 : break;
73 50 : case DefaultFontName::DejaVuSans:
74 50 : return BytesView(reinterpret_cast<const uint8_t *>(s_font_DejaVuSansStappler), sizeof(s_font_DejaVuSansStappler));
75 : break;
76 : }
77 0 : return BytesView();
78 : }
79 :
80 200 : StringView FontLibrary::getFontName(DefaultFontName name) {
81 200 : switch (name) {
82 0 : case DefaultFontName::None: return StringView(); break;
83 50 : case DefaultFontName::RobotoFlex_VariableFont: return StringView("RobotoFlex_VariableFont"); break;
84 50 : case DefaultFontName::RobotoMono_VariableFont: return StringView("RobotoMono_VariableFont"); break;
85 50 : case DefaultFontName::RobotoMono_Italic_VariableFont: return StringView("RobotoMono_Italic_VariableFont"); break;
86 50 : case DefaultFontName::DejaVuSans: return StringView("DejaVuSans"); break;
87 : }
88 0 : return StringView();
89 : }
90 :
91 50 : FontLibrary::FontLibrary() {
92 50 : FT_Init_FreeType( &_library );
93 50 : }
94 :
95 100 : FontLibrary::~FontLibrary() {
96 50 : if (_library) {
97 50 : FT_Done_FreeType(_library);
98 50 : _library = nullptr;
99 : }
100 100 : }
101 :
102 192 : Rc<FontFaceData> FontLibrary::openFontData(StringView dataName, FontLayoutParameters params,
103 : bool isParamsPreconfigured, const Callback<FontData()> &dataCallback) {
104 192 : std::unique_lock lock(_mutex);
105 :
106 200 : auto it = _data.find(dataName);
107 200 : if (it != _data.end()) {
108 0 : return it->second;
109 : }
110 :
111 200 : if (!dataCallback) {
112 0 : return nullptr;
113 : }
114 :
115 200 : lock.unlock();
116 200 : auto fontData = dataCallback();
117 195 : if (fontData.view.empty() && !fontData.callback) {
118 0 : return nullptr;
119 : }
120 :
121 194 : Rc<FontFaceData> dataObject;
122 193 : if (fontData.callback) {
123 148 : dataObject = Rc<FontFaceData>::create(dataName, move(fontData.callback));
124 50 : } else if (fontData.persistent) {
125 50 : dataObject = Rc<FontFaceData>::create(dataName, move(fontData.view), true);
126 : } else {
127 0 : dataObject = Rc<FontFaceData>::create(dataName, move(fontData.bytes));
128 : }
129 200 : if (dataObject) {
130 200 : lock.lock();
131 200 : _data.emplace(dataObject->getName(), dataObject);
132 :
133 200 : auto face = newFontFace(dataObject->getView());
134 200 : lock.unlock();
135 200 : if (!isParamsPreconfigured) {
136 50 : params = dataObject->acquireDefaultParams(face);
137 : }
138 200 : dataObject->inspectVariableFont(params, _library, face);
139 200 : lock.lock();
140 200 : doneFontFace(face);
141 : }
142 200 : return dataObject;
143 200 : }
144 :
145 0 : Rc<FontFaceObject> FontLibrary::openFontFace(StringView dataName, const FontSpecializationVector &spec, const Callback<FontData()> &dataCallback) {
146 0 : String faceName = mem_std::toString(dataName, spec.getSpecializationArgs<Interface>());
147 :
148 0 : std::unique_lock lock(_mutex);
149 : do {
150 0 : auto it = _faces.find(faceName);
151 0 : if (it != _faces.end()) {
152 0 : return it->second;
153 : }
154 : } while (0);
155 :
156 0 : auto it = _data.find(dataName);
157 0 : if (it != _data.end()) {
158 0 : auto face = newFontFace(it->second->getView());
159 0 : auto ret = Rc<FontFaceObject>::create(faceName, it->second, _library, face, spec, getNextId());
160 0 : if (ret) {
161 0 : _faces.emplace(ret->getName(), ret);
162 : } else {
163 0 : doneFontFace(face);
164 : }
165 0 : return ret;
166 0 : }
167 :
168 0 : if (!dataCallback) {
169 0 : return nullptr;
170 : }
171 :
172 0 : auto fontData = dataCallback();
173 0 : if (fontData.view.empty()) {
174 0 : return nullptr;
175 : }
176 :
177 0 : Rc<FontFaceData> dataObject;
178 0 : if (fontData.persistent) {
179 0 : dataObject = Rc<FontFaceData>::create(dataName, move(fontData.view), true);
180 : } else {
181 0 : dataObject = Rc<FontFaceData>::create(dataName, move(fontData.bytes));
182 : }
183 :
184 0 : if (dataObject) {
185 0 : _data.emplace(dataObject->getName(), dataObject);
186 0 : auto face = newFontFace(dataObject->getView());
187 0 : auto ret = Rc<FontFaceObject>::create(faceName, it->second, _library, face, spec, getNextId());
188 0 : if (ret) {
189 0 : _faces.emplace(ret->getName(), ret);
190 : } else {
191 0 : doneFontFace(face);
192 : }
193 0 : return ret;
194 0 : }
195 :
196 0 : return nullptr;
197 0 : }
198 :
199 2245 : Rc<FontFaceObject> FontLibrary::openFontFace(const Rc<FontFaceData> &dataObject, const FontSpecializationVector &spec) {
200 2245 : String faceName = mem_std::toString(dataObject->getName(), spec.getSpecializationArgs<Interface>());
201 :
202 2245 : std::unique_lock lock(_mutex);
203 : do {
204 2245 : auto it = _faces.find(faceName);
205 2245 : if (it != _faces.end()) {
206 0 : return it->second;
207 : }
208 : } while (0);
209 :
210 2245 : auto face = newFontFace(dataObject->getView());
211 2245 : auto ret = Rc<FontFaceObject>::create(faceName, dataObject, _library, face, spec, getNextId());
212 2245 : if (ret) {
213 2245 : _faces.emplace(ret->getName(), ret);
214 : } else {
215 0 : doneFontFace(face);
216 : }
217 2245 : return ret;
218 2245 : }
219 :
220 50 : void FontLibrary::invalidate() {
221 50 : std::unique_lock uniqueLock(_sharedMutex);
222 :
223 50 : _threads.clear();
224 50 : _faces.clear();
225 50 : _data.clear();
226 50 : }
227 :
228 4815 : void FontLibrary::update() {
229 4815 : Vector<Rc<FontFaceObject>> erased;
230 4815 : std::unique_lock lock(_mutex);
231 :
232 : do {
233 4815 : auto it = _faces.begin();
234 41969 : while (it != _faces.end()) {
235 37154 : if (it->second->getReferenceCount() == 1) {
236 1966 : releaseId(it->second->getId());
237 1966 : doneFontFace(it->second->getFace());
238 1966 : erased.emplace_back(it->second.get());
239 1966 : it = _faces.erase(it);
240 : } else {
241 35188 : ++ it;
242 : }
243 : }
244 : } while (0);
245 :
246 : do {
247 4815 : auto it = _data.begin();
248 24002 : while (it != _data.end()) {
249 19187 : if (it->second->getReferenceCount() == 1) {
250 0 : it = _data.erase(it);
251 : } else {
252 19187 : ++ it;
253 : }
254 : }
255 : } while (0);
256 :
257 4815 : lock.unlock();
258 :
259 4815 : std::unique_lock uniqueLock(_sharedMutex);
260 6781 : for (auto &it : erased) {
261 1966 : _threads.erase(it.get());
262 : }
263 4815 : }
264 :
265 2245 : uint16_t FontLibrary::getNextId() {
266 13557 : for (uint32_t i = 1; i < _fontIds.size(); ++ i) {
267 13557 : if (!_fontIds.test(i)) {
268 2245 : _fontIds.set(i);
269 2245 : return i;
270 : }
271 : }
272 0 : abort(); // active font limits exceeded
273 : return 0;
274 : }
275 :
276 1966 : void FontLibrary::releaseId(uint16_t id) {
277 1966 : _fontIds.reset(id);
278 1966 : }
279 :
280 15716 : Rc<FontFaceObjectHandle> FontLibrary::makeThreadHandle(const Rc<FontFaceObject> &obj) {
281 15716 : std::shared_lock sharedLock(_sharedMutex);
282 15677 : auto it = _threads.find(obj.get());
283 15367 : if (it != _threads.end()) {
284 14065 : auto iit = it->second.find(std::this_thread::get_id());
285 14180 : if (iit != it->second.end()) {
286 11184 : return iit->second;
287 : }
288 : }
289 4251 : sharedLock.unlock();
290 :
291 4399 : std::unique_lock uniqueLock(_sharedMutex);
292 4471 : it = _threads.find(obj.get());
293 4471 : if (it != _threads.end()) {
294 3349 : auto iit = it->second.find(std::this_thread::get_id());
295 3349 : if (iit != it->second.end()) {
296 0 : return iit->second;
297 : }
298 : }
299 :
300 4471 : std::unique_lock lock(_mutex);
301 4471 : auto face = newFontFace(obj->getData()->getView());
302 4471 : lock.unlock();
303 4471 : auto target = Rc<FontFaceObject>::create(obj->getName(), obj->getData(), _library, face, obj->getSpec(), obj->getId());
304 :
305 4471 : if (it == _threads.end()) {
306 1122 : it = _threads.emplace(obj.get(), Map<std::thread::id, Rc<FontFaceObjectHandle>>()).first;
307 : }
308 :
309 8942 : auto iit = it->second.emplace(std::this_thread::get_id(), Rc<FontFaceObjectHandle>::create(this, move(target), [this] (const FontFaceObjectHandle *obj) {
310 4471 : std::unique_lock lock(_mutex);
311 4471 : doneFontFace(obj->getFace());
312 8942 : })).first->second;
313 4471 : uniqueLock.unlock();
314 4471 : return iit;
315 15648 : }
316 :
317 6916 : FT_Face FontLibrary::newFontFace(BytesView data) {
318 6916 : FT_Face ret = nullptr;
319 6916 : FT_Error err = FT_Err_Ok;
320 :
321 6916 : err = FT_New_Memory_Face(_library, data.data(), data.size(), 0, &ret );
322 6916 : if (err != FT_Err_Ok) {
323 0 : auto str = FT_Error_String(err);
324 0 : log::error("font::FontLibrary", str ? StringView(str) : "Unknown error");
325 0 : return nullptr;
326 : }
327 :
328 6916 : return ret;
329 : }
330 :
331 6637 : void FontLibrary::doneFontFace(FT_Face face) {
332 6637 : if (face) {
333 6637 : FT_Done_Face(face);
334 : }
335 6637 : }
336 :
337 : }
|