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 "SkStream.h"
     19 
     20 size_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 
     41 size_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
     60 static 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 
     67 static 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 
     85 static 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 
    101 class SkFontConfigInterfaceDirect : public SkFontConfigInterface {
    102 public:
    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 
    119 private:
    120     SkMutex mutex_;
    121 };
    122 
    123 SkFontConfigInterface* 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
    139 static const char* get_name(FcPattern* pattern, const char field[],
    140                             int index = 0) {
    141     const char* name;
    142     if (FcPatternGetString(pattern, field, index,
    143                            (FcChar8**)&name) != FcResultMatch) {
    144         name = NULL;
    145     }
    146     return name;
    147 }
    148 
    149 ///////////////////////////////////////////////////////////////////////////////
    150 
    151 namespace {
    152 
    153 // Equivalence classes, used to match the Liberation and other fonts
    154 // with their metric-compatible replacements.  See the discussion in
    155 // GetFontEquivClass().
    156 enum FontEquivClass
    157 {
    158     OTHER,
    159     SANS,
    160     SERIF,
    161     MONO,
    162     SYMBOL,
    163     PGOTHIC,
    164     GOTHIC,
    165     PMINCHO,
    166     MINCHO,
    167     SIMSUN,
    168     NSIMSUN,
    169     SIMHEI,
    170     PMINGLIU,
    171     MINGLIU,
    172     PMINGLIUHK,
    173     MINGLIUHK,
    174     CAMBRIA,
    175 };
    176 
    177 // Match the font name against a whilelist of fonts, returning the equivalence
    178 // class.
    179 FontEquivClass 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.
    304 bool 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.
    316 bool 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 
    324 static 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.
    343 FcPattern* 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|.
    383 SkTypeface::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 
    421 SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() {
    422     SkAutoMutexAcquire ac(mutex_);
    423 
    424     FcInit();
    425 
    426     SkDEBUGCODE(fontconfiginterface_unittest();)
    427 }
    428 
    429 SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() {
    430 }
    431 
    432 bool 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 
    546 SkStream* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) {
    547     return SkStream::NewFromFile(identity.fString.c_str());
    548 }
    549 
    550 ///////////////////////////////////////////////////////////////////////////////
    551 
    552 static 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 
    562 SkDataTable* 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 
    598 bool 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