• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2009-2015 Google Inc.
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 /* migrated from chrome/src/skia/ext/SkFontHost_fontconfig_direct.cpp */
9 
10 #include "include/core/SkFontStyle.h"
11 #include "include/core/SkStream.h"
12 #include "include/core/SkString.h"
13 #include "include/core/SkTypeface.h"
14 #include "include/private/SkFixed.h"
15 #include "include/private/SkMutex.h"
16 #include "include/private/SkTArray.h"
17 #include "include/private/SkTDArray.h"
18 #include "include/private/SkTemplates.h"
19 #include "src/core/SkAutoMalloc.h"
20 #include "src/core/SkBuffer.h"
21 #include "src/ports/SkFontConfigInterface_direct.h"
22 
23 #include <fontconfig/fontconfig.h>
24 #include <unistd.h>
25 
26 #ifdef SK_DEBUG
27 #    include "src/core/SkTLS.h"
28 #endif
29 
30 namespace {
31 
32 // Fontconfig is not threadsafe before 2.10.91. Before that, we lock with a global mutex.
33 // See https://bug.skia.org/1497 for background.
f_c_mutex()34 static SkMutex& f_c_mutex() {
35     static SkMutex& mutex = *(new SkMutex);
36     return mutex;
37 }
38 
39 #ifdef SK_DEBUG
CreateThreadFcLocked()40 void* CreateThreadFcLocked() { return new bool(false); }
DeleteThreadFcLocked(void * v)41 void DeleteThreadFcLocked(void* v) { delete static_cast<bool*>(v); }
42 #   define THREAD_FC_LOCKED \
43         static_cast<bool*>(SkTLS::Get(CreateThreadFcLocked, DeleteThreadFcLocked))
44 #endif
45 
46 struct FCLocker {
47     // Assume FcGetVersion() has always been thread safe.
48 
FCLocker__anonc1845f130111::FCLocker49     FCLocker() {
50         if (FcGetVersion() < 21091) {
51             f_c_mutex().acquire();
52         } else {
53             SkDEBUGCODE(bool* threadLocked = THREAD_FC_LOCKED);
54             SkASSERT(false == *threadLocked);
55             SkDEBUGCODE(*threadLocked = true);
56         }
57     }
58 
~FCLocker__anonc1845f130111::FCLocker59     ~FCLocker() {
60         AssertHeld();
61         if (FcGetVersion() < 21091) {
62             f_c_mutex().release();
63         } else {
64             SkDEBUGCODE(*THREAD_FC_LOCKED = false);
65         }
66     }
67 
AssertHeld__anonc1845f130111::FCLocker68     static void AssertHeld() { SkDEBUGCODE(
69         if (FcGetVersion() < 21091) {
70             f_c_mutex().assertHeld();
71         } else {
72             SkASSERT(true == *THREAD_FC_LOCKED);
73         }
74     ) }
75 };
76 
77 } // namespace
78 
writeToMemory(void * addr) const79 size_t SkFontConfigInterface::FontIdentity::writeToMemory(void* addr) const {
80     size_t size = sizeof(fID) + sizeof(fTTCIndex);
81     size += sizeof(int32_t) + sizeof(int32_t) + sizeof(uint8_t); // weight, width, italic
82     size += sizeof(int32_t) + fString.size();    // store length+data
83     if (addr) {
84         SkWBuffer buffer(addr, size);
85 
86         buffer.write32(fID);
87         buffer.write32(fTTCIndex);
88         buffer.write32(fString.size());
89         buffer.write32(fStyle.weight());
90         buffer.write32(fStyle.width());
91         buffer.write8(fStyle.slant());
92         buffer.write(fString.c_str(), fString.size());
93         buffer.padToAlign4();
94 
95         SkASSERT(buffer.pos() == size);
96     }
97     return size;
98 }
99 
readFromMemory(const void * addr,size_t size)100 size_t SkFontConfigInterface::FontIdentity::readFromMemory(const void* addr,
101                                                            size_t size) {
102     SkRBuffer buffer(addr, size);
103 
104     (void)buffer.readU32(&fID);
105     (void)buffer.readS32(&fTTCIndex);
106     uint32_t strLen, weight, width;
107     (void)buffer.readU32(&strLen);
108     (void)buffer.readU32(&weight);
109     (void)buffer.readU32(&width);
110     uint8_t u8;
111     (void)buffer.readU8(&u8);
112     SkFontStyle::Slant slant = (SkFontStyle::Slant)u8;
113     fStyle = SkFontStyle(weight, width, slant);
114     fString.resize(strLen);
115     (void)buffer.read(fString.writable_str(), strLen);
116     buffer.skipToAlign4();
117 
118     return buffer.pos();    // the actual number of bytes read
119 }
120 
121 #ifdef SK_DEBUG
make_iden(SkFontConfigInterface::FontIdentity * iden)122 static void make_iden(SkFontConfigInterface::FontIdentity* iden) {
123     iden->fID = 10;
124     iden->fTTCIndex = 2;
125     iden->fString.set("Hello world");
126     iden->fStyle = SkFontStyle(300, 6, SkFontStyle::kItalic_Slant);
127 }
128 
test_writeToMemory(const SkFontConfigInterface::FontIdentity & iden0,int initValue)129 static void test_writeToMemory(const SkFontConfigInterface::FontIdentity& iden0,
130                                int initValue) {
131     SkFontConfigInterface::FontIdentity iden1;
132 
133     size_t size0 = iden0.writeToMemory(nullptr);
134 
135     SkAutoMalloc storage(size0);
136     memset(storage.get(), initValue, size0);
137 
138     size_t size1 = iden0.writeToMemory(storage.get());
139     SkASSERT(size0 == size1);
140 
141     SkASSERT(iden0 != iden1);
142     size_t size2 = iden1.readFromMemory(storage.get(), size1);
143     SkASSERT(size2 == size1);
144     SkASSERT(iden0 == iden1);
145 }
146 
fontconfiginterface_unittest()147 static void fontconfiginterface_unittest() {
148     SkFontConfigInterface::FontIdentity iden0, iden1;
149 
150     SkASSERT(iden0 == iden1);
151 
152     make_iden(&iden0);
153     SkASSERT(iden0 != iden1);
154 
155     make_iden(&iden1);
156     SkASSERT(iden0 == iden1);
157 
158     test_writeToMemory(iden0, 0);
159     test_writeToMemory(iden0, 0);
160 }
161 #endif
162 
163 ///////////////////////////////////////////////////////////////////////////////
164 
165 // Returns the string from the pattern, or nullptr
get_string(FcPattern * pattern,const char field[],int index=0)166 static const char* get_string(FcPattern* pattern, const char field[], int index = 0) {
167     const char* name;
168     if (FcPatternGetString(pattern, field, index, (FcChar8**)&name) != FcResultMatch) {
169         name = nullptr;
170     }
171     return name;
172 }
173 
174 ///////////////////////////////////////////////////////////////////////////////
175 
176 namespace {
177 
178 // Equivalence classes, used to match the Liberation and other fonts
179 // with their metric-compatible replacements.  See the discussion in
180 // GetFontEquivClass().
181 enum FontEquivClass
182 {
183     OTHER,
184     SANS,
185     SERIF,
186     MONO,
187     SYMBOL,
188     PGOTHIC,
189     GOTHIC,
190     PMINCHO,
191     MINCHO,
192     SIMSUN,
193     NSIMSUN,
194     SIMHEI,
195     PMINGLIU,
196     MINGLIU,
197     PMINGLIUHK,
198     MINGLIUHK,
199     CAMBRIA,
200     CALIBRI,
201 };
202 
203 // Match the font name against a whilelist of fonts, returning the equivalence
204 // class.
GetFontEquivClass(const char * fontname)205 FontEquivClass GetFontEquivClass(const char* fontname)
206 {
207     // It would be nice for fontconfig to tell us whether a given suggested
208     // replacement is a "strong" match (that is, an equivalent font) or
209     // a "weak" match (that is, fontconfig's next-best attempt at finding a
210     // substitute).  However, I played around with the fontconfig API for
211     // a good few hours and could not make it reveal this information.
212     //
213     // So instead, we hardcode.  Initially this function emulated
214     //   /etc/fonts/conf.d/30-metric-aliases.conf
215     // from my Ubuntu system, but we're better off being very conservative.
216 
217     // Arimo, Tinos and Cousine are a set of fonts metric-compatible with
218     // Arial, Times New Roman and Courier New  with a character repertoire
219     // much larger than Liberation. Note that Cousine is metrically
220     // compatible with Courier New, but the former is sans-serif while
221     // the latter is serif.
222 
223 
224     struct FontEquivMap {
225         FontEquivClass clazz;
226         const char name[40];
227     };
228 
229     static const FontEquivMap kFontEquivMap[] = {
230         { SANS, "Arial" },
231         { SANS, "Arimo" },
232         { SANS, "Liberation Sans" },
233 
234         { SERIF, "Times New Roman" },
235         { SERIF, "Tinos" },
236         { SERIF, "Liberation Serif" },
237 
238         { MONO, "Courier New" },
239         { MONO, "Cousine" },
240         { MONO, "Liberation Mono" },
241 
242         { SYMBOL, "Symbol" },
243         { SYMBOL, "Symbol Neu" },
244 
245         // MS Pゴシック
246         { PGOTHIC, "MS PGothic" },
247         { PGOTHIC, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0"
248                    "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" },
249         { PGOTHIC, "Noto Sans CJK JP" },
250         { PGOTHIC, "IPAPGothic" },
251         { PGOTHIC, "MotoyaG04Gothic" },
252 
253         // MS ゴシック
254         { GOTHIC, "MS Gothic" },
255         { GOTHIC, "\xef\xbc\xad\xef\xbc\xb3 "
256                   "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" },
257         { GOTHIC, "Noto Sans Mono CJK JP" },
258         { GOTHIC, "IPAGothic" },
259         { GOTHIC, "MotoyaG04GothicMono" },
260 
261         // MS P明朝
262         { PMINCHO, "MS PMincho" },
263         { PMINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0"
264                    "\xe6\x98\x8e\xe6\x9c\x9d"},
265         { PMINCHO, "Noto Serif CJK JP" },
266         { PMINCHO, "IPAPMincho" },
267         { PMINCHO, "MotoyaG04Mincho" },
268 
269         // MS 明朝
270         { MINCHO, "MS Mincho" },
271         { MINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xe6\x98\x8e\xe6\x9c\x9d" },
272         { MINCHO, "Noto Serif CJK JP" },
273         { MINCHO, "IPAMincho" },
274         { MINCHO, "MotoyaG04MinchoMono" },
275 
276         // 宋体
277         { SIMSUN, "Simsun" },
278         { SIMSUN, "\xe5\xae\x8b\xe4\xbd\x93" },
279         { SIMSUN, "Noto Serif CJK SC" },
280         { SIMSUN, "MSung GB18030" },
281         { SIMSUN, "Song ASC" },
282 
283         // 新宋体
284         { NSIMSUN, "NSimsun" },
285         { NSIMSUN, "\xe6\x96\xb0\xe5\xae\x8b\xe4\xbd\x93" },
286         { NSIMSUN, "Noto Serif CJK SC" },
287         { NSIMSUN, "MSung GB18030" },
288         { NSIMSUN, "N Song ASC" },
289 
290         // 黑体
291         { SIMHEI, "Simhei" },
292         { SIMHEI, "\xe9\xbb\x91\xe4\xbd\x93" },
293         { SIMHEI, "Noto Sans CJK SC" },
294         { SIMHEI, "MYingHeiGB18030" },
295         { SIMHEI, "MYingHeiB5HK" },
296 
297         // 新細明體
298         { PMINGLIU, "PMingLiU"},
299         { PMINGLIU, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" },
300         { PMINGLIU, "Noto Serif CJK TC"},
301         { PMINGLIU, "MSung B5HK"},
302 
303         // 細明體
304         { MINGLIU, "MingLiU"},
305         { MINGLIU, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" },
306         { MINGLIU, "Noto Serif CJK TC"},
307         { MINGLIU, "MSung B5HK"},
308 
309         // 新細明體
310         { PMINGLIUHK, "PMingLiU_HKSCS"},
311         { PMINGLIUHK, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" },
312         { PMINGLIUHK, "Noto Serif CJK TC"},
313         { PMINGLIUHK, "MSung B5HK"},
314 
315         // 細明體
316         { MINGLIUHK, "MingLiU_HKSCS"},
317         { MINGLIUHK, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" },
318         { MINGLIUHK, "Noto Serif CJK TC"},
319         { MINGLIUHK, "MSung B5HK"},
320 
321         // Cambria
322         { CAMBRIA, "Cambria" },
323         { CAMBRIA, "Caladea" },
324 
325         // Calibri
326         { CALIBRI, "Calibri" },
327         { CALIBRI, "Carlito" },
328     };
329 
330     static const size_t kFontCount =
331         sizeof(kFontEquivMap)/sizeof(kFontEquivMap[0]);
332 
333     // TODO(jungshik): If this loop turns out to be hot, turn
334     // the array to a static (hash)map to speed it up.
335     for (size_t i = 0; i < kFontCount; ++i) {
336         if (strcasecmp(kFontEquivMap[i].name, fontname) == 0)
337             return kFontEquivMap[i].clazz;
338     }
339     return OTHER;
340 }
341 
342 
343 // Return true if |font_a| and |font_b| are visually and at the metrics
344 // level interchangeable.
IsMetricCompatibleReplacement(const char * font_a,const char * font_b)345 bool IsMetricCompatibleReplacement(const char* font_a, const char* font_b)
346 {
347     FontEquivClass class_a = GetFontEquivClass(font_a);
348     FontEquivClass class_b = GetFontEquivClass(font_b);
349 
350     return class_a != OTHER && class_a == class_b;
351 }
352 
353 // Normally we only return exactly the font asked for. In last-resort
354 // cases, the request either doesn't specify a font or is one of the
355 // basic font names like "Sans", "Serif" or "Monospace". This function
356 // tells you whether a given request is for such a fallback.
IsFallbackFontAllowed(const SkString & family)357 bool IsFallbackFontAllowed(const SkString& family) {
358   const char* family_cstr = family.c_str();
359   return family.isEmpty() ||
360          strcasecmp(family_cstr, "sans") == 0 ||
361          strcasecmp(family_cstr, "serif") == 0 ||
362          strcasecmp(family_cstr, "monospace") == 0;
363 }
364 
365 // Retrieves |is_bold|, |is_italic| and |font_family| properties from |font|.
get_int(FcPattern * pattern,const char object[],int missing)366 static int get_int(FcPattern* pattern, const char object[], int missing) {
367     int value;
368     if (FcPatternGetInteger(pattern, object, 0, &value) != FcResultMatch) {
369         return missing;
370     }
371     return value;
372 }
373 
map_range(SkScalar value,SkScalar old_min,SkScalar old_max,SkScalar new_min,SkScalar new_max)374 static int map_range(SkScalar value,
375                      SkScalar old_min, SkScalar old_max,
376                      SkScalar new_min, SkScalar new_max)
377 {
378     SkASSERT(old_min < old_max);
379     SkASSERT(new_min <= new_max);
380     return new_min + ((value - old_min) * (new_max - new_min) / (old_max - old_min));
381 }
382 
383 struct MapRanges {
384     SkScalar old_val;
385     SkScalar new_val;
386 };
387 
map_ranges(SkScalar val,MapRanges const ranges[],int rangesCount)388 static SkScalar map_ranges(SkScalar val, MapRanges const ranges[], int rangesCount) {
389     // -Inf to [0]
390     if (val < ranges[0].old_val) {
391         return ranges[0].new_val;
392     }
393 
394     // Linear from [i] to [i+1]
395     for (int i = 0; i < rangesCount - 1; ++i) {
396         if (val < ranges[i+1].old_val) {
397             return map_range(val, ranges[i].old_val, ranges[i+1].old_val,
398                                   ranges[i].new_val, ranges[i+1].new_val);
399         }
400     }
401 
402     // From [n] to +Inf
403     // if (fcweight < Inf)
404     return ranges[rangesCount-1].new_val;
405 }
406 
407 #ifndef FC_WEIGHT_DEMILIGHT
408 #define FC_WEIGHT_DEMILIGHT        65
409 #endif
410 
skfontstyle_from_fcpattern(FcPattern * pattern)411 static SkFontStyle skfontstyle_from_fcpattern(FcPattern* pattern) {
412     typedef SkFontStyle SkFS;
413 
414     static constexpr MapRanges weightRanges[] = {
415         { FC_WEIGHT_THIN,       SkFS::kThin_Weight },
416         { FC_WEIGHT_EXTRALIGHT, SkFS::kExtraLight_Weight },
417         { FC_WEIGHT_LIGHT,      SkFS::kLight_Weight },
418         { FC_WEIGHT_DEMILIGHT,  350 },
419         { FC_WEIGHT_BOOK,       380 },
420         { FC_WEIGHT_REGULAR,    SkFS::kNormal_Weight },
421         { FC_WEIGHT_MEDIUM,     SkFS::kMedium_Weight },
422         { FC_WEIGHT_DEMIBOLD,   SkFS::kSemiBold_Weight },
423         { FC_WEIGHT_BOLD,       SkFS::kBold_Weight },
424         { FC_WEIGHT_EXTRABOLD,  SkFS::kExtraBold_Weight },
425         { FC_WEIGHT_BLACK,      SkFS::kBlack_Weight },
426         { FC_WEIGHT_EXTRABLACK, SkFS::kExtraBlack_Weight },
427     };
428     SkScalar weight = map_ranges(get_int(pattern, FC_WEIGHT, FC_WEIGHT_REGULAR),
429                                  weightRanges, SK_ARRAY_COUNT(weightRanges));
430 
431     static constexpr MapRanges widthRanges[] = {
432         { FC_WIDTH_ULTRACONDENSED, SkFS::kUltraCondensed_Width },
433         { FC_WIDTH_EXTRACONDENSED, SkFS::kExtraCondensed_Width },
434         { FC_WIDTH_CONDENSED,      SkFS::kCondensed_Width },
435         { FC_WIDTH_SEMICONDENSED,  SkFS::kSemiCondensed_Width },
436         { FC_WIDTH_NORMAL,         SkFS::kNormal_Width },
437         { FC_WIDTH_SEMIEXPANDED,   SkFS::kSemiExpanded_Width },
438         { FC_WIDTH_EXPANDED,       SkFS::kExpanded_Width },
439         { FC_WIDTH_EXTRAEXPANDED,  SkFS::kExtraExpanded_Width },
440         { FC_WIDTH_ULTRAEXPANDED,  SkFS::kUltraExpanded_Width },
441     };
442     SkScalar width = map_ranges(get_int(pattern, FC_WIDTH, FC_WIDTH_NORMAL),
443                                 widthRanges, SK_ARRAY_COUNT(widthRanges));
444 
445     SkFS::Slant slant = SkFS::kUpright_Slant;
446     switch (get_int(pattern, FC_SLANT, FC_SLANT_ROMAN)) {
447         case FC_SLANT_ROMAN:   slant = SkFS::kUpright_Slant; break;
448         case FC_SLANT_ITALIC : slant = SkFS::kItalic_Slant ; break;
449         case FC_SLANT_OBLIQUE: slant = SkFS::kOblique_Slant; break;
450         default: SkASSERT(false); break;
451     }
452 
453     return SkFontStyle(SkScalarRoundToInt(weight), SkScalarRoundToInt(width), slant);
454 }
455 
fcpattern_from_skfontstyle(SkFontStyle style,FcPattern * pattern)456 static void fcpattern_from_skfontstyle(SkFontStyle style, FcPattern* pattern) {
457     typedef SkFontStyle SkFS;
458 
459     static constexpr MapRanges weightRanges[] = {
460         { SkFS::kThin_Weight,       FC_WEIGHT_THIN },
461         { SkFS::kExtraLight_Weight, FC_WEIGHT_EXTRALIGHT },
462         { SkFS::kLight_Weight,      FC_WEIGHT_LIGHT },
463         { 350,                      FC_WEIGHT_DEMILIGHT },
464         { 380,                      FC_WEIGHT_BOOK },
465         { SkFS::kNormal_Weight,     FC_WEIGHT_REGULAR },
466         { SkFS::kMedium_Weight,     FC_WEIGHT_MEDIUM },
467         { SkFS::kSemiBold_Weight,   FC_WEIGHT_DEMIBOLD },
468         { SkFS::kBold_Weight,       FC_WEIGHT_BOLD },
469         { SkFS::kExtraBold_Weight,  FC_WEIGHT_EXTRABOLD },
470         { SkFS::kBlack_Weight,      FC_WEIGHT_BLACK },
471         { SkFS::kExtraBlack_Weight, FC_WEIGHT_EXTRABLACK },
472     };
473     int weight = map_ranges(style.weight(), weightRanges, SK_ARRAY_COUNT(weightRanges));
474 
475     static constexpr MapRanges widthRanges[] = {
476         { SkFS::kUltraCondensed_Width, FC_WIDTH_ULTRACONDENSED },
477         { SkFS::kExtraCondensed_Width, FC_WIDTH_EXTRACONDENSED },
478         { SkFS::kCondensed_Width,      FC_WIDTH_CONDENSED },
479         { SkFS::kSemiCondensed_Width,  FC_WIDTH_SEMICONDENSED },
480         { SkFS::kNormal_Width,         FC_WIDTH_NORMAL },
481         { SkFS::kSemiExpanded_Width,   FC_WIDTH_SEMIEXPANDED },
482         { SkFS::kExpanded_Width,       FC_WIDTH_EXPANDED },
483         { SkFS::kExtraExpanded_Width,  FC_WIDTH_EXTRAEXPANDED },
484         { SkFS::kUltraExpanded_Width,  FC_WIDTH_ULTRAEXPANDED },
485     };
486     int width = map_ranges(style.width(), widthRanges, SK_ARRAY_COUNT(widthRanges));
487 
488     int slant = FC_SLANT_ROMAN;
489     switch (style.slant()) {
490         case SkFS::kUpright_Slant: slant = FC_SLANT_ROMAN  ; break;
491         case SkFS::kItalic_Slant : slant = FC_SLANT_ITALIC ; break;
492         case SkFS::kOblique_Slant: slant = FC_SLANT_OBLIQUE; break;
493         default: SkASSERT(false); break;
494     }
495 
496     FcPatternAddInteger(pattern, FC_WEIGHT, weight);
497     FcPatternAddInteger(pattern, FC_WIDTH , width);
498     FcPatternAddInteger(pattern, FC_SLANT , slant);
499 }
500 
501 }  // anonymous namespace
502 
503 ///////////////////////////////////////////////////////////////////////////////
504 
505 #define kMaxFontFamilyLength    2048
506 #ifdef SK_FONT_CONFIG_INTERFACE_ONLY_ALLOW_SFNT_FONTS
507 const char* kFontFormatTrueType = "TrueType";
508 const char* kFontFormatCFF = "CFF";
509 #endif
510 
SkFontConfigInterfaceDirect()511 SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() {
512     FCLocker lock;
513 
514     FcInit();
515 
516     SkDEBUGCODE(fontconfiginterface_unittest();)
517 }
518 
~SkFontConfigInterfaceDirect()519 SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() {
520 }
521 
isAccessible(const char * filename)522 bool SkFontConfigInterfaceDirect::isAccessible(const char* filename) {
523     if (access(filename, R_OK) != 0) {
524         return false;
525     }
526     return true;
527 }
528 
isValidPattern(FcPattern * pattern)529 bool SkFontConfigInterfaceDirect::isValidPattern(FcPattern* pattern) {
530 #ifdef SK_FONT_CONFIG_INTERFACE_ONLY_ALLOW_SFNT_FONTS
531     const char* font_format = get_string(pattern, FC_FONTFORMAT);
532     if (font_format
533         && strcmp(font_format, kFontFormatTrueType) != 0
534         && strcmp(font_format, kFontFormatCFF) != 0)
535     {
536         return false;
537     }
538 #endif
539 
540     // fontconfig can also return fonts which are unreadable
541     const char* c_filename = get_string(pattern, FC_FILE);
542     if (!c_filename) {
543         return false;
544     }
545     const char* sysroot = (const char*)FcConfigGetSysRoot(nullptr);
546     SkString resolvedFilename;
547     if (sysroot) {
548         resolvedFilename = sysroot;
549         resolvedFilename += c_filename;
550         c_filename = resolvedFilename.c_str();
551     }
552     return this->isAccessible(c_filename);
553 }
554 
555 // Find matching font from |font_set| for the given font family.
MatchFont(FcFontSet * font_set,const char * post_config_family,const SkString & family)556 FcPattern* SkFontConfigInterfaceDirect::MatchFont(FcFontSet* font_set,
557                                                   const char* post_config_family,
558                                                   const SkString& family) {
559   // Older versions of fontconfig have a bug where they cannot select
560   // only scalable fonts so we have to manually filter the results.
561   FcPattern* match = nullptr;
562   for (int i = 0; i < font_set->nfont; ++i) {
563     FcPattern* current = font_set->fonts[i];
564     if (this->isValidPattern(current)) {
565       match = current;
566       break;
567     }
568   }
569 
570   if (match && !IsFallbackFontAllowed(family)) {
571     bool acceptable_substitute = false;
572     for (int id = 0; id < 255; ++id) {
573       const char* post_match_family = get_string(match, FC_FAMILY, id);
574       if (!post_match_family)
575         break;
576       acceptable_substitute =
577           (strcasecmp(post_config_family, post_match_family) == 0 ||
578            // Workaround for Issue 12530:
579            //   requested family: "Bitstream Vera Sans"
580            //   post_config_family: "Arial"
581            //   post_match_family: "Bitstream Vera Sans"
582            // -> We should treat this case as a good match.
583            strcasecmp(family.c_str(), post_match_family) == 0) ||
584            IsMetricCompatibleReplacement(family.c_str(), post_match_family);
585       if (acceptable_substitute)
586         break;
587     }
588     if (!acceptable_substitute)
589       return nullptr;
590   }
591 
592   return match;
593 }
594 
matchFamilyName(const char familyName[],SkFontStyle style,FontIdentity * outIdentity,SkString * outFamilyName,SkFontStyle * outStyle)595 bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[],
596                                                   SkFontStyle style,
597                                                   FontIdentity* outIdentity,
598                                                   SkString* outFamilyName,
599                                                   SkFontStyle* outStyle) {
600     SkString familyStr(familyName ? familyName : "");
601     if (familyStr.size() > kMaxFontFamilyLength) {
602         return false;
603     }
604 
605     FCLocker lock;
606 
607     FcPattern* pattern = FcPatternCreate();
608 
609     if (familyName) {
610         FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
611     }
612     fcpattern_from_skfontstyle(style, pattern);
613 
614     FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
615 
616     FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
617     FcDefaultSubstitute(pattern);
618 
619     // Font matching:
620     // CSS often specifies a fallback list of families:
621     //    font-family: a, b, c, serif;
622     // However, fontconfig will always do its best to find *a* font when asked
623     // for something so we need a way to tell if the match which it has found is
624     // "good enough" for us. Otherwise, we can return nullptr which gets piped up
625     // and lets WebKit know to try the next CSS family name. However, fontconfig
626     // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
627     // wish to support that.
628     //
629     // Thus, if a specific family is requested we set @family_requested. Then we
630     // record two strings: the family name after config processing and the
631     // family name after resolving. If the two are equal, it's a good match.
632     //
633     // So consider the case where a user has mapped Arial to Helvetica in their
634     // config.
635     //    requested family: "Arial"
636     //    post_config_family: "Helvetica"
637     //    post_match_family: "Helvetica"
638     //      -> good match
639     //
640     // and for a missing font:
641     //    requested family: "Monaco"
642     //    post_config_family: "Monaco"
643     //    post_match_family: "Times New Roman"
644     //      -> BAD match
645     //
646     // However, we special-case fallback fonts; see IsFallbackFontAllowed().
647 
648     const char* post_config_family = get_string(pattern, FC_FAMILY);
649     if (!post_config_family) {
650         // we can just continue with an empty name, e.g. default font
651         post_config_family = "";
652     }
653 
654     FcResult result;
655     FcFontSet* font_set = FcFontSort(nullptr, pattern, 0, nullptr, &result);
656     if (!font_set) {
657         FcPatternDestroy(pattern);
658         return false;
659     }
660 
661     FcPattern* match = this->MatchFont(font_set, post_config_family, familyStr);
662     if (!match) {
663         FcPatternDestroy(pattern);
664         FcFontSetDestroy(font_set);
665         return false;
666     }
667 
668     FcPatternDestroy(pattern);
669 
670     // From here out we just extract our results from 'match'
671 
672     post_config_family = get_string(match, FC_FAMILY);
673     if (!post_config_family) {
674         FcFontSetDestroy(font_set);
675         return false;
676     }
677 
678     const char* c_filename = get_string(match, FC_FILE);
679     if (!c_filename) {
680         FcFontSetDestroy(font_set);
681         return false;
682     }
683     const char* sysroot = (const char*)FcConfigGetSysRoot(nullptr);
684     SkString resolvedFilename;
685     if (sysroot) {
686         resolvedFilename = sysroot;
687         resolvedFilename += c_filename;
688         c_filename = resolvedFilename.c_str();
689     }
690 
691     int face_index = get_int(match, FC_INDEX, 0);
692 
693     FcFontSetDestroy(font_set);
694 
695     if (outIdentity) {
696         outIdentity->fTTCIndex = face_index;
697         outIdentity->fString.set(c_filename);
698     }
699     if (outFamilyName) {
700         outFamilyName->set(post_config_family);
701     }
702     if (outStyle) {
703         *outStyle = skfontstyle_from_fcpattern(match);
704     }
705     return true;
706 }
707 
openStream(const FontIdentity & identity)708 SkStreamAsset* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) {
709     return SkStream::MakeFromFile(identity.fString.c_str()).release();
710 }
711