Home | History | Annotate | Download | only in ports
      1 
      2 /*
      3  * Copyright 2013 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "SkFontConfigInterface.h"
     10 #include "SkTypeface_android.h"
     11 
     12 #include "SkFontConfigParser_android.h"
     13 #include "SkFontConfigTypeface.h"
     14 #include "SkFontMgr.h"
     15 #include "SkGlyphCache.h"
     16 #include "SkPaint.h"
     17 #include "SkString.h"
     18 #include "SkStream.h"
     19 #include "SkThread.h"
     20 #include "SkTypefaceCache.h"
     21 #include "SkTArray.h"
     22 #include "SkTDict.h"
     23 #include "SkTSearch.h"
     24 
     25 #include <stdio.h>
     26 #include <string.h>
     27 
     28 #ifndef SK_DEBUG_FONTS
     29     #define SK_DEBUG_FONTS 0
     30 #endif
     31 
     32 #if SK_DEBUG_FONTS
     33     #define DEBUG_FONT(args) SkDebugf args
     34 #else
     35     #define DEBUG_FONT(args)
     36 #endif
     37 
     38 ///////////////////////////////////////////////////////////////////////////////
     39 
     40 // For test only.
     41 static const char* gTestMainConfigFile = NULL;
     42 static const char* gTestFallbackConfigFile = NULL;
     43 static const char* gTestFontFilePrefix = NULL;
     44 
     45 ///////////////////////////////////////////////////////////////////////////////
     46 
     47 typedef int32_t FontRecID;
     48 #define INVALID_FONT_REC_ID -1
     49 
     50 typedef int32_t FamilyRecID;
     51 #define INVALID_FAMILY_REC_ID -1
     52 
     53 // used to record our notion of the pre-existing fonts
     54 struct FontRec {
     55     SkRefPtr<SkTypeface> fTypeface;
     56     SkString fFileName;
     57     SkTypeface::Style fStyle;
     58     SkPaintOptionsAndroid fPaintOptions;
     59     bool fIsFallbackFont;
     60     bool fIsValid;
     61     FamilyRecID fFamilyRecID;
     62 };
     63 
     64 struct FamilyRec {
     65     FamilyRec() {
     66         memset(fFontRecID, INVALID_FONT_REC_ID, sizeof(fFontRecID));
     67     }
     68 
     69     static const int FONT_STYLE_COUNT = 4;
     70     FontRecID fFontRecID[FONT_STYLE_COUNT];
     71 };
     72 
     73 
     74 typedef SkTDArray<FontRecID> FallbackFontList;
     75 
     76 class SkFontConfigInterfaceAndroid : public SkFontConfigInterface {
     77 public:
     78     SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies);
     79     virtual ~SkFontConfigInterfaceAndroid();
     80 
     81     virtual bool matchFamilyName(const char familyName[],
     82                                  SkTypeface::Style requested,
     83                                  FontIdentity* outFontIdentifier,
     84                                  SkString* outFamilyName,
     85                                  SkTypeface::Style* outStyle) SK_OVERRIDE;
     86     virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE;
     87 
     88     // new APIs
     89     virtual SkDataTable* getFamilyNames() SK_OVERRIDE;
     90     virtual bool matchFamilySet(const char inFamilyName[],
     91                                 SkString* outFamilyName,
     92                                 SkTArray<FontIdentity>*) SK_OVERRIDE;
     93 
     94     /**
     95      *  Get the family name of the font in the default fallback font list that
     96      *  contains the specified chararacter. if no font is found, returns false.
     97      */
     98     bool getFallbackFamilyNameForChar(SkUnichar uni, SkString* name);
     99     /**
    100      *
    101      */
    102     SkTypeface* getTypefaceForChar(SkUnichar uni, SkTypeface::Style style,
    103                                    SkPaintOptionsAndroid::FontVariant fontVariant);
    104     SkTypeface* nextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
    105                                     const SkPaintOptionsAndroid& options);
    106 
    107 private:
    108     void addFallbackFont(FontRecID fontRecID);
    109     SkTypeface* getTypefaceForFontRec(FontRecID fontRecID);
    110     FallbackFontList* getCurrentLocaleFallbackFontList();
    111     FallbackFontList* findFallbackFontList(const SkLanguage& lang, bool isOriginal = true);
    112 
    113     SkTArray<FontRec> fFonts;
    114     SkTArray<FamilyRec> fFontFamilies;
    115     SkTDict<FamilyRecID> fFamilyNameDict;
    116     FamilyRecID fDefaultFamilyRecID;
    117 
    118     // (SkLanguage)<->(fallback chain index) translation
    119     SkTDict<FallbackFontList*> fFallbackFontDict;
    120     SkTDict<FallbackFontList*> fFallbackFontAliasDict;
    121     FallbackFontList fDefaultFallbackList;
    122 
    123     // fallback info for current locale
    124     SkString fCachedLocale;
    125     FallbackFontList* fLocaleFallbackFontList;
    126 };
    127 
    128 ///////////////////////////////////////////////////////////////////////////////
    129 
    130 static SkFontConfigInterfaceAndroid* getSingletonInterface() {
    131     SK_DECLARE_STATIC_MUTEX(gMutex);
    132     static SkFontConfigInterfaceAndroid* gFontConfigInterface;
    133 
    134     SkAutoMutexAcquire ac(gMutex);
    135     if (NULL == gFontConfigInterface) {
    136         // load info from a configuration file that we can use to populate the
    137         // system/fallback font structures
    138         SkTDArray<FontFamily*> fontFamilies;
    139         if (!gTestMainConfigFile) {
    140             SkFontConfigParser::GetFontFamilies(fontFamilies);
    141         } else {
    142             SkFontConfigParser::GetTestFontFamilies(fontFamilies, gTestMainConfigFile,
    143                                                     gTestFallbackConfigFile);
    144         }
    145 
    146         gFontConfigInterface = new SkFontConfigInterfaceAndroid(fontFamilies);
    147 
    148         // cleanup the data we received from the parser
    149         fontFamilies.deleteAll();
    150     }
    151     return gFontConfigInterface;
    152 }
    153 
    154 SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() {
    155     return getSingletonInterface();
    156 }
    157 
    158 ///////////////////////////////////////////////////////////////////////////////
    159 
    160 static bool has_font(const SkTArray<FontRec>& array, const SkString& filename) {
    161     for (int i = 0; i < array.count(); i++) {
    162         if (array[i].fFileName == filename) {
    163             return true;
    164         }
    165     }
    166     return false;
    167 }
    168 
    169 #ifndef SK_FONT_FILE_PREFIX
    170     #define SK_FONT_FILE_PREFIX          "/fonts/"
    171 #endif
    172 
    173 static void get_path_for_sys_fonts(SkString* full, const char name[]) {
    174     if (gTestFontFilePrefix) {
    175         full->set(gTestFontFilePrefix);
    176     } else {
    177         full->set(getenv("ANDROID_ROOT"));
    178         full->append(SK_FONT_FILE_PREFIX);
    179     }
    180     full->append(name);
    181 }
    182 
    183 static void insert_into_name_dict(SkTDict<FamilyRecID>& familyNameDict,
    184                                   const char* name, FamilyRecID familyRecID) {
    185     SkAutoAsciiToLC tolc(name);
    186     if (familyNameDict.find(tolc.lc())) {
    187         SkDebugf("---- system font attempting to use a the same name [%s] for"
    188                  "multiple families. skipping subsequent occurrences", tolc.lc());
    189     } else {
    190         familyNameDict.set(tolc.lc(), familyRecID);
    191     }
    192 }
    193 
    194 // Defined in SkFontHost_FreeType.cpp
    195 bool find_name_and_attributes(SkStream* stream, SkString* name,
    196                               SkTypeface::Style* style, bool* isFixedWidth);
    197 
    198 ///////////////////////////////////////////////////////////////////////////////
    199 
    200 SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies) :
    201         fFonts(fontFamilies.count()),
    202         fFontFamilies(fontFamilies.count() / FamilyRec::FONT_STYLE_COUNT),
    203         fFamilyNameDict(1024),
    204         fDefaultFamilyRecID(INVALID_FAMILY_REC_ID),
    205         fFallbackFontDict(128),
    206         fFallbackFontAliasDict(128),
    207         fLocaleFallbackFontList(NULL) {
    208 
    209     for (int i = 0; i < fontFamilies.count(); ++i) {
    210         FontFamily* family = fontFamilies[i];
    211 
    212         // defer initializing the familyRec until we can be sure that at least
    213         // one of it's children contains a valid font file
    214         FamilyRec* familyRec = NULL;
    215         FamilyRecID familyRecID = INVALID_FAMILY_REC_ID;
    216 
    217         for (int j = 0; j < family->fFontFiles.count(); ++j) {
    218             SkString filename;
    219             get_path_for_sys_fonts(&filename, family->fFontFiles[j]->fFileName);
    220 
    221             if (has_font(fFonts, filename)) {
    222                 SkDebugf("---- system font and fallback font files specify a duplicate "
    223                         "font %s, skipping the second occurrence", filename.c_str());
    224                 continue;
    225             }
    226 
    227             FontRec& fontRec = fFonts.push_back();
    228             fontRec.fFileName = filename;
    229             fontRec.fStyle = SkTypeface::kNormal;
    230             fontRec.fPaintOptions = family->fFontFiles[j]->fPaintOptions;
    231             fontRec.fIsFallbackFont = family->fIsFallbackFont;
    232             fontRec.fIsValid = false;
    233             fontRec.fFamilyRecID = familyRecID;
    234 
    235             const FontRecID fontRecID = fFonts.count() - 1;
    236 
    237             SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(filename.c_str()));
    238             if (stream.get() != NULL) {
    239                 bool isFixedWidth;
    240                 SkString name;
    241                 fontRec.fIsValid = find_name_and_attributes(stream.get(), &name,
    242                                                             &fontRec.fStyle, &isFixedWidth);
    243             } else {
    244                 if (!fontRec.fIsFallbackFont) {
    245                     SkDebugf("---- failed to open <%s> as a font\n", filename.c_str());
    246                 }
    247             }
    248 
    249             if (fontRec.fIsValid) {
    250                 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s",
    251                            i, fFonts.count() - 1, fontRec.fIsFallbackFont, filename.c_str()));
    252             } else {
    253                 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s (INVALID)",
    254                            i, fFonts.count() - 1, fontRec.fIsFallbackFont, filename.c_str()));
    255                 continue;
    256             }
    257 
    258             // create a familyRec now that we know that at least one font in
    259             // the family is valid
    260             if (familyRec == NULL) {
    261                 familyRec = &fFontFamilies.push_back();
    262                 familyRecID = fFontFamilies.count() - 1;
    263                 fontRec.fFamilyRecID = familyRecID;
    264             }
    265 
    266             // add this font to the current familyRec
    267             if (INVALID_FONT_REC_ID != familyRec->fFontRecID[fontRec.fStyle]) {
    268                 DEBUG_FONT(("Overwriting familyRec for style[%d] old,new:(%d,%d)",
    269                             fontRec.fStyle, familyRec->fFontRecID[fontRec.fStyle],
    270                             fontRecID));
    271             }
    272             familyRec->fFontRecID[fontRec.fStyle] = fontRecID;
    273 
    274             // if this is a fallback font then add it to the appropriate fallback chains
    275             if (fontRec.fIsFallbackFont) {
    276                 addFallbackFont(fontRecID);
    277             }
    278 
    279             // add the fallback file name to the name dictionary.  This is needed
    280             // by getFallbackFamilyNameForChar() so that fallback families can be
    281             // requested by the filenames of the fonts they contain.
    282             if (family->fIsFallbackFont && familyRec) {
    283                 insert_into_name_dict(fFamilyNameDict, fontRec.fFileName.c_str(), familyRecID);
    284             }
    285         }
    286 
    287         // add the names that map to this family to the dictionary for easy lookup
    288         if (familyRec && !family->fIsFallbackFont) {
    289             SkTDArray<const char*> names = family->fNames;
    290             if (names.isEmpty()) {
    291                 SkDEBUGFAIL("ERROR: non-fallback font with no name");
    292                 continue;
    293             }
    294 
    295             for (int i = 0; i < names.count(); i++) {
    296                 insert_into_name_dict(fFamilyNameDict, names[i], familyRecID);
    297             }
    298         }
    299 
    300     }
    301 
    302     DEBUG_FONT(("---- We have %d system fonts", fFonts.count()));
    303 
    304     if (fFontFamilies.count() > 0) {
    305         fDefaultFamilyRecID = 0;
    306     }
    307 
    308     // scans the default fallback font chain, adding every entry to every other
    309     // fallback font chain to which it does not belong. this results in every
    310     // language-specific fallback font chain having all of its fallback fonts at
    311     // the front of the chain, and everything else at the end.
    312     FallbackFontList* fallbackList;
    313     SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict);
    314     const char* fallbackLang = iter.next(&fallbackList);
    315     while(fallbackLang != NULL) {
    316         for (int i = 0; i < fDefaultFallbackList.count(); i++) {
    317             FontRecID fontRecID = fDefaultFallbackList[i];
    318             const SkString& fontLang = fFonts[fontRecID].fPaintOptions.getLanguage().getTag();
    319             if (strcmp(fallbackLang, fontLang.c_str()) != 0) {
    320                 fallbackList->push(fontRecID);
    321             }
    322         }
    323         // move to the next fallback list in the dictionary
    324         fallbackLang = iter.next(&fallbackList);
    325     }
    326 }
    327 
    328 SkFontConfigInterfaceAndroid::~SkFontConfigInterfaceAndroid() {
    329     // iterate through and cleanup fFallbackFontDict
    330     SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict);
    331     FallbackFontList* fallbackList;
    332     while(iter.next(&fallbackList) != NULL) {
    333         SkDELETE(fallbackList);
    334     }
    335 }
    336 
    337 void SkFontConfigInterfaceAndroid::addFallbackFont(FontRecID fontRecID) {
    338     SkASSERT(fontRecID < fFonts.count());
    339     const FontRec& fontRec = fFonts[fontRecID];
    340     SkASSERT(fontRec.fIsFallbackFont);
    341 
    342     // add to the default fallback list
    343     fDefaultFallbackList.push(fontRecID);
    344 
    345     // stop here if it is the default language tag
    346     const SkString& languageTag = fontRec.fPaintOptions.getLanguage().getTag();
    347     if (languageTag.isEmpty()) {
    348         return;
    349     }
    350 
    351     // add to the appropriate language's custom fallback list
    352     FallbackFontList* customList = NULL;
    353     if (!fFallbackFontDict.find(languageTag.c_str(), &customList)) {
    354         DEBUG_FONT(("----  Created fallback list for \"%s\"", languageTag.c_str()));
    355         customList = SkNEW(FallbackFontList);
    356         fFallbackFontDict.set(languageTag.c_str(), customList);
    357     }
    358     SkASSERT(customList != NULL);
    359     customList->push(fontRecID);
    360 }
    361 
    362 
    363 static FontRecID find_best_style(const FamilyRec& family, SkTypeface::Style style) {
    364 
    365     const FontRecID* fontRecIDs = family.fFontRecID;
    366 
    367     if (fontRecIDs[style] != INVALID_FONT_REC_ID) { // exact match
    368         return fontRecIDs[style];
    369     }
    370     // look for a matching bold
    371     style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
    372     if (fontRecIDs[style] != INVALID_FONT_REC_ID) {
    373         return fontRecIDs[style];
    374     }
    375     // look for the plain
    376     if (fontRecIDs[SkTypeface::kNormal] != INVALID_FONT_REC_ID) {
    377         return fontRecIDs[SkTypeface::kNormal];
    378     }
    379     // look for anything
    380     for (int i = 0; i < FamilyRec::FONT_STYLE_COUNT; i++) {
    381         if (fontRecIDs[i] != INVALID_FONT_REC_ID) {
    382             return fontRecIDs[i];
    383         }
    384     }
    385     // should never get here, since the fontRecID list should not be empty
    386     SkDEBUGFAIL("No valid fonts exist for this family");
    387     return -1;
    388 }
    389 
    390 bool SkFontConfigInterfaceAndroid::matchFamilyName(const char familyName[],
    391                                                    SkTypeface::Style style,
    392                                                    FontIdentity* outFontIdentifier,
    393                                                    SkString* outFamilyName,
    394                                                    SkTypeface::Style* outStyle) {
    395     // clip to legal style bits
    396     style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
    397 
    398     bool exactNameMatch = false;
    399 
    400     FamilyRecID familyRecID = INVALID_FAMILY_REC_ID;
    401     if (NULL != familyName) {
    402         SkAutoAsciiToLC tolc(familyName);
    403         if (fFamilyNameDict.find(tolc.lc(), &familyRecID)) {
    404             exactNameMatch = true;
    405         }
    406     } else {
    407         familyRecID = fDefaultFamilyRecID;
    408 
    409     }
    410 
    411     if (INVALID_FAMILY_REC_ID == familyRecID) {
    412         //TODO this ensures that we always return something
    413         familyRecID = fDefaultFamilyRecID;
    414         //return false;
    415     }
    416 
    417     FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], style);
    418     FontRec& fontRec = fFonts[fontRecID];
    419 
    420     if (NULL != outFontIdentifier) {
    421         outFontIdentifier->fID = fontRecID;
    422         outFontIdentifier->fTTCIndex = 0;
    423         outFontIdentifier->fString.set(fontRec.fFileName);
    424 //        outFontIdentifier->fStyle = fontRec.fStyle;
    425     }
    426 
    427     if (NULL != outFamilyName) {
    428         if (exactNameMatch) {
    429             outFamilyName->set(familyName);
    430         } else {
    431             // find familyName from list of names
    432             const char* familyName = NULL;
    433             SkAssertResult(fFamilyNameDict.findKey(familyRecID, &familyName));
    434             SkASSERT(familyName);
    435             outFamilyName->set(familyName);
    436         }
    437     }
    438 
    439     if (NULL != outStyle) {
    440         *outStyle = fontRec.fStyle;
    441     }
    442 
    443     return true;
    444 }
    445 
    446 SkStream* SkFontConfigInterfaceAndroid::openStream(const FontIdentity& identity) {
    447     return SkStream::NewFromFile(identity.fString.c_str());
    448 }
    449 
    450 SkDataTable* SkFontConfigInterfaceAndroid::getFamilyNames() {
    451     SkTDArray<const char*> names;
    452     SkTDArray<size_t> sizes;
    453 
    454     SkTDict<FamilyRecID>::Iter iter(fFamilyNameDict);
    455     const char* familyName = iter.next(NULL);
    456     while(familyName != NULL) {
    457         *names.append() = familyName;
    458         *sizes.append() = strlen(familyName) + 1;
    459 
    460         // move to the next familyName in the dictionary
    461         familyName = iter.next(NULL);
    462     }
    463 
    464     return SkDataTable::NewCopyArrays((const void*const*)names.begin(),
    465                                       sizes.begin(), names.count());
    466 }
    467 
    468 bool SkFontConfigInterfaceAndroid::matchFamilySet(const char inFamilyName[],
    469                                                   SkString* outFamilyName,
    470                                                   SkTArray<FontIdentity>*) {
    471     return false;
    472 }
    473 
    474 static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) {
    475     const FontRecID* fontRecID = (const FontRecID*)ctx;
    476     FontRecID currFontRecID = ((FontConfigTypeface*)face)->getIdentity().fID;
    477     return currFontRecID == *fontRecID;
    478 }
    479 
    480 SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForFontRec(FontRecID fontRecID) {
    481     FontRec& fontRec = fFonts[fontRecID];
    482     SkTypeface* face = fontRec.fTypeface.get();
    483     if (!face) {
    484         // look for it in the typeface cache
    485         face = SkTypefaceCache::FindByProcAndRef(find_proc, &fontRecID);
    486 
    487         // if it is not in the cache then create it
    488         if (!face) {
    489             const char* familyName = NULL;
    490             SkAssertResult(fFamilyNameDict.findKey(fontRec.fFamilyRecID, &familyName));
    491             SkASSERT(familyName);
    492             face = SkTypeface::CreateFromName(familyName, fontRec.fStyle);
    493         }
    494 
    495         // store the result for subsequent lookups
    496         fontRec.fTypeface = face;
    497     }
    498     SkASSERT(face);
    499     return face;
    500 }
    501 
    502 bool SkFontConfigInterfaceAndroid::getFallbackFamilyNameForChar(SkUnichar uni, SkString* name) {
    503     FallbackFontList* fallbackFontList = this->getCurrentLocaleFallbackFontList();
    504     for (int i = 0; i < fallbackFontList->count(); i++) {
    505         FontRecID fontRecID = fallbackFontList->getAt(i);
    506         SkTypeface* face = this->getTypefaceForFontRec(fontRecID);
    507 
    508         SkPaint paint;
    509         paint.setTypeface(face);
    510         paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
    511 
    512         uint16_t glyphID;
    513         paint.textToGlyphs(&uni, sizeof(uni), &glyphID);
    514         if (glyphID != 0) {
    515             name->set(fFonts[fontRecID].fFileName);
    516             return true;
    517         }
    518     }
    519     return false;
    520 }
    521 
    522 SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForChar(SkUnichar uni,
    523                                                              SkTypeface::Style style,
    524                                                              SkPaintOptionsAndroid::FontVariant fontVariant) {
    525     FontRecID fontRecID = find_best_style(fFontFamilies[fDefaultFamilyRecID], style);
    526     SkTypeface* face = this->getTypefaceForFontRec(fontRecID);
    527 
    528     SkPaintOptionsAndroid paintOptions;
    529     paintOptions.setFontVariant(fontVariant);
    530     paintOptions.setUseFontFallbacks(true);
    531 
    532     SkPaint paint;
    533     paint.setTypeface(face);
    534     paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
    535     paint.setPaintOptionsAndroid(paintOptions);
    536 
    537     SkAutoGlyphCache autoCache(paint, NULL, NULL);
    538     SkGlyphCache*    cache = autoCache.getCache();
    539 
    540     SkScalerContext* ctx = cache->getScalerContext();
    541     if (ctx) {
    542         SkFontID fontID = ctx->findTypefaceIdForChar(uni);
    543         return SkTypefaceCache::FindByID(fontID);
    544     }
    545     return NULL;
    546 }
    547 
    548 FallbackFontList* SkFontConfigInterfaceAndroid::getCurrentLocaleFallbackFontList() {
    549     SkString locale = SkFontConfigParser::GetLocale();
    550     if (NULL == fLocaleFallbackFontList || locale != fCachedLocale) {
    551         fCachedLocale = locale;
    552         fLocaleFallbackFontList = this->findFallbackFontList(locale);
    553     }
    554     return fLocaleFallbackFontList;
    555 }
    556 
    557 FallbackFontList* SkFontConfigInterfaceAndroid::findFallbackFontList(const SkLanguage& lang,
    558                                                                      bool isOriginal) {
    559     const SkString& langTag = lang.getTag();
    560     if (langTag.isEmpty()) {
    561         return &fDefaultFallbackList;
    562     }
    563 
    564     FallbackFontList* fallbackFontList;
    565     if (fFallbackFontDict.find(langTag.c_str(), langTag.size(), &fallbackFontList) ||
    566         fFallbackFontAliasDict.find(langTag.c_str(), langTag.size(), &fallbackFontList)) {
    567         return fallbackFontList;
    568     }
    569 
    570     // attempt a recursive fuzzy match
    571     SkLanguage parent = lang.getParent();
    572     fallbackFontList = findFallbackFontList(parent, false);
    573 
    574     // cache the original lang so we don't have to do the recursion again.
    575     if (isOriginal) {
    576         DEBUG_FONT(("----  Created fallback list alias for \"%s\"", langTag.c_str()));
    577         fFallbackFontAliasDict.set(langTag.c_str(), fallbackFontList);
    578     }
    579     return fallbackFontList;
    580 }
    581 
    582 SkTypeface* SkFontConfigInterfaceAndroid::nextLogicalTypeface(SkFontID currFontID,
    583                                                               SkFontID origFontID,
    584                                                               const SkPaintOptionsAndroid& opts) {
    585     // Skia does not support font fallback by default. This enables clients such
    586     // as WebKit to customize their font selection. In any case, clients can use
    587     // GetFallbackFamilyNameForChar() to get the fallback font for individual
    588     // characters.
    589     if (!opts.isUsingFontFallbacks()) {
    590         return NULL;
    591     }
    592 
    593     FallbackFontList* currentFallbackList = findFallbackFontList(opts.getLanguage());
    594     SkASSERT(currentFallbackList);
    595 
    596     // we must convert currTypeface into a FontRecID
    597     FontRecID currFontRecID = INVALID_FONT_REC_ID;
    598     const SkTypeface* currTypeface = SkTypefaceCache::FindByID(currFontID);
    599     // non-system fonts are not in the font cache so if we are asked to fallback
    600     // for a non-system font we will start at the front of the chain.
    601     if (NULL != currTypeface && currFontID != origFontID) {
    602         currFontRecID = ((FontConfigTypeface*)currTypeface)->getIdentity().fID;
    603         SkASSERT(INVALID_FONT_REC_ID != currFontRecID);
    604     }
    605 
    606     // lookup the index next font in the chain
    607     int currFallbackFontIndex = currentFallbackList->find(currFontRecID);
    608     // We add 1 to the returned index for 2 reasons: (1) if find succeeds it moves
    609     // our index to the next entry in the list; (2) if find() fails it returns
    610     // -1 and incrementing it will set our starting index to 0 (the head of the list)
    611     int nextFallbackFontIndex = currFallbackFontIndex + 1;
    612 
    613     if(nextFallbackFontIndex >= currentFallbackList->count()) {
    614         return NULL;
    615     }
    616 
    617     // If a rec object is set to prefer "kDefault_Variant" it means they have no preference
    618     // In this case, we set the value to "kCompact_Variant"
    619     SkPaintOptionsAndroid::FontVariant variant = opts.getFontVariant();
    620     if (variant == SkPaintOptionsAndroid::kDefault_Variant) {
    621         variant = SkPaintOptionsAndroid::kCompact_Variant;
    622     }
    623 
    624     int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | variant;
    625 
    626     SkTypeface* nextLogicalTypeface = 0;
    627     while (nextFallbackFontIndex < currentFallbackList->count()) {
    628         FontRecID fontRecID = currentFallbackList->getAt(nextFallbackFontIndex);
    629         if ((fFonts[fontRecID].fPaintOptions.getFontVariant() & acceptedVariants) != 0) {
    630             nextLogicalTypeface = this->getTypefaceForFontRec(fontRecID);
    631             break;
    632         }
    633         nextFallbackFontIndex++;
    634     }
    635 
    636     DEBUG_FONT(("---- nextLogicalFont: currFontID=%d, origFontID=%d, currRecID=%d, "
    637                 "lang=%s, variant=%d, nextFallbackIndex[%d,%d] => nextLogicalTypeface=%d",
    638                 currFontID, origFontID, currFontRecID, opts.getLanguage().getTag().c_str(),
    639                 variant, nextFallbackFontIndex, currentFallbackList->getAt(nextFallbackFontIndex),
    640                 (nextLogicalTypeface) ? nextLogicalTypeface->uniqueID() : 0));
    641     return SkSafeRef(nextLogicalTypeface);
    642 }
    643 
    644 ///////////////////////////////////////////////////////////////////////////////
    645 
    646 bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name) {
    647     SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
    648     return fontConfig->getFallbackFamilyNameForChar(uni, name);
    649 }
    650 
    651 void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf,
    652                              const char* fontsdir) {
    653     gTestMainConfigFile = mainconf;
    654     gTestFallbackConfigFile = fallbackconf;
    655     gTestFontFilePrefix = fontsdir;
    656     SkASSERT(gTestMainConfigFile);
    657     SkASSERT(gTestFallbackConfigFile);
    658     SkASSERT(gTestFontFilePrefix);
    659     SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s",
    660               gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix));
    661 }
    662 
    663 SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
    664                                          const SkPaintOptionsAndroid& options) {
    665     SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
    666     return fontConfig->nextLogicalTypeface(currFontID, origFontID, options);
    667 
    668 }
    669 
    670 ///////////////////////////////////////////////////////////////////////////////
    671 
    672 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    673 
    674 struct HB_UnicodeMapping {
    675     // TODO: when the WebView no longer needs harfbuzz_old, remove
    676     HB_Script script_old;
    677     hb_script_t script;
    678     const SkUnichar unicode;
    679 };
    680 
    681 /*
    682  * The following scripts are not complex fonts and we do not expect them to be parsed by this table
    683  * HB_SCRIPT_COMMON,
    684  * HB_SCRIPT_GREEK,
    685  * HB_SCRIPT_CYRILLIC,
    686  * HB_SCRIPT_HANGUL
    687  * HB_SCRIPT_INHERITED
    688  */
    689 
    690 /* Harfbuzz (old) is missing a number of scripts in its table. For these,
    691  * we include a value which can never happen. We won't get complex script
    692  * shaping in these cases, but the library wouldn't know how to shape
    693  * them anyway. */
    694 #define HB_Script_Unknown HB_ScriptCount
    695 
    696 static HB_UnicodeMapping HB_UnicodeMappingArray[] = {
    697     {HB_Script_Armenian,   HB_SCRIPT_ARMENIAN,    0x0531},
    698     {HB_Script_Hebrew,     HB_SCRIPT_HEBREW,      0x0591},
    699     {HB_Script_Arabic,     HB_SCRIPT_ARABIC,      0x0600},
    700     {HB_Script_Syriac,     HB_SCRIPT_SYRIAC,      0x0710},
    701     {HB_Script_Thaana,     HB_SCRIPT_THAANA,      0x0780},
    702     {HB_Script_Nko,        HB_SCRIPT_NKO,         0x07C0},
    703     {HB_Script_Devanagari, HB_SCRIPT_DEVANAGARI,  0x0901},
    704     {HB_Script_Bengali,    HB_SCRIPT_BENGALI,     0x0981},
    705     {HB_Script_Gurmukhi,   HB_SCRIPT_GURMUKHI,    0x0A10},
    706     {HB_Script_Gujarati,   HB_SCRIPT_GUJARATI,    0x0A90},
    707     {HB_Script_Oriya,      HB_SCRIPT_ORIYA,       0x0B10},
    708     {HB_Script_Tamil,      HB_SCRIPT_TAMIL,       0x0B82},
    709     {HB_Script_Telugu,     HB_SCRIPT_TELUGU,      0x0C10},
    710     {HB_Script_Kannada,    HB_SCRIPT_KANNADA,     0x0C90},
    711     {HB_Script_Malayalam,  HB_SCRIPT_MALAYALAM,   0x0D10},
    712     {HB_Script_Sinhala,    HB_SCRIPT_SINHALA,     0x0D90},
    713     {HB_Script_Thai,       HB_SCRIPT_THAI,        0x0E01},
    714     {HB_Script_Lao,        HB_SCRIPT_LAO,         0x0E81},
    715     {HB_Script_Tibetan,    HB_SCRIPT_TIBETAN,     0x0F00},
    716     {HB_Script_Myanmar,    HB_SCRIPT_MYANMAR,     0x1000},
    717     {HB_Script_Georgian,   HB_SCRIPT_GEORGIAN,    0x10A0},
    718     {HB_Script_Unknown,    HB_SCRIPT_ETHIOPIC,    0x1200},
    719     {HB_Script_Unknown,    HB_SCRIPT_CHEROKEE,    0x13A0},
    720     {HB_Script_Ogham,      HB_SCRIPT_OGHAM,       0x1680},
    721     {HB_Script_Runic,      HB_SCRIPT_RUNIC,       0x16A0},
    722     {HB_Script_Khmer,      HB_SCRIPT_KHMER,       0x1780},
    723     {HB_Script_Unknown,    HB_SCRIPT_TAI_LE,      0x1950},
    724     {HB_Script_Unknown,    HB_SCRIPT_NEW_TAI_LUE, 0x1980},
    725     {HB_Script_Unknown,    HB_SCRIPT_TAI_THAM,    0x1A20},
    726     {HB_Script_Unknown,    HB_SCRIPT_CHAM,        0xAA00},
    727 };
    728 
    729 static hb_script_t getHBScriptFromHBScriptOld(HB_Script script_old) {
    730     hb_script_t script = HB_SCRIPT_INVALID;
    731     int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping);
    732     for (int i = 0; i < numSupportedFonts; i++) {
    733         if (script_old == HB_UnicodeMappingArray[i].script_old) {
    734             script = HB_UnicodeMappingArray[i].script;
    735             break;
    736         }
    737     }
    738     return script;
    739 }
    740 
    741 // returns 0 for "Not Found"
    742 static SkUnichar getUnicodeFromHBScript(hb_script_t script) {
    743     SkUnichar unichar = 0;
    744     int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping);
    745     for (int i = 0; i < numSupportedFonts; i++) {
    746         if (script == HB_UnicodeMappingArray[i].script) {
    747             unichar = HB_UnicodeMappingArray[i].unicode;
    748             break;
    749         }
    750     }
    751     return unichar;
    752 }
    753 
    754 struct TypefaceLookupStruct {
    755     hb_script_t script;
    756     SkTypeface::Style style;
    757     SkPaintOptionsAndroid::FontVariant fontVariant;
    758     SkTypeface* typeface;
    759 };
    760 
    761 SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex);  // This is the mutex for gTypefaceTable
    762 static SkTDArray<TypefaceLookupStruct> gTypefaceTable;  // This is protected by gTypefaceTableMutex
    763 
    764 static int typefaceLookupCompare(const TypefaceLookupStruct& first,
    765                                  const TypefaceLookupStruct& second) {
    766     if (first.script != second.script) {
    767         return (first.script > second.script) ? 1 : -1;
    768     }
    769     if (first.style != second.style) {
    770         return (first.style > second.style) ? 1 : -1;
    771     }
    772     if (first.fontVariant != second.fontVariant) {
    773         return (first.fontVariant > second.fontVariant) ? 1 : -1;
    774     }
    775     return 0;
    776 }
    777 
    778 SkTypeface* SkCreateTypefaceForScriptNG(hb_script_t script, SkTypeface::Style style,
    779                                         SkPaintOptionsAndroid::FontVariant fontVariant) {
    780     SkAutoMutexAcquire ac(gTypefaceTableMutex);
    781 
    782     TypefaceLookupStruct key;
    783     key.script = script;
    784     key.style = style;
    785     key.fontVariant = fontVariant;
    786 
    787     int index = SkTSearch<TypefaceLookupStruct>(
    788             (const TypefaceLookupStruct*) gTypefaceTable.begin(),
    789             gTypefaceTable.count(), key, sizeof(TypefaceLookupStruct),
    790             typefaceLookupCompare);
    791 
    792     SkTypeface* retTypeface = NULL;
    793     if (index >= 0) {
    794         retTypeface = gTypefaceTable[index].typeface;
    795     }
    796     else {
    797         SkUnichar unichar = getUnicodeFromHBScript(script);
    798         if (!unichar) {
    799             return NULL;
    800         }
    801 
    802         SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
    803         retTypeface = fontConfig->getTypefaceForChar(unichar, style, fontVariant);
    804 
    805         // add to the lookup table
    806         key.typeface = retTypeface;
    807         *gTypefaceTable.insert(~index) = key;
    808     }
    809 
    810     // we ref(), the caller is expected to unref when they are done
    811     return SkSafeRef(retTypeface);
    812 }
    813 
    814 SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style,
    815                                       SkPaintOptionsAndroid::FontVariant fontVariant) {
    816     return SkCreateTypefaceForScriptNG(getHBScriptFromHBScriptOld(script), style, fontVariant);
    817 }
    818 
    819 #endif
    820 
    821 ///////////////////////////////////////////////////////////////////////////////
    822 
    823 SkFontMgr* SkFontMgr::Factory() {
    824     return NULL;
    825 }
    826