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