Line data Source code
1 : /**
2 : Copyright (c) 2023-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 "SPFontFace.h"
24 : #include "SPFontLibrary.h"
25 :
26 : #include "ft2build.h"
27 : #include FT_FREETYPE_H
28 : #include FT_GLYPH_H
29 : #include FT_MULTIPLE_MASTERS_H
30 : #include FT_TRUETYPE_TABLES_H
31 : #include FT_SFNT_NAMES_H
32 : #include FT_ADVANCES_H
33 :
34 : namespace STAPPLER_VERSIONIZED stappler::font {
35 :
36 381070 : static constexpr uint32_t getAxisTag(char c1, char c2, char c3, char c4) {
37 381070 : return uint32_t(c1 & 0xFF) << 24 | uint32_t(c2 & 0xFF) << 16 | uint32_t(c3 & 0xFF) << 8 | uint32_t(c4 & 0xFF);
38 : }
39 :
40 381070 : static constexpr uint32_t getAxisTag(const char c[4]) {
41 381070 : return getAxisTag(c[0], c[1], c[2], c[3]);
42 : }
43 :
44 0 : static CharGroupId getCharGroupForChar(char16_t c) {
45 : using namespace chars;
46 0 : if (CharGroup<char16_t, CharGroupId::Numbers>::match(c)) {
47 0 : return CharGroupId::Numbers;
48 0 : } else if (CharGroup<char16_t, CharGroupId::Latin>::match(c)) {
49 0 : return CharGroupId::Latin;
50 0 : } else if (CharGroup<char16_t, CharGroupId::Cyrillic>::match(c)) {
51 0 : return CharGroupId::Cyrillic;
52 0 : } else if (CharGroup<char16_t, CharGroupId::Currency>::match(c)) {
53 0 : return CharGroupId::Currency;
54 0 : } else if (CharGroup<char16_t, CharGroupId::GreekBasic>::match(c)) {
55 0 : return CharGroupId::GreekBasic;
56 0 : } else if (CharGroup<char16_t, CharGroupId::Math>::match(c)) {
57 0 : return CharGroupId::Math;
58 0 : } else if (CharGroup<char16_t, CharGroupId::TextPunctuation>::match(c)) {
59 0 : return CharGroupId::TextPunctuation;
60 : }
61 0 : return CharGroupId::None;
62 : }
63 :
64 50 : bool FontFaceData::init(StringView name, BytesView data, bool persistent) {
65 50 : if (persistent) {
66 50 : _view = data;
67 50 : _persistent = true;
68 50 : _name = name.str<Interface>();
69 50 : return true;
70 : } else {
71 0 : return init(name, data.bytes<Interface>());
72 : }
73 : }
74 :
75 0 : bool FontFaceData::init(StringView name, Bytes &&data) {
76 0 : _persistent = false;
77 0 : _data = move(data);
78 0 : _view = _data;
79 0 : _name = name.str<Interface>();
80 0 : return true;
81 : }
82 :
83 148 : bool FontFaceData::init(StringView name, Function<Bytes()> &&cb) {
84 148 : _persistent = true;
85 148 : _data = cb();
86 150 : _view = _data;
87 150 : _name = name.str<Interface>();
88 150 : return true;
89 : }
90 :
91 50 : FontLayoutParameters FontFaceData::acquireDefaultParams(FT_Face face) {
92 50 : FontLayoutParameters sfnt;
93 :
94 50 : if (face->style_flags & FT_STYLE_FLAG_ITALIC) {
95 0 : sfnt.fontStyle = FontStyle::Italic;
96 : }
97 :
98 50 : if (face->style_flags & FT_STYLE_FLAG_BOLD) {
99 0 : sfnt.fontWeight = FontWeight::Bold;
100 : }
101 :
102 50 : auto table = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
103 50 : if (table) {
104 50 : sfnt.fontWeight = FontWeight(table->usWeightClass);
105 50 : switch (table->usWidthClass) {
106 0 : case 1: sfnt.fontStretch = FontStretch::UltraCondensed; break;
107 0 : case 2: sfnt.fontStretch = FontStretch::ExtraCondensed; break;
108 0 : case 3: sfnt.fontStretch = FontStretch::Condensed; break;
109 0 : case 4: sfnt.fontStretch = FontStretch::SemiCondensed; break;
110 50 : case 5: sfnt.fontStretch = FontStretch::Normal; break;
111 0 : case 6: sfnt.fontStretch = FontStretch::SemiExpanded; break;
112 0 : case 7: sfnt.fontStretch = FontStretch::Expanded; break;
113 0 : case 8: sfnt.fontStretch = FontStretch::ExtraExpanded; break;
114 0 : case 9: sfnt.fontStretch = FontStretch::UltraExpanded; break;
115 0 : default: break;
116 : }
117 :
118 50 : if (table->panose[0] == 2) {
119 : // only for Latin Text
120 50 : FontLayoutParameters panose;
121 50 : switch (table->panose[2]) {
122 0 : case 2: panose.fontWeight = FontWeight::ExtraLight; break;
123 0 : case 3: panose.fontWeight = FontWeight::Light; break;
124 0 : case 4: panose.fontWeight = FontWeight::Thin; break;
125 0 : case 5: panose.fontWeight = FontWeight::Normal; break;
126 50 : case 6: panose.fontWeight = FontWeight::Medium; break;
127 0 : case 7: panose.fontWeight = FontWeight::SemiBold; break;
128 0 : case 8: panose.fontWeight = FontWeight::Bold; break;
129 0 : case 9: panose.fontWeight = FontWeight::ExtraBold; break;
130 0 : case 10: panose.fontWeight = FontWeight::Heavy; break;
131 0 : case 11: panose.fontWeight = FontWeight::Black; break;
132 0 : default: break;
133 : }
134 :
135 50 : switch (table->panose[3]) {
136 0 : case 2: panose.fontStretch = FontStretch::Normal; break;
137 0 : case 5: panose.fontStretch = FontStretch::Expanded; break;
138 0 : case 6: panose.fontStretch = FontStretch::Condensed; break;
139 0 : case 7: panose.fontStretch = FontStretch::ExtraExpanded; break;
140 0 : case 8: panose.fontStretch = FontStretch::ExtraCondensed; break;
141 50 : default: break;
142 : }
143 :
144 50 : switch (table->panose[7]) {
145 0 : case 5: panose.fontStyle = FontStyle::Oblique; break;
146 0 : case 9: panose.fontStyle = FontStyle::Oblique; break;
147 0 : case 10: panose.fontStyle = FontStyle::Oblique; break;
148 0 : case 11: panose.fontStyle = FontStyle::Oblique; break;
149 0 : case 12: panose.fontStyle = FontStyle::Oblique; break;
150 0 : case 13: panose.fontStyle = FontStyle::Oblique; break;
151 0 : case 14: panose.fontStyle = FontStyle::Oblique; break;
152 50 : default: break;
153 : }
154 :
155 50 : if (panose.fontWeight != sfnt.fontWeight) {
156 50 : if (panose.fontWeight != FontWeight::Normal) {
157 50 : sfnt.fontWeight = panose.fontWeight;
158 : }
159 : }
160 :
161 50 : if (panose.fontStretch != sfnt.fontStretch) {
162 0 : if (panose.fontStretch != FontStretch::Normal) {
163 0 : sfnt.fontStretch = panose.fontStretch;
164 : }
165 : }
166 :
167 50 : if (sfnt.fontStyle == FontStyle::Normal && panose.fontStyle != sfnt.fontStyle) {
168 0 : sfnt.fontStyle = panose.fontStyle;
169 : }
170 : }
171 : } else {
172 0 : log::error("font::FontFaceData", "No preconfigured style or OS/2 table for font: ", _name);
173 : }
174 50 : return sfnt;
175 : }
176 :
177 200 : void FontFaceData::inspectVariableFont(FontLayoutParameters params, FT_Library lib, FT_Face face) {
178 200 : FT_MM_Var *masters = nullptr;
179 200 : FT_Get_MM_Var(face, &masters);
180 :
181 200 : _variations.weight = params.fontWeight;
182 200 : _variations.stretch = params.fontStretch;
183 200 : _variations.opticalSize = uint32_t(0);
184 200 : _variations.italic = uint32_t(params.fontStyle == FontStyle::Italic ? 1 : 0);
185 200 : _variations.slant = params.fontStyle;
186 200 : _variations.grade = params.fontGrade;
187 :
188 200 : if (masters) {
189 900 : for (FT_UInt i = 0; i < masters->num_axis; ++ i) {
190 750 : auto tag = masters->axis[i].tag;
191 750 : if (tag == getAxisTag("wght")) {
192 150 : _variations.axisMask |= FontVariableAxis::Weight;
193 150 : _variations.weight.min = FontWeight(masters->axis[i].minimum >> 16);
194 150 : _variations.weight.max = FontWeight(masters->axis[i].maximum >> 16);
195 600 : } else if (tag == getAxisTag("wdth")) {
196 50 : _variations.axisMask |= FontVariableAxis::Width;
197 50 : _variations.stretch.min = FontStretch(masters->axis[i].minimum >> 15);
198 50 : _variations.stretch.max = FontStretch(masters->axis[i].maximum >> 15);
199 550 : } else if (tag == getAxisTag("ital")) {
200 0 : _variations.axisMask |= FontVariableAxis::Italic;
201 0 : _variations.italic.min = masters->axis[i].minimum;
202 0 : _variations.italic.max = masters->axis[i].maximum;
203 550 : } else if (tag == getAxisTag("slnt")) {
204 50 : _variations.axisMask |= FontVariableAxis::Slant;
205 50 : _variations.slant.min = FontStyle(masters->axis[i].minimum >> 10);
206 50 : _variations.slant.max = FontStyle(masters->axis[i].maximum >> 10);
207 500 : } else if (tag == getAxisTag("opsz")) {
208 50 : _variations.axisMask |= FontVariableAxis::OpticalSize;
209 50 : _variations.opticalSize.min = masters->axis[i].minimum;
210 50 : _variations.opticalSize.max = masters->axis[i].maximum;
211 450 : } else if (tag == getAxisTag("GRAD")) {
212 50 : _variations.axisMask |= FontVariableAxis::Grade;
213 50 : _variations.grade.min = FontGrade(masters->axis[i].minimum >> 16);
214 50 : _variations.grade.max = FontGrade(masters->axis[i].maximum >> 16);
215 : }
216 : /* std::cout << "Variable axis: [" << masters->axis[i].tag << "] "
217 : << (masters->axis[i].minimum >> 16) << " - " << (masters->axis[i].maximum >> 16)
218 : << " def: "<< (masters->axis[i].def >> 16) << "\n"; */
219 : }
220 :
221 150 : FT_Done_MM_Var(lib, masters);
222 : }
223 :
224 200 : _params = params;
225 200 : }
226 :
227 6916 : BytesView FontFaceData::getView() const {
228 6916 : return _view;
229 : }
230 :
231 5724 : FontSpecializationVector FontFaceData::getSpecialization(const FontSpecializationVector &vec) const {
232 5724 : return _variations.getSpecialization(vec);
233 : }
234 :
235 13432 : FontFaceObject::~FontFaceObject() { }
236 :
237 6716 : bool FontFaceObject::init(StringView name, const Rc<FontFaceData> &data, FT_Library lib, FT_Face face, const FontSpecializationVector &spec, uint16_t id) {
238 6716 : auto err = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
239 6716 : if (err != FT_Err_Ok) {
240 0 : return false;
241 : }
242 :
243 6716 : auto &var = data->getVariations();
244 6716 : if (var.axisMask != FontVariableAxis::None) {
245 5870 : Vector<FT_Fixed> vector;
246 :
247 : FT_MM_Var *masters;
248 5870 : FT_Get_MM_Var(face, &masters);
249 :
250 5870 : if (masters) {
251 80380 : for (FT_UInt i = 0; i < masters->num_axis; ++ i) {
252 74510 : auto tag = masters->axis[i].tag;
253 74510 : if (tag == getAxisTag("wght")) {
254 5870 : vector.emplace_back(var.weight.clamp(spec.fontWeight).get() << 16);
255 68640 : } else if (tag == getAxisTag("wdth")) {
256 5720 : vector.emplace_back(var.stretch.clamp(spec.fontStretch).get() << 15);
257 62920 : } else if (tag == getAxisTag("ital")) {
258 0 : if (spec.fontStyle.get() == FontStyle::Normal.get()) {
259 0 : vector.emplace_back(var.italic.min);
260 0 : } else if (spec.fontStyle.get() == FontStyle::Italic.get()) {
261 0 : vector.emplace_back(var.italic.max);
262 : } else {
263 0 : if ((var.axisMask & FontVariableAxis::Slant) != FontVariableAxis::None) {
264 0 : vector.emplace_back(var.italic.min); // has true oblique
265 : } else {
266 0 : vector.emplace_back(var.italic.max);
267 : }
268 : }
269 62920 : } else if (tag == getAxisTag("slnt")) {
270 5720 : if (spec.fontStyle.get() == FontStyle::Normal.get()) {
271 1865 : vector.emplace_back(0);
272 3855 : } else if (spec.fontStyle.get() == FontStyle::Italic.get()) {
273 0 : if ((var.axisMask & FontVariableAxis::Italic) != FontVariableAxis::None) {
274 0 : vector.emplace_back(masters->axis[i].def);
275 : } else {
276 0 : vector.emplace_back(var.slant.clamp(FontStyle::Oblique).get() << 10);
277 : }
278 : } else {
279 3855 : vector.emplace_back(var.slant.clamp(spec.fontStyle).get() << 10);
280 : }
281 57200 : } else if (tag == getAxisTag("opsz")) {
282 5720 : auto opticalSize = uint32_t(floorf(spec.fontSize.get() / spec.density)) << 16;
283 5720 : vector.emplace_back(var.opticalSize.clamp(opticalSize));
284 51480 : } else if (tag == getAxisTag("GRAD")) {
285 5720 : vector.emplace_back(var.grade.clamp(spec.fontGrade).get() << 16);
286 : } else {
287 45760 : vector.emplace_back(masters->axis[i].def);
288 : }
289 : }
290 :
291 5870 : FT_Set_Var_Design_Coordinates(face, vector.size(), vector.data());
292 5870 : FT_Done_MM_Var(lib, masters);
293 : }
294 5870 : }
295 :
296 : // set the requested font size
297 6716 : err = FT_Set_Pixel_Sizes(face, spec.fontSize.get(), spec.fontSize.get());
298 6716 : if (err != FT_Err_Ok) {
299 0 : return false;
300 : }
301 :
302 6716 : _spec = spec;
303 6716 : _metrics.size = spec.fontSize.get();
304 6716 : _metrics.height = face->size->metrics.height >> 6;
305 6716 : _metrics.ascender = face->size->metrics.ascender >> 6;
306 6716 : _metrics.descender = face->size->metrics.descender >> 6;
307 6716 : _metrics.underlinePosition = face->underline_position >> 6;
308 6716 : _metrics.underlineThickness = face->underline_thickness >> 6;
309 :
310 6716 : _name = name.str<Interface>();
311 6716 : _id = id;
312 6716 : _data = data;
313 6716 : _face = face;
314 :
315 6716 : return true;
316 : }
317 :
318 0 : bool FontFaceObject::acquireTexture(char32_t theChar, const Callback<void(const CharTexture &)> &cb) {
319 0 : std::unique_lock lock(_faceMutex);
320 :
321 0 : return acquireTextureUnsafe(theChar, cb);
322 0 : }
323 :
324 149310 : bool FontFaceObject::acquireTextureUnsafe(char32_t theChar, const Callback<void(const CharTexture &)> &cb) {
325 149310 : int glyph_index = FT_Get_Char_Index(_face, theChar);
326 149701 : if (!glyph_index) {
327 0 : return false;
328 : }
329 :
330 149701 : auto err = FT_Load_Glyph(_face, glyph_index, FT_LOAD_DEFAULT | FT_LOAD_RENDER);
331 150152 : if (err != FT_Err_Ok) {
332 0 : return false;
333 : }
334 :
335 : //log::format("Texture", "%s: %d '%s'", data.layout->getName().c_str(), theChar.charID, string::toUtf8(theChar.charID).c_str());
336 :
337 150152 : if (_face->glyph->bitmap.buffer != nullptr) {
338 150152 : if (_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
339 0 : cb(CharTexture{theChar,
340 150158 : static_cast<int16_t>(_face->glyph->metrics.horiBearingX >> 6),
341 150158 : static_cast<int16_t>(- (_face->glyph->metrics.horiBearingY >> 6)),
342 150158 : static_cast<uint16_t>(_face->glyph->metrics.width >> 6),
343 150158 : static_cast<uint16_t>(_face->glyph->metrics.height >> 6),
344 150158 : static_cast<uint16_t>(_face->glyph->bitmap.width),
345 150158 : static_cast<uint16_t>(_face->glyph->bitmap.rows),
346 150158 : _face->glyph->bitmap.pitch ? int16_t(_face->glyph->bitmap.pitch) : int16_t(_face->glyph->bitmap.width),
347 150158 : _id,
348 150158 : _face->glyph->bitmap.buffer
349 : });
350 150303 : return true;
351 : }
352 : } else {
353 0 : if (!chars::isspace(theChar) && theChar != char16_t(0x0A)) {
354 0 : log::format(log::Warn, "Font", "error: no bitmap for (%d) '%s'", theChar, string::toUtf8<Interface>(theChar).data());
355 : }
356 : }
357 0 : return false;
358 : }
359 :
360 30366 : bool FontFaceObject::addChars(const Vector<char32_t> &chars, bool expand, Vector<char32_t> *failed) {
361 30366 : bool updated = false;
362 30366 : uint32_t mask = 0;
363 :
364 : if constexpr (!config::FontPreloadGroups) {
365 30366 : expand = false;
366 : }
367 :
368 : // for some chars, we add full group, not only requested char
369 537488 : for (auto &c : chars) {
370 507122 : if (expand) {
371 0 : auto g = getCharGroupForChar(c);
372 0 : if (g != CharGroupId::None) {
373 0 : if ((mask & toInt(g)) == 0) {
374 0 : mask |= toInt(g);
375 0 : if (addCharGroup(g, failed)) {
376 0 : updated = true;
377 : }
378 0 : continue;
379 : }
380 : }
381 : }
382 :
383 507122 : if (!addChar(c, updated) && failed) {
384 25306 : mem_std::emplace_ordered(*failed, c);
385 : }
386 : }
387 30366 : return updated;
388 : }
389 :
390 0 : bool FontFaceObject::addCharGroup(CharGroupId g, Vector<char32_t> *failed) {
391 0 : bool updated = false;
392 : using namespace chars;
393 0 : auto f = [&, this] (char32_t c) {
394 0 : if (!addChar(c, updated) && failed) {
395 0 : mem_std::emplace_ordered(*failed, c);
396 : }
397 0 : };
398 :
399 0 : switch (g) {
400 0 : case CharGroupId::Numbers: CharGroup<char32_t, CharGroupId::Numbers>::foreach(f); break;
401 0 : case CharGroupId::Latin: CharGroup<char32_t, CharGroupId::Latin>::foreach(f); break;
402 0 : case CharGroupId::Cyrillic: CharGroup<char32_t, CharGroupId::Cyrillic>::foreach(f); break;
403 0 : case CharGroupId::Currency: CharGroup<char32_t, CharGroupId::Currency>::foreach(f); break;
404 0 : case CharGroupId::GreekBasic: CharGroup<char32_t, CharGroupId::GreekBasic>::foreach(f); break;
405 0 : case CharGroupId::Math: CharGroup<char32_t, CharGroupId::Math>::foreach(f); break;
406 0 : case CharGroupId::TextPunctuation: CharGroup<char32_t, CharGroupId::TextPunctuation>::foreach(f); break;
407 0 : default: break;
408 : }
409 0 : return updated;
410 : }
411 :
412 721805 : bool FontFaceObject::addRequiredChar(char32_t ch) {
413 721805 : std::unique_lock lock(_requiredMutex);
414 1443610 : return mem_std::emplace_ordered(_required, ch);
415 721805 : }
416 :
417 8820 : auto FontFaceObject::getRequiredChars() const -> Vector<char32_t> {
418 8820 : std::unique_lock lock(_requiredMutex);
419 17640 : return _required;
420 8820 : }
421 :
422 1572398 : CharShape FontFaceObject::getChar(char16_t c) const {
423 1572398 : std::shared_lock lock(_charsMutex);
424 1572836 : auto l = _chars.get(c);
425 1572604 : if (l && l->charID == c) {
426 1572774 : return *l;
427 : }
428 0 : return CharShape{0};
429 1572604 : }
430 :
431 728488 : int16_t FontFaceObject::getKerningAmount(char16_t first, char16_t second) const {
432 728488 : std::shared_lock lock(_charsMutex);
433 728488 : uint32_t key = (first << 16) | (second & 0xffff);
434 728488 : auto it = _kerning.find(key);
435 728488 : if (it != _kerning.end()) {
436 0 : return it->second;
437 : }
438 728488 : return 0;
439 728488 : }
440 :
441 507122 : bool FontFaceObject::addChar(char16_t theChar, bool &updated) {
442 : do {
443 : // try to get char with shared lock
444 507122 : std::shared_lock charsLock(_charsMutex);
445 507122 : auto value = _chars.get(theChar);
446 507122 : if (value) {
447 503988 : if (value->charID == theChar) {
448 405427 : return true;
449 98561 : } else if (value->charID == char16_t(0xFFFF)) {
450 23564 : return false;
451 : }
452 : }
453 507122 : } while (0);
454 :
455 78131 : std::unique_lock charsUniqueLock(_charsMutex);
456 78131 : auto value = _chars.get(theChar);
457 78131 : if (value) {
458 74997 : if (value->charID == theChar) {
459 0 : return true;
460 74997 : } else if (value->charID == char16_t(0xFFFF)) {
461 0 : return false;
462 : }
463 : }
464 :
465 78131 : std::unique_lock faceLock(_faceMutex);
466 78131 : FT_UInt cIdx = FT_Get_Char_Index(_face, theChar);
467 78131 : if (!cIdx) {
468 1742 : _chars.emplace(theChar, CharShape{char16_t(0xFFFF)});
469 1742 : return false;
470 : }
471 :
472 : FT_Fixed advance;
473 76389 : auto err = FT_Get_Advance(_face, cIdx, FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP, &advance);
474 76389 : if (err != FT_Err_Ok) {
475 0 : _chars.emplace(theChar, CharShape{char16_t(0xFFFF)});
476 0 : return false;
477 : }
478 :
479 : /*auto err = FT_Load_Glyph(_face, cIdx, FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP);
480 : if (err != FT_Err_Ok) {
481 : _chars.emplace(theChar, CharLayout{char16_t(0xFFFF)});
482 : return false;
483 : }*/
484 :
485 : // store result in the passed rectangle
486 0 : _chars.emplace(theChar, CharShape{theChar,
487 : //static_cast<int16_t>(_face->glyph->metrics.horiBearingX >> 6),
488 : //static_cast<int16_t>(- (_face->glyph->metrics.horiBearingY >> 6)),
489 76389 : static_cast<uint16_t>(advance >> 16),
490 : //static_cast<uint16_t>(_face->glyph->metrics.width >> 6),
491 : //static_cast<uint16_t>(_face->glyph->metrics.height >> 6)
492 : });
493 :
494 76389 : if (!chars::isspace(theChar)) {
495 75246 : updated = true;
496 : }
497 :
498 76389 : if (FT_HAS_KERNING(_face)) {
499 0 : _chars.foreach([&, this] (const CharShape & it) {
500 0 : if (it.charID == 0 || it.charID == char16_t(0xFFFF)) {
501 0 : return;
502 : }
503 :
504 0 : if (it.charID != theChar) {
505 : FT_Vector kerning;
506 0 : auto err = FT_Get_Kerning(_face, cIdx, cIdx, FT_KERNING_DEFAULT, &kerning);
507 0 : if (err == FT_Err_Ok) {
508 0 : auto value = int16_t(kerning.x >> 6);
509 0 : if (value != 0) {
510 0 : _kerning.emplace(theChar << 16 | (it.charID & 0xffff), value);
511 : }
512 : }
513 : } else {
514 0 : auto kIdx = FT_Get_Char_Index(_face, it.charID);
515 :
516 : FT_Vector kerning;
517 0 : auto err = FT_Get_Kerning(_face, cIdx, kIdx, FT_KERNING_DEFAULT, &kerning);
518 0 : if (err == FT_Err_Ok) {
519 0 : auto value = int16_t(kerning.x >> 6);
520 0 : if (value != 0) {
521 0 : _kerning.emplace(theChar << 16 | (it.charID & 0xffff), value);
522 : }
523 : }
524 :
525 0 : err = FT_Get_Kerning(_face, kIdx, cIdx, FT_KERNING_DEFAULT, &kerning);
526 0 : if (err == FT_Err_Ok) {
527 0 : auto value = int16_t(kerning.x >> 6);
528 0 : if (value != 0) {
529 0 : _kerning.emplace(it.charID << 16 | (theChar & 0xffff), value);
530 : }
531 : }
532 : }
533 : });
534 : }
535 76389 : return true;
536 78131 : }
537 :
538 23025 : auto FontFaceSet::constructName(StringView family, const FontSpecializationVector &vec) -> String {
539 23025 : return FontParameters::getFontConfigName<Interface>(family, vec.fontSize, vec.fontStyle, vec.fontWeight, vec.fontStretch, vec.fontGrade, FontVariant::Normal, false);
540 : }
541 :
542 0 : bool FontFaceSet::init(String &&name, StringView family, FontSpecializationVector &&spec, Rc<FontFaceData> &&data, FontLibrary *c) {
543 0 : _name = move(name);
544 0 : _family = family.str<Interface>();
545 0 : _spec = move(spec);
546 0 : _sources.emplace_back(move(data));
547 0 : _library = c;
548 0 : _faces.resize(_sources.size(), nullptr);
549 0 : if (auto face = _library->openFontFace(_sources.front(), _spec)) {
550 0 : _faces[0] = face;
551 0 : _metrics = _faces.front()->getMetrics();
552 0 : }
553 0 : return true;
554 : }
555 :
556 1374 : bool FontFaceSet::init(String &&name, StringView family, FontSpecializationVector &&spec, Vector<Rc<FontFaceData>> &&data, FontLibrary *c) {
557 1374 : _name = move(name);
558 1374 : _family = family.str<Interface>();
559 1374 : _spec = move(spec);
560 1374 : _sources = move(data);
561 1374 : _faces.resize(_sources.size(), nullptr);
562 1374 : _library = c;
563 1374 : if (auto face = _library->openFontFace(_sources.front(), _spec)) {
564 1374 : _faces[0] = face;
565 1374 : _metrics = _faces.front()->getMetrics();
566 1374 : }
567 1374 : return true;
568 : }
569 :
570 20163 : void FontFaceSet::touch(uint64_t clock, bool persistent) {
571 20163 : _accessTime = clock;
572 20163 : _persistent = persistent;
573 20163 : }
574 :
575 17713 : bool FontFaceSet::addString(const CharVector &str) {
576 17713 : Vector<char32_t> failed;
577 35426 : return addString(str, failed);
578 17713 : }
579 :
580 17713 : bool FontFaceSet::addString(const CharVector &str, Vector<char32_t> &failed) {
581 17713 : std::shared_lock sharedLock(_mutex);
582 :
583 17713 : bool shouldOpenFonts = false;
584 17713 : bool updated = false;
585 17713 : size_t i = 0;
586 :
587 42148 : for (auto &it : _faces) {
588 30366 : if (i == 0) {
589 17713 : if (it->addChars(str.chars, i == 0, &failed)) {
590 2414 : updated = true;
591 : }
592 : } else {
593 12653 : if (it == nullptr) {
594 871 : shouldOpenFonts = true;
595 871 : break;
596 : }
597 :
598 11782 : auto tmp = move(failed);
599 11782 : failed.clear();
600 :
601 11782 : if (it->addChars(tmp, i == 0, &failed)) {
602 0 : updated = true;
603 : }
604 11782 : }
605 :
606 29495 : if (failed.empty()) {
607 5060 : break;
608 : }
609 :
610 24435 : ++ i;
611 : }
612 :
613 17713 : if (shouldOpenFonts) {
614 871 : sharedLock.unlock();
615 871 : std::unique_lock lock(_mutex);
616 :
617 1742 : for (; i < _faces.size(); ++ i) {
618 871 : if (_faces[i] == nullptr) {
619 871 : _faces[i] = _library->openFontFace(_sources[i], _spec);
620 : }
621 :
622 871 : auto tmp = move(failed);
623 871 : failed.clear();
624 :
625 871 : if (_faces[i]->addChars(tmp, i == 0, &failed)) {
626 0 : updated = true;
627 : }
628 :
629 871 : if (failed.empty()) {
630 0 : break;
631 : }
632 871 : }
633 871 : }
634 :
635 17713 : return updated;
636 17713 : }
637 :
638 74112 : uint16_t FontFaceSet::getFontHeight() const {
639 74112 : return _metrics.height;
640 : }
641 :
642 745946 : int16_t FontFaceSet::getKerningAmount(char16_t first, char16_t second, uint16_t face) const {
643 745946 : std::shared_lock lock(_mutex);
644 777240 : for (auto &it : _faces) {
645 763404 : if (it) {
646 759782 : if (it->getId() == face) {
647 732110 : return it->getKerningAmount(first, second);
648 : }
649 : } else {
650 3622 : return 0;
651 : }
652 : }
653 13836 : return 0;
654 745946 : }
655 :
656 33634 : Metrics FontFaceSet::getMetrics() const {
657 33634 : return _metrics;
658 : }
659 :
660 1572160 : CharShape FontFaceSet::getChar(char16_t ch, uint16_t &face) const {
661 1572160 : std::shared_lock lock(_mutex);
662 1572798 : for (auto &it : _faces) {
663 1572615 : auto l = it->getChar(ch);
664 1572547 : if (l.charID != 0) {
665 1572547 : face = it->getId();
666 1572595 : return l;
667 : }
668 : }
669 0 : return CharShape();
670 1572595 : }
671 :
672 15886 : bool FontFaceSet::addTextureChars(SpanView<CharLayoutData> chars) const {
673 15886 : std::shared_lock lock(_mutex);
674 :
675 15886 : bool ret = false;
676 878373 : for (auto &it : chars) {
677 862487 : if (chars::isspace(it.charID) || it.charID == char16_t(0x0A) || it.charID == char16_t(0x00AD)) {
678 140682 : continue;
679 : }
680 :
681 2021961 : for (auto &f : _faces) {
682 1371883 : if (f && f->getId() == it.face) {
683 721805 : if (f->addRequiredChar(it.charID)) {
684 71727 : ++ _texturesCount;
685 71727 : ret = true;
686 71727 : break;
687 : }
688 : }
689 : }
690 : }
691 15886 : return ret;
692 15886 : }
693 :
694 5539 : auto FontFaceSet::getFaces() const -> const Vector<Rc<FontFaceObject>> & {
695 5539 : return _faces;
696 : }
697 :
698 0 : size_t FontFaceSet::getFaceCount() const {
699 0 : return _sources.size();
700 : }
701 :
702 0 : Rc<FontFaceData> FontFaceSet::getSource(size_t idx) const {
703 0 : if (idx < _sources.size()) {
704 0 : return _sources[idx];
705 : }
706 0 : return nullptr;
707 : }
708 :
709 : }
|