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