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
30namespace {
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.
34SK_DECLARE_STATIC_MUTEX(gFCMutex);
35
36#ifdef SK_DEBUG
37void* CreateThreadFcLocked() { return new bool(false); }
38void DeleteThreadFcLocked(void* v) { delete static_cast<bool*>(v); }
39#   define THREAD_FC_LOCKED \
40        static_cast<bool*>(SkTLS::Get(CreateThreadFcLocked, DeleteThreadFcLocked))
41#endif
42
43struct FCLocker {
44    // Assume FcGetVersion() has always been thread safe.
45
46    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
56    ~FCLocker() {
57        AssertHeld();
58        if (FcGetVersion() < 21091) {
59            gFCMutex.release();
60        } else {
61            SkDEBUGCODE(*THREAD_FC_LOCKED = false);
62        }
63    }
64
65    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
76size_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
97size_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
119static 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
126static 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
144static 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
163static 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
173namespace {
174
175// Equivalence classes, used to match the Liberation and other fonts
176// with their metric-compatible replacements.  See the discussion in
177// GetFontEquivClass().
178enum 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.
202FontEquivClass 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.
342bool 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.
354bool 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|.
363static 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
371static 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
380struct MapRanges {
381    SkFixed old_val;
382    SkFixed new_val;
383};
384
385static 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
404static int map_ranges(int val, MapRanges const ranges[], int rangesCount) {
405    return SkFixedRoundToInt(map_ranges_fixed(SkIntToFixed(val), ranges, rangesCount));
406}
407
408template<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
413static 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
456static 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
505const char* kFontFormatTrueType = "TrueType";
506const char* kFontFormatCFF = "CFF";
507#endif
508
509SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() {
510    FCLocker lock;
511
512    FcInit();
513
514    SkDEBUGCODE(fontconfiginterface_unittest();)
515}
516
517SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() {
518}
519
520bool SkFontConfigInterfaceDirect::isAccessible(const char* filename) {
521    if (access(filename, R_OK) != 0) {
522        return false;
523    }
524    return true;
525}
526
527bool 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.
547FcPattern* 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
586bool 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
692SkStreamAsset* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) {
693    return SkStream::MakeFromFile(identity.fString.c_str()).release();
694}
695