• 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/base/SkFixed.h"
15 #include "include/private/base/SkMutex.h"
16 #include "include/private/base/SkTArray.h"
17 #include "include/private/base/SkTDArray.h"
18 #include "include/private/base/SkTemplates.h"
19 #include "src/base/SkAutoMalloc.h"
20 #include "src/base/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__anond6ffa5f20111::FCLocker40     FCLocker() {
41         if (FcGetVersion() < FontConfigThreadSafeVersion) {
42             f_c_mutex().acquire();
43         }
44     }
45 
~FCLocker__anond6ffa5f20111::FCLocker46     ~FCLocker() {
47         AssertHeld();
48         if (FcGetVersion() < FontConfigThreadSafeVersion) {
49             f_c_mutex().release();
50         }
51     }
52 
AssertHeld__anond6ffa5f20111::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, SkFunctionObject<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.data(), 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, std::size(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, std::size(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, std::size(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, std::size(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(FcConfig * fc)496 SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect(FcConfig* fc) : fFC(fc)
497 {
498     SkDEBUGCODE(fontconfiginterface_unittest();)
499 }
500 
~SkFontConfigInterfaceDirect()501 SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() {
502     if (fFC) {
503         FcConfigDestroy(fFC);
504     }
505 }
506 
isAccessible(const char * filename)507 bool SkFontConfigInterfaceDirect::isAccessible(const char* filename) {
508     if (access(filename, R_OK) != 0) {
509         return false;
510     }
511     return true;
512 }
513 
isValidPattern(FcPattern * pattern)514 bool SkFontConfigInterfaceDirect::isValidPattern(FcPattern* pattern) {
515 #ifdef SK_FONT_CONFIG_INTERFACE_ONLY_ALLOW_SFNT_FONTS
516     const char* font_format = get_string(pattern, FC_FONTFORMAT);
517     if (font_format
518         && 0 != strcmp(font_format, kFontFormatTrueType)
519         && 0 != strcmp(font_format, kFontFormatCFF))
520     {
521         return false;
522     }
523 #endif
524 
525     // fontconfig can also return fonts which are unreadable
526     const char* c_filename = get_string(pattern, FC_FILE);
527     if (!c_filename) {
528         return false;
529     }
530 
531     FcConfig* fc = fFC;
532     UniqueFCConfig fcStorage;
533     if (!fc) {
534         fcStorage.reset(FcConfigReference(nullptr));
535         fc = fcStorage.get();
536     }
537 
538     const char* sysroot = (const char*)FcConfigGetSysRoot(fc);
539     SkString resolvedFilename;
540     if (sysroot) {
541         resolvedFilename = sysroot;
542         resolvedFilename += c_filename;
543         c_filename = resolvedFilename.c_str();
544     }
545     return this->isAccessible(c_filename);
546 }
547 
548 // Find matching font from |font_set| for the given font family.
MatchFont(FcFontSet * font_set,const char * post_config_family,const SkString & family)549 FcPattern* SkFontConfigInterfaceDirect::MatchFont(FcFontSet* font_set,
550                                                   const char* post_config_family,
551                                                   const SkString& family) {
552   // Older versions of fontconfig have a bug where they cannot select
553   // only scalable fonts so we have to manually filter the results.
554   FcPattern* match = nullptr;
555   for (int i = 0; i < font_set->nfont; ++i) {
556     FcPattern* current = font_set->fonts[i];
557     if (this->isValidPattern(current)) {
558       match = current;
559       break;
560     }
561   }
562 
563   if (match && !IsFallbackFontAllowed(family)) {
564     bool acceptable_substitute = false;
565     for (int id = 0; id < 255; ++id) {
566       const char* post_match_family = get_string(match, FC_FAMILY, id);
567       if (!post_match_family)
568         break;
569       acceptable_substitute =
570           (strcasecmp(post_config_family, post_match_family) == 0 ||
571            // Workaround for Issue 12530:
572            //   requested family: "Bitstream Vera Sans"
573            //   post_config_family: "Arial"
574            //   post_match_family: "Bitstream Vera Sans"
575            // -> We should treat this case as a good match.
576            strcasecmp(family.c_str(), post_match_family) == 0) ||
577            IsMetricCompatibleReplacement(family.c_str(), post_match_family);
578       if (acceptable_substitute)
579         break;
580     }
581     if (!acceptable_substitute)
582       return nullptr;
583   }
584 
585   return match;
586 }
587 
matchFamilyName(const char familyName[],SkFontStyle style,FontIdentity * outIdentity,SkString * outFamilyName,SkFontStyle * outStyle)588 bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[],
589                                                   SkFontStyle style,
590                                                   FontIdentity* outIdentity,
591                                                   SkString* outFamilyName,
592                                                   SkFontStyle* outStyle) {
593     SkString familyStr(familyName ? familyName : "");
594     if (familyStr.size() > kMaxFontFamilyLength) {
595         return false;
596     }
597 
598     FcConfig* fc = fFC;
599     UniqueFCConfig fcStorage;
600     if (!fc) {
601         fcStorage.reset(FcConfigReference(nullptr));
602         fc = fcStorage.get();
603     }
604 
605     FCLocker lock;
606     FcPattern* pattern = FcPatternCreate();
607 
608     if (familyName) {
609         FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
610     }
611     fcpattern_from_skfontstyle(style, pattern);
612 
613     FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
614 
615     FcConfigSubstitute(fc, pattern, FcMatchPattern);
616     FcDefaultSubstitute(pattern);
617 
618     // Font matching:
619     // CSS often specifies a fallback list of families:
620     //    font-family: a, b, c, serif;
621     // However, fontconfig will always do its best to find *a* font when asked
622     // for something so we need a way to tell if the match which it has found is
623     // "good enough" for us. Otherwise, we can return nullptr which gets piped up
624     // and lets WebKit know to try the next CSS family name. However, fontconfig
625     // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
626     // wish to support that.
627     //
628     // Thus, if a specific family is requested we set @family_requested. Then we
629     // record two strings: the family name after config processing and the
630     // family name after resolving. If the two are equal, it's a good match.
631     //
632     // So consider the case where a user has mapped Arial to Helvetica in their
633     // config.
634     //    requested family: "Arial"
635     //    post_config_family: "Helvetica"
636     //    post_match_family: "Helvetica"
637     //      -> good match
638     //
639     // and for a missing font:
640     //    requested family: "Monaco"
641     //    post_config_family: "Monaco"
642     //    post_match_family: "Times New Roman"
643     //      -> BAD match
644     //
645     // However, we special-case fallback fonts; see IsFallbackFontAllowed().
646 
647     const char* post_config_family = get_string(pattern, FC_FAMILY);
648     if (!post_config_family) {
649         // we can just continue with an empty name, e.g. default font
650         post_config_family = "";
651     }
652 
653     FcResult result;
654     FcFontSet* font_set = FcFontSort(fc, pattern, 0, nullptr, &result);
655     if (!font_set) {
656         FcPatternDestroy(pattern);
657         return false;
658     }
659 
660     FcPattern* match = this->MatchFont(font_set, post_config_family, familyStr);
661     if (!match) {
662         FcPatternDestroy(pattern);
663         FcFontSetDestroy(font_set);
664         return false;
665     }
666 
667     FcPatternDestroy(pattern);
668 
669     // From here out we just extract our results from 'match'
670 
671     post_config_family = get_string(match, FC_FAMILY);
672     if (!post_config_family) {
673         FcFontSetDestroy(font_set);
674         return false;
675     }
676 
677     const char* c_filename = get_string(match, FC_FILE);
678     if (!c_filename) {
679         FcFontSetDestroy(font_set);
680         return false;
681     }
682     const char* sysroot = (const char*)FcConfigGetSysRoot(fc);
683     SkString resolvedFilename;
684     if (sysroot) {
685         resolvedFilename = sysroot;
686         resolvedFilename += c_filename;
687         c_filename = resolvedFilename.c_str();
688     }
689 
690     int face_index = get_int(match, FC_INDEX, 0);
691 
692     FcFontSetDestroy(font_set);
693 
694     if (outIdentity) {
695         outIdentity->fTTCIndex = face_index;
696         outIdentity->fString.set(c_filename);
697     }
698     if (outFamilyName) {
699         outFamilyName->set(post_config_family);
700     }
701     if (outStyle) {
702         *outStyle = skfontstyle_from_fcpattern(match);
703     }
704     return true;
705 }
706 
openStream(const FontIdentity & identity)707 SkStreamAsset* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) {
708     return SkStream::MakeFromFile(identity.fString.c_str()).release();
709 }
710