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