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