Home | History | Annotate | Download | only in ports
      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 
     21 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 
     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
     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 
     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 
     89 static void fontconfiginterface_unittest() {
     90     SkFontConfigInterface::FontIdentity iden0, iden1;
     91 
     92     SkASSERT(iden0 == iden1);
     93 
     94     make_iden(&iden0);
     95     SkASSERT(iden0 != iden1);
     96 
     97     make_iden(&iden1);
     98     SkASSERT(iden0 == iden1);
     99 
    100     test_writeToMemory(iden0, 0);
    101     test_writeToMemory(iden0, 0);
    102 }
    103 #endif
    104 
    105 class SkFontConfigInterfaceDirect : public SkFontConfigInterface {
    106 public:
    107             SkFontConfigInterfaceDirect();
    108     virtual ~SkFontConfigInterfaceDirect();
    109 
    110     virtual bool matchFamilyName(const char familyName[],
    111                                  SkTypeface::Style requested,
    112                                  FontIdentity* outFontIdentifier,
    113                                  SkString* outFamilyName,
    114                                  SkTypeface::Style* outStyle) SK_OVERRIDE;
    115     virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE;
    116 
    117     // new APIs
    118     virtual SkDataTable* getFamilyNames() SK_OVERRIDE;
    119     virtual bool matchFamilySet(const char inFamilyName[],
    120                                 SkString* outFamilyName,
    121                                 SkTArray<FontIdentity>*) SK_OVERRIDE;
    122 
    123 private:
    124     SkMutex mutex_;
    125 };
    126 
    127 SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() {
    128     SK_DECLARE_STATIC_LAZY_PTR(SkFontConfigInterfaceDirect, direct);
    129     return direct.get();
    130 }
    131 
    132 ///////////////////////////////////////////////////////////////////////////////
    133 
    134 // Returns the string from the pattern, or NULL
    135 static const char* get_name(FcPattern* pattern, const char field[],
    136                             int index = 0) {
    137     const char* name;
    138     if (FcPatternGetString(pattern, field, index,
    139                            (FcChar8**)&name) != FcResultMatch) {
    140         name = NULL;
    141     }
    142     return name;
    143 }
    144 
    145 ///////////////////////////////////////////////////////////////////////////////
    146 
    147 namespace {
    148 
    149 // Equivalence classes, used to match the Liberation and other fonts
    150 // with their metric-compatible replacements.  See the discussion in
    151 // GetFontEquivClass().
    152 enum FontEquivClass
    153 {
    154     OTHER,
    155     SANS,
    156     SERIF,
    157     MONO,
    158     SYMBOL,
    159     PGOTHIC,
    160     GOTHIC,
    161     PMINCHO,
    162     MINCHO,
    163     SIMSUN,
    164     NSIMSUN,
    165     SIMHEI,
    166     PMINGLIU,
    167     MINGLIU,
    168     PMINGLIUHK,
    169     MINGLIUHK,
    170     CAMBRIA,
    171     CALIBRI,
    172 };
    173 
    174 // Match the font name against a whilelist of fonts, returning the equivalence
    175 // class.
    176 FontEquivClass GetFontEquivClass(const char* fontname)
    177 {
    178     // It would be nice for fontconfig to tell us whether a given suggested
    179     // replacement is a "strong" match (that is, an equivalent font) or
    180     // a "weak" match (that is, fontconfig's next-best attempt at finding a
    181     // substitute).  However, I played around with the fontconfig API for
    182     // a good few hours and could not make it reveal this information.
    183     //
    184     // So instead, we hardcode.  Initially this function emulated
    185     //   /etc/fonts/conf.d/30-metric-aliases.conf
    186     // from my Ubuntu system, but we're better off being very conservative.
    187 
    188     // Arimo, Tinos and Cousine are a set of fonts metric-compatible with
    189     // Arial, Times New Roman and Courier New  with a character repertoire
    190     // much larger than Liberation. Note that Cousine is metrically
    191     // compatible with Courier New, but the former is sans-serif while
    192     // the latter is serif.
    193 
    194 
    195     struct FontEquivMap {
    196         FontEquivClass clazz;
    197         const char name[40];
    198     };
    199 
    200     static const FontEquivMap kFontEquivMap[] = {
    201         { SANS, "Arial" },
    202         { SANS, "Arimo" },
    203         { SANS, "Liberation Sans" },
    204 
    205         { SERIF, "Times New Roman" },
    206         { SERIF, "Tinos" },
    207         { SERIF, "Liberation Serif" },
    208 
    209         { MONO, "Courier New" },
    210         { MONO, "Cousine" },
    211         { MONO, "Liberation Mono" },
    212 
    213         { SYMBOL, "Symbol" },
    214         { SYMBOL, "Symbol Neu" },
    215 
    216         //  
    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         //  
    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         //  
    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         //  
    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.
    305 bool IsMetricCompatibleReplacement(const char* font_a, const char* font_b)
    306 {
    307     FontEquivClass class_a = GetFontEquivClass(font_a);
    308     FontEquivClass class_b = GetFontEquivClass(font_b);
    309 
    310     return class_a != OTHER && class_a == class_b;
    311 }
    312 
    313 // Normally we only return exactly the font asked for. In last-resort
    314 // cases, the request either doesn't specify a font or is one of the
    315 // basic font names like "Sans", "Serif" or "Monospace". This function
    316 // tells you whether a given request is for such a fallback.
    317 bool IsFallbackFontAllowed(const std::string& family) {
    318   const char* family_cstr = family.c_str();
    319   return family.empty() ||
    320          strcasecmp(family_cstr, "sans") == 0 ||
    321          strcasecmp(family_cstr, "serif") == 0 ||
    322          strcasecmp(family_cstr, "monospace") == 0;
    323 }
    324 
    325 static bool valid_pattern(FcPattern* pattern) {
    326 #ifdef SK_FONT_CONFIG_ONLY_ALLOW_SCALABLE_FONTS
    327     FcBool is_scalable;
    328     if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch
    329         || !is_scalable) {
    330         return false;
    331     }
    332 #endif
    333 
    334     // fontconfig can also return fonts which are unreadable
    335     const char* c_filename = get_name(pattern, FC_FILE);
    336     if (!c_filename) {
    337         return false;
    338     }
    339     if (access(c_filename, R_OK) != 0) {
    340         return false;
    341     }
    342     return true;
    343 }
    344 
    345 // Find matching font from |font_set| for the given font family.
    346 FcPattern* MatchFont(FcFontSet* font_set,
    347                      const char* post_config_family,
    348                      const std::string& family) {
    349   // Older versions of fontconfig have a bug where they cannot select
    350   // only scalable fonts so we have to manually filter the results.
    351   FcPattern* match = NULL;
    352   for (int i = 0; i < font_set->nfont; ++i) {
    353     FcPattern* current = font_set->fonts[i];
    354     if (valid_pattern(current)) {
    355       match = current;
    356       break;
    357     }
    358   }
    359 
    360   if (match && !IsFallbackFontAllowed(family)) {
    361     bool acceptable_substitute = false;
    362     for (int id = 0; id < 255; ++id) {
    363       const char* post_match_family = get_name(match, FC_FAMILY, id);
    364       if (!post_match_family)
    365         break;
    366       acceptable_substitute =
    367           (strcasecmp(post_config_family, post_match_family) == 0 ||
    368            // Workaround for Issue 12530:
    369            //   requested family: "Bitstream Vera Sans"
    370            //   post_config_family: "Arial"
    371            //   post_match_family: "Bitstream Vera Sans"
    372            // -> We should treat this case as a good match.
    373            strcasecmp(family.c_str(), post_match_family) == 0) ||
    374            IsMetricCompatibleReplacement(family.c_str(), post_match_family);
    375       if (acceptable_substitute)
    376         break;
    377     }
    378     if (!acceptable_substitute)
    379       return NULL;
    380   }
    381 
    382   return match;
    383 }
    384 
    385 // Retrieves |is_bold|, |is_italic| and |font_family| properties from |font|.
    386 SkTypeface::Style GetFontStyle(FcPattern* font) {
    387     int resulting_bold;
    388     if (FcPatternGetInteger(font, FC_WEIGHT, 0, &resulting_bold))
    389         resulting_bold = FC_WEIGHT_NORMAL;
    390 
    391     int resulting_italic;
    392     if (FcPatternGetInteger(font, FC_SLANT, 0, &resulting_italic))
    393         resulting_italic = FC_SLANT_ROMAN;
    394 
    395     // If we ask for an italic font, fontconfig might take a roman font and set
    396     // the undocumented property FC_MATRIX to a skew matrix. It'll then say
    397     // that the font is italic or oblique. So, if we see a matrix, we don't
    398     // believe that it's italic.
    399     FcValue matrix;
    400     const bool have_matrix = FcPatternGet(font, FC_MATRIX, 0, &matrix) == 0;
    401 
    402     // If we ask for an italic font, fontconfig might take a roman font and set
    403     // FC_EMBOLDEN.
    404     FcValue embolden;
    405     const bool have_embolden = FcPatternGet(font, FC_EMBOLDEN, 0, &embolden) == 0;
    406 
    407     int styleBits = 0;
    408     if (resulting_bold > FC_WEIGHT_MEDIUM && !have_embolden) {
    409         styleBits |= SkTypeface::kBold;
    410     }
    411     if (resulting_italic > FC_SLANT_ROMAN && !have_matrix) {
    412         styleBits |= SkTypeface::kItalic;
    413     }
    414 
    415     return (SkTypeface::Style)styleBits;
    416 }
    417 
    418 }  // anonymous namespace
    419 
    420 ///////////////////////////////////////////////////////////////////////////////
    421 
    422 #define kMaxFontFamilyLength    2048
    423 
    424 SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() {
    425     SkAutoMutexAcquire ac(mutex_);
    426 
    427     FcInit();
    428 
    429     SkDEBUGCODE(fontconfiginterface_unittest();)
    430 }
    431 
    432 SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() {
    433 }
    434 
    435 bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[],
    436                                                   SkTypeface::Style style,
    437                                                   FontIdentity* outIdentity,
    438                                                   SkString* outFamilyName,
    439                                                   SkTypeface::Style* outStyle) {
    440     std::string familyStr(familyName ? familyName : "");
    441     if (familyStr.length() > kMaxFontFamilyLength) {
    442         return false;
    443     }
    444 
    445     SkAutoMutexAcquire ac(mutex_);
    446 
    447     FcPattern* pattern = FcPatternCreate();
    448 
    449     if (familyName) {
    450         FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
    451     }
    452     FcPatternAddInteger(pattern, FC_WEIGHT,
    453                         (style & SkTypeface::kBold) ? FC_WEIGHT_BOLD
    454                                                     : FC_WEIGHT_NORMAL);
    455     FcPatternAddInteger(pattern, FC_SLANT,
    456                         (style & SkTypeface::kItalic) ? FC_SLANT_ITALIC
    457                                                       : FC_SLANT_ROMAN);
    458     FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
    459 
    460     FcConfigSubstitute(NULL, pattern, FcMatchPattern);
    461     FcDefaultSubstitute(pattern);
    462 
    463     // Font matching:
    464     // CSS often specifies a fallback list of families:
    465     //    font-family: a, b, c, serif;
    466     // However, fontconfig will always do its best to find *a* font when asked
    467     // for something so we need a way to tell if the match which it has found is
    468     // "good enough" for us. Otherwise, we can return NULL which gets piped up
    469     // and lets WebKit know to try the next CSS family name. However, fontconfig
    470     // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
    471     // wish to support that.
    472     //
    473     // Thus, if a specific family is requested we set @family_requested. Then we
    474     // record two strings: the family name after config processing and the
    475     // family name after resolving. If the two are equal, it's a good match.
    476     //
    477     // So consider the case where a user has mapped Arial to Helvetica in their
    478     // config.
    479     //    requested family: "Arial"
    480     //    post_config_family: "Helvetica"
    481     //    post_match_family: "Helvetica"
    482     //      -> good match
    483     //
    484     // and for a missing font:
    485     //    requested family: "Monaco"
    486     //    post_config_family: "Monaco"
    487     //    post_match_family: "Times New Roman"
    488     //      -> BAD match
    489     //
    490     // However, we special-case fallback fonts; see IsFallbackFontAllowed().
    491 
    492     const char* post_config_family = get_name(pattern, FC_FAMILY);
    493     if (!post_config_family) {
    494         // we can just continue with an empty name, e.g. default font
    495         post_config_family = "";
    496     }
    497 
    498     FcResult result;
    499     FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
    500     if (!font_set) {
    501         FcPatternDestroy(pattern);
    502         return false;
    503     }
    504 
    505     FcPattern* match = MatchFont(font_set, post_config_family, familyStr);
    506     if (!match) {
    507         FcPatternDestroy(pattern);
    508         FcFontSetDestroy(font_set);
    509         return false;
    510     }
    511 
    512     FcPatternDestroy(pattern);
    513 
    514     // From here out we just extract our results from 'match'
    515 
    516     post_config_family = get_name(match, FC_FAMILY);
    517     if (!post_config_family) {
    518         FcFontSetDestroy(font_set);
    519         return false;
    520     }
    521 
    522     const char* c_filename = get_name(match, FC_FILE);
    523     if (!c_filename) {
    524         FcFontSetDestroy(font_set);
    525         return false;
    526     }
    527 
    528     int face_index;
    529     if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) {
    530         FcFontSetDestroy(font_set);
    531         return false;
    532     }
    533 
    534     FcFontSetDestroy(font_set);
    535 
    536     if (outIdentity) {
    537         outIdentity->fTTCIndex = face_index;
    538         outIdentity->fString.set(c_filename);
    539     }
    540     if (outFamilyName) {
    541         outFamilyName->set(post_config_family);
    542     }
    543     if (outStyle) {
    544         *outStyle = GetFontStyle(match);
    545     }
    546     return true;
    547 }
    548 
    549 SkStream* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) {
    550     return SkStream::NewFromFile(identity.fString.c_str());
    551 }
    552 
    553 ///////////////////////////////////////////////////////////////////////////////
    554 
    555 static bool find_name(const SkTDArray<const char*>& list, const char* str) {
    556     int count = list.count();
    557     for (int i = 0; i < count; ++i) {
    558         if (!strcmp(list[i], str)) {
    559             return true;
    560         }
    561     }
    562     return false;
    563 }
    564 
    565 SkDataTable* SkFontConfigInterfaceDirect::getFamilyNames() {
    566     SkAutoMutexAcquire ac(mutex_);
    567 
    568     FcPattern* pat = FcPatternCreate();
    569     SkAutoTCallVProc<FcPattern, FcPatternDestroy> autoDestroyPat(pat);
    570     if (NULL == pat) {
    571         return NULL;
    572     }
    573 
    574     FcObjectSet* os = FcObjectSetBuild(FC_FAMILY, (char *)0);
    575     SkAutoTCallVProc<FcObjectSet, FcObjectSetDestroy> autoDestroyOs(os);
    576     if (NULL == os) {
    577         return NULL;
    578     }
    579 
    580     FcFontSet* fs = FcFontList(NULL, pat, os);
    581     SkAutoTCallVProc<FcFontSet, FcFontSetDestroy> autoDestroyFs(fs);
    582     if (NULL == fs) {
    583         return NULL;
    584     }
    585 
    586     SkTDArray<const char*> names;
    587     SkTDArray<size_t> sizes;
    588     for (int i = 0; i < fs->nfont; ++i) {
    589         FcPattern* match = fs->fonts[i];
    590         const char* famName = get_name(match, FC_FAMILY);
    591         if (famName && !find_name(names, famName)) {
    592             *names.append() = famName;
    593             *sizes.append() = strlen(famName) + 1;
    594         }
    595     }
    596 
    597     return SkDataTable::NewCopyArrays((const void*const*)names.begin(),
    598                                       sizes.begin(), names.count());
    599 }
    600 
    601 bool SkFontConfigInterfaceDirect::matchFamilySet(const char inFamilyName[],
    602                                                  SkString* outFamilyName,
    603                                                  SkTArray<FontIdentity>* ids) {
    604     SkAutoMutexAcquire ac(mutex_);
    605 
    606 #if 0
    607     std::string familyStr(familyName ? familyName : "");
    608     if (familyStr.length() > kMaxFontFamilyLength) {
    609         return false;
    610     }
    611 
    612     SkAutoMutexAcquire ac(mutex_);
    613 
    614     FcPattern* pattern = FcPatternCreate();
    615 
    616     if (familyName) {
    617         FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
    618     }
    619     FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
    620 
    621     FcConfigSubstitute(NULL, pattern, FcMatchPattern);
    622     FcDefaultSubstitute(pattern);
    623 
    624     // Font matching:
    625     // CSS often specifies a fallback list of families:
    626     //    font-family: a, b, c, serif;
    627     // However, fontconfig will always do its best to find *a* font when asked
    628     // for something so we need a way to tell if the match which it has found is
    629     // "good enough" for us. Otherwise, we can return NULL which gets piped up
    630     // and lets WebKit know to try the next CSS family name. However, fontconfig
    631     // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
    632     // wish to support that.
    633     //
    634     // Thus, if a specific family is requested we set @family_requested. Then we
    635     // record two strings: the family name after config processing and the
    636     // family name after resolving. If the two are equal, it's a good match.
    637     //
    638     // So consider the case where a user has mapped Arial to Helvetica in their
    639     // config.
    640     //    requested family: "Arial"
    641     //    post_config_family: "Helvetica"
    642     //    post_match_family: "Helvetica"
    643     //      -> good match
    644     //
    645     // and for a missing font:
    646     //    requested family: "Monaco"
    647     //    post_config_family: "Monaco"
    648     //    post_match_family: "Times New Roman"
    649     //      -> BAD match
    650     //
    651     // However, we special-case fallback fonts; see IsFallbackFontAllowed().
    652 
    653     const char* post_config_family = get_name(pattern, FC_FAMILY);
    654 
    655     FcResult result;
    656     FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
    657     if (!font_set) {
    658         FcPatternDestroy(pattern);
    659         return false;
    660     }
    661 
    662     FcPattern* match = MatchFont(font_set, post_config_family, familyStr);
    663     if (!match) {
    664         FcPatternDestroy(pattern);
    665         FcFontSetDestroy(font_set);
    666         return false;
    667     }
    668 
    669     FcPatternDestroy(pattern);
    670 
    671     // From here out we just extract our results from 'match'
    672 
    673     if (FcPatternGetString(match, FC_FAMILY, 0, &post_config_family) != FcResultMatch) {
    674         FcFontSetDestroy(font_set);
    675         return false;
    676     }
    677 
    678     FcChar8* c_filename;
    679     if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) {
    680         FcFontSetDestroy(font_set);
    681         return false;
    682     }
    683 
    684     int face_index;
    685     if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) {
    686         FcFontSetDestroy(font_set);
    687         return false;
    688     }
    689 
    690     FcFontSetDestroy(font_set);
    691 
    692     if (outIdentity) {
    693         outIdentity->fTTCIndex = face_index;
    694         outIdentity->fString.set((const char*)c_filename);
    695     }
    696     if (outFamilyName) {
    697         outFamilyName->set((const char*)post_config_family);
    698     }
    699     if (outStyle) {
    700         *outStyle = GetFontStyle(match);
    701     }
    702     return true;
    703 
    704 ////////////////////
    705 
    706         int count;
    707         FcPattern** match = MatchFont(font_set, post_config_family, &count);
    708         if (!match) {
    709             FcPatternDestroy(pattern);
    710             FcFontSetDestroy(font_set);
    711             return NULL;
    712         }
    713 
    714         FcPatternDestroy(pattern);
    715 
    716         SkTDArray<FcPattern*> trimmedMatches;
    717         for (int i = 0; i < count; ++i) {
    718             const char* justName = find_just_name(get_name(match[i], FC_FILE));
    719             if (!is_lower(*justName)) {
    720                 *trimmedMatches.append() = match[i];
    721             }
    722         }
    723 
    724         SkFontStyleSet_FC* sset = SkNEW_ARGS(SkFontStyleSet_FC,
    725                                              (trimmedMatches.begin(),
    726                                               trimmedMatches.count()));
    727 #endif
    728     return false;
    729 }
    730