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
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() {
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
135static 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
147namespace {
148
149// Equivalence classes, used to match the Liberation and other fonts
150// with their metric-compatible replacements.  See the discussion in
151// GetFontEquivClass().
152enum 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.
176FontEquivClass 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.
305bool 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.
317bool 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
325static 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.
346FcPattern* 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|.
386SkTypeface::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
424SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() {
425    SkAutoMutexAcquire ac(mutex_);
426
427    FcInit();
428
429    SkDEBUGCODE(fontconfiginterface_unittest();)
430}
431
432SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() {
433}
434
435bool 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
549SkStream* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) {
550    return SkStream::NewFromFile(identity.fString.c_str());
551}
552
553///////////////////////////////////////////////////////////////////////////////
554
555static 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
565SkDataTable* 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
601bool 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