• 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__anon15a98bec0111::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__anon15a98bec0111::FCLocker56     ~FCLocker() {
57         AssertHeld();
58         if (FcGetVersion() < 21091) {
59             gFCMutex.release();
60         } else {
61             SkDEBUGCODE(*THREAD_FC_LOCKED = false);
62         }
63     }
64 
AssertHeld__anon15a98bec0111::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, "IPAPMincho" },
263         { PMINCHO, "MotoyaG04Mincho" },
264 
265         // MS 明朝
266         { MINCHO, "MS Mincho" },
267         { MINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xe6\x98\x8e\xe6\x9c\x9d" },
268         { MINCHO, "IPAMincho" },
269         { MINCHO, "MotoyaG04MinchoMono" },
270 
271         // 宋体
272         { SIMSUN, "Simsun" },
273         { SIMSUN, "\xe5\xae\x8b\xe4\xbd\x93" },
274         { SIMSUN, "MSung GB18030" },
275         { SIMSUN, "Song ASC" },
276 
277         // 新宋体
278         { NSIMSUN, "NSimsun" },
279         { NSIMSUN, "\xe6\x96\xb0\xe5\xae\x8b\xe4\xbd\x93" },
280         { NSIMSUN, "MSung GB18030" },
281         { NSIMSUN, "N Song ASC" },
282 
283         // 黑体
284         { SIMHEI, "Simhei" },
285         { SIMHEI, "\xe9\xbb\x91\xe4\xbd\x93" },
286         { SIMHEI, "Noto Sans CJK SC" },
287         { SIMHEI, "MYingHeiGB18030" },
288         { SIMHEI, "MYingHeiB5HK" },
289 
290         // 新細明體
291         { PMINGLIU, "PMingLiU"},
292         { PMINGLIU, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" },
293         { PMINGLIU, "MSung B5HK"},
294 
295         // 細明體
296         { MINGLIU, "MingLiU"},
297         { MINGLIU, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" },
298         { MINGLIU, "MSung B5HK"},
299 
300         // 新細明體
301         { PMINGLIUHK, "PMingLiU_HKSCS"},
302         { PMINGLIUHK, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" },
303         { PMINGLIUHK, "MSung B5HK"},
304 
305         // 細明體
306         { MINGLIUHK, "MingLiU_HKSCS"},
307         { MINGLIUHK, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" },
308         { MINGLIUHK, "MSung B5HK"},
309 
310         // Cambria
311         { CAMBRIA, "Cambria" },
312         { CAMBRIA, "Caladea" },
313 
314         // Calibri
315         { CALIBRI, "Calibri" },
316         { CALIBRI, "Carlito" },
317     };
318 
319     static const size_t kFontCount =
320         sizeof(kFontEquivMap)/sizeof(kFontEquivMap[0]);
321 
322     // TODO(jungshik): If this loop turns out to be hot, turn
323     // the array to a static (hash)map to speed it up.
324     for (size_t i = 0; i < kFontCount; ++i) {
325         if (strcasecmp(kFontEquivMap[i].name, fontname) == 0)
326             return kFontEquivMap[i].clazz;
327     }
328     return OTHER;
329 }
330 
331 
332 // Return true if |font_a| and |font_b| are visually and at the metrics
333 // level interchangeable.
IsMetricCompatibleReplacement(const char * font_a,const char * font_b)334 bool IsMetricCompatibleReplacement(const char* font_a, const char* font_b)
335 {
336     FontEquivClass class_a = GetFontEquivClass(font_a);
337     FontEquivClass class_b = GetFontEquivClass(font_b);
338 
339     return class_a != OTHER && class_a == class_b;
340 }
341 
342 // Normally we only return exactly the font asked for. In last-resort
343 // cases, the request either doesn't specify a font or is one of the
344 // basic font names like "Sans", "Serif" or "Monospace". This function
345 // tells you whether a given request is for such a fallback.
IsFallbackFontAllowed(const SkString & family)346 bool IsFallbackFontAllowed(const SkString& family) {
347   const char* family_cstr = family.c_str();
348   return family.isEmpty() ||
349          strcasecmp(family_cstr, "sans") == 0 ||
350          strcasecmp(family_cstr, "serif") == 0 ||
351          strcasecmp(family_cstr, "monospace") == 0;
352 }
353 
354 // Retrieves |is_bold|, |is_italic| and |font_family| properties from |font|.
get_int(FcPattern * pattern,const char object[],int missing)355 static int get_int(FcPattern* pattern, const char object[], int missing) {
356     int value;
357     if (FcPatternGetInteger(pattern, object, 0, &value) != FcResultMatch) {
358         return missing;
359     }
360     return value;
361 }
362 
map_range(SkFixed value,SkFixed old_min,SkFixed old_max,SkFixed new_min,SkFixed new_max)363 static int map_range(SkFixed value,
364                      SkFixed old_min, SkFixed old_max,
365                      SkFixed new_min, SkFixed new_max)
366 {
367     SkASSERT(old_min < old_max);
368     SkASSERT(new_min <= new_max);
369     return new_min + SkMulDiv(value - old_min, new_max - new_min, old_max - old_min);
370 }
371 
372 struct MapRanges {
373     SkFixed old_val;
374     SkFixed new_val;
375 };
376 
map_ranges_fixed(SkFixed val,MapRanges const ranges[],int rangesCount)377 static SkFixed map_ranges_fixed(SkFixed val, MapRanges const ranges[], int rangesCount) {
378     // -Inf to [0]
379     if (val < ranges[0].old_val) {
380         return ranges[0].new_val;
381     }
382 
383     // Linear from [i] to [i+1]
384     for (int i = 0; i < rangesCount - 1; ++i) {
385         if (val < ranges[i+1].old_val) {
386             return map_range(val, ranges[i].old_val, ranges[i+1].old_val,
387                                   ranges[i].new_val, ranges[i+1].new_val);
388         }
389     }
390 
391     // From [n] to +Inf
392     // if (fcweight < Inf)
393     return ranges[rangesCount-1].new_val;
394 }
395 
map_ranges(int val,MapRanges const ranges[],int rangesCount)396 static int map_ranges(int val, MapRanges const ranges[], int rangesCount) {
397     return SkFixedRoundToInt(map_ranges_fixed(SkIntToFixed(val), ranges, rangesCount));
398 }
399 
400 template<int n> struct SkTFixed {
401     static_assert(-32768 <= n && n <= 32767, "SkTFixed_n_not_in_range");
402     static const SkFixed value = static_cast<SkFixed>(n << 16);
403 };
404 
skfontstyle_from_fcpattern(FcPattern * pattern)405 static SkFontStyle skfontstyle_from_fcpattern(FcPattern* pattern) {
406     typedef SkFontStyle SkFS;
407 
408     static const MapRanges weightRanges[] = {
409         { SkTFixed<FC_WEIGHT_THIN>::value,       SkTFixed<SkFS::kThin_Weight>::value },
410         { SkTFixed<FC_WEIGHT_EXTRALIGHT>::value, SkTFixed<SkFS::kExtraLight_Weight>::value },
411         { SkTFixed<FC_WEIGHT_LIGHT>::value,      SkTFixed<SkFS::kLight_Weight>::value },
412         { SkTFixed<FC_WEIGHT_REGULAR>::value,    SkTFixed<SkFS::kNormal_Weight>::value },
413         { SkTFixed<FC_WEIGHT_MEDIUM>::value,     SkTFixed<SkFS::kMedium_Weight>::value },
414         { SkTFixed<FC_WEIGHT_DEMIBOLD>::value,   SkTFixed<SkFS::kSemiBold_Weight>::value },
415         { SkTFixed<FC_WEIGHT_BOLD>::value,       SkTFixed<SkFS::kBold_Weight>::value },
416         { SkTFixed<FC_WEIGHT_EXTRABOLD>::value,  SkTFixed<SkFS::kExtraBold_Weight>::value },
417         { SkTFixed<FC_WEIGHT_BLACK>::value,      SkTFixed<SkFS::kBlack_Weight>::value },
418         { SkTFixed<FC_WEIGHT_EXTRABLACK>::value, SkTFixed<SkFS::kExtraBlack_Weight>::value },
419     };
420     int weight = map_ranges(get_int(pattern, FC_WEIGHT, FC_WEIGHT_REGULAR),
421                             weightRanges, SK_ARRAY_COUNT(weightRanges));
422 
423     static const MapRanges widthRanges[] = {
424         { SkTFixed<FC_WIDTH_ULTRACONDENSED>::value, SkTFixed<SkFS::kUltraCondensed_Width>::value },
425         { SkTFixed<FC_WIDTH_EXTRACONDENSED>::value, SkTFixed<SkFS::kExtraCondensed_Width>::value },
426         { SkTFixed<FC_WIDTH_CONDENSED>::value,      SkTFixed<SkFS::kCondensed_Width>::value },
427         { SkTFixed<FC_WIDTH_SEMICONDENSED>::value,  SkTFixed<SkFS::kSemiCondensed_Width>::value },
428         { SkTFixed<FC_WIDTH_NORMAL>::value,         SkTFixed<SkFS::kNormal_Width>::value },
429         { SkTFixed<FC_WIDTH_SEMIEXPANDED>::value,   SkTFixed<SkFS::kSemiExpanded_Width>::value },
430         { SkTFixed<FC_WIDTH_EXPANDED>::value,       SkTFixed<SkFS::kExpanded_Width>::value },
431         { SkTFixed<FC_WIDTH_EXTRAEXPANDED>::value,  SkTFixed<SkFS::kExtraExpanded_Width>::value },
432         { SkTFixed<FC_WIDTH_ULTRAEXPANDED>::value,  SkTFixed<SkFS::kUltraExpanded_Width>::value },
433     };
434     int width = map_ranges(get_int(pattern, FC_WIDTH, FC_WIDTH_NORMAL),
435                            widthRanges, SK_ARRAY_COUNT(widthRanges));
436 
437     SkFS::Slant slant = SkFS::kUpright_Slant;
438     switch (get_int(pattern, FC_SLANT, FC_SLANT_ROMAN)) {
439         case FC_SLANT_ROMAN:   slant = SkFS::kUpright_Slant; break;
440         case FC_SLANT_ITALIC : slant = SkFS::kItalic_Slant ; break;
441         case FC_SLANT_OBLIQUE: slant = SkFS::kOblique_Slant; break;
442         default: SkASSERT(false); break;
443     }
444 
445     return SkFontStyle(weight, width, slant);
446 }
447 
fcpattern_from_skfontstyle(SkFontStyle style,FcPattern * pattern)448 static void fcpattern_from_skfontstyle(SkFontStyle style, FcPattern* pattern) {
449     typedef SkFontStyle SkFS;
450 
451     static const MapRanges weightRanges[] = {
452         { SkTFixed<SkFS::kThin_Weight>::value,       SkTFixed<FC_WEIGHT_THIN>::value },
453         { SkTFixed<SkFS::kExtraLight_Weight>::value, SkTFixed<FC_WEIGHT_EXTRALIGHT>::value },
454         { SkTFixed<SkFS::kLight_Weight>::value,      SkTFixed<FC_WEIGHT_LIGHT>::value },
455         { SkTFixed<SkFS::kNormal_Weight>::value,     SkTFixed<FC_WEIGHT_REGULAR>::value },
456         { SkTFixed<SkFS::kMedium_Weight>::value,     SkTFixed<FC_WEIGHT_MEDIUM>::value },
457         { SkTFixed<SkFS::kSemiBold_Weight>::value,   SkTFixed<FC_WEIGHT_DEMIBOLD>::value },
458         { SkTFixed<SkFS::kBold_Weight>::value,       SkTFixed<FC_WEIGHT_BOLD>::value },
459         { SkTFixed<SkFS::kExtraBold_Weight>::value,  SkTFixed<FC_WEIGHT_EXTRABOLD>::value },
460         { SkTFixed<SkFS::kBlack_Weight>::value,      SkTFixed<FC_WEIGHT_BLACK>::value },
461         { SkTFixed<SkFS::kExtraBlack_Weight>::value, SkTFixed<FC_WEIGHT_EXTRABLACK>::value },
462     };
463     int weight = map_ranges(style.weight(), weightRanges, SK_ARRAY_COUNT(weightRanges));
464 
465     static const MapRanges widthRanges[] = {
466         { SkTFixed<SkFS::kUltraCondensed_Width>::value, SkTFixed<FC_WIDTH_ULTRACONDENSED>::value },
467         { SkTFixed<SkFS::kExtraCondensed_Width>::value, SkTFixed<FC_WIDTH_EXTRACONDENSED>::value },
468         { SkTFixed<SkFS::kCondensed_Width>::value,      SkTFixed<FC_WIDTH_CONDENSED>::value },
469         { SkTFixed<SkFS::kSemiCondensed_Width>::value,  SkTFixed<FC_WIDTH_SEMICONDENSED>::value },
470         { SkTFixed<SkFS::kNormal_Width>::value,         SkTFixed<FC_WIDTH_NORMAL>::value },
471         { SkTFixed<SkFS::kSemiExpanded_Width>::value,   SkTFixed<FC_WIDTH_SEMIEXPANDED>::value },
472         { SkTFixed<SkFS::kExpanded_Width>::value,       SkTFixed<FC_WIDTH_EXPANDED>::value },
473         { SkTFixed<SkFS::kExtraExpanded_Width>::value,  SkTFixed<FC_WIDTH_EXTRAEXPANDED>::value },
474         { SkTFixed<SkFS::kUltraExpanded_Width>::value,  SkTFixed<FC_WIDTH_ULTRAEXPANDED>::value },
475     };
476     int width = map_ranges(style.width(), widthRanges, SK_ARRAY_COUNT(widthRanges));
477 
478     int slant = FC_SLANT_ROMAN;
479     switch (style.slant()) {
480         case SkFS::kUpright_Slant: slant = FC_SLANT_ROMAN  ; break;
481         case SkFS::kItalic_Slant : slant = FC_SLANT_ITALIC ; break;
482         case SkFS::kOblique_Slant: slant = FC_SLANT_OBLIQUE; break;
483         default: SkASSERT(false); break;
484     }
485 
486     FcPatternAddInteger(pattern, FC_WEIGHT, weight);
487     FcPatternAddInteger(pattern, FC_WIDTH , width);
488     FcPatternAddInteger(pattern, FC_SLANT , slant);
489 }
490 
491 }  // anonymous namespace
492 
493 ///////////////////////////////////////////////////////////////////////////////
494 
495 #define kMaxFontFamilyLength    2048
496 #ifdef SK_FONT_CONFIG_INTERFACE_ONLY_ALLOW_SFNT_FONTS
497 const char* kFontFormatTrueType = "TrueType";
498 const char* kFontFormatCFF = "CFF";
499 #endif
500 
SkFontConfigInterfaceDirect()501 SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() {
502     FCLocker lock;
503 
504     FcInit();
505 
506     SkDEBUGCODE(fontconfiginterface_unittest();)
507 }
508 
~SkFontConfigInterfaceDirect()509 SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() {
510 }
511 
isAccessible(const char * filename)512 bool SkFontConfigInterfaceDirect::isAccessible(const char* filename) {
513     if (access(filename, R_OK) != 0) {
514         return false;
515     }
516     return true;
517 }
518 
isValidPattern(FcPattern * pattern)519 bool SkFontConfigInterfaceDirect::isValidPattern(FcPattern* pattern) {
520 #ifdef SK_FONT_CONFIG_INTERFACE_ONLY_ALLOW_SFNT_FONTS
521     const char* font_format = get_string(pattern, FC_FONTFORMAT);
522     if (font_format
523         && strcmp(font_format, kFontFormatTrueType) != 0
524         && strcmp(font_format, kFontFormatCFF) != 0)
525     {
526         return false;
527     }
528 #endif
529 
530     // fontconfig can also return fonts which are unreadable
531     const char* c_filename = get_string(pattern, FC_FILE);
532     if (!c_filename) {
533         return false;
534     }
535     return this->isAccessible(c_filename);
536 }
537 
538 // Find matching font from |font_set| for the given font family.
MatchFont(FcFontSet * font_set,const char * post_config_family,const SkString & family)539 FcPattern* SkFontConfigInterfaceDirect::MatchFont(FcFontSet* font_set,
540                                                   const char* post_config_family,
541                                                   const SkString& family) {
542   // Older versions of fontconfig have a bug where they cannot select
543   // only scalable fonts so we have to manually filter the results.
544   FcPattern* match = nullptr;
545   for (int i = 0; i < font_set->nfont; ++i) {
546     FcPattern* current = font_set->fonts[i];
547     if (this->isValidPattern(current)) {
548       match = current;
549       break;
550     }
551   }
552 
553   if (match && !IsFallbackFontAllowed(family)) {
554     bool acceptable_substitute = false;
555     for (int id = 0; id < 255; ++id) {
556       const char* post_match_family = get_string(match, FC_FAMILY, id);
557       if (!post_match_family)
558         break;
559       acceptable_substitute =
560           (strcasecmp(post_config_family, post_match_family) == 0 ||
561            // Workaround for Issue 12530:
562            //   requested family: "Bitstream Vera Sans"
563            //   post_config_family: "Arial"
564            //   post_match_family: "Bitstream Vera Sans"
565            // -> We should treat this case as a good match.
566            strcasecmp(family.c_str(), post_match_family) == 0) ||
567            IsMetricCompatibleReplacement(family.c_str(), post_match_family);
568       if (acceptable_substitute)
569         break;
570     }
571     if (!acceptable_substitute)
572       return nullptr;
573   }
574 
575   return match;
576 }
577 
matchFamilyName(const char familyName[],SkFontStyle style,FontIdentity * outIdentity,SkString * outFamilyName,SkFontStyle * outStyle)578 bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[],
579                                                   SkFontStyle style,
580                                                   FontIdentity* outIdentity,
581                                                   SkString* outFamilyName,
582                                                   SkFontStyle* outStyle) {
583     SkString familyStr(familyName ? familyName : "");
584     if (familyStr.size() > kMaxFontFamilyLength) {
585         return false;
586     }
587 
588     FCLocker lock;
589 
590     FcPattern* pattern = FcPatternCreate();
591 
592     if (familyName) {
593         FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
594     }
595     fcpattern_from_skfontstyle(style, pattern);
596 
597     FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
598 
599     FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
600     FcDefaultSubstitute(pattern);
601 
602     // Font matching:
603     // CSS often specifies a fallback list of families:
604     //    font-family: a, b, c, serif;
605     // However, fontconfig will always do its best to find *a* font when asked
606     // for something so we need a way to tell if the match which it has found is
607     // "good enough" for us. Otherwise, we can return nullptr which gets piped up
608     // and lets WebKit know to try the next CSS family name. However, fontconfig
609     // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
610     // wish to support that.
611     //
612     // Thus, if a specific family is requested we set @family_requested. Then we
613     // record two strings: the family name after config processing and the
614     // family name after resolving. If the two are equal, it's a good match.
615     //
616     // So consider the case where a user has mapped Arial to Helvetica in their
617     // config.
618     //    requested family: "Arial"
619     //    post_config_family: "Helvetica"
620     //    post_match_family: "Helvetica"
621     //      -> good match
622     //
623     // and for a missing font:
624     //    requested family: "Monaco"
625     //    post_config_family: "Monaco"
626     //    post_match_family: "Times New Roman"
627     //      -> BAD match
628     //
629     // However, we special-case fallback fonts; see IsFallbackFontAllowed().
630 
631     const char* post_config_family = get_string(pattern, FC_FAMILY);
632     if (!post_config_family) {
633         // we can just continue with an empty name, e.g. default font
634         post_config_family = "";
635     }
636 
637     FcResult result;
638     FcFontSet* font_set = FcFontSort(nullptr, pattern, 0, nullptr, &result);
639     if (!font_set) {
640         FcPatternDestroy(pattern);
641         return false;
642     }
643 
644     FcPattern* match = this->MatchFont(font_set, post_config_family, familyStr);
645     if (!match) {
646         FcPatternDestroy(pattern);
647         FcFontSetDestroy(font_set);
648         return false;
649     }
650 
651     FcPatternDestroy(pattern);
652 
653     // From here out we just extract our results from 'match'
654 
655     post_config_family = get_string(match, FC_FAMILY);
656     if (!post_config_family) {
657         FcFontSetDestroy(font_set);
658         return false;
659     }
660 
661     const char* c_filename = get_string(match, FC_FILE);
662     if (!c_filename) {
663         FcFontSetDestroy(font_set);
664         return false;
665     }
666 
667     int face_index = get_int(match, FC_INDEX, 0);
668 
669     FcFontSetDestroy(font_set);
670 
671     if (outIdentity) {
672         outIdentity->fTTCIndex = face_index;
673         outIdentity->fString.set(c_filename);
674     }
675     if (outFamilyName) {
676         outFamilyName->set(post_config_family);
677     }
678     if (outStyle) {
679         *outStyle = skfontstyle_from_fcpattern(match);
680     }
681     return true;
682 }
683 
openStream(const FontIdentity & identity)684 SkStreamAsset* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) {
685     return SkStream::MakeFromFile(identity.fString.c_str()).release();
686 }
687