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