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