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