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