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 <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 
     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(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
    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     CALIBRI,
    176 };
    177 
    178 // Match the font name against a whilelist of fonts, returning the equivalence
    179 // class.
    180 FontEquivClass 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         //  
    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         //  
    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         //  
    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         //  
    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.
    311 bool 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.
    323 bool 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 
    331 static 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.
    352 FcPattern* 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|.
    392 SkTypeface::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 
    430 SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() {
    431     SkAutoMutexAcquire ac(mutex_);
    432 
    433     FcInit();
    434 
    435     SkDEBUGCODE(fontconfiginterface_unittest();)
    436 }
    437 
    438 SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() {
    439 }
    440 
    441 bool 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 
    555 SkStream* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) {
    556     return SkStream::NewFromFile(identity.fString.c_str());
    557 }
    558 
    559 ///////////////////////////////////////////////////////////////////////////////
    560 
    561 static 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 
    571 SkDataTable* 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 
    607 bool 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