Home | History | Annotate | Download | only in ports
      1 /* libs/graphics/ports/SkFontHost_android.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #include "SkFontHost.h"
     19 #include "SkGraphics.h"
     20 #include "SkDescriptor.h"
     21 #include "SkMMapStream.h"
     22 #include "SkPaint.h"
     23 #include "SkString.h"
     24 #include "SkStream.h"
     25 #include "SkThread.h"
     26 #include "SkTSearch.h"
     27 #include "FontHostConfiguration_android.h"
     28 #include <stdio.h>
     29 #include <string.h>
     30 #include "SkGlyphCache.h"
     31 #include "SkLanguage.h"
     32 #include "SkTypeface_android.h"
     33 #include "SkTArray.h"
     34 #include "SkTDict.h"
     35 #include "SkTSearch.h"
     36 
     37 //#define SkDEBUGF(args       )       SkDebugf args
     38 
     39 #ifndef SK_FONT_FILE_PREFIX
     40     #define SK_FONT_FILE_PREFIX          "/fonts/"
     41 #endif
     42 
     43 // Defined in SkFontHost_FreeType.cpp
     44 bool find_name_and_attributes(SkStream* stream, SkString* name,
     45                               SkTypeface::Style* style, bool* isFixedWidth);
     46 
     47 static void getFullPathForSysFonts(SkString* full, const char name[]) {
     48     full->set(getenv("ANDROID_ROOT"));
     49     full->append(SK_FONT_FILE_PREFIX);
     50     full->append(name);
     51 }
     52 
     53 static bool getNameAndStyle(const char path[], SkString* name,
     54                                SkTypeface::Style* style,
     55                                bool* isFixedWidth, bool isExpected) {
     56     SkString        fullpath;
     57     getFullPathForSysFonts(&fullpath, path);
     58 
     59     SkMMAPStream stream(fullpath.c_str());
     60     if (stream.getLength() > 0) {
     61         return find_name_and_attributes(&stream, name, style, isFixedWidth);
     62     }
     63     else {
     64         SkFILEStream stream(fullpath.c_str());
     65         if (stream.getLength() > 0) {
     66             return find_name_and_attributes(&stream, name, style, isFixedWidth);
     67         }
     68     }
     69 
     70     if (isExpected) {
     71         SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
     72     }
     73     return false;
     74 }
     75 
     76 static SkTypeface* deserializeLocked(SkStream* stream);
     77 static SkTypeface* createTypefaceLocked(const SkTypeface* familyFace,
     78         const char familyName[], const void* data, size_t bytelength,
     79         SkTypeface::Style style);
     80 static SkStream* openStreamLocked(uint32_t fontID);
     81 static size_t getFileNameLocked(SkFontID fontID, char path[], size_t length, int32_t* index);
     82 static SkFontID nextLogicalFontLocked(const SkScalerContext::Rec& rec);
     83 static SkTypeface* createTypefaceFromStreamLocked(SkStream* stream);
     84 
     85 
     86 ///////////////////////////////////////////////////////////////////////////////
     87 
     88 struct FamilyRec;
     89 
     90 /*  This guy holds a mapping of a name -> family, used for looking up fonts.
     91     Since it is stored in a stretchy array that doesn't preserve object
     92     semantics, we don't use constructor/destructors, but just have explicit
     93     helpers to manage our internal bookkeeping.
     94 */
     95 struct NameFamilyPair {
     96     const char* fName;      // we own this
     97     FamilyRec*  fFamily;    // we don't own this, we just reference it
     98 
     99     void construct(const char name[], FamilyRec* family) {
    100         fName = strdup(name);
    101         fFamily = family;   // we don't own this, so just record the reference
    102     }
    103 
    104     void destruct() {
    105         free((char*)fName);
    106         // we don't own family, so just ignore our reference
    107     }
    108 };
    109 typedef SkTDArray<NameFamilyPair> NameFamilyPairList;
    110 
    111 // we use atomic_inc to grow this for each typeface we create
    112 static int32_t gUniqueFontID;
    113 
    114 // this is the mutex that protects all of the global data structures in this module
    115 // functions with the Locked() suffix must be called while holding this mutex
    116 SK_DECLARE_STATIC_MUTEX(gFamilyHeadAndNameListMutex);
    117 static FamilyRec* gFamilyHead = NULL;
    118 static SkTDArray<NameFamilyPair> gFallbackFilenameList;
    119 static NameFamilyPairList gNameList;
    120 
    121 struct FamilyRec {
    122     FamilyRec*  fNext;
    123     SkTypeface* fFaces[4];
    124 
    125     FamilyRec() : fNext(NULL) {
    126         memset(fFaces, 0, sizeof(fFaces));
    127     }
    128 };
    129 
    130 static SkTypeface* findBestFaceLocked(const FamilyRec* family,
    131                                   SkTypeface::Style style) {
    132     SkTypeface* const* faces = family->fFaces;
    133 
    134     if (faces[style] != NULL) { // exact match
    135         return faces[style];
    136     }
    137     // look for a matching bold
    138     style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
    139     if (faces[style] != NULL) {
    140         return faces[style];
    141     }
    142     // look for the plain
    143     if (faces[SkTypeface::kNormal] != NULL) {
    144         return faces[SkTypeface::kNormal];
    145     }
    146     // look for anything
    147     for (int i = 0; i < 4; i++) {
    148         if (faces[i] != NULL) {
    149             return faces[i];
    150         }
    151     }
    152     // should never get here, since the faces list should not be empty
    153     SkDEBUGFAIL("faces list is empty");
    154     return NULL;
    155 }
    156 
    157 static SkTypeface* FindBestFace(const FamilyRec* family,
    158             SkTypeface::Style style) {
    159     SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
    160     return findBestFaceLocked(family, style);
    161 }
    162 
    163 static FamilyRec* findFamilyLocked(const SkTypeface* member) {
    164     FamilyRec* curr = gFamilyHead;
    165     while (curr != NULL) {
    166         for (int i = 0; i < 4; i++) {
    167             if (curr->fFaces[i] == member) {
    168                 return curr;
    169             }
    170         }
    171         curr = curr->fNext;
    172     }
    173     return NULL;
    174 }
    175 
    176 /*  Returns the matching typeface, or NULL. If a typeface is found, its refcnt
    177     is not modified.
    178  */
    179 static SkTypeface* findFromUniqueIDLocked(uint32_t uniqueID) {
    180     FamilyRec* curr = gFamilyHead;
    181     while (curr != NULL) {
    182         for (int i = 0; i < 4; i++) {
    183             SkTypeface* face = curr->fFaces[i];
    184             if (face != NULL && face->uniqueID() == uniqueID) {
    185                 return face;
    186             }
    187         }
    188         curr = curr->fNext;
    189     }
    190     return NULL;
    191 }
    192 
    193 /*  Returns the matching typeface, or NULL. If a typeface is found, its refcnt
    194     is not modified.
    195  */
    196 static SkTypeface* FindFromUniqueID(uint32_t uniqueID) {
    197     SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
    198     return findFromUniqueIDLocked(uniqueID);
    199 }
    200 
    201 /*  Remove reference to this face from its family. If the resulting family
    202     is empty (has no faces), return that family, otherwise return NULL
    203 */
    204 static FamilyRec* removeFromFamilyLocked(const SkTypeface* face) {
    205     FamilyRec* family = findFamilyLocked(face);
    206     if (family) {
    207         SkASSERT(family->fFaces[face->style()] == face);
    208         family->fFaces[face->style()] = NULL;
    209 
    210         for (int i = 0; i < 4; i++) {
    211             if (family->fFaces[i] != NULL) {    // family is non-empty
    212                 return NULL;
    213             }
    214         }
    215     } else {
    216 //        SkDebugf("removeFromFamilyLocked(%p) face not found", face);
    217     }
    218     return family;  // return the empty family
    219 }
    220 
    221 // maybe we should make FamilyRec be doubly-linked
    222 static void detachAndDeleteFamilyLocked(FamilyRec* family) {
    223     FamilyRec* curr = gFamilyHead;
    224     FamilyRec* prev = NULL;
    225 
    226     while (curr != NULL) {
    227         FamilyRec* next = curr->fNext;
    228         if (curr == family) {
    229             if (prev == NULL) {
    230                 gFamilyHead = next;
    231             } else {
    232                 prev->fNext = next;
    233             }
    234             SkDELETE(family);
    235             return;
    236         }
    237         prev = curr;
    238         curr = next;
    239     }
    240     SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
    241 }
    242 
    243 static SkTypeface* findTypefaceLocked(const char name[], SkTypeface::Style style) {
    244     int count = gNameList.count();
    245     NameFamilyPair* list = gNameList.begin();
    246     int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
    247     if (index >= 0) {
    248         return findBestFaceLocked(list[index].fFamily, style);
    249     }
    250     return NULL;
    251 }
    252 
    253 static SkTypeface* findTypefaceLocked(const SkTypeface* familyMember,
    254                                  SkTypeface::Style style) {
    255     const FamilyRec* family = findFamilyLocked(familyMember);
    256     return family ? findBestFaceLocked(family, style) : NULL;
    257 }
    258 
    259 static void addNameLocked(const char name[], FamilyRec* family) {
    260     SkAutoAsciiToLC tolc(name);
    261     name = tolc.lc();
    262 
    263     int count = gNameList.count();
    264     NameFamilyPair* list = gNameList.begin();
    265     int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
    266     if (index < 0) {
    267         list = gNameList.insert(~index);
    268         list->construct(name, family);
    269     }
    270 }
    271 
    272 static void removeFromNamesLocked(FamilyRec* emptyFamily) {
    273 #ifdef SK_DEBUG
    274     for (int i = 0; i < 4; i++) {
    275         SkASSERT(emptyFamily->fFaces[i] == NULL);
    276     }
    277 #endif
    278 
    279     // must go backwards when removing
    280     for (int i = gNameList.count() - 1; i >= 0; --i) {
    281         NameFamilyPair& pair = gNameList[i];
    282         if (pair.fFamily == emptyFamily) {
    283             pair.destruct();
    284             gNameList.remove(i);
    285         }
    286     }
    287 }
    288 
    289 static void addTypefaceLocked(SkTypeface* typeface, SkTypeface* familyMember) {
    290     FamilyRec* rec = NULL;
    291     if (familyMember) {
    292         rec = findFamilyLocked(familyMember);
    293         SkASSERT(rec);
    294     } else {
    295         rec = SkNEW(FamilyRec);
    296         rec->fNext = gFamilyHead;
    297         gFamilyHead = rec;
    298     }
    299     rec->fFaces[typeface->style()] = typeface;
    300 }
    301 
    302 static void removeTypeface(SkTypeface* typeface) {
    303     SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
    304 
    305     // remove us from our family. If the family is now empty, we return
    306     // that and then remove that family from the name list
    307     FamilyRec* family = removeFromFamilyLocked(typeface);
    308     if (NULL != family) {
    309         removeFromNamesLocked(family);
    310         detachAndDeleteFamilyLocked(family);
    311     }
    312 }
    313 
    314 ///////////////////////////////////////////////////////////////////////////////
    315 
    316 class FamilyTypeface : public SkTypeface {
    317 protected:
    318     FamilyTypeface(Style style, bool sysFont, bool isFixedWidth)
    319     : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) {
    320         fIsSysFont = sysFont;
    321     }
    322 
    323 public:
    324     virtual ~FamilyTypeface() {
    325         removeTypeface(this);
    326     }
    327 
    328     bool isSysFont() const { return fIsSysFont; }
    329 
    330     virtual SkStream* openStream() = 0;
    331     virtual const char* getUniqueString() const = 0;
    332     virtual const char* getFilePath() const = 0;
    333 
    334 private:
    335     bool    fIsSysFont;
    336 
    337     typedef SkTypeface INHERITED;
    338 };
    339 
    340 ///////////////////////////////////////////////////////////////////////////////
    341 
    342 class StreamTypeface : public FamilyTypeface {
    343 public:
    344     StreamTypeface(Style style, bool sysFont, SkStream* stream, bool isFixedWidth)
    345     : INHERITED(style, sysFont, isFixedWidth) {
    346         SkASSERT(stream);
    347         stream->ref();
    348         fStream = stream;
    349     }
    350 
    351     virtual ~StreamTypeface() {
    352         fStream->unref();
    353     }
    354 
    355     // overrides
    356     virtual SkStream* openStream() {
    357         // we just ref our existing stream, since the caller will call unref()
    358         // when they are through
    359         fStream->ref();
    360         // must rewind each time, since the caller assumes a "new" stream
    361         fStream->rewind();
    362         return fStream;
    363     }
    364     virtual const char* getUniqueString() const { return NULL; }
    365     virtual const char* getFilePath() const { return NULL; }
    366 
    367 private:
    368     SkStream* fStream;
    369 
    370     typedef FamilyTypeface INHERITED;
    371 };
    372 
    373 class FileTypeface : public FamilyTypeface {
    374 public:
    375     FileTypeface(Style style, bool sysFont, const char path[], bool isFixedWidth)
    376     : INHERITED(style, sysFont, isFixedWidth) {
    377         fPath.set(path);
    378     }
    379 
    380     // overrides
    381     virtual SkStream* openStream() {
    382         SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
    383 
    384         // check for failure
    385         if (stream->getLength() <= 0) {
    386             SkDELETE(stream);
    387             // maybe MMAP isn't supported. try FILE
    388             stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
    389             if (stream->getLength() <= 0) {
    390                 SkDELETE(stream);
    391                 stream = NULL;
    392             }
    393         }
    394         return stream;
    395     }
    396     virtual const char* getUniqueString() const {
    397         const char* str = strrchr(fPath.c_str(), '/');
    398         if (str) {
    399             str += 1;   // skip the '/'
    400         }
    401         return str;
    402     }
    403     virtual const char* getFilePath() const {
    404         return fPath.c_str();
    405     }
    406 
    407 private:
    408     SkString fPath;
    409 
    410     typedef FamilyTypeface INHERITED;
    411 };
    412 
    413 ///////////////////////////////////////////////////////////////////////////////
    414 ///////////////////////////////////////////////////////////////////////////////
    415 
    416 // used to record our notion of the pre-existing fonts
    417 struct FontInitRec {
    418     const char*          fFileName;
    419     const char* const*   fNames;     // null-terminated list
    420     SkPaint::FontVariant fVariant;
    421     SkLanguage           fLanguage;
    422 };
    423 
    424 //used to record information about the fallback fonts
    425 struct FallbackFontRec {
    426     SkFontID             fFontID;
    427     SkPaint::FontVariant fVariant;
    428 };
    429 
    430 struct FallbackFontList {
    431     FallbackFontList(const SkLanguage& language) : fLanguage(language) { }
    432     SkTDArray<FallbackFontRec> fList;
    433     SkLanguage                 fLanguage;
    434 };
    435 
    436 // deliberately empty, but we use the address to identify fallback fonts
    437 static const char* gFBNames[] = { NULL };
    438 
    439 /*  Fonts are grouped by family, with the first font in a family having the
    440     list of names (even if that list is empty), and the following members having
    441     null for the list. The names list must be NULL-terminated.
    442 */
    443 static SkTArray<FontInitRec> gSystemFonts;
    444 static SkTDArray<FallbackFontList*> gFallbackFontLists;
    445 
    446 // these globals are assigned (once) by loadSystemFontsLocked()
    447 static FamilyRec* gDefaultFamily = NULL;
    448 static SkTypeface* gDefaultNormal = NULL;
    449 static char** gDefaultNames = NULL;
    450 
    451 static FallbackFontList* getFallbackFontListLocked(const SkLanguage& lang);
    452 static void dumpGlobalsLocked() {
    453     SkDebugf("gDefaultNormal=%p id=%u refCnt=%d", gDefaultNormal,
    454              gDefaultNormal ? gDefaultNormal->uniqueID() : 0,
    455              gDefaultNormal ? gDefaultNormal->getRefCnt() : 0);
    456 
    457     if (gDefaultFamily) {
    458         SkDebugf("gDefaultFamily=%p fFaces={%u,%u,%u,%u} refCnt={%d,%d,%d,%d}",
    459                  gDefaultFamily,
    460                  gDefaultFamily->fFaces[0] ? gDefaultFamily->fFaces[0]->uniqueID() : 0,
    461                  gDefaultFamily->fFaces[1] ? gDefaultFamily->fFaces[1]->uniqueID() : 0,
    462                  gDefaultFamily->fFaces[2] ? gDefaultFamily->fFaces[2]->uniqueID() : 0,
    463                  gDefaultFamily->fFaces[3] ? gDefaultFamily->fFaces[3]->uniqueID() : 0,
    464                  gDefaultFamily->fFaces[0] ? gDefaultFamily->fFaces[0]->getRefCnt() : 0,
    465                  gDefaultFamily->fFaces[1] ? gDefaultFamily->fFaces[1]->getRefCnt() : 0,
    466                  gDefaultFamily->fFaces[2] ? gDefaultFamily->fFaces[2]->getRefCnt() : 0,
    467                  gDefaultFamily->fFaces[3] ? gDefaultFamily->fFaces[3]->getRefCnt() : 0);
    468     } else {
    469         SkDebugf("gDefaultFamily=%p", gDefaultFamily);
    470     }
    471 
    472     FallbackFontList* defaultFallbackList =
    473             getFallbackFontListLocked(SkLanguage());
    474     SkASSERT(defaultFallbackList != NULL);
    475     SkDebugf("gSystemFonts.count()=%d defaultFallbackList->fList.count()=%d",
    476            gSystemFonts.count(), defaultFallbackList->fList.count());
    477 
    478     for (int i = 0; i < gSystemFonts.count(); ++i) {
    479         SkDebugf("gSystemFonts[%d] fileName=%s", i, gSystemFonts[i].fFileName);
    480         size_t namesIndex = 0;
    481         if (gSystemFonts[i].fNames)
    482             for (const char* fontName = gSystemFonts[i].fNames[namesIndex];
    483                     fontName != 0;
    484                     fontName = gSystemFonts[i].fNames[++namesIndex]) {
    485                 SkDebugf("       name[%u]=%s", namesIndex, fontName);
    486             }
    487     }
    488 
    489     if (gFamilyHead) {
    490         FamilyRec* rec = gFamilyHead;
    491         int i=0;
    492         while (rec) {
    493             SkDebugf("gFamilyHead[%d]=%p fFaces={%u,%u,%u,%u} refCnt={%d,%d,%d,%d}",
    494                      i++, rec,
    495                      rec->fFaces[0] ? rec->fFaces[0]->uniqueID() : 0,
    496                      rec->fFaces[1] ? rec->fFaces[1]->uniqueID() : 0,
    497                      rec->fFaces[2] ? rec->fFaces[2]->uniqueID() : 0,
    498                      rec->fFaces[3] ? rec->fFaces[3]->uniqueID() : 0,
    499                      rec->fFaces[0] ? rec->fFaces[0]->getRefCnt() : 0,
    500                      rec->fFaces[1] ? rec->fFaces[1]->getRefCnt() : 0,
    501                      rec->fFaces[2] ? rec->fFaces[2]->getRefCnt() : 0,
    502                      rec->fFaces[3] ? rec->fFaces[3]->getRefCnt() : 0);
    503             rec = rec->fNext;
    504         }
    505     } else {
    506         SkDebugf("gFamilyHead=%p", gFamilyHead);
    507     }
    508 
    509 }
    510 
    511 
    512 static bool haveSystemFont(const char* filename) {
    513     for (int i = 0; i < gSystemFonts.count(); i++) {
    514         if (strcmp(gSystemFonts[i].fFileName, filename) == 0) {
    515             return true;
    516         }
    517     }
    518     return false;
    519 }
    520 
    521 // (SkLanguage)<->(fallback chain index) translation
    522 static const size_t kLangDictSize = 128;
    523 static SkTDict<FallbackFontList*> gLangTagToFallbackFontList(kLangDictSize);
    524 static bool gIsOKToUseFallbackFontListCache = false;
    525 
    526 // crawl fallback font lists by hand looking for a specific language
    527 static FallbackFontList* getFallbackFontListNoCacheLocked(
    528         const SkLanguage& lang) {
    529     unsigned int numLists = gFallbackFontLists.count();
    530     for (unsigned int listIdx = 0; listIdx < numLists; ++listIdx) {
    531         FallbackFontList* list = gFallbackFontLists[listIdx];
    532         SkASSERT(list != NULL);
    533         if (list->fLanguage == lang) {
    534             return list;
    535         }
    536     }
    537     return NULL;
    538 }
    539 
    540 // perform fancy fuzzy-matching memoized query for a fallback font list.
    541 // should only be called after fallback font lists are fully loaded.
    542 static FallbackFontList* getFallbackFontListLocked(const SkLanguage& lang) {
    543     SkASSERT(gIsOKToUseFallbackFontListCache);
    544     const SkString& langTag = lang.getTag();
    545     FallbackFontList* fallbackFontList;
    546     if (gLangTagToFallbackFontList.find(langTag.c_str(), langTag.size(),
    547             &fallbackFontList)) {
    548         // cache hit!
    549         return fallbackFontList;
    550     }
    551 
    552     // try again without the cache
    553     fallbackFontList = getFallbackFontListNoCacheLocked(lang);
    554     if (fallbackFontList != NULL) {
    555         // found it - cache and return
    556         gLangTagToFallbackFontList.set(langTag.c_str(), langTag.size(),
    557                 fallbackFontList);
    558         SkDEBUGF(("new fallback cache entry: \"%s\"", langTag.c_str()));
    559         return fallbackFontList;
    560     }
    561 
    562     // no hit - can we fuzzy-match?
    563     if (lang.getTag().isEmpty()) {
    564         // nope! this happens if attempting to direct match with no default
    565         return NULL;
    566     }
    567 
    568     // attempt fuzzy match
    569     SkLanguage parent = lang.getParent();
    570     fallbackFontList = getFallbackFontListLocked(parent);
    571     if (fallbackFontList != NULL) {
    572         // found it - cache and return
    573         gLangTagToFallbackFontList.set(langTag.c_str(), langTag.size(),
    574                 fallbackFontList);
    575         SkDEBUGF(("new fallback cache entry: \"%s\" -> \"%s\"", langTag.c_str(),
    576                 fallbackFontList->fLanguage.getTag().c_str()));
    577         return fallbackFontList;
    578     }
    579 
    580     // utter failure. this happens if attempting to fuzzy-match with no default
    581     SkASSERT(fallbackFontList != NULL);
    582     return NULL;
    583 }
    584 
    585 // creates a new fallback font list for the specified language
    586 static FallbackFontList* createFallbackFontListLocked(const SkLanguage& lang) {
    587     SkASSERT(!gIsOKToUseFallbackFontListCache);
    588     SkDEBUGF(("new fallback list: \"%s\"", lang.getTag().c_str()));
    589     FallbackFontList* fallbackFontList = new FallbackFontList(lang);
    590     gFallbackFontLists.push(fallbackFontList);
    591     return fallbackFontList;
    592 }
    593 
    594 // adds a fallback font record to both the default fallback chain and the
    595 // language-specific fallback chain to which it belongs, if any
    596 static void addFallbackFontLocked(const FallbackFontRec& fallbackRec,
    597         const SkLanguage& lang) {
    598     SkASSERT(!gIsOKToUseFallbackFontListCache);
    599     SkDEBUGF(("new fallback font: %d, in \"%s\"", fallbackRec.fFontID,
    600             lang.getTag().c_str()));
    601     // add to the default fallback list
    602     FallbackFontList* fallbackList =
    603             getFallbackFontListNoCacheLocked(SkLanguage());
    604     if (fallbackList == NULL) {
    605         // oops! no default list yet. create one.
    606         fallbackList = createFallbackFontListLocked(SkLanguage());
    607     }
    608     SkASSERT(fallbackList != NULL);
    609     fallbackList->fList.push(fallbackRec);
    610     if (lang.getTag().isEmpty()) {
    611         return;
    612     }
    613     // also add to the appropriate language's fallback list
    614     fallbackList = getFallbackFontListNoCacheLocked(lang);
    615     if (fallbackList == NULL) {
    616         // first entry for this list!
    617         fallbackList = createFallbackFontListLocked(lang);
    618     }
    619     SkASSERT(fallbackList != NULL);
    620     fallbackList->fList.push(fallbackRec);
    621 }
    622 
    623 static int getSystemFontIndexForFontID(SkFontID fontID) {
    624     // font unique id = one-based index in system font table
    625     SkASSERT(fontID - 1 < gSystemFonts.count());
    626     return fontID - 1;
    627 }
    628 
    629 // scans the default fallback font chain, adding every entry to every other
    630 // fallback font chain to which it does not belong. this results in every
    631 // language-specific fallback font chain having all of its fallback fonts at
    632 // the front of the chain, and everything else at the end. after this has been
    633 // run, it is ok to use the fallback font chain lookup table.
    634 static void finaliseFallbackFontListsLocked() {
    635     SkASSERT(!gIsOKToUseFallbackFontListCache);
    636     // if we have more than one list, we need to finalise non-default lists
    637     unsigned int numLists = gFallbackFontLists.count();
    638     if (numLists > 1) {
    639         // pull fonts off of the default list...
    640         FallbackFontList* defaultList = getFallbackFontListNoCacheLocked(
    641                 SkLanguage());
    642         SkASSERT(defaultList != NULL);
    643         int numDefaultFonts = defaultList->fList.count();
    644         for (int fontIdx = 0; fontIdx < numDefaultFonts; ++fontIdx) {
    645             // figure out which language they represent
    646             SkFontID fontID = defaultList->fList[fontIdx].fFontID;
    647             int sysFontIdx = getSystemFontIndexForFontID(fontID);
    648             const SkLanguage& lang = gSystemFonts[sysFontIdx].fLanguage;
    649             for (unsigned int listIdx = 0; listIdx < numLists; ++listIdx) {
    650                 // and add them to every other language's list
    651                 FallbackFontList* thisList = gFallbackFontLists[listIdx];
    652                 SkASSERT(thisList != NULL);
    653                 if (thisList != defaultList && thisList->fLanguage != lang) {
    654                     thisList->fList.push(defaultList->fList[fontIdx]);
    655                 }
    656             }
    657         }
    658     }
    659     gIsOKToUseFallbackFontListCache = true;
    660 }
    661 
    662 static void resetFallbackFontListsLocked() {
    663     // clear cache
    664     gLangTagToFallbackFontList.reset();
    665     // clear the data it pointed at
    666     int numFallbackLists = gFallbackFontLists.count();
    667     for (int fallbackIdx = 0; fallbackIdx < numFallbackLists; ++fallbackIdx) {
    668         delete gFallbackFontLists[fallbackIdx];
    669     }
    670     gFallbackFontLists.reset();
    671     gIsOKToUseFallbackFontListCache = false;
    672 }
    673 
    674 /*  Load info from a configuration file that populates the system/fallback font structures
    675 */
    676 static void loadFontInfoLocked() {
    677     resetFallbackFontListsLocked();
    678 
    679     SkTDArray<FontFamily*> fontFamilies;
    680     getFontFamilies(fontFamilies);
    681 
    682     gSystemFonts.reset();
    683 
    684     for (int i = 0; i < fontFamilies.count(); ++i) {
    685         FontFamily *family = fontFamilies[i];
    686         for (int j = 0; j < family->fFontFileArray.count(); ++j) {
    687             const char* filename = family->fFontFileArray[j]->fFileName;
    688             if (haveSystemFont(filename)) {
    689                 SkDebugf("---- system font and fallback font files specify a duplicate "
    690                         "font %s, skipping the second occurrence", filename);
    691                 continue;
    692             }
    693 
    694             FontInitRec fontInfoRecord;
    695             fontInfoRecord.fFileName = filename;
    696             fontInfoRecord.fVariant = family->fFontFileArray[j]->fVariant;
    697             fontInfoRecord.fLanguage = family->fFontFileArray[j]->fLanguage;
    698             if (j == 0) {
    699                 if (family->fNames.count() == 0) {
    700                     // Fallback font
    701                     fontInfoRecord.fNames = (char **)gFBNames;
    702                 } else {
    703                     SkTDArray<const char*> names = family->fNames;
    704                     const char **nameList = (const char**)
    705                             malloc((names.count() + 1) * sizeof(char*));
    706                     if (nameList == NULL) {
    707                         // shouldn't get here
    708                         break;
    709                     }
    710                     if (gDefaultNames == NULL) {
    711                         gDefaultNames = (char**) nameList;
    712                     }
    713                     for (int i = 0; i < names.count(); ++i) {
    714                         nameList[i] = names[i];
    715                     }
    716                     nameList[names.count()] = NULL;
    717                     fontInfoRecord.fNames = nameList;
    718                 }
    719             } else {
    720                 fontInfoRecord.fNames = NULL;
    721             }
    722             gSystemFonts.push_back(fontInfoRecord);
    723         }
    724     }
    725     fontFamilies.deleteAll();
    726 
    727     SkDEBUGF(("---- We have %d system fonts", gSystemFonts.count()));
    728     for (int i = 0; i < gSystemFonts.count(); ++i) {
    729         SkDEBUGF(("---- gSystemFonts[%d] fileName=%s", i, gSystemFonts[i].fFileName));
    730     }
    731 }
    732 
    733 /*
    734  *  Called once (ensured by the sentinel check at the beginning of our body).
    735  *  Initializes all the globals, and register the system fonts.
    736  */
    737 static void initSystemFontsLocked() {
    738     // check if we've already been called
    739     if (gDefaultNormal) {
    740         return;
    741     }
    742 
    743     SkASSERT(gUniqueFontID == 0);
    744 
    745     loadFontInfoLocked();
    746 
    747     SkTypeface* firstInFamily = NULL;
    748     for (int i = 0; i < gSystemFonts.count(); i++) {
    749         // if we're the first in a new family, clear firstInFamily
    750         const char* const* names = gSystemFonts[i].fNames;
    751         if (names != NULL) {
    752             firstInFamily = NULL;
    753         }
    754 
    755         bool isFixedWidth;
    756         SkString name;
    757         SkTypeface::Style style;
    758 
    759         // we expect all the fonts, except the "fallback" fonts
    760         bool isExpected = (names != gFBNames);
    761         if (!getNameAndStyle(gSystemFonts[i].fFileName, &name, &style,
    762                 &isFixedWidth, isExpected)) {
    763             // We need to increase gUniqueFontID here so that the unique id of
    764             // each font matches its index in gSystemFonts array, as expected
    765             // by findUniqueIDLocked.
    766             sk_atomic_inc(&gUniqueFontID);
    767             continue;
    768         }
    769 
    770         SkString fullpath;
    771         getFullPathForSysFonts(&fullpath, gSystemFonts[i].fFileName);
    772 
    773         SkTypeface* tf = SkNEW_ARGS(FileTypeface, (style,
    774                 true,  // system-font (cannot delete)
    775                 fullpath.c_str(), // filename
    776                 isFixedWidth));
    777         addTypefaceLocked(tf, firstInFamily);
    778 
    779         SkDEBUGF(("---- SkTypeface[%d] %s fontID %d\n",
    780                   i, gSystemFonts[i].fFileName, tf->uniqueID()));
    781 
    782         if (names != NULL) {
    783             // see if this is one of our fallback fonts
    784             if (names == gFBNames) {
    785                 // add to appropriate fallback chains
    786                 FallbackFontRec fallbackRec;
    787                 fallbackRec.fFontID = tf->uniqueID();
    788                 fallbackRec.fVariant = gSystemFonts[i].fVariant;
    789                 addFallbackFontLocked(fallbackRec, gSystemFonts[i].fLanguage);
    790             }
    791 
    792             firstInFamily = tf;
    793             FamilyRec* family = findFamilyLocked(tf);
    794 
    795             // record the default family if this is it
    796             if (names == gDefaultNames) {
    797                 gDefaultFamily = family;
    798             }
    799             // add the names to map to this family
    800             while (*names) {
    801                 addNameLocked(*names, family);
    802                 names += 1;
    803             }
    804         }
    805     }
    806     finaliseFallbackFontListsLocked();
    807 
    808     // do this after all fonts are loaded. This is our default font, and it
    809     // acts as a sentinel so we only execute loadSystemFontsLocked() once
    810     gDefaultNormal = findBestFaceLocked(gDefaultFamily, SkTypeface::kNormal);
    811 
    812     SkDEBUGCODE(dumpGlobalsLocked());
    813 }
    814 
    815 static int findFallbackFontIndex(SkFontID fontId, FallbackFontList* currentFallbackList) {
    816     for (int i = 0; i < currentFallbackList->fList.count(); i++) {
    817         if (currentFallbackList->fList[i].fFontID == fontId) {
    818             return i;
    819         }
    820     }
    821     return -1;
    822 }
    823 
    824 static void loadSystemFontsLocked() {
    825     if (!gDefaultNormal) {
    826         initSystemFontsLocked();
    827     }
    828 }
    829 
    830 ///////////////////////////////////////////////////////////////////////////////
    831 
    832 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
    833     // lookup and record if the font is custom (i.e. not a system font)
    834     bool isCustomFont = !((FamilyTypeface*)face)->isSysFont();
    835     stream->writeBool(isCustomFont);
    836 
    837     if (isCustomFont) {
    838         SkStream* fontStream = ((FamilyTypeface*)face)->openStream();
    839 
    840         // store the length of the custom font
    841         uint32_t len = fontStream->getLength();
    842         stream->write32(len);
    843 
    844         // store the entire font in the serialized stream
    845         void* fontData = malloc(len);
    846 
    847         fontStream->read(fontData, len);
    848         stream->write(fontData, len);
    849 
    850         fontStream->unref();
    851         free(fontData);
    852 //      SkDebugf("--- fonthost custom serialize %d %d\n", face->style(), len);
    853 
    854     } else {
    855         const char* name = ((FamilyTypeface*)face)->getUniqueString();
    856 
    857         stream->write8((uint8_t)face->style());
    858 
    859         if (NULL == name || 0 == *name) {
    860             stream->writePackedUInt(0);
    861 //          SkDebugf("--- fonthost serialize null\n");
    862         } else {
    863             uint32_t len = strlen(name);
    864             stream->writePackedUInt(len);
    865             stream->write(name, len);
    866 //          SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
    867         }
    868     }
    869 }
    870 
    871 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
    872     SkAutoMutexAcquire  ac(gFamilyHeadAndNameListMutex);
    873     return deserializeLocked(stream);
    874 }
    875 
    876 static SkTypeface* deserializeLocked(SkStream* stream) {
    877     loadSystemFontsLocked();
    878 
    879     // check if the font is a custom or system font
    880     bool isCustomFont = stream->readBool();
    881 
    882     if (isCustomFont) {
    883 
    884         // read the length of the custom font from the stream
    885         uint32_t len = stream->readU32();
    886 
    887         // generate a new stream to store the custom typeface
    888         SkMemoryStream* fontStream = new SkMemoryStream(len);
    889         stream->read((void*)fontStream->getMemoryBase(), len);
    890 
    891         SkTypeface* face = createTypefaceFromStreamLocked(fontStream);
    892 
    893         fontStream->unref();
    894 
    895 //      SkDebugf("--- fonthost custom deserialize %d %d\n", face->style(), len);
    896         return face;
    897 
    898     } else {
    899         int style = stream->readU8();
    900 
    901         int len = stream->readPackedUInt();
    902         if (len > 0) {
    903             SkString str;
    904             str.resize(len);
    905             stream->read(str.writable_str(), len);
    906 
    907             for (int i = 0; i < gSystemFonts.count(); i++) {
    908                 if (strcmp(gSystemFonts[i].fFileName, str.c_str()) == 0) {
    909                     // backup until we hit the fNames
    910                     for (int j = i; j >= 0; --j) {
    911                         if (gSystemFonts[j].fNames != NULL) {
    912                             return createTypefaceLocked(NULL,
    913                                     gSystemFonts[j].fNames[0], NULL, 0,
    914                                     (SkTypeface::Style)style);
    915                         }
    916                     }
    917                 }
    918             }
    919         }
    920     }
    921     return NULL;
    922 }
    923 
    924 ///////////////////////////////////////////////////////////////////////////////
    925 
    926 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
    927                                        const char familyName[],
    928                                        const void* data, size_t bytelength,
    929                                        SkTypeface::Style style) {
    930     SkAutoMutexAcquire  ac(gFamilyHeadAndNameListMutex);
    931     return createTypefaceLocked(familyFace, familyName, data, bytelength, style);
    932 }
    933 
    934 static SkTypeface* createTypefaceLocked(const SkTypeface* familyFace,
    935         const char familyName[], const void* data, size_t bytelength,
    936         SkTypeface::Style style) {
    937     loadSystemFontsLocked();
    938 
    939     // clip to legal style bits
    940     style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
    941 
    942     SkTypeface* tf = NULL;
    943 
    944     if (NULL != familyFace) {
    945         tf = findTypefaceLocked(familyFace, style);
    946     } else if (NULL != familyName) {
    947 //        SkDebugf("======= familyName <%s>\n", familyName);
    948         tf = findTypefaceLocked(familyName, style);
    949     }
    950 
    951     if (NULL == tf) {
    952         tf = findBestFaceLocked(gDefaultFamily, style);
    953     }
    954 
    955     // we ref(), since the semantic is to return a new instance
    956     tf->ref();
    957     return tf;
    958 }
    959 
    960 SkStream* SkFontHost::OpenStream(uint32_t fontID) {
    961     SkAutoMutexAcquire  ac(gFamilyHeadAndNameListMutex);
    962     return openStreamLocked(fontID);
    963 }
    964 
    965 static SkStream* openStreamLocked(uint32_t fontID) {
    966     FamilyTypeface* tf = (FamilyTypeface*)findFromUniqueIDLocked(fontID);
    967     SkStream* stream = tf ? tf->openStream() : NULL;
    968 
    969     if (stream && stream->getLength() == 0) {
    970         stream->unref();
    971         stream = NULL;
    972     }
    973     return stream;
    974 }
    975 
    976 size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
    977                                int32_t* index) {
    978     SkAutoMutexAcquire  ac(gFamilyHeadAndNameListMutex);
    979     return getFileNameLocked(fontID, path, length, index);
    980 }
    981 
    982 static size_t getFileNameLocked(SkFontID fontID, char path[], size_t length, int32_t* index) {
    983     FamilyTypeface* tf = (FamilyTypeface*)findFromUniqueIDLocked(fontID);
    984     const char* src = tf ? tf->getFilePath() : NULL;
    985 
    986     if (src) {
    987         size_t size = strlen(src);
    988         if (path) {
    989             memcpy(path, src, SkMin32(size, length));
    990         }
    991         if (index) {
    992             *index = 0; // we don't have collections (yet)
    993         }
    994         return size;
    995     } else {
    996         return 0;
    997     }
    998 }
    999 
   1000 SkFontID SkFontHost::NextLogicalFont(const SkScalerContext::Rec& rec) {
   1001     SkAutoMutexAcquire  ac(gFamilyHeadAndNameListMutex);
   1002     return nextLogicalFontLocked(rec);
   1003 }
   1004 
   1005 static SkFontID nextLogicalFontLocked(const SkScalerContext::Rec& rec) {
   1006     loadSystemFontsLocked();
   1007 
   1008     const SkTypeface* origTypeface = findFromUniqueIDLocked(rec.fOrigFontID);
   1009     const SkTypeface* currTypeface = findFromUniqueIDLocked(rec.fFontID);
   1010 
   1011     FallbackFontList* currentFallbackList =
   1012             getFallbackFontListLocked(rec.fLanguage);
   1013     SkASSERT(currentFallbackList);
   1014 
   1015     SkASSERT(origTypeface != 0);
   1016     SkASSERT(currTypeface != 0);
   1017 
   1018     // Our fallback list always stores the id of the plain in each fallback
   1019     // family, so we transform currFontID to its plain equivalent.
   1020     SkFontID plainFontID = findTypefaceLocked(currTypeface, SkTypeface::kNormal)->uniqueID();
   1021 
   1022     /*  First see if fontID is already one of our fallbacks. If so, return
   1023         its successor. If fontID is not in our list, then return the first one
   1024         in our list. Note: list is zero-terminated, and returning zero means
   1025         we have no more fonts to use for fallbacks.
   1026      */
   1027     int plainFallbackFontIndex = findFallbackFontIndex(plainFontID, currentFallbackList);
   1028     int nextFallbackFontIndex = plainFallbackFontIndex + 1;
   1029 
   1030     // If a rec object is set to prefer "kDefault_Variant" it means they have no preference
   1031     // In this case, we set the value to "kCompact_Variant"
   1032     SkPaint::FontVariant recPreference = rec.fFontVariant;
   1033     if (recPreference == SkPaint::kDefault_Variant) {
   1034         recPreference = SkPaint::kCompact_Variant;
   1035     }
   1036     SkFontID nextFontID = 0;
   1037     while (nextFallbackFontIndex < currentFallbackList->fList.count()) {
   1038         bool normalFont =
   1039                 (currentFallbackList->fList[nextFallbackFontIndex].fVariant == SkPaint::kDefault_Variant);
   1040         bool fontChosen = (currentFallbackList->fList[nextFallbackFontIndex].fVariant == recPreference);
   1041         if (normalFont || fontChosen) {
   1042             const SkTypeface* nextTypeface =
   1043                     findFromUniqueIDLocked(currentFallbackList->fList[nextFallbackFontIndex].fFontID);
   1044             nextFontID = findTypefaceLocked(nextTypeface, origTypeface->style())->uniqueID();
   1045             break;
   1046         }
   1047         nextFallbackFontIndex++;
   1048     }
   1049 
   1050     SkDEBUGF(("---- nextLogicalFont: currFontID=%d, origFontID=%d, plainFontID=%d, "
   1051             "plainFallbackFontIndex=%d, nextFallbackFontIndex=%d "
   1052             "=> nextFontID=%d", rec.fFontID, rec.fOrigFontID, plainFontID,
   1053             plainFallbackFontIndex, nextFallbackFontIndex, nextFontID));
   1054     return nextFontID;
   1055 }
   1056 
   1057 ///////////////////////////////////////////////////////////////////////////////
   1058 
   1059 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
   1060     SkAutoMutexAcquire  ac(gFamilyHeadAndNameListMutex);
   1061     return createTypefaceFromStreamLocked(stream);
   1062 }
   1063 
   1064 static SkTypeface* createTypefaceFromStreamLocked(SkStream* stream) {
   1065     if (NULL == stream || stream->getLength() <= 0) {
   1066         return NULL;
   1067     }
   1068 
   1069     // Make sure system fonts are loaded first to comply with the assumption
   1070     // that the font's uniqueID can be found using the findUniqueIDLocked method.
   1071     loadSystemFontsLocked();
   1072 
   1073     bool isFixedWidth;
   1074     SkTypeface::Style style;
   1075 
   1076     if (find_name_and_attributes(stream, NULL, &style, &isFixedWidth)) {
   1077         SkTypeface* typeface = SkNEW_ARGS(StreamTypeface, (style, false, stream, isFixedWidth));
   1078         addTypefaceLocked(typeface, NULL);
   1079         return typeface;
   1080     } else {
   1081         return NULL;
   1082     }
   1083 }
   1084 
   1085 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
   1086     SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
   1087     SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
   1088     // since we created the stream, we let go of our ref() here
   1089     stream->unref();
   1090     return face;
   1091 }
   1092 
   1093 ///////////////////////////////////////////////////////////////////////////////
   1094 // Function from SkTypeface_android.h
   1095 ///////////////////////////////////////////////////////////////////////////////
   1096 
   1097 static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style,
   1098         SkPaint::FontVariant fontVariant) {
   1099     SkTypeface* face = FindBestFace(gDefaultFamily, style);
   1100     if (!face) {
   1101         return 0;
   1102     }
   1103 
   1104     SkPaint paint;
   1105     paint.setTypeface(face);
   1106     paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
   1107     paint.setFontVariant(fontVariant);
   1108 
   1109     SkAutoGlyphCache autoCache(paint, NULL);
   1110     SkGlyphCache*    cache = autoCache.getCache();
   1111     SkFontID         fontID = 0;
   1112 
   1113     SkScalerContext* ctx = cache->getScalerContext();
   1114     if (ctx) {
   1115         return ctx->findTypefaceIdForChar(uni);
   1116     }
   1117     return 0;
   1118 }
   1119 
   1120 struct HB_UnicodeMapping {
   1121     HB_Script script;
   1122     const SkUnichar unicode;
   1123 };
   1124 
   1125 /*
   1126  * The following scripts are not complex fonts and we do not expect them to be parsed by this table
   1127  * HB_Script_Common,
   1128  * HB_Script_Greek,
   1129  * HB_Script_Cyrillic,
   1130  * HB_Script_Hangul
   1131  * HB_Script_Inherited
   1132  */
   1133 
   1134 static HB_UnicodeMapping HB_UnicodeMappingArray[] {
   1135     {HB_Script_Armenian,      0x0531},
   1136     {HB_Script_Hebrew,        0x0591},
   1137     {HB_Script_Arabic,        0x0600},
   1138     {HB_Script_Syriac,        0x0710},
   1139     {HB_Script_Thaana,        0x0780},
   1140     {HB_Script_Nko,           0x07C0},
   1141     {HB_Script_Devanagari,    0x0901},
   1142     {HB_Script_Bengali,       0x0981},
   1143     {HB_Script_Gurmukhi,      0x0A10},
   1144     {HB_Script_Gujarati,      0x0A90},
   1145     {HB_Script_Oriya,         0x0B10},
   1146     {HB_Script_Tamil,         0x0B82},
   1147     {HB_Script_Telugu,        0x0C10},
   1148     {HB_Script_Kannada,       0x0C90},
   1149     {HB_Script_Malayalam,     0x0D10},
   1150     {HB_Script_Sinhala,       0x0D90},
   1151     {HB_Script_Thai,          0x0E01},
   1152     {HB_Script_Lao,           0x0E81},
   1153     {HB_Script_Tibetan,       0x0F00},
   1154     {HB_Script_Myanmar,       0x1000},
   1155     {HB_Script_Georgian,      0x10A0},
   1156     // we don't currently support HB_Script_Ethiopic, it is a placeholder for an upstream merge
   1157     //{HB_Script_Ethiopic,    0x1200},
   1158     {HB_Script_Ogham,         0x1680},
   1159     {HB_Script_Runic,         0x16A0},
   1160     {HB_Script_Khmer,         0x1780},
   1161 };
   1162 
   1163 // returns 0 for "Not Found"
   1164 static SkUnichar getUnicodeFromHBScript(HB_Script script) {
   1165     SkUnichar unichar = 0;
   1166     int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping);
   1167     for (int i = 0; i < numSupportedFonts; i++) {
   1168         if (script == HB_UnicodeMappingArray[i].script) {
   1169             unichar = HB_UnicodeMappingArray[i].unicode;
   1170             break;
   1171         }
   1172     }
   1173     return unichar;
   1174 }
   1175 
   1176 struct TypefaceLookupStruct {
   1177     HB_Script            script;
   1178     SkTypeface::Style    style;
   1179     SkPaint::FontVariant fontVariant;
   1180     SkTypeface*          typeface;
   1181 };
   1182 
   1183 SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex);  // This is the mutex for gTypefaceTable
   1184 static SkTDArray<TypefaceLookupStruct> gTypefaceTable;  // This is protected by gTypefaceTableMutex
   1185 
   1186 static int typefaceLookupCompare(const TypefaceLookupStruct& first,
   1187         const TypefaceLookupStruct& second) {
   1188     if (first.script != second.script) {
   1189         return (first.script > second.script) ? 1 : -1;
   1190     }
   1191     if (first.style != second.style) {
   1192         return (first.style > second.style) ? 1 : -1;
   1193     }
   1194     if (first.fontVariant != second.fontVariant) {
   1195         return (first.fontVariant > second.fontVariant) ? 1 : -1;
   1196     }
   1197     return 0;
   1198 }
   1199 
   1200 SK_API SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style,
   1201         SkPaint::FontVariant fontVariant) {
   1202     SkTypeface* retTypeface = NULL;
   1203 
   1204     SkAutoMutexAcquire ac(gTypefaceTableMutex); // Note: NOT gFamilyHeadAndNameListMutex
   1205     TypefaceLookupStruct key;
   1206     key.script = script;
   1207     key.style = style;
   1208     key.fontVariant = fontVariant;
   1209     int index = SkTSearch<TypefaceLookupStruct>(
   1210             (const TypefaceLookupStruct*) gTypefaceTable.begin(),
   1211             gTypefaceTable.count(), key, sizeof(TypefaceLookupStruct),
   1212             &typefaceLookupCompare);
   1213     if (index >= 0) {
   1214         retTypeface = gTypefaceTable[index].typeface;
   1215     }
   1216     else {
   1217         SkUnichar unichar = getUnicodeFromHBScript(script);
   1218         if (!unichar) {
   1219             return NULL;
   1220         }
   1221         SkFontID newFontID = findFontIDForChar(unichar, style, fontVariant);
   1222         // retrieve the typeface that corresponds to this fontID
   1223         retTypeface = FindFromUniqueID(newFontID);
   1224         key.typeface = retTypeface;
   1225         index = ~index;
   1226         *gTypefaceTable.insert(index) = key;
   1227     }
   1228     // we ref(), the caller is expected to unref when they are done
   1229     SkSafeRef(retTypeface);
   1230     return retTypeface;
   1231 }
   1232