• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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