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 
     31 //#define SkDEBUGF(args       )       SkDebugf args
     32 
     33 #ifndef SK_FONT_FILE_PREFIX
     34     #define SK_FONT_FILE_PREFIX          "/fonts/"
     35 #endif
     36 
     37 // Defined in SkFontHost_FreeType.cpp
     38 bool find_name_and_attributes(SkStream* stream, SkString* name,
     39                               SkTypeface::Style* style, bool* isFixedWidth);
     40 
     41 static void getFullPathForSysFonts(SkString* full, const char name[]) {
     42     full->set(getenv("ANDROID_ROOT"));
     43     full->append(SK_FONT_FILE_PREFIX);
     44     full->append(name);
     45 }
     46 
     47 static bool getNameAndStyle(const char path[], SkString* name,
     48                                SkTypeface::Style* style,
     49                                bool* isFixedWidth, bool isExpected) {
     50     SkString        fullpath;
     51     getFullPathForSysFonts(&fullpath, path);
     52 
     53     SkMMAPStream stream(fullpath.c_str());
     54     if (stream.getLength() > 0) {
     55         return find_name_and_attributes(&stream, name, style, isFixedWidth);
     56     }
     57     else {
     58         SkFILEStream stream(fullpath.c_str());
     59         if (stream.getLength() > 0) {
     60             return find_name_and_attributes(&stream, name, style, isFixedWidth);
     61         }
     62     }
     63 
     64     if (isExpected) {
     65         SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
     66     }
     67     return false;
     68 }
     69 
     70 static SkTypeface* deserializeLocked(SkStream* stream);
     71 static SkTypeface* createTypefaceLocked(const SkTypeface* familyFace,
     72         const char familyName[], const void* data, size_t bytelength,
     73         SkTypeface::Style style);
     74 static SkStream* openStreamLocked(uint32_t fontID);
     75 static size_t getFileNameLocked(SkFontID fontID, char path[], size_t length, int32_t* index);
     76 static SkFontID nextLogicalFontLocked(SkFontID currFontID, SkFontID origFontID);
     77 static SkTypeface* createTypefaceFromStreamLocked(SkStream* stream);
     78 
     79 ///////////////////////////////////////////////////////////////////////////////
     80 
     81 struct FamilyRec;
     82 
     83 /*  This guy holds a mapping of a name -> family, used for looking up fonts.
     84     Since it is stored in a stretchy array that doesn't preserve object
     85     semantics, we don't use constructor/destructors, but just have explicit
     86     helpers to manage our internal bookkeeping.
     87 */
     88 struct NameFamilyPair {
     89     const char* fName;      // we own this
     90     FamilyRec*  fFamily;    // we don't own this, we just reference it
     91 
     92     void construct(const char name[], FamilyRec* family) {
     93         fName = strdup(name);
     94         fFamily = family;   // we don't own this, so just record the reference
     95     }
     96 
     97     void destruct() {
     98         free((char*)fName);
     99         // we don't own family, so just ignore our reference
    100     }
    101 };
    102 typedef SkTDArray<NameFamilyPair> NameFamilyPairList;
    103 
    104 // we use atomic_inc to grow this for each typeface we create
    105 static int32_t gUniqueFontID;
    106 
    107 // this is the mutex that protects all of the global data structures in this module
    108 // functions with the Locked() suffix must be called while holding this mutex
    109 SK_DECLARE_STATIC_MUTEX(gFamilyHeadAndNameListMutex);
    110 static FamilyRec* gFamilyHead = NULL;
    111 static SkTDArray<NameFamilyPair> gFallbackFilenameList;
    112 static NameFamilyPairList gNameList;
    113 
    114 struct FamilyRec {
    115     FamilyRec*  fNext;
    116     SkTypeface* fFaces[4];
    117 
    118     FamilyRec() : fNext(NULL) {
    119         memset(fFaces, 0, sizeof(fFaces));
    120     }
    121 };
    122 
    123 static SkTypeface* findBestFaceLocked(const FamilyRec* family,
    124                                   SkTypeface::Style style) {
    125     SkTypeface* const* faces = family->fFaces;
    126 
    127     if (faces[style] != NULL) { // exact match
    128         return faces[style];
    129     }
    130     // look for a matching bold
    131     style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
    132     if (faces[style] != NULL) {
    133         return faces[style];
    134     }
    135     // look for the plain
    136     if (faces[SkTypeface::kNormal] != NULL) {
    137         return faces[SkTypeface::kNormal];
    138     }
    139     // look for anything
    140     for (int i = 0; i < 4; i++) {
    141         if (faces[i] != NULL) {
    142             return faces[i];
    143         }
    144     }
    145     // should never get here, since the faces list should not be empty
    146     SkDEBUGFAIL("faces list is empty");
    147     return NULL;
    148 }
    149 
    150 static FamilyRec* findFamilyLocked(const SkTypeface* member) {
    151     FamilyRec* curr = gFamilyHead;
    152     while (curr != NULL) {
    153         for (int i = 0; i < 4; i++) {
    154             if (curr->fFaces[i] == member) {
    155                 return curr;
    156             }
    157         }
    158         curr = curr->fNext;
    159     }
    160     return NULL;
    161 }
    162 
    163 /*  Returns the matching typeface, or NULL. If a typeface is found, its refcnt
    164     is not modified.
    165  */
    166 static SkTypeface* findFromUniqueIDLocked(uint32_t uniqueID) {
    167     FamilyRec* curr = gFamilyHead;
    168     while (curr != NULL) {
    169         for (int i = 0; i < 4; i++) {
    170             SkTypeface* face = curr->fFaces[i];
    171             if (face != NULL && face->uniqueID() == uniqueID) {
    172                 return face;
    173             }
    174         }
    175         curr = curr->fNext;
    176     }
    177     return NULL;
    178 }
    179 
    180 /*  Remove reference to this face from its family. If the resulting family
    181     is empty (has no faces), return that family, otherwise return NULL
    182 */
    183 static FamilyRec* removeFromFamilyLocked(const SkTypeface* face) {
    184     FamilyRec* family = findFamilyLocked(face);
    185     if (family) {
    186         SkASSERT(family->fFaces[face->style()] == face);
    187         family->fFaces[face->style()] = NULL;
    188 
    189         for (int i = 0; i < 4; i++) {
    190             if (family->fFaces[i] != NULL) {    // family is non-empty
    191                 return NULL;
    192             }
    193         }
    194     } else {
    195 //        SkDebugf("removeFromFamilyLocked(%p) face not found", face);
    196     }
    197     return family;  // return the empty family
    198 }
    199 
    200 // maybe we should make FamilyRec be doubly-linked
    201 static void detachAndDeleteFamilyLocked(FamilyRec* family) {
    202     FamilyRec* curr = gFamilyHead;
    203     FamilyRec* prev = NULL;
    204 
    205     while (curr != NULL) {
    206         FamilyRec* next = curr->fNext;
    207         if (curr == family) {
    208             if (prev == NULL) {
    209                 gFamilyHead = next;
    210             } else {
    211                 prev->fNext = next;
    212             }
    213             SkDELETE(family);
    214             return;
    215         }
    216         prev = curr;
    217         curr = next;
    218     }
    219     SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
    220 }
    221 
    222 static SkTypeface* findTypefaceLocked(const char name[], SkTypeface::Style style) {
    223     int count = gNameList.count();
    224     NameFamilyPair* list = gNameList.begin();
    225     int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
    226     if (index >= 0) {
    227         return findBestFaceLocked(list[index].fFamily, style);
    228     }
    229     return NULL;
    230 }
    231 
    232 static SkTypeface* findTypefaceLocked(const SkTypeface* familyMember,
    233                                  SkTypeface::Style style) {
    234     const FamilyRec* family = findFamilyLocked(familyMember);
    235     return family ? findBestFaceLocked(family, style) : NULL;
    236 }
    237 
    238 static void addNameLocked(const char name[], FamilyRec* family) {
    239     SkAutoAsciiToLC tolc(name);
    240     name = tolc.lc();
    241 
    242     int count = gNameList.count();
    243     NameFamilyPair* list = gNameList.begin();
    244     int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
    245     if (index < 0) {
    246         list = gNameList.insert(~index);
    247         list->construct(name, family);
    248     }
    249 }
    250 
    251 static void removeFromNamesLocked(FamilyRec* emptyFamily) {
    252 #ifdef SK_DEBUG
    253     for (int i = 0; i < 4; i++) {
    254         SkASSERT(emptyFamily->fFaces[i] == NULL);
    255     }
    256 #endif
    257 
    258     // must go backwards when removing
    259     for (int i = gNameList.count() - 1; i >= 0; --i) {
    260         NameFamilyPair& pair = gNameList[i];
    261         if (pair.fFamily == emptyFamily) {
    262             pair.destruct();
    263             gNameList.remove(i);
    264         }
    265     }
    266 }
    267 
    268 static void addTypefaceLocked(SkTypeface* typeface, SkTypeface* familyMember) {
    269     FamilyRec* rec = NULL;
    270     if (familyMember) {
    271         rec = findFamilyLocked(familyMember);
    272         SkASSERT(rec);
    273     } else {
    274         rec = SkNEW(FamilyRec);
    275         rec->fNext = gFamilyHead;
    276         gFamilyHead = rec;
    277     }
    278     rec->fFaces[typeface->style()] = typeface;
    279 }
    280 
    281 static void removeTypeface(SkTypeface* typeface) {
    282     SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
    283 
    284     // remove us from our family. If the family is now empty, we return
    285     // that and then remove that family from the name list
    286     FamilyRec* family = removeFromFamilyLocked(typeface);
    287     if (NULL != family) {
    288         removeFromNamesLocked(family);
    289         detachAndDeleteFamilyLocked(family);
    290     }
    291 }
    292 
    293 ///////////////////////////////////////////////////////////////////////////////
    294 
    295 class FamilyTypeface : public SkTypeface {
    296 protected:
    297     FamilyTypeface(Style style, bool sysFont, bool isFixedWidth)
    298     : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) {
    299         fIsSysFont = sysFont;
    300     }
    301 
    302 public:
    303     virtual ~FamilyTypeface() {
    304         removeTypeface(this);
    305     }
    306 
    307     bool isSysFont() const { return fIsSysFont; }
    308 
    309     virtual SkStream* openStream() = 0;
    310     virtual const char* getUniqueString() const = 0;
    311     virtual const char* getFilePath() const = 0;
    312 
    313 private:
    314     bool    fIsSysFont;
    315 
    316     typedef SkTypeface INHERITED;
    317 };
    318 
    319 ///////////////////////////////////////////////////////////////////////////////
    320 
    321 class StreamTypeface : public FamilyTypeface {
    322 public:
    323     StreamTypeface(Style style, bool sysFont, SkStream* stream, bool isFixedWidth)
    324     : INHERITED(style, sysFont, isFixedWidth) {
    325         SkASSERT(stream);
    326         stream->ref();
    327         fStream = stream;
    328     }
    329 
    330     virtual ~StreamTypeface() {
    331         fStream->unref();
    332     }
    333 
    334     // overrides
    335     virtual SkStream* openStream() {
    336         // we just ref our existing stream, since the caller will call unref()
    337         // when they are through
    338         fStream->ref();
    339         // must rewind each time, since the caller assumes a "new" stream
    340         fStream->rewind();
    341         return fStream;
    342     }
    343     virtual const char* getUniqueString() const { return NULL; }
    344     virtual const char* getFilePath() const { return NULL; }
    345 
    346 private:
    347     SkStream* fStream;
    348 
    349     typedef FamilyTypeface INHERITED;
    350 };
    351 
    352 class FileTypeface : public FamilyTypeface {
    353 public:
    354     FileTypeface(Style style, bool sysFont, const char path[], bool isFixedWidth)
    355     : INHERITED(style, sysFont, isFixedWidth) {
    356         fPath.set(path);
    357     }
    358 
    359     // overrides
    360     virtual SkStream* openStream() {
    361         SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
    362 
    363         // check for failure
    364         if (stream->getLength() <= 0) {
    365             SkDELETE(stream);
    366             // maybe MMAP isn't supported. try FILE
    367             stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
    368             if (stream->getLength() <= 0) {
    369                 SkDELETE(stream);
    370                 stream = NULL;
    371             }
    372         }
    373         return stream;
    374     }
    375     virtual const char* getUniqueString() const {
    376         const char* str = strrchr(fPath.c_str(), '/');
    377         if (str) {
    378             str += 1;   // skip the '/'
    379         }
    380         return str;
    381     }
    382     virtual const char* getFilePath() const {
    383         return fPath.c_str();
    384     }
    385 
    386 private:
    387     SkString fPath;
    388 
    389     typedef FamilyTypeface INHERITED;
    390 };
    391 
    392 ///////////////////////////////////////////////////////////////////////////////
    393 ///////////////////////////////////////////////////////////////////////////////
    394 
    395 // used to record our notion of the pre-existing fonts
    396 struct FontInitRec {
    397     const char*         fFileName;
    398     const char* const*  fNames;     // null-terminated list
    399 };
    400 
    401 // deliberately empty, but we use the address to identify fallback fonts
    402 static const char* gFBNames[] = { NULL };
    403 
    404 
    405 /*  Fonts are grouped by family, with the first font in a family having the
    406     list of names (even if that list is empty), and the following members having
    407     null for the list. The names list must be NULL-terminated.
    408 */
    409 static SkTDArray<FontInitRec> gSystemFonts;
    410 static SkTDArray<SkFontID> gFallbackFonts;
    411 
    412 // these globals are assigned (once) by loadSystemFontsLocked()
    413 static FamilyRec* gDefaultFamily = NULL;
    414 static SkTypeface* gDefaultNormal = NULL;
    415 static char** gDefaultNames = NULL;
    416 
    417 static void dumpGlobalsLocked() {
    418     SkDebugf("gDefaultNormal=%p id=%u refCnt=%d", gDefaultNormal,
    419              gDefaultNormal ? gDefaultNormal->uniqueID() : 0,
    420              gDefaultNormal ? gDefaultNormal->getRefCnt() : 0);
    421 
    422     if (gDefaultFamily) {
    423         SkDebugf("gDefaultFamily=%p fFaces={%u,%u,%u,%u} refCnt={%d,%d,%d,%d}",
    424                  gDefaultFamily,
    425                  gDefaultFamily->fFaces[0] ? gDefaultFamily->fFaces[0]->uniqueID() : 0,
    426                  gDefaultFamily->fFaces[1] ? gDefaultFamily->fFaces[1]->uniqueID() : 0,
    427                  gDefaultFamily->fFaces[2] ? gDefaultFamily->fFaces[2]->uniqueID() : 0,
    428                  gDefaultFamily->fFaces[3] ? gDefaultFamily->fFaces[3]->uniqueID() : 0,
    429                  gDefaultFamily->fFaces[0] ? gDefaultFamily->fFaces[0]->getRefCnt() : 0,
    430                  gDefaultFamily->fFaces[1] ? gDefaultFamily->fFaces[1]->getRefCnt() : 0,
    431                  gDefaultFamily->fFaces[2] ? gDefaultFamily->fFaces[2]->getRefCnt() : 0,
    432                  gDefaultFamily->fFaces[3] ? gDefaultFamily->fFaces[3]->getRefCnt() : 0);
    433     } else {
    434         SkDebugf("gDefaultFamily=%p", gDefaultFamily);
    435     }
    436 
    437     SkDebugf("gSystemFonts.count()=%d gFallbackFonts.count()=%d",
    438             gSystemFonts.count(), gFallbackFonts.count());
    439 
    440     for (int i = 0; i < gSystemFonts.count(); ++i) {
    441         SkDebugf("gSystemFonts[%d] fileName=%s", i, gSystemFonts[i].fFileName);
    442         size_t namesIndex = 0;
    443         if (gSystemFonts[i].fNames)
    444             for (const char* fontName = gSystemFonts[i].fNames[namesIndex];
    445                     fontName != 0;
    446                     fontName = gSystemFonts[i].fNames[++namesIndex]) {
    447                 SkDebugf("       name[%u]=%s", namesIndex, fontName);
    448             }
    449     }
    450 
    451     if (gFamilyHead) {
    452         FamilyRec* rec = gFamilyHead;
    453         int i=0;
    454         while (rec) {
    455             SkDebugf("gFamilyHead[%d]=%p fFaces={%u,%u,%u,%u} refCnt={%d,%d,%d,%d}",
    456                      i++, rec,
    457                      rec->fFaces[0] ? rec->fFaces[0]->uniqueID() : 0,
    458                      rec->fFaces[1] ? rec->fFaces[1]->uniqueID() : 0,
    459                      rec->fFaces[2] ? rec->fFaces[2]->uniqueID() : 0,
    460                      rec->fFaces[3] ? rec->fFaces[3]->uniqueID() : 0,
    461                      rec->fFaces[0] ? rec->fFaces[0]->getRefCnt() : 0,
    462                      rec->fFaces[1] ? rec->fFaces[1]->getRefCnt() : 0,
    463                      rec->fFaces[2] ? rec->fFaces[2]->getRefCnt() : 0,
    464                      rec->fFaces[3] ? rec->fFaces[3]->getRefCnt() : 0);
    465             rec = rec->fNext;
    466         }
    467     } else {
    468         SkDebugf("gFamilyHead=%p", gFamilyHead);
    469     }
    470 
    471 }
    472 
    473 
    474 static bool haveSystemFont(const char* filename) {
    475     for (int i = 0; i < gSystemFonts.count(); i++) {
    476         if (strcmp(gSystemFonts[i].fFileName, filename) == 0) {
    477             return true;
    478         }
    479     }
    480     return false;
    481 }
    482 
    483 /*  Load info from a configuration file that populates the system/fallback font structures
    484 */
    485 static void loadFontInfoLocked() {
    486     SkTDArray<FontFamily*> fontFamilies;
    487     getFontFamilies(fontFamilies);
    488 
    489     gSystemFonts.reset();
    490 
    491     for (int i = 0; i < fontFamilies.count(); ++i) {
    492         FontFamily *family = fontFamilies[i];
    493         for (int j = 0; j < family->fFileNames.count(); ++j) {
    494             const char* filename = family->fFileNames[j];
    495             if (haveSystemFont(filename)) {
    496                 SkDebugf("---- system font and fallback font files specify a duplicate "
    497                         "font %s, skipping the second occurrence", filename);
    498                 continue;
    499             }
    500 
    501             FontInitRec fontInfoRecord;
    502             fontInfoRecord.fFileName = filename;
    503             if (j == 0) {
    504                 if (family->fNames.count() == 0) {
    505                     // Fallback font
    506                     fontInfoRecord.fNames = (char **)gFBNames;
    507                 } else {
    508                     SkTDArray<const char*> names = family->fNames;
    509                     const char **nameList = (const char**)
    510                             malloc((names.count() + 1) * sizeof(char*));
    511                     if (nameList == NULL) {
    512                         // shouldn't get here
    513                         break;
    514                     }
    515                     if (gDefaultNames == NULL) {
    516                         gDefaultNames = (char**) nameList;
    517                     }
    518                     for (int i = 0; i < names.count(); ++i) {
    519                         nameList[i] = names[i];
    520                     }
    521                     nameList[names.count()] = NULL;
    522                     fontInfoRecord.fNames = nameList;
    523                 }
    524             } else {
    525                 fontInfoRecord.fNames = NULL;
    526             }
    527             *gSystemFonts.append() = fontInfoRecord;
    528         }
    529     }
    530     fontFamilies.deleteAll();
    531 
    532     SkDEBUGF(("---- We have %d system fonts", gSystemFonts.count()));
    533     for (int i = 0; i < gSystemFonts.count(); ++i) {
    534         SkDEBUGF(("---- gSystemFonts[%d] fileName=%s", i, gSystemFonts[i].fFileName));
    535     }
    536 }
    537 
    538 
    539 /*
    540  *  Called once (ensured by the sentinel check at the beginning of our body).
    541  *  Initializes all the globals, and register the system fonts.
    542  */
    543 static void initSystemFontsLocked() {
    544     // check if we've already been called
    545     if (gDefaultNormal) {
    546         return;
    547     }
    548 
    549     SkASSERT(gUniqueFontID == 0);
    550 
    551     loadFontInfoLocked();
    552 
    553     gFallbackFonts.reset();
    554 
    555     SkTypeface* firstInFamily = NULL;
    556     for (int i = 0; i < gSystemFonts.count(); i++) {
    557         // if we're the first in a new family, clear firstInFamily
    558         const char* const* names = gSystemFonts[i].fNames;
    559         if (names != NULL) {
    560             firstInFamily = NULL;
    561         }
    562 
    563         bool isFixedWidth;
    564         SkString name;
    565         SkTypeface::Style style;
    566 
    567         // we expect all the fonts, except the "fallback" fonts
    568         bool isExpected = (names != gFBNames);
    569         if (!getNameAndStyle(gSystemFonts[i].fFileName, &name, &style,
    570                 &isFixedWidth, isExpected)) {
    571             // We need to increase gUniqueFontID here so that the unique id of
    572             // each font matches its index in gSystemFonts array, as expected
    573             // by findUniqueIDLocked.
    574             sk_atomic_inc(&gUniqueFontID);
    575             continue;
    576         }
    577 
    578         SkString fullpath;
    579         getFullPathForSysFonts(&fullpath, gSystemFonts[i].fFileName);
    580 
    581         SkTypeface* tf = SkNEW_ARGS(FileTypeface, (style,
    582                 true,  // system-font (cannot delete)
    583                 fullpath.c_str(), // filename
    584                 isFixedWidth));
    585         addTypefaceLocked(tf, firstInFamily);
    586 
    587         SkDEBUGF(("---- SkTypeface[%d] %s fontID %d\n",
    588                   i, gSystemFonts[i].fFileName, tf->uniqueID()));
    589 
    590         if (names != NULL) {
    591             // see if this is one of our fallback fonts
    592             if (names == gFBNames) {
    593                 SkDEBUGF(("---- adding %s as fallback[%d] fontID %d\n",
    594                         gSystemFonts[i].fFileName, gFallbackFonts.count(), tf->uniqueID()));
    595                 *gFallbackFonts.append() = tf->uniqueID();
    596             }
    597 
    598             firstInFamily = tf;
    599             FamilyRec* family = findFamilyLocked(tf);
    600 
    601             // record the default family if this is it
    602             if (names == gDefaultNames) {
    603                 gDefaultFamily = family;
    604             }
    605             // add the names to map to this family
    606             while (*names) {
    607                 addNameLocked(*names, family);
    608                 names += 1;
    609             }
    610         }
    611     }
    612 
    613     // do this after all fonts are loaded. This is our default font, and it
    614     // acts as a sentinel so we only execute loadSystemFontsLocked() once
    615     gDefaultNormal = findBestFaceLocked(gDefaultFamily, SkTypeface::kNormal);
    616 
    617     SkDEBUGCODE(dumpGlobalsLocked());
    618 }
    619 
    620 static SkFontID findUniqueIDLocked(const char* filename) {
    621     // uniqueID is the index, offset by one, of the associated element in
    622     // gSystemFonts[] (assumes system fonts are loaded before external fonts)
    623     // return 0 if not found
    624     for (int i = 0; i < gSystemFonts.count(); i++) {
    625         if (strcmp(gSystemFonts[i].fFileName, filename) == 0) {
    626             return i + 1; // assume unique id of i'th system font is i + 1
    627         }
    628     }
    629     return 0;
    630 }
    631 
    632 static int findFallbackFontIndex(SkFontID fontId) {
    633     for (int i = 0; i < gFallbackFonts.count(); i++) {
    634         if (gFallbackFonts[i] == fontId) {
    635             return i;
    636         }
    637     }
    638     return -1;
    639 }
    640 
    641 static void reloadFallbackFontsLocked() {
    642     SkGraphics::PurgeFontCache();
    643 
    644     SkTDArray<FontFamily*> fallbackFamilies;
    645     getFallbackFontFamilies(fallbackFamilies);
    646 
    647     gFallbackFonts.reset();
    648 
    649     for (int i = 0; i < fallbackFamilies.count(); ++i) {
    650         FontFamily *family = fallbackFamilies[i];
    651 
    652         for (int j = 0; j < family->fFileNames.count(); ++j) {
    653             const char* filename = family->fFileNames[j];
    654             if (filename) {
    655                 if (!haveSystemFont(filename)) {
    656                     SkDebugf("---- skipping fallback font %s because it was not "
    657                             "previously loaded as a system font", filename);
    658                     continue;
    659                 }
    660 
    661                 // ensure the fallback font exists before adding it to the list
    662                 bool isFixedWidth;
    663                 SkString name;
    664                 SkTypeface::Style style;
    665                 if (!getNameAndStyle(filename, &name, &style,
    666                                         &isFixedWidth, false)) {
    667                     continue;
    668                 }
    669 
    670                 SkFontID uniqueID = findUniqueIDLocked(filename);
    671                 SkASSERT(uniqueID != 0);
    672                 if (findFallbackFontIndex(uniqueID) >= 0) {
    673                     SkDebugf("---- system font and fallback font files specify a duplicate "
    674                             "font %s, skipping the second occurrence", filename);
    675                     continue;
    676                 }
    677 
    678                 SkDEBUGF(("---- reload %s as fallback[%d] fontID %d\n",
    679                           filename, gFallbackFonts.count(), uniqueID));
    680 
    681                 *gFallbackFonts.append() = uniqueID;
    682                 break;  // The fallback set contains only the first font of each family
    683             }
    684         }
    685     }
    686 
    687     fallbackFamilies.deleteAll();
    688 }
    689 
    690 static void loadSystemFontsLocked() {
    691 #if !defined(SK_BUILD_FOR_ANDROID_NDK)
    692     static char prevLanguage[3];
    693     static char prevRegion[3];
    694     char language[3] = "";
    695     char region[3] = "";
    696 
    697     getLocale(language, region);
    698 
    699     if (!gDefaultNormal) {
    700         strncpy(prevLanguage, language, 2);
    701         strncpy(prevRegion, region, 2);
    702         initSystemFontsLocked();
    703     } else if (strncmp(language, prevLanguage, 2) || strncmp(region, prevRegion, 2)) {
    704         strncpy(prevLanguage, language, 2);
    705         strncpy(prevRegion, region, 2);
    706         reloadFallbackFontsLocked();
    707     }
    708 #else
    709     if (!gDefaultNormal) {
    710         initSystemFontsLocked();
    711         reloadFallbackFontsLocked();
    712     }
    713 #endif
    714 }
    715 
    716 ///////////////////////////////////////////////////////////////////////////////
    717 
    718 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
    719     // lookup and record if the font is custom (i.e. not a system font)
    720     bool isCustomFont = !((FamilyTypeface*)face)->isSysFont();
    721     stream->writeBool(isCustomFont);
    722 
    723     if (isCustomFont) {
    724         SkStream* fontStream = ((FamilyTypeface*)face)->openStream();
    725 
    726         // store the length of the custom font
    727         uint32_t len = fontStream->getLength();
    728         stream->write32(len);
    729 
    730         // store the entire font in the serialized stream
    731         void* fontData = malloc(len);
    732 
    733         fontStream->read(fontData, len);
    734         stream->write(fontData, len);
    735 
    736         fontStream->unref();
    737         free(fontData);
    738 //      SkDebugf("--- fonthost custom serialize %d %d\n", face->style(), len);
    739 
    740     } else {
    741         const char* name = ((FamilyTypeface*)face)->getUniqueString();
    742 
    743         stream->write8((uint8_t)face->style());
    744 
    745         if (NULL == name || 0 == *name) {
    746             stream->writePackedUInt(0);
    747 //          SkDebugf("--- fonthost serialize null\n");
    748         } else {
    749             uint32_t len = strlen(name);
    750             stream->writePackedUInt(len);
    751             stream->write(name, len);
    752 //          SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
    753         }
    754     }
    755 }
    756 
    757 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
    758     SkAutoMutexAcquire  ac(gFamilyHeadAndNameListMutex);
    759     return deserializeLocked(stream);
    760 }
    761 
    762 static SkTypeface* deserializeLocked(SkStream* stream) {
    763     loadSystemFontsLocked();
    764 
    765     // check if the font is a custom or system font
    766     bool isCustomFont = stream->readBool();
    767 
    768     if (isCustomFont) {
    769 
    770         // read the length of the custom font from the stream
    771         uint32_t len = stream->readU32();
    772 
    773         // generate a new stream to store the custom typeface
    774         SkMemoryStream* fontStream = new SkMemoryStream(len);
    775         stream->read((void*)fontStream->getMemoryBase(), len);
    776 
    777         SkTypeface* face = createTypefaceFromStreamLocked(fontStream);
    778 
    779         fontStream->unref();
    780 
    781 //      SkDebugf("--- fonthost custom deserialize %d %d\n", face->style(), len);
    782         return face;
    783 
    784     } else {
    785         int style = stream->readU8();
    786 
    787         int len = stream->readPackedUInt();
    788         if (len > 0) {
    789             SkString str;
    790             str.resize(len);
    791             stream->read(str.writable_str(), len);
    792 
    793             for (int i = 0; i < gSystemFonts.count(); i++) {
    794                 if (strcmp(gSystemFonts[i].fFileName, str.c_str()) == 0) {
    795                     // backup until we hit the fNames
    796                     for (int j = i; j >= 0; --j) {
    797                         if (gSystemFonts[j].fNames != NULL) {
    798                             return createTypefaceLocked(NULL,
    799                                     gSystemFonts[j].fNames[0], NULL, 0,
    800                                     (SkTypeface::Style)style);
    801                         }
    802                     }
    803                 }
    804             }
    805         }
    806     }
    807     return NULL;
    808 }
    809 
    810 ///////////////////////////////////////////////////////////////////////////////
    811 
    812 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
    813                                        const char familyName[],
    814                                        const void* data, size_t bytelength,
    815                                        SkTypeface::Style style) {
    816     SkAutoMutexAcquire  ac(gFamilyHeadAndNameListMutex);
    817     return createTypefaceLocked(familyFace, familyName, data, bytelength, style);
    818 }
    819 
    820 static SkTypeface* createTypefaceLocked(const SkTypeface* familyFace,
    821         const char familyName[], const void* data, size_t bytelength,
    822         SkTypeface::Style style) {
    823     loadSystemFontsLocked();
    824 
    825     // clip to legal style bits
    826     style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
    827 
    828     SkTypeface* tf = NULL;
    829 
    830     if (NULL != familyFace) {
    831         tf = findTypefaceLocked(familyFace, style);
    832     } else if (NULL != familyName) {
    833 //        SkDebugf("======= familyName <%s>\n", familyName);
    834         tf = findTypefaceLocked(familyName, style);
    835     }
    836 
    837     if (NULL == tf) {
    838         tf = findBestFaceLocked(gDefaultFamily, style);
    839     }
    840 
    841     // we ref(), since the semantic is to return a new instance
    842     tf->ref();
    843     return tf;
    844 }
    845 
    846 SkStream* SkFontHost::OpenStream(uint32_t fontID) {
    847     SkAutoMutexAcquire  ac(gFamilyHeadAndNameListMutex);
    848     return openStreamLocked(fontID);
    849 }
    850 
    851 static SkStream* openStreamLocked(uint32_t fontID) {
    852     FamilyTypeface* tf = (FamilyTypeface*)findFromUniqueIDLocked(fontID);
    853     SkStream* stream = tf ? tf->openStream() : NULL;
    854 
    855     if (stream && stream->getLength() == 0) {
    856         stream->unref();
    857         stream = NULL;
    858     }
    859     return stream;
    860 }
    861 
    862 size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
    863                                int32_t* index) {
    864     SkAutoMutexAcquire  ac(gFamilyHeadAndNameListMutex);
    865     return getFileNameLocked(fontID, path, length, index);
    866 }
    867 
    868 static size_t getFileNameLocked(SkFontID fontID, char path[], size_t length, int32_t* index) {
    869     FamilyTypeface* tf = (FamilyTypeface*)findFromUniqueIDLocked(fontID);
    870     const char* src = tf ? tf->getFilePath() : NULL;
    871 
    872     if (src) {
    873         size_t size = strlen(src);
    874         if (path) {
    875             memcpy(path, src, SkMin32(size, length));
    876         }
    877         if (index) {
    878             *index = 0; // we don't have collections (yet)
    879         }
    880         return size;
    881     } else {
    882         return 0;
    883     }
    884 }
    885 
    886 SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
    887     SkAutoMutexAcquire  ac(gFamilyHeadAndNameListMutex);
    888     return nextLogicalFontLocked(currFontID, origFontID);
    889 }
    890 
    891 static SkFontID nextLogicalFontLocked(SkFontID currFontID, SkFontID origFontID) {
    892     loadSystemFontsLocked();
    893 
    894     const SkTypeface* origTypeface = findFromUniqueIDLocked(origFontID);
    895     const SkTypeface* currTypeface = findFromUniqueIDLocked(currFontID);
    896 
    897     SkASSERT(origTypeface != 0);
    898     SkASSERT(currTypeface != 0);
    899 
    900     // Our fallback list always stores the id of the plain in each fallback
    901     // family, so we transform currFontID to its plain equivalent.
    902     SkFontID plainFontID = findTypefaceLocked(currTypeface, SkTypeface::kNormal)->uniqueID();
    903 
    904     /*  First see if fontID is already one of our fallbacks. If so, return
    905         its successor. If fontID is not in our list, then return the first one
    906         in our list. Note: list is zero-terminated, and returning zero means
    907         we have no more fonts to use for fallbacks.
    908      */
    909     int plainFallbackFontIndex = findFallbackFontIndex(plainFontID);
    910     int nextFallbackFontIndex = plainFallbackFontIndex + 1;
    911     SkFontID nextFontID;
    912     if (nextFallbackFontIndex == gFallbackFonts.count()) {
    913         nextFontID = 0; // no more fallbacks
    914     } else {
    915         const SkTypeface* nextTypeface = findFromUniqueIDLocked(gFallbackFonts[nextFallbackFontIndex]);
    916         nextFontID = findTypefaceLocked(nextTypeface, origTypeface->style())->uniqueID();
    917     }
    918 
    919     SkDEBUGF(("---- nextLogicalFont: currFontID=%d, origFontID=%d, plainFontID=%d, "
    920             "plainFallbackFontIndex=%d, nextFallbackFontIndex=%d "
    921             "=> nextFontID=%d", currFontID, origFontID, plainFontID,
    922             plainFallbackFontIndex, nextFallbackFontIndex, nextFontID));
    923     return nextFontID;
    924 }
    925 
    926 ///////////////////////////////////////////////////////////////////////////////
    927 
    928 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
    929     SkAutoMutexAcquire  ac(gFamilyHeadAndNameListMutex);
    930     return createTypefaceFromStreamLocked(stream);
    931 }
    932 
    933 static SkTypeface* createTypefaceFromStreamLocked(SkStream* stream) {
    934     if (NULL == stream || stream->getLength() <= 0) {
    935         return NULL;
    936     }
    937 
    938     // Make sure system fonts are loaded first to comply with the assumption
    939     // that the font's uniqueID can be found using the findUniqueIDLocked method.
    940     loadSystemFontsLocked();
    941 
    942     bool isFixedWidth;
    943     SkTypeface::Style style;
    944 
    945     if (find_name_and_attributes(stream, NULL, &style, &isFixedWidth)) {
    946         SkTypeface* typeface = SkNEW_ARGS(StreamTypeface, (style, false, stream, isFixedWidth));
    947         addTypefaceLocked(typeface, NULL);
    948         return typeface;
    949     } else {
    950         return NULL;
    951     }
    952 }
    953 
    954 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
    955     SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
    956     SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
    957     // since we created the stream, we let go of our ref() here
    958     stream->unref();
    959     return face;
    960 }
    961