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