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