• 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 <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