• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkBitmap.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkData.h"
11 #include "include/core/SkFontMetrics.h"
12 #include "include/core/SkPath.h"
13 #include "include/core/SkStream.h"
14 #include "include/core/SkString.h"
15 #include "include/private/SkColorData.h"
16 #include "include/private/SkMalloc.h"
17 #include "include/private/SkMutex.h"
18 #include "include/private/SkTPin.h"
19 #include "include/private/SkTemplates.h"
20 #include "include/private/SkTo.h"
21 #include "src/core/SkAdvancedTypefaceMetrics.h"
22 #include "src/core/SkDescriptor.h"
23 #include "src/core/SkFDot6.h"
24 #include "src/core/SkFontDescriptor.h"
25 #include "src/core/SkGlyph.h"
26 #include "src/core/SkMask.h"
27 #include "src/core/SkMaskGamma.h"
28 #include "src/core/SkScalerContext.h"
29 #include "src/core/SkTSearch.h"
30 #include "src/ports/SkFontHost_FreeType_common.h"
31 #include "src/sfnt/SkOTUtils.h"
32 #include "src/utils/SkCallableTraits.h"
33 #include "src/utils/SkMatrix22.h"
34 
35 #include <memory>
36 #include <tuple>
37 
38 #include <ft2build.h>
39 #include <freetype/ftadvanc.h>
40 #include <freetype/ftimage.h>
41 #include <freetype/ftbitmap.h>
42 #ifdef FT_COLOR_H  // 2.10.0
43 #   include <freetype/ftcolor.h>
44 #endif
45 #include <freetype/freetype.h>
46 #include <freetype/ftlcdfil.h>
47 #include <freetype/ftmodapi.h>
48 #include <freetype/ftmm.h>
49 #include <freetype/ftoutln.h>
50 #include <freetype/ftsizes.h>
51 #include <freetype/ftsystem.h>
52 #include <freetype/tttables.h>
53 #include <freetype/t1tables.h>
54 #include <freetype/ftfntfmt.h>
55 #ifdef OHOS_SUPPORT
56 #include <freetype/ftsnames.h>
57 #include <freetype/ttnameid.h>
58 #include <securec.h>
59 #endif
60 
61 // SK_FREETYPE_MINIMUM_RUNTIME_VERSION 0x<major><minor><patch><flags>
62 // Flag SK_FREETYPE_DLOPEN: also try dlopen to get newer features.
63 #define SK_FREETYPE_DLOPEN (0x1)
64 #ifndef SK_FREETYPE_MINIMUM_RUNTIME_VERSION
65 #  if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) || defined (SK_BUILD_FOR_GOOGLE3)
66 #    define SK_FREETYPE_MINIMUM_RUNTIME_VERSION (((FREETYPE_MAJOR) << 24) | ((FREETYPE_MINOR) << 16) | ((FREETYPE_PATCH) << 8))
67 #  else
68 #    define SK_FREETYPE_MINIMUM_RUNTIME_VERSION ((2 << 24) | (8 << 16) | (1 << 8) | (SK_FREETYPE_DLOPEN))
69 #  endif
70 #endif
71 #if SK_FREETYPE_MINIMUM_RUNTIME_VERSION & SK_FREETYPE_DLOPEN
72 #  include <dlfcn.h>
73 #endif
74 
75 //#define ENABLE_GLYPH_SPEW     // for tracing calls
76 //#define DUMP_STRIKE_CREATION
77 //#define SK_FONTHOST_FREETYPE_RUNTIME_VERSION
78 //#define SK_GAMMA_APPLY_TO_A8
79 
80 #if 1
81     #define LOG_INFO(...)
82 #else
83     #define LOG_INFO SkDEBUGF
84 #endif
85 
isLCD(const SkScalerContextRec & rec)86 static bool isLCD(const SkScalerContextRec& rec) {
87     return SkMask::kLCD16_Format == rec.fMaskFormat;
88 }
89 
SkFT_FixedToScalar(FT_Fixed x)90 static SkScalar SkFT_FixedToScalar(FT_Fixed x) {
91   return SkFixedToScalar(x);
92 }
93 
94 using SkUniqueFTFace =
95         std::unique_ptr<FT_FaceRec, SkFunctionWrapper<decltype(FT_Done_Face), FT_Done_Face>>;
96 
97 //////////////////////////////////////////////////////////////////////////
98 
99 using FT_Alloc_size_t = SkCallableTraits<FT_Alloc_Func>::argument<1>::type;
100 static_assert(std::is_same<FT_Alloc_size_t, long  >::value ||
101               std::is_same<FT_Alloc_size_t, size_t>::value,"");
102 
103 extern "C" {
sk_ft_alloc(FT_Memory,FT_Alloc_size_t size)104     static void* sk_ft_alloc(FT_Memory, FT_Alloc_size_t size) {
105         return sk_malloc_throw(size);
106     }
sk_ft_free(FT_Memory,void * block)107     static void sk_ft_free(FT_Memory, void* block) {
108         sk_free(block);
109     }
sk_ft_realloc(FT_Memory,FT_Alloc_size_t cur_size,FT_Alloc_size_t new_size,void * block)110     static void* sk_ft_realloc(FT_Memory, FT_Alloc_size_t cur_size,
111                                           FT_Alloc_size_t new_size, void* block) {
112         return sk_realloc_throw(block, new_size);
113     }
114 };
115 FT_MemoryRec_ gFTMemory = { nullptr, sk_ft_alloc, sk_ft_free, sk_ft_realloc };
116 
117 class FreeTypeLibrary : SkNoncopyable {
118 public:
FreeTypeLibrary()119     FreeTypeLibrary() : fLibrary(nullptr) {
120         if (FT_New_Library(&gFTMemory, &fLibrary)) {
121             return;
122         }
123         FT_Add_Default_Modules(fLibrary);
124         FT_Set_Default_Properties(fLibrary);
125 
126         // Subpixel anti-aliasing may be unfiltered until the LCD filter is set.
127         // Newer versions may still need this, so this test with side effects must come first.
128         // The default has changed over time, so this doesn't mean the same thing to all users.
129         FT_Library_SetLcdFilter(fLibrary, FT_LCD_FILTER_DEFAULT);
130     }
~FreeTypeLibrary()131     ~FreeTypeLibrary() {
132         if (fLibrary) {
133             FT_Done_Library(fLibrary);
134         }
135     }
136 
library()137     FT_Library library() { return fLibrary; }
138 
139 private:
140     FT_Library fLibrary;
141 
142     // FT_Library_SetLcdFilterWeights 2.4.0
143     // FT_LOAD_COLOR 2.5.0
144     // FT_Pixel_Mode::FT_PIXEL_MODE_BGRA 2.5.0
145     // Thread safety in 2.6.0
146     // freetype/ftfntfmt.h (rename) 2.6.0
147     // Direct header inclusion 2.6.1
148     // FT_Get_Var_Design_Coordinates 2.7.1
149     // FT_LOAD_BITMAP_METRICS_ONLY 2.7.1
150     // FT_Set_Default_Properties 2.7.2
151     // The 'light' hinting is vertical only from 2.8.0
152     // FT_Get_Var_Axis_Flags 2.8.1
153     // FT_VAR_AXIS_FLAG_HIDDEN was introduced in FreeType 2.8.1
154     // --------------------
155     // FT_Done_MM_Var 2.9.0 (Currenty setting ft_free to a known allocator.)
156     // freetype/ftcolor.h 2.10.0 (Currently assuming if compiled with FT_COLOR_H runtime available.)
157 
158     // Ubuntu 18.04       2.8.1
159     // Debian 10          2.9.1
160     // openSUSE Leap 15.2 2.10.1
161     // Fedora 32          2.10.4
162     // RHEL 8             2.9.1
163 };
164 
f_t_mutex()165 static SkMutex& f_t_mutex() {
166     static SkMutex& mutex = *(new SkMutex);
167     return mutex;
168 }
169 
170 static FreeTypeLibrary* gFTLibrary;
171 
172 ///////////////////////////////////////////////////////////////////////////
173 
174 class SkTypeface_FreeType::FaceRec {
175 public:
176     SkUniqueFTFace fFace;
177     FT_StreamRec fFTStream;
178     std::unique_ptr<SkStreamAsset> fSkStream;
179 
180     static std::unique_ptr<FaceRec> Make(const SkTypeface_FreeType* typeface);
181     ~FaceRec();
182 
183 private:
184     FaceRec(std::unique_ptr<SkStreamAsset> stream);
185     void setupAxes(const SkFontData& data);
186 
187     // Private to ref_ft_library and unref_ft_library
188     static int gFTCount;
189 
190     // Caller must lock f_t_mutex() before calling this function.
ref_ft_library()191     static bool ref_ft_library() {
192         f_t_mutex().assertHeld();
193         SkASSERT(gFTCount >= 0);
194 
195         if (0 == gFTCount) {
196             SkASSERT(nullptr == gFTLibrary);
197             gFTLibrary = new FreeTypeLibrary;
198         }
199         ++gFTCount;
200         return gFTLibrary->library();
201     }
202 
203     // Caller must lock f_t_mutex() before calling this function.
unref_ft_library()204     static void unref_ft_library() {
205         f_t_mutex().assertHeld();
206         SkASSERT(gFTCount > 0);
207 
208         --gFTCount;
209         if (0 == gFTCount) {
210             SkASSERT(nullptr != gFTLibrary);
211             delete gFTLibrary;
212             SkDEBUGCODE(gFTLibrary = nullptr;)
213         }
214     }
215 };
216 int SkTypeface_FreeType::FaceRec::gFTCount;
217 
218 extern "C" {
sk_ft_stream_io(FT_Stream ftStream,unsigned long offset,unsigned char * buffer,unsigned long count)219     static unsigned long sk_ft_stream_io(FT_Stream ftStream,
220                                          unsigned long offset,
221                                          unsigned char* buffer,
222                                          unsigned long count)
223     {
224         SkStreamAsset* stream = static_cast<SkStreamAsset*>(ftStream->descriptor.pointer);
225 
226         if (count) {
227             if (!stream->seek(offset)) {
228                 return 0;
229             }
230             count = stream->read(buffer, count);
231         }
232         return count;
233     }
234 
sk_ft_stream_close(FT_Stream)235     static void sk_ft_stream_close(FT_Stream) {}
236 }
237 
FaceRec(std::unique_ptr<SkStreamAsset> stream)238 SkTypeface_FreeType::FaceRec::FaceRec(std::unique_ptr<SkStreamAsset> stream)
239         : fSkStream(std::move(stream))
240 {
241     sk_bzero(&fFTStream, sizeof(fFTStream));
242     fFTStream.size = fSkStream->getLength();
243     fFTStream.descriptor.pointer = fSkStream.get();
244     fFTStream.read  = sk_ft_stream_io;
245     fFTStream.close = sk_ft_stream_close;
246 
247     f_t_mutex().assertHeld();
248     ref_ft_library();
249 }
250 
~FaceRec()251 SkTypeface_FreeType::FaceRec::~FaceRec() {
252     f_t_mutex().assertHeld();
253     fFace.reset(); // Must release face before the library, the library frees existing faces.
254     unref_ft_library();
255 }
256 
setupAxes(const SkFontData & data)257 void SkTypeface_FreeType::FaceRec::setupAxes(const SkFontData& data) {
258     if (!(fFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
259         return;
260     }
261 
262     // If a named variation is requested, don't overwrite the named variation's position.
263     if (data.getIndex() > 0xFFFF) {
264         return;
265     }
266 
267     SkDEBUGCODE(
268         FT_MM_Var* variations = nullptr;
269         if (FT_Get_MM_Var(fFace.get(), &variations)) {
270             LOG_INFO("INFO: font %s claims variations, but none found.\n",
271                      rec->fFace->family_name);
272             return;
273         }
274         SkAutoFree autoFreeVariations(variations);
275 
276         if (static_cast<FT_UInt>(data.getAxisCount()) != variations->num_axis) {
277             LOG_INFO("INFO: font %s has %d variations, but %d were specified.\n",
278                      rec->fFace->family_name, variations->num_axis, data.getAxisCount());
279             return;
280         }
281     )
282 
283     SkAutoSTMalloc<4, FT_Fixed> coords(data.getAxisCount());
284     for (int i = 0; i < data.getAxisCount(); ++i) {
285         coords[i] = data.getAxis()[i];
286     }
287     if (FT_Set_Var_Design_Coordinates(fFace.get(), data.getAxisCount(), coords.get())) {
288         LOG_INFO("INFO: font %s has variations, but specified variations could not be set.\n",
289                  rec->fFace->family_name);
290         return;
291     }
292 }
293 
294 // Will return nullptr on failure
295 // Caller must lock f_t_mutex() before calling this function.
296 std::unique_ptr<SkTypeface_FreeType::FaceRec>
Make(const SkTypeface_FreeType * typeface)297 SkTypeface_FreeType::FaceRec::Make(const SkTypeface_FreeType* typeface) {
298     f_t_mutex().assertHeld();
299 
300     std::unique_ptr<SkFontData> data = typeface->makeFontData();
301     if (nullptr == data || !data->hasStream()) {
302         return nullptr;
303     }
304 
305     std::unique_ptr<FaceRec> rec(new FaceRec(data->detachStream()));
306 
307     FT_Open_Args args;
308     memset(&args, 0, sizeof(args));
309     const void* memoryBase = rec->fSkStream->getMemoryBase();
310     if (memoryBase) {
311         args.flags = FT_OPEN_MEMORY;
312         args.memory_base = (const FT_Byte*)memoryBase;
313         args.memory_size = rec->fSkStream->getLength();
314     } else {
315         args.flags = FT_OPEN_STREAM;
316         args.stream = &rec->fFTStream;
317     }
318 
319     {
320         FT_Face rawFace;
321         FT_Error err = FT_Open_Face(gFTLibrary->library(), &args, data->getIndex(), &rawFace);
322         if (err) {
323             SK_TRACEFTR(err, "unable to open font '%x'", typeface->uniqueID());
324             return nullptr;
325         }
326         rec->fFace.reset(rawFace);
327     }
328     SkASSERT(rec->fFace);
329 
330     rec->setupAxes(*data);
331 
332     // FreeType will set the charmap to the "most unicode" cmap if it exists.
333     // If there are no unicode cmaps, the charmap is set to nullptr.
334     // However, "symbol" cmaps should also be considered "fallback unicode" cmaps
335     // because they are effectively private use area only (even if they aren't).
336     // This is the last on the fallback list at
337     // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html
338     if (!rec->fFace->charmap) {
339         FT_Select_Charmap(rec->fFace.get(), FT_ENCODING_MS_SYMBOL);
340     }
341 
342     return rec;
343 }
344 
345 class AutoFTAccess {
346 public:
AutoFTAccess(const SkTypeface_FreeType * tf)347     AutoFTAccess(const SkTypeface_FreeType* tf) : fFaceRec(nullptr) {
348         f_t_mutex().acquire();
349         fFaceRec = tf->getFaceRec();
350     }
351 
~AutoFTAccess()352     ~AutoFTAccess() {
353         f_t_mutex().release();
354     }
355 
face()356     FT_Face face() { return fFaceRec ? fFaceRec->fFace.get() : nullptr; }
357 
358 private:
359     SkTypeface_FreeType::FaceRec* fFaceRec;
360 };
361 
362 ///////////////////////////////////////////////////////////////////////////
363 
364 class SkScalerContext_FreeType : public SkScalerContext_FreeType_Base {
365 public:
366     SkScalerContext_FreeType(sk_sp<SkTypeface_FreeType>,
367                              const SkScalerContextEffects&,
368                              const SkDescriptor* desc);
369     ~SkScalerContext_FreeType() override;
370 
success() const371     bool success() const {
372         return fFTSize != nullptr && fFace != nullptr;
373     }
374 
375 protected:
376     bool generateAdvance(SkGlyph* glyph) override;
377     void generateMetrics(SkGlyph* glyph) override;
378     void generateImage(const SkGlyph& glyph) override;
379     bool generatePath(SkGlyphID glyphID, SkPath* path) override;
380     void generateFontMetrics(SkFontMetrics*) override;
381 
382 private:
383     SkTypeface_FreeType::FaceRec* fFaceRec; // Borrowed face from the typeface's FaceRec.
384     FT_Face   fFace;  // Borrowed face from fFaceRec.
385     FT_Size   fFTSize;  // The size to apply to the fFace.
386     FT_Int    fStrikeIndex; // The bitmap strike for the fFace (or -1 if none).
387 
388     /** The rest of the matrix after FreeType handles the size.
389      *  With outline font rasterization this is handled by FreeType with FT_Set_Transform.
390      *  With bitmap only fonts this matrix must be applied to scale the bitmap.
391      */
392     SkMatrix  fMatrix22Scalar;
393     /** Same as fMatrix22Scalar, but in FreeType units and space. */
394     FT_Matrix fMatrix22;
395     /** The actual size requested. */
396     SkVector  fScale;
397 
398     uint32_t  fLoadGlyphFlags;
399     bool      fDoLinearMetrics;
400     bool      fLCDIsVert;
401 
402     FT_Error setupSize();
403     void getBBoxForCurrentGlyph(const SkGlyph* glyph, FT_BBox* bbox,
404                                 bool snapToPixelBoundary = false);
405     bool getCBoxForLetter(char letter, FT_BBox* bbox);
406     // Caller must lock f_t_mutex() before calling this function.
407     void updateGlyphIfLCD(SkGlyph* glyph);
408     // Caller must lock f_t_mutex() before calling this function.
409     // update FreeType2 glyph slot with glyph emboldened
410     void emboldenIfNeeded(FT_Face face, FT_GlyphSlot glyph, SkGlyphID gid);
411     bool shouldSubpixelBitmap(const SkGlyph&, const SkMatrix&);
412 };
413 
414 ///////////////////////////////////////////////////////////////////////////
415 
canEmbed(FT_Face face)416 static bool canEmbed(FT_Face face) {
417     FT_UShort fsType = FT_Get_FSType_Flags(face);
418     return (fsType & (FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING |
419                       FT_FSTYPE_BITMAP_EMBEDDING_ONLY)) == 0;
420 }
421 
canSubset(FT_Face face)422 static bool canSubset(FT_Face face) {
423     FT_UShort fsType = FT_Get_FSType_Flags(face);
424     return (fsType & FT_FSTYPE_NO_SUBSETTING) == 0;
425 }
426 
get_font_type(FT_Face face)427 static SkAdvancedTypefaceMetrics::FontType get_font_type(FT_Face face) {
428     const char* fontType = FT_Get_X11_Font_Format(face);
429     static struct { const char* s; SkAdvancedTypefaceMetrics::FontType t; } values[] = {
430         { "Type 1",     SkAdvancedTypefaceMetrics::kType1_Font    },
431         { "CID Type 1", SkAdvancedTypefaceMetrics::kType1CID_Font },
432         { "CFF",        SkAdvancedTypefaceMetrics::kCFF_Font      },
433         { "TrueType",   SkAdvancedTypefaceMetrics::kTrueType_Font },
434     };
435     for(const auto& v : values) { if (strcmp(fontType, v.s) == 0) { return v.t; } }
436     return SkAdvancedTypefaceMetrics::kOther_Font;
437 }
438 
onGetAdvancedMetrics() const439 std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface_FreeType::onGetAdvancedMetrics() const {
440     AutoFTAccess fta(this);
441     FT_Face face = fta.face();
442     if (!face) {
443         return nullptr;
444     }
445 
446     std::unique_ptr<SkAdvancedTypefaceMetrics> info(new SkAdvancedTypefaceMetrics);
447     info->fPostScriptName.set(FT_Get_Postscript_Name(face));
448     info->fFontName = info->fPostScriptName;
449 
450     if (FT_HAS_MULTIPLE_MASTERS(face)) {
451         info->fFlags |= SkAdvancedTypefaceMetrics::kVariable_FontFlag;
452     }
453     if (!canEmbed(face)) {
454         info->fFlags |= SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag;
455     }
456     if (!canSubset(face)) {
457         info->fFlags |= SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag;
458     }
459 
460     info->fType = get_font_type(face);
461     info->fStyle = (SkAdvancedTypefaceMetrics::StyleFlags)0;
462     if (FT_IS_FIXED_WIDTH(face)) {
463         info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
464     }
465     if (face->style_flags & FT_STYLE_FLAG_ITALIC) {
466         info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
467     }
468 
469     PS_FontInfoRec psFontInfo;
470     TT_Postscript* postTable;
471     if (FT_Get_PS_Font_Info(face, &psFontInfo) == 0) {
472         info->fItalicAngle = psFontInfo.italic_angle;
473     } else if ((postTable = (TT_Postscript*)FT_Get_Sfnt_Table(face, ft_sfnt_post)) != nullptr) {
474         info->fItalicAngle = SkFixedFloorToInt(postTable->italicAngle);
475     } else {
476         info->fItalicAngle = 0;
477     }
478 
479     info->fAscent = face->ascender;
480     info->fDescent = face->descender;
481 
482     TT_PCLT* pcltTable;
483     TT_OS2* os2Table;
484     if ((pcltTable = (TT_PCLT*)FT_Get_Sfnt_Table(face, ft_sfnt_pclt)) != nullptr) {
485         info->fCapHeight = pcltTable->CapHeight;
486         uint8_t serif_style = pcltTable->SerifStyle & 0x3F;
487         if (2 <= serif_style && serif_style <= 6) {
488             info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
489         } else if (9 <= serif_style && serif_style <= 12) {
490             info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
491         }
492     } else if (((os2Table = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2)) != nullptr) &&
493                // sCapHeight is available only when version 2 or later.
494                os2Table->version != 0xFFFF &&
495                os2Table->version >= 2)
496     {
497         info->fCapHeight = os2Table->sCapHeight;
498     }
499     info->fBBox = SkIRect::MakeLTRB(face->bbox.xMin, face->bbox.yMax,
500                                     face->bbox.xMax, face->bbox.yMin);
501     return info;
502 }
503 
getGlyphToUnicodeMap(SkUnichar * dstArray) const504 void SkTypeface_FreeType::getGlyphToUnicodeMap(SkUnichar* dstArray) const {
505     AutoFTAccess fta(this);
506     FT_Face face = fta.face();
507     if (!face) {
508         return;
509     }
510 
511     FT_Long numGlyphs = face->num_glyphs;
512     if (!dstArray) { SkASSERT(numGlyphs == 0); }
513     sk_bzero(dstArray, sizeof(SkUnichar) * numGlyphs);
514 
515     FT_UInt glyphIndex;
516     SkUnichar charCode = FT_Get_First_Char(face, &glyphIndex);
517     while (glyphIndex) {
518         SkASSERT(glyphIndex < SkToUInt(numGlyphs));
519         // Use the first character that maps to this glyphID. https://crbug.com/359065
520         if (0 == dstArray[glyphIndex]) {
521             dstArray[glyphIndex] = charCode;
522         }
523         charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
524     }
525 }
526 
getPostScriptGlyphNames(SkString * dstArray) const527 void SkTypeface_FreeType::getPostScriptGlyphNames(SkString* dstArray) const {
528     AutoFTAccess fta(this);
529     FT_Face face = fta.face();
530     if (!face) {
531         return;
532     }
533 
534     FT_Long numGlyphs = face->num_glyphs;
535     if (!dstArray) { SkASSERT(numGlyphs == 0); }
536 
537     if (FT_HAS_GLYPH_NAMES(face)) {
538         for (int gID = 0; gID < numGlyphs; ++gID) {
539             char glyphName[128];  // PS limit for names is 127 bytes.
540             FT_Get_Glyph_Name(face, gID, glyphName, 128);
541             dstArray[gID] = glyphName;
542         }
543     }
544 }
545 
onGetPostScriptName(SkString * skPostScriptName) const546 bool SkTypeface_FreeType::onGetPostScriptName(SkString* skPostScriptName) const {
547     AutoFTAccess fta(this);
548     FT_Face face = fta.face();
549     if (!face) {
550         return false;
551     }
552 
553     const char* ftPostScriptName = FT_Get_Postscript_Name(face);
554     if (!ftPostScriptName) {
555         return false;
556     }
557     if (skPostScriptName) {
558         *skPostScriptName = ftPostScriptName;
559     }
560     return true;
561 }
562 
563 ///////////////////////////////////////////////////////////////////////////
564 
bothZero(SkScalar a,SkScalar b)565 static bool bothZero(SkScalar a, SkScalar b) {
566     return 0 == a && 0 == b;
567 }
568 
569 // returns false if there is any non-90-rotation or skew
isAxisAligned(const SkScalerContextRec & rec)570 static bool isAxisAligned(const SkScalerContextRec& rec) {
571     return 0 == rec.fPreSkewX &&
572            (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
573             bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
574 }
575 
onCreateScalerContext(const SkScalerContextEffects & effects,const SkDescriptor * desc) const576 std::unique_ptr<SkScalerContext> SkTypeface_FreeType::onCreateScalerContext(
577     const SkScalerContextEffects& effects, const SkDescriptor* desc) const
578 {
579     auto c = std::make_unique<SkScalerContext_FreeType>(
580             sk_ref_sp(const_cast<SkTypeface_FreeType*>(this)), effects, desc);
581     if (c->success()) {
582         return std::move(c);
583     }
584     return SkScalerContext::MakeEmpty(
585             sk_ref_sp(const_cast<SkTypeface_FreeType*>(this)), effects, desc);
586 }
587 
588 /** Copy the design variation coordinates into 'coordinates'.
589  *
590  *  @param coordinates the buffer into which to write the design variation coordinates.
591  *  @param coordinateCount the number of entries available through 'coordinates'.
592  *
593  *  @return The number of axes, or -1 if there is an error.
594  *  If 'coordinates != nullptr' and 'coordinateCount >= numAxes' then 'coordinates' will be
595  *  filled with the variation coordinates describing the position of this typeface in design
596  *  variation space. It is possible the number of axes can be retrieved but actual position
597  *  cannot.
598  */
GetVariationDesignPosition(AutoFTAccess & fta,SkFontArguments::VariationPosition::Coordinate coordinates[],int coordinateCount)599 static int GetVariationDesignPosition(AutoFTAccess& fta,
600     SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount)
601 {
602     FT_Face face = fta.face();
603     if (!face) {
604         return -1;
605     }
606 
607     if (!(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
608         return 0;
609     }
610 
611     FT_MM_Var* variations = nullptr;
612     if (FT_Get_MM_Var(face, &variations)) {
613         return -1;
614     }
615     SkAutoFree autoFreeVariations(variations);
616 
617     if (!coordinates || coordinateCount < SkToInt(variations->num_axis)) {
618         return variations->num_axis;
619     }
620 
621     SkAutoSTMalloc<4, FT_Fixed> coords(variations->num_axis);
622     if (FT_Get_Var_Design_Coordinates(face, variations->num_axis, coords.get())) {
623         return -1;
624     }
625     for (FT_UInt i = 0; i < variations->num_axis; ++i) {
626         coordinates[i].axis = variations->axis[i].tag;
627         coordinates[i].value = SkFixedToScalar(coords[i]);
628     }
629 
630     return variations->num_axis;
631 }
632 
cloneFontData(const SkFontArguments & args) const633 std::unique_ptr<SkFontData> SkTypeface_FreeType::cloneFontData(const SkFontArguments& args) const {
634     AutoFTAccess fta(this);
635     FT_Face face = fta.face();
636     if (!face) {
637         return nullptr;
638     }
639 
640     Scanner::AxisDefinitions axisDefinitions;
641     if (!Scanner::GetAxes(face, &axisDefinitions)) {
642         return nullptr;
643     }
644     int axisCount = axisDefinitions.count();
645 
646     SkAutoSTMalloc<4, SkFontArguments::VariationPosition::Coordinate> currentPosition(axisCount);
647     int currentAxisCount = GetVariationDesignPosition(fta, currentPosition, axisCount);
648 
649     SkString name;
650     SkAutoSTMalloc<4, SkFixed> axisValues(axisCount);
651     Scanner::computeAxisValues(axisDefinitions, args.getVariationDesignPosition(), axisValues, name,
652                                currentAxisCount == axisCount ? currentPosition.get() : nullptr);
653     int ttcIndex;
654     std::unique_ptr<SkStreamAsset> stream = this->openStream(&ttcIndex);
655     return std::make_unique<SkFontData>(std::move(stream), ttcIndex, axisValues.get(), axisCount);
656 }
657 
onFilterRec(SkScalerContextRec * rec) const658 void SkTypeface_FreeType::onFilterRec(SkScalerContextRec* rec) const {
659     //BOGUS: http://code.google.com/p/chromium/issues/detail?id=121119
660     //Cap the requested size as larger sizes give bogus values.
661     //Remove when http://code.google.com/p/skia/issues/detail?id=554 is fixed.
662     //Note that this also currently only protects against large text size requests,
663     //the total matrix is not taken into account here.
664     if (rec->fTextSize > SkIntToScalar(1 << 14)) {
665         rec->fTextSize = SkIntToScalar(1 << 14);
666     }
667 
668     SkFontHinting h = rec->getHinting();
669     if (SkFontHinting::kFull == h && !isLCD(*rec)) {
670         // collapse full->normal hinting if we're not doing LCD
671         h = SkFontHinting::kNormal;
672     }
673 
674     // rotated text looks bad with hinting, so we disable it as needed
675     if (!isAxisAligned(*rec)) {
676         h = SkFontHinting::kNone;
677     }
678     rec->setHinting(h);
679 
680 #ifndef SK_GAMMA_APPLY_TO_A8
681     if (!isLCD(*rec)) {
682         // SRGBTODO: Is this correct? Do we want contrast boost?
683         rec->ignorePreBlend();
684     }
685 #endif
686 }
687 
GetUnitsPerEm(FT_Face face)688 int SkTypeface_FreeType::GetUnitsPerEm(FT_Face face) {
689     SkASSERT(face);
690 
691     SkScalar upem = SkIntToScalar(face->units_per_EM);
692     // At least some versions of FreeType set face->units_per_EM to 0 for bitmap only fonts.
693     if (upem == 0) {
694         TT_Header* ttHeader = (TT_Header*)FT_Get_Sfnt_Table(face, ft_sfnt_head);
695         if (ttHeader) {
696             upem = SkIntToScalar(ttHeader->Units_Per_EM);
697         }
698     }
699     return upem;
700 }
701 
onGetUPEM() const702 int SkTypeface_FreeType::onGetUPEM() const {
703     AutoFTAccess fta(this);
704     FT_Face face = fta.face();
705     if (!face) {
706         return 0;
707     }
708     return GetUnitsPerEm(face);
709 }
710 
onGetKerningPairAdjustments(const uint16_t glyphs[],int count,int32_t adjustments[]) const711 bool SkTypeface_FreeType::onGetKerningPairAdjustments(const uint16_t glyphs[],
712                                       int count, int32_t adjustments[]) const {
713     AutoFTAccess fta(this);
714     FT_Face face = fta.face();
715     if (!face || !FT_HAS_KERNING(face)) {
716         return false;
717     }
718 
719     for (int i = 0; i < count - 1; ++i) {
720         FT_Vector delta;
721         FT_Error err = FT_Get_Kerning(face, glyphs[i], glyphs[i+1],
722                                       FT_KERNING_UNSCALED, &delta);
723         if (err) {
724             return false;
725         }
726         adjustments[i] = delta.x;
727     }
728     return true;
729 }
730 
731 /** Returns the bitmap strike equal to or just larger than the requested size. */
chooseBitmapStrike(FT_Face face,FT_F26Dot6 scaleY)732 static FT_Int chooseBitmapStrike(FT_Face face, FT_F26Dot6 scaleY) {
733     if (face == nullptr) {
734         LOG_INFO("chooseBitmapStrike aborted due to nullptr face.\n");
735         return -1;
736     }
737 
738     FT_Pos requestedPPEM = scaleY;  // FT_Bitmap_Size::y_ppem is in 26.6 format.
739     FT_Int chosenStrikeIndex = -1;
740     FT_Pos chosenPPEM = 0;
741     for (FT_Int strikeIndex = 0; strikeIndex < face->num_fixed_sizes; ++strikeIndex) {
742         FT_Pos strikePPEM = face->available_sizes[strikeIndex].y_ppem;
743         if (strikePPEM == requestedPPEM) {
744             // exact match - our search stops here
745             return strikeIndex;
746         } else if (chosenPPEM < requestedPPEM) {
747             // attempt to increase chosenPPEM
748             if (chosenPPEM < strikePPEM) {
749                 chosenPPEM = strikePPEM;
750                 chosenStrikeIndex = strikeIndex;
751             }
752         } else {
753             // attempt to decrease chosenPPEM, but not below requestedPPEM
754             if (requestedPPEM < strikePPEM && strikePPEM < chosenPPEM) {
755                 chosenPPEM = strikePPEM;
756                 chosenStrikeIndex = strikeIndex;
757             }
758         }
759     }
760     return chosenStrikeIndex;
761 }
762 
SkScalerContext_FreeType(sk_sp<SkTypeface_FreeType> typeface,const SkScalerContextEffects & effects,const SkDescriptor * desc)763 SkScalerContext_FreeType::SkScalerContext_FreeType(sk_sp<SkTypeface_FreeType> typeface,
764                                                    const SkScalerContextEffects& effects,
765                                                    const SkDescriptor* desc)
766     : SkScalerContext_FreeType_Base(std::move(typeface), effects, desc)
767     , fFace(nullptr)
768     , fFTSize(nullptr)
769     , fStrikeIndex(-1)
770 {
771     SkAutoMutexExclusive  ac(f_t_mutex());
772     fFaceRec = static_cast<SkTypeface_FreeType*>(this->getTypeface())->getFaceRec();
773 
774     // load the font file
775     if (nullptr == fFaceRec) {
776         LOG_INFO("Could not create FT_Face.\n");
777         return;
778     }
779 
780     fLCDIsVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
781 
782     // compute the flags we send to Load_Glyph
783     bool linearMetrics = this->isLinearMetrics();
784     {
785         FT_Int32 loadFlags = FT_LOAD_DEFAULT;
786 
787         if (SkMask::kBW_Format == fRec.fMaskFormat) {
788             // See http://code.google.com/p/chromium/issues/detail?id=43252#c24
789             loadFlags = FT_LOAD_TARGET_MONO;
790             if (fRec.getHinting() == SkFontHinting::kNone) {
791                 loadFlags = FT_LOAD_NO_HINTING;
792                 linearMetrics = true;
793             }
794         } else {
795             switch (fRec.getHinting()) {
796             case SkFontHinting::kNone:
797                 loadFlags = FT_LOAD_NO_HINTING;
798                 linearMetrics = true;
799                 break;
800             case SkFontHinting::kSlight:
801                 loadFlags = FT_LOAD_TARGET_LIGHT;  // This implies FORCE_AUTOHINT
802                 linearMetrics = true;
803                 break;
804             case SkFontHinting::kNormal:
805                 loadFlags = FT_LOAD_TARGET_NORMAL;
806                 break;
807             case SkFontHinting::kFull:
808                 loadFlags = FT_LOAD_TARGET_NORMAL;
809                 if (isLCD(fRec)) {
810                     if (fLCDIsVert) {
811                         loadFlags = FT_LOAD_TARGET_LCD_V;
812                     } else {
813                         loadFlags = FT_LOAD_TARGET_LCD;
814                     }
815                 }
816                 break;
817             default:
818                 LOG_INFO("---------- UNKNOWN hinting %d\n", fRec.getHinting());
819                 break;
820             }
821         }
822 
823         if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) {
824             loadFlags |= FT_LOAD_FORCE_AUTOHINT;
825 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
826         } else {
827             loadFlags |= FT_LOAD_NO_AUTOHINT;
828 #endif
829         }
830 
831         if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) {
832             loadFlags |= FT_LOAD_NO_BITMAP;
833         }
834 
835         // Always using FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH to get correct
836         // advances, as fontconfig and cairo do.
837         // See http://code.google.com/p/skia/issues/detail?id=222.
838         loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
839 
840         // Use vertical layout if requested.
841         if (this->isVertical()) {
842             loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
843         }
844 
845         loadFlags |= FT_LOAD_COLOR;
846 
847         fLoadGlyphFlags = loadFlags;
848     }
849 
850     using DoneFTSize = SkFunctionWrapper<decltype(FT_Done_Size), FT_Done_Size>;
851     std::unique_ptr<std::remove_pointer_t<FT_Size>, DoneFTSize> ftSize([this]() -> FT_Size {
852         FT_Size size;
853         FT_Error err = FT_New_Size(fFaceRec->fFace.get(), &size);
854         if (err != 0) {
855             SK_TRACEFTR(err, "FT_New_Size(%s) failed.", fFaceRec->fFace->family_name);
856             return nullptr;
857         }
858         return size;
859     }());
860     if (nullptr == ftSize) {
861         LOG_INFO("Could not create FT_Size.\n");
862         return;
863     }
864 
865     FT_Error err = FT_Activate_Size(ftSize.get());
866     if (err != 0) {
867         SK_TRACEFTR(err, "FT_Activate_Size(%s) failed.", fFaceRec->fFace->family_name);
868         return;
869     }
870 
871     fRec.computeMatrices(SkScalerContextRec::kFull_PreMatrixScale, &fScale, &fMatrix22Scalar);
872     FT_F26Dot6 scaleX = SkScalarToFDot6(fScale.fX);
873     FT_F26Dot6 scaleY = SkScalarToFDot6(fScale.fY);
874 
875     if (FT_IS_SCALABLE(fFaceRec->fFace)) {
876         err = FT_Set_Char_Size(fFaceRec->fFace.get(), scaleX, scaleY, 72, 72);
877         if (err != 0) {
878             SK_TRACEFTR(err, "FT_Set_CharSize(%s, %f, %f) failed.",
879                         fFaceRec->fFace->family_name, fScale.fX, fScale.fY);
880             return;
881         }
882 
883         // Adjust the matrix to reflect the actually chosen scale.
884         // FreeType currently does not allow requesting sizes less than 1, this allow for scaling.
885         // Don't do this at all sizes as that will interfere with hinting.
886         if (fScale.fX < 1 || fScale.fY < 1) {
887             SkScalar upem = fFaceRec->fFace->units_per_EM;
888             FT_Size_Metrics& ftmetrics = fFaceRec->fFace->size->metrics;
889             SkScalar x_ppem = upem * SkFT_FixedToScalar(ftmetrics.x_scale) / 64.0f;
890             SkScalar y_ppem = upem * SkFT_FixedToScalar(ftmetrics.y_scale) / 64.0f;
891             fMatrix22Scalar.preScale(fScale.x() / x_ppem, fScale.y() / y_ppem);
892         }
893 
894     } else if (FT_HAS_FIXED_SIZES(fFaceRec->fFace)) {
895         fStrikeIndex = chooseBitmapStrike(fFaceRec->fFace.get(), scaleY);
896         if (fStrikeIndex == -1) {
897             LOG_INFO("No glyphs for font \"%s\" size %f.\n",
898                      fFaceRec->fFace->family_name, fScale.fY);
899             return;
900         }
901 
902         err = FT_Select_Size(fFaceRec->fFace.get(), fStrikeIndex);
903         if (err != 0) {
904             SK_TRACEFTR(err, "FT_Select_Size(%s, %d) failed.",
905                         fFaceRec->fFace->family_name, fStrikeIndex);
906             fStrikeIndex = -1;
907             return;
908         }
909 
910         // Adjust the matrix to reflect the actually chosen scale.
911         // It is likely that the ppem chosen was not the one requested, this allows for scaling.
912         fMatrix22Scalar.preScale(fScale.x() / fFaceRec->fFace->size->metrics.x_ppem,
913                                  fScale.y() / fFaceRec->fFace->size->metrics.y_ppem);
914 
915         // FreeType does not provide linear metrics for bitmap fonts.
916         linearMetrics = false;
917 
918         // FreeType documentation says:
919         // FT_LOAD_NO_BITMAP -- Ignore bitmap strikes when loading.
920         // Bitmap-only fonts ignore this flag.
921         //
922         // However, in FreeType 2.5.1 color bitmap only fonts do not ignore this flag.
923         // Force this flag off for bitmap only fonts.
924         fLoadGlyphFlags &= ~FT_LOAD_NO_BITMAP;
925     } else {
926         LOG_INFO("Unknown kind of font \"%s\" size %f.\n", fFaceRec->fFace->family_name, fScale.fY);
927         return;
928     }
929 
930     fMatrix22.xx = SkScalarToFixed(fMatrix22Scalar.getScaleX());
931     fMatrix22.xy = SkScalarToFixed(-fMatrix22Scalar.getSkewX());
932     fMatrix22.yx = SkScalarToFixed(-fMatrix22Scalar.getSkewY());
933     fMatrix22.yy = SkScalarToFixed(fMatrix22Scalar.getScaleY());
934 
935 #ifdef FT_COLOR_H
936     FT_Palette_Select(fFaceRec->fFace.get(), 0, nullptr);
937 #endif
938 
939     fFTSize = ftSize.release();
940     fFace = fFaceRec->fFace.get();
941     fDoLinearMetrics = linearMetrics;
942 }
943 
~SkScalerContext_FreeType()944 SkScalerContext_FreeType::~SkScalerContext_FreeType() {
945     SkAutoMutexExclusive  ac(f_t_mutex());
946 
947     if (fFTSize != nullptr) {
948         FT_Done_Size(fFTSize);
949     }
950 
951     fFaceRec = nullptr;
952 }
953 
954 /*  We call this before each use of the fFace, since we may be sharing
955     this face with other context (at different sizes).
956 */
setupSize()957 FT_Error SkScalerContext_FreeType::setupSize() {
958     f_t_mutex().assertHeld();
959     FT_Error err = FT_Activate_Size(fFTSize);
960     if (err != 0) {
961         return err;
962     }
963     FT_Set_Transform(fFace, &fMatrix22, nullptr);
964     return 0;
965 }
966 
generateAdvance(SkGlyph * glyph)967 bool SkScalerContext_FreeType::generateAdvance(SkGlyph* glyph) {
968    /* unhinted and light hinted text have linearly scaled advances
969     * which are very cheap to compute with some font formats...
970     */
971     if (!fDoLinearMetrics) {
972         return false;
973     }
974 
975     SkAutoMutexExclusive  ac(f_t_mutex());
976 
977     if (this->setupSize()) {
978         glyph->zeroMetrics();
979         return true;
980     }
981 
982     FT_Error    error;
983     FT_Fixed    advance;
984 
985     error = FT_Get_Advance( fFace, glyph->getGlyphID(),
986                             fLoadGlyphFlags | FT_ADVANCE_FLAG_FAST_ONLY,
987                             &advance );
988 
989     if (error != 0) {
990         return false;
991     }
992 
993     const SkScalar advanceScalar = SkFT_FixedToScalar(advance);
994     glyph->fAdvanceX = SkScalarToFloat(fMatrix22Scalar.getScaleX() * advanceScalar);
995     glyph->fAdvanceY = SkScalarToFloat(fMatrix22Scalar.getSkewY() * advanceScalar);
996     return true;
997 }
998 
getBBoxForCurrentGlyph(const SkGlyph * glyph,FT_BBox * bbox,bool snapToPixelBoundary)999 void SkScalerContext_FreeType::getBBoxForCurrentGlyph(const SkGlyph* glyph,
1000                                                       FT_BBox* bbox,
1001                                                       bool snapToPixelBoundary) {
1002 
1003     FT_Outline_Get_CBox(&fFace->glyph->outline, bbox);
1004 
1005     if (this->isSubpixel()) {
1006         int dx = SkFixedToFDot6(glyph->getSubXFixed());
1007         int dy = SkFixedToFDot6(glyph->getSubYFixed());
1008         // negate dy since freetype-y-goes-up and skia-y-goes-down
1009         bbox->xMin += dx;
1010         bbox->yMin -= dy;
1011         bbox->xMax += dx;
1012         bbox->yMax -= dy;
1013     }
1014 
1015     // outset the box to integral boundaries
1016     if (snapToPixelBoundary) {
1017         bbox->xMin &= ~63;
1018         bbox->yMin &= ~63;
1019         bbox->xMax  = (bbox->xMax + 63) & ~63;
1020         bbox->yMax  = (bbox->yMax + 63) & ~63;
1021     }
1022 
1023     // Must come after snapToPixelBoundary so that the width and height are
1024     // consistent. Otherwise asserts will fire later on when generating the
1025     // glyph image.
1026     if (this->isVertical()) {
1027         FT_Vector vector;
1028         vector.x = fFace->glyph->metrics.vertBearingX - fFace->glyph->metrics.horiBearingX;
1029         vector.y = -fFace->glyph->metrics.vertBearingY - fFace->glyph->metrics.horiBearingY;
1030         FT_Vector_Transform(&vector, &fMatrix22);
1031         bbox->xMin += vector.x;
1032         bbox->xMax += vector.x;
1033         bbox->yMin += vector.y;
1034         bbox->yMax += vector.y;
1035     }
1036 }
1037 
getCBoxForLetter(char letter,FT_BBox * bbox)1038 bool SkScalerContext_FreeType::getCBoxForLetter(char letter, FT_BBox* bbox) {
1039     const FT_UInt glyph_id = FT_Get_Char_Index(fFace, letter);
1040     if (!glyph_id) {
1041         return false;
1042     }
1043     if (FT_Load_Glyph(fFace, glyph_id, fLoadGlyphFlags) != 0) {
1044         return false;
1045     }
1046     emboldenIfNeeded(fFace, fFace->glyph, SkTo<SkGlyphID>(glyph_id));
1047     FT_Outline_Get_CBox(&fFace->glyph->outline, bbox);
1048     return true;
1049 }
1050 
updateGlyphIfLCD(SkGlyph * glyph)1051 void SkScalerContext_FreeType::updateGlyphIfLCD(SkGlyph* glyph) {
1052     if (glyph->fMaskFormat == SkMask::kLCD16_Format) {
1053         if (fLCDIsVert) {
1054             glyph->fHeight += 2;
1055             glyph->fTop -= 1;
1056         } else {
1057             glyph->fWidth += 2;
1058             glyph->fLeft -= 1;
1059         }
1060     }
1061 }
1062 
shouldSubpixelBitmap(const SkGlyph & glyph,const SkMatrix & matrix)1063 bool SkScalerContext_FreeType::shouldSubpixelBitmap(const SkGlyph& glyph, const SkMatrix& matrix) {
1064     // If subpixel rendering of a bitmap *can* be done.
1065     bool mechanism = fFace->glyph->format == FT_GLYPH_FORMAT_BITMAP &&
1066                      this->isSubpixel() &&
1067                      (glyph.getSubXFixed() || glyph.getSubYFixed());
1068 
1069     // If subpixel rendering of a bitmap *should* be done.
1070     // 1. If the face is not scalable then always allow subpixel rendering.
1071     //    Otherwise, if the font has an 8ppem strike 7 will subpixel render but 8 won't.
1072     // 2. If the matrix is already not identity the bitmap will already be resampled,
1073     //    so resampling slightly differently shouldn't make much difference.
1074     bool policy = !FT_IS_SCALABLE(fFace) || !matrix.isIdentity();
1075 
1076     return mechanism && policy;
1077 }
1078 
generateMetrics(SkGlyph * glyph)1079 void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
1080     SkAutoMutexExclusive  ac(f_t_mutex());
1081 
1082     glyph->fMaskFormat = fRec.fMaskFormat;
1083 
1084     if (this->setupSize()) {
1085         glyph->zeroMetrics();
1086         return;
1087     }
1088 
1089     FT_Error    err;
1090     err = FT_Load_Glyph( fFace, glyph->getGlyphID(),
1091                          fLoadGlyphFlags | FT_LOAD_BITMAP_METRICS_ONLY );
1092     if (err != 0) {
1093         glyph->zeroMetrics();
1094         return;
1095     }
1096     emboldenIfNeeded(fFace, fFace->glyph, glyph->getGlyphID());
1097 
1098     if (fFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
1099         using FT_PosLimits = std::numeric_limits<FT_Pos>;
1100         FT_BBox bounds = { FT_PosLimits::max(), FT_PosLimits::max(),
1101                            FT_PosLimits::min(), FT_PosLimits::min() };
1102 #ifdef FT_COLOR_H
1103         FT_Bool haveLayers = false;
1104         FT_LayerIterator layerIterator = { 0, 0, nullptr };
1105         FT_UInt layerGlyphIndex;
1106         FT_UInt layerColorIndex;
1107 
1108 #ifdef TT_SUPPORT_COLRV1
1109         FT_OpaquePaint opaqueLayerPaint;
1110         opaqueLayerPaint.p = nullptr;
1111         if (FT_Get_Color_Glyph_Paint(fFace, glyph->getGlyphID(),
1112                                      FT_COLOR_INCLUDE_ROOT_TRANSFORM, &opaqueLayerPaint)) {
1113             haveLayers = true;
1114 
1115             FT_ClipBox colrGlyphBbox;
1116 
1117             // COLRv1 optionally provides a ClipBox that we can use for allocation.
1118             if (FT_Get_Color_Glyph_ClipBox(fFace, glyph->getGlyphID(), &colrGlyphBbox)) {
1119                 // Find enclosing bounding box of clip box corner points, needed
1120                 // when clipbox is transformed.
1121                 bounds.xMin = colrGlyphBbox.bottom_left.x;
1122                 bounds.xMax = colrGlyphBbox.bottom_left.x;
1123                 bounds.yMin = colrGlyphBbox.bottom_left.y;
1124                 bounds.yMax = colrGlyphBbox.bottom_left.y;
1125 
1126                 for (auto& corner : {colrGlyphBbox.top_left,
1127                                      colrGlyphBbox.top_right,
1128                                      colrGlyphBbox.bottom_right}) {
1129                     if (corner.x < bounds.xMin) {
1130                         bounds.xMin = corner.x;
1131                     }
1132                     if (corner.y < bounds.yMin) {
1133                         bounds.yMin = corner.y;
1134                     }
1135                     if (corner.x > bounds.xMax) {
1136                         bounds.xMax = corner.x;
1137                     }
1138                     if (corner.y > bounds.yMax) {
1139                         bounds.yMax = corner.y;
1140                     }
1141                 }
1142           } else {
1143               // Otherwise we need to traverse the glyph graph with a focus on measuring the
1144               // required bounding box.
1145               FT_BBox computed_bounds;
1146               if (!computeColrV1GlyphBoundingBox(fFace, glyph->getGlyphID(), &computed_bounds)) {
1147                   glyph->zeroMetrics();
1148                   return;
1149               }
1150 
1151               // Reset face so the main glyph slot contains information about the
1152               // base glyph again, for usage for computing and copying horizontal
1153               // metrics from FreeType to Skia below.
1154               if (this->setupSize()) {
1155                   glyph->zeroMetrics();
1156                   return;
1157               }
1158 
1159               err = FT_Load_Glyph(
1160                       fFace, glyph->getGlyphID(), fLoadGlyphFlags | FT_LOAD_BITMAP_METRICS_ONLY);
1161               if (err != 0) {
1162                   glyph->zeroMetrics();
1163                   return;
1164               }
1165 
1166               bounds = computed_bounds;
1167           }
1168         }
1169 #endif // #TT_SUPPORT_COLRV1
1170 
1171         if (!haveLayers) {
1172             // For COLRv0 compute the glyph bounding box from the union of layer bounding boxes.
1173             while (FT_Get_Color_Glyph_Layer(fFace, glyph->getGlyphID(), &layerGlyphIndex,
1174                                             &layerColorIndex, &layerIterator)) {
1175                 haveLayers = true;
1176                 err = FT_Load_Glyph(fFace, layerGlyphIndex,
1177                                     fLoadGlyphFlags | FT_LOAD_BITMAP_METRICS_ONLY);
1178                 if (err != 0) {
1179                     glyph->zeroMetrics();
1180                     return;
1181                 }
1182                 emboldenIfNeeded(fFace, fFace->glyph, layerGlyphIndex);
1183 
1184                 if (0 < fFace->glyph->outline.n_contours) {
1185                     FT_BBox bbox;
1186                     getBBoxForCurrentGlyph(glyph, &bbox, true);
1187 
1188                     // Union
1189                     bounds.xMin = std::min(bbox.xMin, bounds.xMin);
1190                     bounds.yMin = std::min(bbox.yMin, bounds.yMin);
1191                     bounds.xMax = std::max(bbox.xMax, bounds.xMax);
1192                     bounds.yMax = std::max(bbox.yMax, bounds.yMax);
1193                 }
1194             }
1195         }
1196 
1197         if (haveLayers) {
1198             glyph->fMaskFormat = SkMask::kARGB32_Format;
1199             if (!(bounds.xMin < bounds.xMax && bounds.yMin < bounds.yMax)) {
1200                 bounds = { 0, 0, 0, 0 };
1201             }
1202         } else {
1203 #endif
1204             if (0 < fFace->glyph->outline.n_contours) {
1205                 getBBoxForCurrentGlyph(glyph, &bounds, true);
1206             } else {
1207                 bounds = { 0, 0, 0, 0 };
1208             }
1209 #ifdef FT_COLOR_H
1210         }
1211 #endif
1212         // Round out, no longer dot6.
1213         bounds.xMin = SkFDot6Floor(bounds.xMin);
1214         bounds.yMin = SkFDot6Floor(bounds.yMin);
1215         bounds.xMax = SkFDot6Ceil (bounds.xMax);
1216         bounds.yMax = SkFDot6Ceil (bounds.yMax);
1217 
1218         FT_Pos width  =  bounds.xMax - bounds.xMin;
1219         FT_Pos height =  bounds.yMax - bounds.yMin;
1220         FT_Pos top    = -bounds.yMax;  // Freetype y-up, Skia y-down.
1221         FT_Pos left   =  bounds.xMin;
1222         if (!SkTFitsIn<decltype(glyph->fWidth )>(width ) ||
1223             !SkTFitsIn<decltype(glyph->fHeight)>(height) ||
1224             !SkTFitsIn<decltype(glyph->fTop   )>(top   ) ||
1225             !SkTFitsIn<decltype(glyph->fLeft  )>(left  )  )
1226         {
1227             width = height = top = left = 0;
1228         }
1229 
1230         glyph->fWidth  = SkToU16(width );
1231         glyph->fHeight = SkToU16(height);
1232         glyph->fTop    = SkToS16(top   );
1233         glyph->fLeft   = SkToS16(left  );
1234         updateGlyphIfLCD(glyph);
1235 
1236     } else if (fFace->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
1237         if (this->isVertical()) {
1238             FT_Vector vector;
1239             vector.x = fFace->glyph->metrics.vertBearingX - fFace->glyph->metrics.horiBearingX;
1240             vector.y = -fFace->glyph->metrics.vertBearingY - fFace->glyph->metrics.horiBearingY;
1241             FT_Vector_Transform(&vector, &fMatrix22);
1242             fFace->glyph->bitmap_left += SkFDot6Floor(vector.x);
1243             fFace->glyph->bitmap_top  += SkFDot6Floor(vector.y);
1244         }
1245 
1246         if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
1247             glyph->fMaskFormat = SkMask::kARGB32_Format;
1248         }
1249 
1250         {
1251             SkRect rect = SkRect::MakeXYWH(SkIntToScalar(fFace->glyph->bitmap_left),
1252                                           -SkIntToScalar(fFace->glyph->bitmap_top),
1253                                            SkIntToScalar(fFace->glyph->bitmap.width),
1254                                            SkIntToScalar(fFace->glyph->bitmap.rows));
1255             fMatrix22Scalar.mapRect(&rect);
1256             if (this->shouldSubpixelBitmap(*glyph, fMatrix22Scalar)) {
1257                 rect.offset(SkFixedToScalar(glyph->getSubXFixed()),
1258                             SkFixedToScalar(glyph->getSubYFixed()));
1259             }
1260             SkIRect irect = rect.roundOut();
1261             glyph->fWidth   = SkToU16(irect.width());
1262             glyph->fHeight  = SkToU16(irect.height());
1263             glyph->fTop     = SkToS16(irect.top());
1264             glyph->fLeft    = SkToS16(irect.left());
1265         }
1266     } else {
1267         SkDEBUGFAIL("unknown glyph format");
1268         glyph->zeroMetrics();
1269         return;
1270     }
1271 
1272     if (this->isVertical()) {
1273         if (fDoLinearMetrics) {
1274             const SkScalar advanceScalar = SkFT_FixedToScalar(fFace->glyph->linearVertAdvance);
1275             glyph->fAdvanceX = SkScalarToFloat(fMatrix22Scalar.getSkewX() * advanceScalar);
1276             glyph->fAdvanceY = SkScalarToFloat(fMatrix22Scalar.getScaleY() * advanceScalar);
1277         } else {
1278             glyph->fAdvanceX = -SkFDot6ToFloat(fFace->glyph->advance.x);
1279             glyph->fAdvanceY = SkFDot6ToFloat(fFace->glyph->advance.y);
1280         }
1281     } else {
1282         if (fDoLinearMetrics) {
1283             const SkScalar advanceScalar = SkFT_FixedToScalar(fFace->glyph->linearHoriAdvance);
1284             glyph->fAdvanceX = SkScalarToFloat(fMatrix22Scalar.getScaleX() * advanceScalar);
1285             glyph->fAdvanceY = SkScalarToFloat(fMatrix22Scalar.getSkewY() * advanceScalar);
1286         } else {
1287             glyph->fAdvanceX = SkFDot6ToFloat(fFace->glyph->advance.x);
1288             glyph->fAdvanceY = -SkFDot6ToFloat(fFace->glyph->advance.y);
1289         }
1290     }
1291 
1292 #ifdef ENABLE_GLYPH_SPEW
1293     LOG_INFO("Metrics(glyph:%d flags:0x%x) w:%d\n", glyph->getGlyphID(), fLoadGlyphFlags, glyph->fWidth);
1294 #endif
1295 }
1296 
generateImage(const SkGlyph & glyph)1297 void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) {
1298     SkAutoMutexExclusive  ac(f_t_mutex());
1299 
1300     if (this->setupSize()) {
1301         sk_bzero(glyph.fImage, glyph.imageSize());
1302         return;
1303     }
1304 
1305     FT_Error err = FT_Load_Glyph(fFace, glyph.getGlyphID(), fLoadGlyphFlags);
1306     if (err != 0) {
1307         SK_TRACEFTR(err, "SkScalerContext_FreeType::generateImage: FT_Load_Glyph(glyph:%d "
1308                      "width:%d height:%d rb:%zu flags:%d) failed.",
1309                      glyph.getGlyphID(), glyph.width(), glyph.height(), glyph.rowBytes(),
1310                      fLoadGlyphFlags);
1311         sk_bzero(glyph.fImage, glyph.imageSize());
1312         return;
1313     }
1314 
1315     emboldenIfNeeded(fFace, fFace->glyph, glyph.getGlyphID());
1316     SkMatrix* bitmapMatrix = &fMatrix22Scalar;
1317     SkMatrix subpixelBitmapMatrix;
1318     if (this->shouldSubpixelBitmap(glyph, *bitmapMatrix)) {
1319         subpixelBitmapMatrix = fMatrix22Scalar;
1320         subpixelBitmapMatrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()),
1321                                            SkFixedToScalar(glyph.getSubYFixed()));
1322         bitmapMatrix = &subpixelBitmapMatrix;
1323     }
1324     generateGlyphImage(fFace, glyph, *bitmapMatrix);
1325 }
1326 
1327 
generatePath(SkGlyphID glyphID,SkPath * path)1328 bool SkScalerContext_FreeType::generatePath(SkGlyphID glyphID, SkPath* path) {
1329     SkASSERT(path);
1330 
1331     SkAutoMutexExclusive  ac(f_t_mutex());
1332 
1333     // FT_IS_SCALABLE is documented to mean the face contains outline glyphs.
1334     if (!FT_IS_SCALABLE(fFace) || this->setupSize()) {
1335         path->reset();
1336         return false;
1337     }
1338 
1339     uint32_t flags = fLoadGlyphFlags;
1340     flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
1341     flags &= ~FT_LOAD_RENDER;   // don't scan convert (we just want the outline)
1342 
1343     FT_Error err = FT_Load_Glyph(fFace, glyphID, flags);
1344     if (err != 0 || fFace->glyph->format != FT_GLYPH_FORMAT_OUTLINE) {
1345         path->reset();
1346         return false;
1347     }
1348     emboldenIfNeeded(fFace, fFace->glyph, glyphID);
1349 
1350     if (!generateGlyphPath(fFace, path)) {
1351         path->reset();
1352         return false;
1353     }
1354 
1355     // The path's origin from FreeType is always the horizontal layout origin.
1356     // Offset the path so that it is relative to the vertical origin if needed.
1357     if (this->isVertical()) {
1358         FT_Vector vector;
1359         vector.x = fFace->glyph->metrics.vertBearingX - fFace->glyph->metrics.horiBearingX;
1360         vector.y = -fFace->glyph->metrics.vertBearingY - fFace->glyph->metrics.horiBearingY;
1361         FT_Vector_Transform(&vector, &fMatrix22);
1362         path->offset(SkFDot6ToScalar(vector.x), -SkFDot6ToScalar(vector.y));
1363     }
1364     return true;
1365 }
1366 
generateFontMetrics(SkFontMetrics * metrics)1367 void SkScalerContext_FreeType::generateFontMetrics(SkFontMetrics* metrics) {
1368     if (nullptr == metrics) {
1369         return;
1370     }
1371 
1372     SkAutoMutexExclusive ac(f_t_mutex());
1373 
1374     if (this->setupSize()) {
1375         sk_bzero(metrics, sizeof(*metrics));
1376         return;
1377     }
1378 
1379     FT_Face face = fFace;
1380     metrics->fFlags = 0;
1381 
1382     SkScalar upem = SkIntToScalar(SkTypeface_FreeType::GetUnitsPerEm(face));
1383 
1384     // use the os/2 table as a source of reasonable defaults.
1385     SkScalar x_height = 0.0f;
1386     SkScalar avgCharWidth = 0.0f;
1387     SkScalar cap_height = 0.0f;
1388     SkScalar strikeoutThickness = 0.0f, strikeoutPosition = 0.0f;
1389     TT_OS2* os2 = (TT_OS2*) FT_Get_Sfnt_Table(face, ft_sfnt_os2);
1390     if (os2) {
1391         x_height = SkIntToScalar(os2->sxHeight) / upem * fScale.y();
1392         avgCharWidth = SkIntToScalar(os2->xAvgCharWidth) / upem;
1393         strikeoutThickness = SkIntToScalar(os2->yStrikeoutSize) / upem;
1394         strikeoutPosition = -SkIntToScalar(os2->yStrikeoutPosition) / upem;
1395         metrics->fFlags |= SkFontMetrics::kStrikeoutThicknessIsValid_Flag;
1396         metrics->fFlags |= SkFontMetrics::kStrikeoutPositionIsValid_Flag;
1397         if (os2->version != 0xFFFF && os2->version >= 2) {
1398             cap_height = SkIntToScalar(os2->sCapHeight) / upem * fScale.y();
1399         }
1400     }
1401 
1402     // pull from format-specific metrics as needed
1403     SkScalar ascent, descent, leading, xmin, xmax, ymin, ymax;
1404     SkScalar underlineThickness, underlinePosition;
1405     if (face->face_flags & FT_FACE_FLAG_SCALABLE) { // scalable outline font
1406         // FreeType will always use HHEA metrics if they're not zero.
1407         // It completely ignores the OS/2 fsSelection::UseTypoMetrics bit.
1408         // It also ignores the VDMX tables, which are also of interest here
1409         // (and override everything else when they apply).
1410         static const int kUseTypoMetricsMask = (1 << 7);
1411         if (os2 && os2->version != 0xFFFF && (os2->fsSelection & kUseTypoMetricsMask)) {
1412             ascent = -SkIntToScalar(os2->sTypoAscender) / upem;
1413             descent = -SkIntToScalar(os2->sTypoDescender) / upem;
1414             leading = SkIntToScalar(os2->sTypoLineGap) / upem;
1415         } else {
1416             ascent = -SkIntToScalar(face->ascender) / upem;
1417             descent = -SkIntToScalar(face->descender) / upem;
1418             leading = SkIntToScalar(face->height + (face->descender - face->ascender)) / upem;
1419         }
1420         xmin = SkIntToScalar(face->bbox.xMin) / upem;
1421         xmax = SkIntToScalar(face->bbox.xMax) / upem;
1422         ymin = -SkIntToScalar(face->bbox.yMin) / upem;
1423         ymax = -SkIntToScalar(face->bbox.yMax) / upem;
1424         underlineThickness = SkIntToScalar(face->underline_thickness) / upem;
1425         underlinePosition = -SkIntToScalar(face->underline_position +
1426                                            face->underline_thickness / 2) / upem;
1427 
1428         metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag;
1429         metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag;
1430 
1431         // we may be able to synthesize x_height and cap_height from outline
1432         if (!x_height) {
1433             FT_BBox bbox;
1434             if (getCBoxForLetter('x', &bbox)) {
1435                 x_height = SkIntToScalar(bbox.yMax) / 64.0f;
1436             }
1437         }
1438         if (!cap_height) {
1439             FT_BBox bbox;
1440             if (getCBoxForLetter('H', &bbox)) {
1441                 cap_height = SkIntToScalar(bbox.yMax) / 64.0f;
1442             }
1443         }
1444     } else if (fStrikeIndex != -1) { // bitmap strike metrics
1445         SkScalar xppem = SkIntToScalar(face->size->metrics.x_ppem);
1446         SkScalar yppem = SkIntToScalar(face->size->metrics.y_ppem);
1447         ascent = -SkIntToScalar(face->size->metrics.ascender) / (yppem * 64.0f);
1448         descent = -SkIntToScalar(face->size->metrics.descender) / (yppem * 64.0f);
1449         leading = (SkIntToScalar(face->size->metrics.height) / (yppem * 64.0f)) + ascent - descent;
1450 
1451         xmin = 0.0f;
1452         xmax = SkIntToScalar(face->available_sizes[fStrikeIndex].width) / xppem;
1453         ymin = descent;
1454         ymax = ascent;
1455         // The actual bitmaps may be any size and placed at any offset.
1456         metrics->fFlags |= SkFontMetrics::kBoundsInvalid_Flag;
1457 
1458         underlineThickness = 0;
1459         underlinePosition = 0;
1460         metrics->fFlags &= ~SkFontMetrics::kUnderlineThicknessIsValid_Flag;
1461         metrics->fFlags &= ~SkFontMetrics::kUnderlinePositionIsValid_Flag;
1462 
1463         TT_Postscript* post = (TT_Postscript*) FT_Get_Sfnt_Table(face, ft_sfnt_post);
1464         if (post) {
1465             underlineThickness = SkIntToScalar(post->underlineThickness) / upem;
1466             underlinePosition = -SkIntToScalar(post->underlinePosition) / upem;
1467             metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag;
1468             metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag;
1469         }
1470     } else {
1471         sk_bzero(metrics, sizeof(*metrics));
1472         return;
1473     }
1474 
1475     // synthesize elements that were not provided by the os/2 table or format-specific metrics
1476     if (!x_height) {
1477         x_height = -ascent * fScale.y();
1478     }
1479     if (!avgCharWidth) {
1480         avgCharWidth = xmax - xmin;
1481     }
1482     if (!cap_height) {
1483       cap_height = -ascent * fScale.y();
1484     }
1485 
1486     // disallow negative linespacing
1487     if (leading < 0.0f) {
1488         leading = 0.0f;
1489     }
1490 
1491     metrics->fTop = ymax * fScale.y();
1492     metrics->fAscent = ascent * fScale.y();
1493     metrics->fDescent = descent * fScale.y();
1494     metrics->fBottom = ymin * fScale.y();
1495     metrics->fLeading = leading * fScale.y();
1496     metrics->fAvgCharWidth = avgCharWidth * fScale.y();
1497     metrics->fXMin = xmin * fScale.y();
1498     metrics->fXMax = xmax * fScale.y();
1499     metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
1500     metrics->fXHeight = x_height;
1501     metrics->fCapHeight = cap_height;
1502     metrics->fUnderlineThickness = underlineThickness * fScale.y();
1503     metrics->fUnderlinePosition = underlinePosition * fScale.y();
1504     metrics->fStrikeoutThickness = strikeoutThickness * fScale.y();
1505     metrics->fStrikeoutPosition = strikeoutPosition * fScale.y();
1506 
1507     if (face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
1508         // The bounds are only valid for the default variation.
1509         metrics->fFlags |= SkFontMetrics::kBoundsInvalid_Flag;
1510     }
1511 }
1512 
1513 ///////////////////////////////////////////////////////////////////////////////
1514 
1515 // hand-tuned value to reduce outline embolden strength
1516 #ifndef SK_OUTLINE_EMBOLDEN_DIVISOR
1517     #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1518         #define SK_OUTLINE_EMBOLDEN_DIVISOR   34
1519     #else
1520         #define SK_OUTLINE_EMBOLDEN_DIVISOR   24
1521     #endif
1522 #endif
1523 
1524 ///////////////////////////////////////////////////////////////////////////////
1525 
emboldenIfNeeded(FT_Face face,FT_GlyphSlot glyph,SkGlyphID gid)1526 void SkScalerContext_FreeType::emboldenIfNeeded(FT_Face face, FT_GlyphSlot glyph, SkGlyphID gid) {
1527     // check to see if the embolden bit is set
1528     if (0 == (fRec.fFlags & SkScalerContext::kEmbolden_Flag)) {
1529         return;
1530     }
1531 
1532     switch (glyph->format) {
1533         case FT_GLYPH_FORMAT_OUTLINE:
1534             FT_Pos strength;
1535             strength = FT_MulFix(face->units_per_EM, face->size->metrics.y_scale)
1536                        / SK_OUTLINE_EMBOLDEN_DIVISOR;
1537             FT_Outline_Embolden(&glyph->outline, strength);
1538             break;
1539         case FT_GLYPH_FORMAT_BITMAP:
1540             if (!fFace->glyph->bitmap.buffer) {
1541                 FT_Load_Glyph(fFace, gid, fLoadGlyphFlags);
1542             }
1543             FT_GlyphSlot_Own_Bitmap(glyph);
1544             FT_Bitmap_Embolden(glyph->library, &glyph->bitmap, kBitmapEmboldenStrength, 0);
1545             break;
1546         default:
1547             SkDEBUGFAIL("unknown glyph format");
1548     }
1549 }
1550 
1551 ///////////////////////////////////////////////////////////////////////////////
1552 
1553 #include "src/core/SkUtils.h"
1554 
SkTypeface_FreeType(const SkFontStyle & style,bool isFixedPitch)1555 SkTypeface_FreeType::SkTypeface_FreeType(const SkFontStyle& style, bool isFixedPitch)
1556     : INHERITED(style, isFixedPitch)
1557 {}
1558 
~SkTypeface_FreeType()1559 SkTypeface_FreeType::~SkTypeface_FreeType() {
1560     if (fFaceRec) {
1561         SkAutoMutexExclusive ac(f_t_mutex());
1562         fFaceRec.reset();
1563     }
1564 }
1565 
1566 // Just made up, so we don't end up storing 1000s of entries
1567 constexpr int kMaxC2GCacheCount = 512;
1568 
onCharsToGlyphs(const SkUnichar uni[],int count,SkGlyphID glyphs[]) const1569 void SkTypeface_FreeType::onCharsToGlyphs(const SkUnichar uni[], int count,
1570                                           SkGlyphID glyphs[]) const {
1571     // Try the cache first, *before* accessing freetype lib/face, as that
1572     // can be very slow. If we do need to compute a new glyphID, then
1573     // access those freetype objects and continue the loop.
1574 
1575     int i;
1576     {
1577         // Optimistically use a shared lock.
1578         SkAutoSharedMutexShared ama(fC2GCacheMutex);
1579         for (i = 0; i < count; ++i) {
1580             int index = fC2GCache.findGlyphIndex(uni[i]);
1581             if (index < 0) {
1582                 break;
1583             }
1584             glyphs[i] = SkToU16(index);
1585         }
1586         if (i == count) {
1587             // we're done, no need to access the freetype objects
1588             return;
1589         }
1590     }
1591 
1592     // Need to add more so grab an exclusive lock.
1593     SkAutoSharedMutexExclusive ama(fC2GCacheMutex);
1594     AutoFTAccess fta(this);
1595     FT_Face face = fta.face();
1596     if (!face) {
1597         sk_bzero(glyphs, count * sizeof(glyphs[0]));
1598         return;
1599     }
1600 
1601     for (; i < count; ++i) {
1602         SkUnichar c = uni[i];
1603         int index = fC2GCache.findGlyphIndex(c);
1604         if (index >= 0) {
1605             glyphs[i] = SkToU16(index);
1606         } else {
1607             glyphs[i] = SkToU16(FT_Get_Char_Index(face, c));
1608             fC2GCache.insertCharAndGlyph(~index, c, glyphs[i]);
1609         }
1610     }
1611 
1612     if (fC2GCache.count() > kMaxC2GCacheCount) {
1613         fC2GCache.reset();
1614     }
1615 }
1616 
onCountGlyphs() const1617 int SkTypeface_FreeType::onCountGlyphs() const {
1618     AutoFTAccess fta(this);
1619     FT_Face face = fta.face();
1620     return face ? face->num_glyphs : 0;
1621 }
1622 
onCreateFamilyNameIterator() const1623 SkTypeface::LocalizedStrings* SkTypeface_FreeType::onCreateFamilyNameIterator() const {
1624     sk_sp<SkTypeface::LocalizedStrings> nameIter =
1625         SkOTUtils::LocalizedStrings_NameTable::MakeForFamilyNames(*this);
1626     if (!nameIter) {
1627         SkString familyName;
1628         this->getFamilyName(&familyName);
1629         SkString language("und"); //undetermined
1630         nameIter = sk_make_sp<SkOTUtils::LocalizedStrings_SingleName>(familyName, language);
1631     }
1632     return nameIter.release();
1633 }
1634 
onGlyphMaskNeedsCurrentColor() const1635 bool SkTypeface_FreeType::onGlyphMaskNeedsCurrentColor() const {
1636     return this->getTableSize(SkSetFourByteTag('C', 'O', 'L', 'R')) > 0;
1637 }
1638 
onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],int coordinateCount) const1639 int SkTypeface_FreeType::onGetVariationDesignPosition(
1640     SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
1641 {
1642     AutoFTAccess fta(this);
1643     return GetVariationDesignPosition(fta, coordinates, coordinateCount);
1644 }
1645 
onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],int parameterCount) const1646 int SkTypeface_FreeType::onGetVariationDesignParameters(
1647     SkFontParameters::Variation::Axis parameters[], int parameterCount) const
1648 {
1649     AutoFTAccess fta(this);
1650     FT_Face face = fta.face();
1651     if (!face) {
1652         return -1;
1653     }
1654 
1655     if (!(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
1656         return 0;
1657     }
1658 
1659     FT_MM_Var* variations = nullptr;
1660     if (FT_Get_MM_Var(face, &variations)) {
1661         return -1;
1662     }
1663     SkAutoFree autoFreeVariations(variations);
1664 
1665     if (!parameters || parameterCount < SkToInt(variations->num_axis)) {
1666         return variations->num_axis;
1667     }
1668 
1669     for (FT_UInt i = 0; i < variations->num_axis; ++i) {
1670         parameters[i].tag = variations->axis[i].tag;
1671         parameters[i].min = SkFixedToScalar(variations->axis[i].minimum);
1672         parameters[i].def = SkFixedToScalar(variations->axis[i].def);
1673         parameters[i].max = SkFixedToScalar(variations->axis[i].maximum);
1674         FT_UInt flags = 0;
1675         bool hidden = !FT_Get_Var_Axis_Flags(variations, i, &flags) &&
1676                       (flags & FT_VAR_AXIS_FLAG_HIDDEN);
1677         parameters[i].setHidden(hidden);
1678     }
1679 
1680     return variations->num_axis;
1681 }
1682 
onGetTableTags(SkFontTableTag tags[]) const1683 int SkTypeface_FreeType::onGetTableTags(SkFontTableTag tags[]) const {
1684     AutoFTAccess fta(this);
1685     FT_Face face = fta.face();
1686     if (!face) {
1687         return 0;
1688     }
1689 
1690     FT_ULong tableCount = 0;
1691     FT_Error error;
1692 
1693     // When 'tag' is nullptr, returns number of tables in 'length'.
1694     error = FT_Sfnt_Table_Info(face, 0, nullptr, &tableCount);
1695     if (error) {
1696         return 0;
1697     }
1698 
1699     if (tags) {
1700         for (FT_ULong tableIndex = 0; tableIndex < tableCount; ++tableIndex) {
1701             FT_ULong tableTag;
1702             FT_ULong tablelength;
1703             error = FT_Sfnt_Table_Info(face, tableIndex, &tableTag, &tablelength);
1704             if (error) {
1705                 return 0;
1706             }
1707             tags[tableIndex] = static_cast<SkFontTableTag>(tableTag);
1708         }
1709     }
1710     return tableCount;
1711 }
1712 
onGetTableData(SkFontTableTag tag,size_t offset,size_t length,void * data) const1713 size_t SkTypeface_FreeType::onGetTableData(SkFontTableTag tag, size_t offset,
1714                                            size_t length, void* data) const
1715 {
1716     AutoFTAccess fta(this);
1717     FT_Face face = fta.face();
1718     if (!face) {
1719         return 0;
1720     }
1721 
1722     FT_ULong tableLength = 0;
1723     FT_Error error;
1724 
1725     // When 'length' is 0 it is overwritten with the full table length; 'offset' is ignored.
1726     error = FT_Load_Sfnt_Table(face, tag, 0, nullptr, &tableLength);
1727     if (error) {
1728         return 0;
1729     }
1730 
1731     if (offset > tableLength) {
1732         return 0;
1733     }
1734     FT_ULong size = std::min((FT_ULong)length, tableLength - (FT_ULong)offset);
1735     if (data) {
1736         error = FT_Load_Sfnt_Table(face, tag, offset, reinterpret_cast<FT_Byte*>(data), &size);
1737         if (error) {
1738             return 0;
1739         }
1740     }
1741 
1742     return size;
1743 }
1744 
onCopyTableData(SkFontTableTag tag) const1745 sk_sp<SkData> SkTypeface_FreeType::onCopyTableData(SkFontTableTag tag) const {
1746     AutoFTAccess fta(this);
1747     FT_Face face = fta.face();
1748     if (!face) {
1749         return nullptr;
1750     }
1751 
1752     FT_ULong tableLength = 0;
1753     FT_Error error;
1754 
1755     // When 'length' is 0 it is overwritten with the full table length; 'offset' is ignored.
1756     error = FT_Load_Sfnt_Table(face, tag, 0, nullptr, &tableLength);
1757     if (error) {
1758         return nullptr;
1759     }
1760 
1761     sk_sp<SkData> data = SkData::MakeUninitialized(tableLength);
1762     if (data) {
1763         error = FT_Load_Sfnt_Table(face, tag, 0,
1764                                    reinterpret_cast<FT_Byte*>(data->writable_data()), &tableLength);
1765         if (error) {
1766             data.reset();
1767         }
1768     }
1769     return data;
1770 }
1771 
getFaceRec() const1772 SkTypeface_FreeType::FaceRec* SkTypeface_FreeType::getFaceRec() const {
1773     f_t_mutex().assertHeld();
1774     fFTFaceOnce([this]{ fFaceRec = SkTypeface_FreeType::FaceRec::Make(this); });
1775     return fFaceRec.get();
1776 }
1777 
makeFontData() const1778 std::unique_ptr<SkFontData> SkTypeface_FreeType::makeFontData() const {
1779     return this->onMakeFontData();
1780 }
1781 
1782 ///////////////////////////////////////////////////////////////////////////////
1783 ///////////////////////////////////////////////////////////////////////////////
1784 
Scanner()1785 SkTypeface_FreeType::Scanner::Scanner() : fLibrary(nullptr) {
1786     if (FT_New_Library(&gFTMemory, &fLibrary)) {
1787         return;
1788     }
1789     FT_Add_Default_Modules(fLibrary);
1790     FT_Set_Default_Properties(fLibrary);
1791 }
~Scanner()1792 SkTypeface_FreeType::Scanner::~Scanner() {
1793     if (fLibrary) {
1794         FT_Done_Library(fLibrary);
1795     }
1796 }
1797 
openFace(SkStreamAsset * stream,int ttcIndex,FT_Stream ftStream) const1798 FT_Face SkTypeface_FreeType::Scanner::openFace(SkStreamAsset* stream, int ttcIndex,
1799                                                FT_Stream ftStream) const
1800 {
1801     if (fLibrary == nullptr || stream == nullptr) {
1802         return nullptr;
1803     }
1804 
1805     FT_Open_Args args;
1806     memset(&args, 0, sizeof(args));
1807 
1808     const void* memoryBase = stream->getMemoryBase();
1809 
1810     if (memoryBase) {
1811         args.flags = FT_OPEN_MEMORY;
1812         args.memory_base = (const FT_Byte*)memoryBase;
1813         args.memory_size = stream->getLength();
1814     } else {
1815         memset(ftStream, 0, sizeof(*ftStream));
1816         ftStream->size = stream->getLength();
1817         ftStream->descriptor.pointer = stream;
1818         ftStream->read  = sk_ft_stream_io;
1819         ftStream->close = sk_ft_stream_close;
1820 
1821         args.flags = FT_OPEN_STREAM;
1822         args.stream = ftStream;
1823     }
1824 
1825     FT_Face face;
1826     if (FT_Open_Face(fLibrary, &args, ttcIndex, &face)) {
1827         return nullptr;
1828     }
1829     return face;
1830 }
1831 
recognizedFont(SkStreamAsset * stream,int * numFaces) const1832 bool SkTypeface_FreeType::Scanner::recognizedFont(SkStreamAsset* stream, int* numFaces) const {
1833     SkAutoMutexExclusive libraryLock(fLibraryMutex);
1834 
1835     FT_StreamRec streamRec;
1836     SkUniqueFTFace face(this->openFace(stream, -1, &streamRec));
1837     if (!face) {
1838         return false;
1839     }
1840 
1841     *numFaces = face->num_faces;
1842     return true;
1843 }
1844 
1845 static const struct {
1846     const char* const name;
1847     int const weight;
1848 } gCommonWeights[] = {
1849     // There are probably more common names, but these are known to exist.
1850     {"all", SkFontStyle::kNormal_Weight},  // Multiple Masters usually default to normal.
1851     {"black", SkFontStyle::kBlack_Weight},
1852     {"bold", SkFontStyle::kBold_Weight},
1853     {"book", (SkFontStyle::kNormal_Weight + SkFontStyle::kLight_Weight) / 2},
1854     {"demi", SkFontStyle::kSemiBold_Weight},
1855     {"demibold", SkFontStyle::kSemiBold_Weight},
1856     {"extra", SkFontStyle::kExtraBold_Weight},
1857     {"extrabold", SkFontStyle::kExtraBold_Weight},
1858     {"extralight", SkFontStyle::kExtraLight_Weight},
1859     {"hairline", SkFontStyle::kThin_Weight},
1860     {"heavy", SkFontStyle::kBlack_Weight},
1861     {"light", SkFontStyle::kLight_Weight},
1862     {"medium", SkFontStyle::kMedium_Weight},
1863     {"normal", SkFontStyle::kNormal_Weight},
1864     {"plain", SkFontStyle::kNormal_Weight},
1865     {"regular", SkFontStyle::kNormal_Weight},
1866     {"roman", SkFontStyle::kNormal_Weight},
1867     {"semibold", SkFontStyle::kSemiBold_Weight},
1868     {"standard", SkFontStyle::kNormal_Weight},
1869     {"thin", SkFontStyle::kThin_Weight},
1870     {"ultra", SkFontStyle::kExtraBold_Weight},
1871     {"ultrablack", SkFontStyle::kExtraBlack_Weight},
1872     {"ultrabold", SkFontStyle::kExtraBold_Weight},
1873     {"ultraheavy", SkFontStyle::kExtraBlack_Weight},
1874     {"ultralight", SkFontStyle::kExtraLight_Weight},
1875 };
1876 
scanFont(SkStreamAsset * stream,int ttcIndex,SkString * name,SkFontStyle * style,bool * isFixedPitch,AxisDefinitions * axes) const1877 bool SkTypeface_FreeType::Scanner::scanFont(
1878     SkStreamAsset* stream, int ttcIndex,
1879     SkString* name, SkFontStyle* style, bool* isFixedPitch, AxisDefinitions* axes) const
1880 {
1881     SkAutoMutexExclusive libraryLock(fLibraryMutex);
1882 
1883     FT_StreamRec streamRec;
1884     SkUniqueFTFace face(this->openFace(stream, ttcIndex, &streamRec));
1885     if (!face) {
1886         return false;
1887     }
1888 
1889     int weight = SkFontStyle::kNormal_Weight;
1890     int width = SkFontStyle::kNormal_Width;
1891     SkFontStyle::Slant slant = SkFontStyle::kUpright_Slant;
1892     if (face->style_flags & FT_STYLE_FLAG_BOLD) {
1893         weight = SkFontStyle::kBold_Weight;
1894     }
1895     if (face->style_flags & FT_STYLE_FLAG_ITALIC) {
1896         slant = SkFontStyle::kItalic_Slant;
1897     }
1898 
1899     PS_FontInfoRec psFontInfo;
1900     TT_OS2* os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(face.get(), ft_sfnt_os2));
1901     if (os2 && os2->version != 0xffff) {
1902         weight = os2->usWeightClass;
1903         width = os2->usWidthClass;
1904 
1905         // OS/2::fsSelection bit 9 indicates oblique.
1906         if (SkToBool(os2->fsSelection & (1u << 9))) {
1907             slant = SkFontStyle::kOblique_Slant;
1908         }
1909     } else if (0 == FT_Get_PS_Font_Info(face.get(), &psFontInfo) && psFontInfo.weight) {
1910         int const index = SkStrLCSearch(&gCommonWeights[0].name, SK_ARRAY_COUNT(gCommonWeights),
1911                                         psFontInfo.weight, sizeof(gCommonWeights[0]));
1912         if (index >= 0) {
1913             weight = gCommonWeights[index].weight;
1914         } else {
1915             LOG_INFO("Do not know weight for: %s (%s) \n", face->family_name, psFontInfo.weight);
1916         }
1917     }
1918 
1919     if (name != nullptr) {
1920         name->set(face->family_name);
1921     }
1922     if (style != nullptr) {
1923         *style = SkFontStyle(weight, width, slant);
1924     }
1925     if (isFixedPitch != nullptr) {
1926         *isFixedPitch = FT_IS_FIXED_WIDTH(face);
1927     }
1928 
1929     if (axes != nullptr && !GetAxes(face.get(), axes)) {
1930         return false;
1931     }
1932     return true;
1933 }
1934 
scanFont(SkStreamAsset * stream,FontInfo & info,std::array<uint32_t,4> & range) const1935 bool SkTypeface_FreeType::Scanner::scanFont(SkStreamAsset* stream, FontInfo& info, std::array<uint32_t, 4>& range) const
1936 {
1937     SkAutoMutexExclusive libraryLock(fLibraryMutex);
1938 
1939     FT_StreamRec streamRec;
1940     SkUniqueFTFace face(this->openFace(stream, info.index, &streamRec));
1941     if (!face) {
1942         return false;
1943     }
1944 
1945     int weight = face->style_flags & FT_STYLE_FLAG_BOLD ? SkFontStyle::kBold_Weight : SkFontStyle::kNormal_Weight;
1946     int width = SkFontStyle::kNormal_Width;
1947     SkFontStyle::Slant slant = face->style_flags & FT_STYLE_FLAG_ITALIC
1948                                        ? SkFontStyle::kItalic_Slant
1949                                        : SkFontStyle::kUpright_Slant;
1950     PS_FontInfoRec psFontInfo;
1951     TT_OS2* os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(face.get(), ft_sfnt_os2));
1952     if (os2 && os2->version != 0xffff) {
1953         weight = os2->usWeightClass;
1954         width = os2->usWidthClass;
1955         // OS/2::ulUnicodeRange is bigendian, so we need to swap it
1956         range[0] = os2->ulUnicodeRange1;
1957         range[1] = os2->ulUnicodeRange2;
1958         range[2] = os2->ulUnicodeRange3;  // the 3rd range at index 2
1959         range[3] = os2->ulUnicodeRange4;  // the 4th range at index 3
1960 
1961         // OS/2::fsSelection bit 9 indicates oblique.
1962         if (SkToBool(os2->fsSelection & (1u << 9))) {
1963             slant = SkFontStyle::kOblique_Slant;
1964         }
1965     } else if (FT_Get_PS_Font_Info(face.get(), &psFontInfo) == 0 && psFontInfo.weight) {
1966         int const index = SkStrLCSearch(&gCommonWeights[0].name, SK_ARRAY_COUNT(gCommonWeights),
1967                                         psFontInfo.weight, sizeof(gCommonWeights[0]));
1968         if (index >= 0) {
1969             weight = gCommonWeights[index].weight;
1970         } else {
1971             LOG_INFO("Do not know weight for: %s (%s) \n", face->family_name, psFontInfo.weight);
1972         }
1973     }
1974     info.familyName.set(face->family_name);
1975     info.style = SkFontStyle(weight, width, slant);
1976     info.isFixedWidth = FT_IS_FIXED_WIDTH(face);
1977     return true;
1978 }
1979 
1980 #ifdef OHOS_SUPPORT
1981 /**
1982  *  Gets fullname from stream, true means success
1983  */
GetTypefaceFullname(SkStreamAsset * stream,int ttcIndex,SkByteArray & fullname) const1984 bool SkTypeface_FreeType::Scanner::GetTypefaceFullname(SkStreamAsset* stream,
1985     int ttcIndex, SkByteArray& fullname) const
1986 {
1987     if (stream == nullptr) {
1988         return false;
1989     }
1990     SkAutoMutexExclusive libraryLock(fLibraryMutex);
1991     FT_StreamRec streamRec;
1992     SkUniqueFTFace face(this->openFace(stream, ttcIndex, &streamRec));
1993     if (!face) {
1994         return false;
1995     }
1996 
1997     constexpr FT_UShort EN_LANGUAGE_ID = 1033;
1998     FT_SfntName sfntName;
1999     FT_UInt nameCount = FT_Get_Sfnt_Name_Count(face.get());
2000     for (FT_UInt i = 0; i < nameCount; ++i) {
2001         if (FT_Get_Sfnt_Name(face.get(), i, &sfntName) != 0) {
2002             continue;
2003         }
2004         if (sfntName.name_id != TT_NAME_ID_FULL_NAME) {
2005             continue;
2006         }
2007 
2008         if (fullname.strData != nullptr && sfntName.language_id != EN_LANGUAGE_ID) {
2009             continue;
2010         }
2011         fullname.strData = std::make_unique<uint8_t[]>(sfntName.string_len);
2012         if (memcpy_s(fullname.strData.get(), sfntName.string_len, sfntName.string, sfntName.string_len) == EOK) {
2013             fullname.strLen = sfntName.string_len;
2014             if (sfntName.language_id == EN_LANGUAGE_ID) {
2015                 return true;
2016             }
2017         }
2018     }
2019     return fullname.strData != nullptr;
2020 }
2021 #endif
2022 
GetAxes(FT_Face face,AxisDefinitions * axes)2023 bool SkTypeface_FreeType::Scanner::GetAxes(FT_Face face, AxisDefinitions* axes) {
2024     SkASSERT(face && axes);
2025     if (face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
2026         FT_MM_Var* variations = nullptr;
2027         FT_Error err = FT_Get_MM_Var(face, &variations);
2028         if (err) {
2029             LOG_INFO("INFO: font %s claims to have variations, but none found.\n",
2030                      face->family_name);
2031             return false;
2032         }
2033         SkAutoFree autoFreeVariations(variations);
2034 
2035         axes->reset(variations->num_axis);
2036         for (FT_UInt i = 0; i < variations->num_axis; ++i) {
2037             const FT_Var_Axis& ftAxis = variations->axis[i];
2038             (*axes)[i].fTag = ftAxis.tag;
2039             (*axes)[i].fMinimum = ftAxis.minimum;
2040             (*axes)[i].fDefault = ftAxis.def;
2041             (*axes)[i].fMaximum = ftAxis.maximum;
2042         }
2043     }
2044     return true;
2045 }
2046 
computeAxisValues(AxisDefinitions axisDefinitions,const SkFontArguments::VariationPosition position,SkFixed * axisValues,const SkString & name,const SkFontArguments::VariationPosition::Coordinate * current)2047 /*static*/ void SkTypeface_FreeType::Scanner::computeAxisValues(
2048     AxisDefinitions axisDefinitions,
2049     const SkFontArguments::VariationPosition position,
2050     SkFixed* axisValues,
2051     const SkString& name,
2052     const SkFontArguments::VariationPosition::Coordinate* current)
2053 {
2054     for (int i = 0; i < axisDefinitions.count(); ++i) {
2055         const Scanner::AxisDefinition& axisDefinition = axisDefinitions[i];
2056         const SkScalar axisMin = SkFixedToScalar(axisDefinition.fMinimum);
2057         const SkScalar axisMax = SkFixedToScalar(axisDefinition.fMaximum);
2058 
2059         // Start with the default value.
2060         axisValues[i] = axisDefinition.fDefault;
2061 
2062         // Then the current value.
2063         if (current) {
2064             for (int j = 0; j < axisDefinitions.count(); ++j) {
2065                 const auto& coordinate = current[j];
2066                 if (axisDefinition.fTag == coordinate.axis) {
2067                     const SkScalar axisValue = SkTPin(coordinate.value, axisMin, axisMax);
2068                     axisValues[i] = SkScalarToFixed(axisValue);
2069                     break;
2070                 }
2071             }
2072         }
2073 
2074         // Then the requested value.
2075         // The position may be over specified. If there are multiple values for a given axis,
2076         // use the last one since that's what css-fonts-4 requires.
2077         for (int j = position.coordinateCount; j --> 0;) {
2078             const auto& coordinate = position.coordinates[j];
2079             if (axisDefinition.fTag == coordinate.axis) {
2080                 const SkScalar axisValue = SkTPin(coordinate.value, axisMin, axisMax);
2081                 if (coordinate.value != axisValue) {
2082                     LOG_INFO("Requested font axis value out of range: "
2083                              "%s '%c%c%c%c' %f; pinned to %f.\n",
2084                              name.c_str(),
2085                              (axisDefinition.fTag >> 24) & 0xFF,
2086                              (axisDefinition.fTag >> 16) & 0xFF,
2087                              (axisDefinition.fTag >>  8) & 0xFF,
2088                              (axisDefinition.fTag      ) & 0xFF,
2089                              SkScalarToDouble(coordinate.value),
2090                              SkScalarToDouble(axisValue));
2091                 }
2092                 axisValues[i] = SkScalarToFixed(axisValue);
2093                 break;
2094             }
2095         }
2096         // TODO: warn on defaulted axis?
2097     }
2098 
2099     SkDEBUGCODE(
2100         // Check for axis specified, but not matched in font.
2101         for (int i = 0; i < position.coordinateCount; ++i) {
2102             SkFourByteTag skTag = position.coordinates[i].axis;
2103             bool found = false;
2104             for (int j = 0; j < axisDefinitions.count(); ++j) {
2105                 if (skTag == axisDefinitions[j].fTag) {
2106                     found = true;
2107                     break;
2108                 }
2109             }
2110             if (!found) {
2111                 LOG_INFO("Requested font axis not found: %s '%c%c%c%c'\n",
2112                          name.c_str(),
2113                          (skTag >> 24) & 0xFF,
2114                          (skTag >> 16) & 0xFF,
2115                          (skTag >>  8) & 0xFF,
2116                          (skTag)       & 0xFF);
2117             }
2118         }
2119     )
2120 }
2121