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 "SkDescriptor.h"
     20 #include "SkMMapStream.h"
     21 #include "SkPaint.h"
     22 #include "SkString.h"
     23 #include "SkStream.h"
     24 #include "SkThread.h"
     25 #include "SkTSearch.h"
     26 #include <stdio.h>
     27 
     28 #define FONT_CACHE_MEMORY_BUDGET    (768 * 1024)
     29 
     30 #ifndef SK_FONT_FILE_PREFIX
     31     #define SK_FONT_FILE_PREFIX          "/fonts/"
     32 #endif
     33 
     34 bool find_name_and_style(SkStream* stream, SkString* name, SkTypeface::Style* style);
     35 
     36 static void GetFullPathForSysFonts(SkString* full, const char name[]) {
     37     full->set(getenv("ANDROID_ROOT"));
     38     full->append(SK_FONT_FILE_PREFIX);
     39     full->append(name);
     40 }
     41 
     42 ///////////////////////////////////////////////////////////////////////////////
     43 
     44 struct FamilyRec;
     45 
     46 /*  This guy holds a mapping of a name -> family, used for looking up fonts.
     47     Since it is stored in a stretchy array that doesn't preserve object
     48     semantics, we don't use constructor/destructors, but just have explicit
     49     helpers to manage our internal bookkeeping.
     50 */
     51 struct NameFamilyPair {
     52     const char* fName;      // we own this
     53     FamilyRec*  fFamily;    // we don't own this, we just reference it
     54 
     55     void construct(const char name[], FamilyRec* family) {
     56         fName = strdup(name);
     57         fFamily = family;   // we don't own this, so just record the referene
     58     }
     59 
     60     void destruct() {
     61         free((char*)fName);
     62         // we don't own family, so just ignore our reference
     63     }
     64 };
     65 
     66 // we use atomic_inc to grow this for each typeface we create
     67 static int32_t gUniqueFontID;
     68 
     69 // this is the mutex that protects these globals
     70 static SkMutex gFamilyMutex;
     71 static FamilyRec* gFamilyHead;
     72 static SkTDArray<NameFamilyPair> gNameList;
     73 
     74 struct FamilyRec {
     75     FamilyRec*  fNext;
     76     SkTypeface* fFaces[4];
     77 
     78     FamilyRec()
     79     {
     80         fNext = gFamilyHead;
     81         memset(fFaces, 0, sizeof(fFaces));
     82         gFamilyHead = this;
     83     }
     84 };
     85 
     86 static SkTypeface* find_best_face(const FamilyRec* family,
     87                                   SkTypeface::Style style) {
     88     SkTypeface* const* faces = family->fFaces;
     89 
     90     if (faces[style] != NULL) { // exact match
     91         return faces[style];
     92     }
     93     // look for a matching bold
     94     style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
     95     if (faces[style] != NULL) {
     96         return faces[style];
     97     }
     98     // look for the plain
     99     if (faces[SkTypeface::kNormal] != NULL) {
    100         return faces[SkTypeface::kNormal];
    101     }
    102     // look for anything
    103     for (int i = 0; i < 4; i++) {
    104         if (faces[i] != NULL) {
    105             return faces[i];
    106         }
    107     }
    108     // should never get here, since the faces list should not be empty
    109     SkASSERT(!"faces list is empty");
    110     return NULL;
    111 }
    112 
    113 static FamilyRec* find_family(const SkTypeface* member) {
    114     FamilyRec* curr = gFamilyHead;
    115     while (curr != NULL) {
    116         for (int i = 0; i < 4; i++) {
    117             if (curr->fFaces[i] == member) {
    118                 return curr;
    119             }
    120         }
    121         curr = curr->fNext;
    122     }
    123     return NULL;
    124 }
    125 
    126 /*  Returns the matching typeface, or NULL. If a typeface is found, its refcnt
    127     is not modified.
    128  */
    129 static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
    130     FamilyRec* curr = gFamilyHead;
    131     while (curr != NULL) {
    132         for (int i = 0; i < 4; i++) {
    133             SkTypeface* face = curr->fFaces[i];
    134             if (face != NULL && face->uniqueID() == uniqueID) {
    135                 return face;
    136             }
    137         }
    138         curr = curr->fNext;
    139     }
    140     return NULL;
    141 }
    142 
    143 /*  Remove reference to this face from its family. If the resulting family
    144     is empty (has no faces), return that family, otherwise return NULL
    145 */
    146 static FamilyRec* remove_from_family(const SkTypeface* face) {
    147     FamilyRec* family = find_family(face);
    148     SkASSERT(family->fFaces[face->style()] == face);
    149     family->fFaces[face->style()] = NULL;
    150 
    151     for (int i = 0; i < 4; i++) {
    152         if (family->fFaces[i] != NULL) {    // family is non-empty
    153             return NULL;
    154         }
    155     }
    156     return family;  // return the empty family
    157 }
    158 
    159 // maybe we should make FamilyRec be doubly-linked
    160 static void detach_and_delete_family(FamilyRec* family) {
    161     FamilyRec* curr = gFamilyHead;
    162     FamilyRec* prev = NULL;
    163 
    164     while (curr != NULL) {
    165         FamilyRec* next = curr->fNext;
    166         if (curr == family) {
    167             if (prev == NULL) {
    168                 gFamilyHead = next;
    169             } else {
    170                 prev->fNext = next;
    171             }
    172             SkDELETE(family);
    173             return;
    174         }
    175         prev = curr;
    176         curr = next;
    177     }
    178     SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
    179 }
    180 
    181 static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
    182     NameFamilyPair* list = gNameList.begin();
    183     int             count = gNameList.count();
    184 
    185     int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
    186 
    187     if (index >= 0) {
    188         return find_best_face(list[index].fFamily, style);
    189     }
    190     return NULL;
    191 }
    192 
    193 static SkTypeface* find_typeface(const SkTypeface* familyMember,
    194                                  SkTypeface::Style style) {
    195     const FamilyRec* family = find_family(familyMember);
    196     return family ? find_best_face(family, style) : NULL;
    197 }
    198 
    199 static void add_name(const char name[], FamilyRec* family) {
    200     SkAutoAsciiToLC tolc(name);
    201     name = tolc.lc();
    202 
    203     NameFamilyPair* list = gNameList.begin();
    204     int             count = gNameList.count();
    205 
    206     int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
    207 
    208     if (index < 0) {
    209         list = gNameList.insert(~index);
    210         list->construct(name, family);
    211     }
    212 }
    213 
    214 static void remove_from_names(FamilyRec* emptyFamily)
    215 {
    216 #ifdef SK_DEBUG
    217     for (int i = 0; i < 4; i++) {
    218         SkASSERT(emptyFamily->fFaces[i] == NULL);
    219     }
    220 #endif
    221 
    222     SkTDArray<NameFamilyPair>& list = gNameList;
    223 
    224     // must go backwards when removing
    225     for (int i = list.count() - 1; i >= 0; --i) {
    226         NameFamilyPair* pair = &list[i];
    227         if (pair->fFamily == emptyFamily) {
    228             pair->destruct();
    229             list.remove(i);
    230         }
    231     }
    232 }
    233 
    234 ///////////////////////////////////////////////////////////////////////////////
    235 
    236 class FamilyTypeface : public SkTypeface {
    237 public:
    238     FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember)
    239     : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1) {
    240         fIsSysFont = sysFont;
    241 
    242         SkAutoMutexAcquire  ac(gFamilyMutex);
    243 
    244         FamilyRec* rec = NULL;
    245         if (familyMember) {
    246             rec = find_family(familyMember);
    247             SkASSERT(rec);
    248         } else {
    249             rec = SkNEW(FamilyRec);
    250         }
    251         rec->fFaces[style] = this;
    252     }
    253 
    254     virtual ~FamilyTypeface() {
    255         SkAutoMutexAcquire  ac(gFamilyMutex);
    256 
    257         // remove us from our family. If the family is now empty, we return
    258         // that and then remove that family from the name list
    259         FamilyRec* family = remove_from_family(this);
    260         if (NULL != family) {
    261             remove_from_names(family);
    262             detach_and_delete_family(family);
    263         }
    264     }
    265 
    266     bool isSysFont() const { return fIsSysFont; }
    267 
    268     virtual SkStream* openStream() = 0;
    269     virtual const char* getUniqueString() const = 0;
    270     virtual const char* getFilePath() const = 0;
    271 
    272 private:
    273     bool    fIsSysFont;
    274 
    275     typedef SkTypeface INHERITED;
    276 };
    277 
    278 ///////////////////////////////////////////////////////////////////////////////
    279 
    280 class StreamTypeface : public FamilyTypeface {
    281 public:
    282     StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
    283                    SkStream* stream)
    284     : INHERITED(style, sysFont, familyMember) {
    285         SkASSERT(stream);
    286         stream->ref();
    287         fStream = stream;
    288     }
    289     virtual ~StreamTypeface() {
    290         fStream->unref();
    291     }
    292 
    293     // overrides
    294     virtual SkStream* openStream() {
    295         // we just ref our existing stream, since the caller will call unref()
    296         // when they are through
    297         fStream->ref();
    298         return fStream;
    299     }
    300     virtual const char* getUniqueString() const { return NULL; }
    301     virtual const char* getFilePath() const { return NULL; }
    302 
    303 private:
    304     SkStream* fStream;
    305 
    306     typedef FamilyTypeface INHERITED;
    307 };
    308 
    309 class FileTypeface : public FamilyTypeface {
    310 public:
    311     FileTypeface(Style style, bool sysFont, SkTypeface* familyMember,
    312                  const char path[])
    313     : INHERITED(style, sysFont, familyMember) {
    314         SkString fullpath;
    315 
    316         if (sysFont) {
    317             GetFullPathForSysFonts(&fullpath, path);
    318             path = fullpath.c_str();
    319         }
    320         fPath.set(path);
    321     }
    322 
    323     // overrides
    324     virtual SkStream* openStream() {
    325         SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
    326 
    327         // check for failure
    328         if (stream->getLength() <= 0) {
    329             SkDELETE(stream);
    330             // maybe MMAP isn't supported. try FILE
    331             stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
    332             if (stream->getLength() <= 0) {
    333                 SkDELETE(stream);
    334                 stream = NULL;
    335             }
    336         }
    337         return stream;
    338     }
    339     virtual const char* getUniqueString() const {
    340         const char* str = strrchr(fPath.c_str(), '/');
    341         if (str) {
    342             str += 1;   // skip the '/'
    343         }
    344         return str;
    345     }
    346     virtual const char* getFilePath() const {
    347         return fPath.c_str();
    348     }
    349 
    350 private:
    351     SkString fPath;
    352 
    353     typedef FamilyTypeface INHERITED;
    354 };
    355 
    356 ///////////////////////////////////////////////////////////////////////////////
    357 ///////////////////////////////////////////////////////////////////////////////
    358 
    359 static bool get_name_and_style(const char path[], SkString* name,
    360                                SkTypeface::Style* style, bool isExpected) {
    361     SkString        fullpath;
    362     GetFullPathForSysFonts(&fullpath, path);
    363 
    364     SkMMAPStream stream(fullpath.c_str());
    365     if (stream.getLength() > 0) {
    366         return find_name_and_style(&stream, name, style);
    367     }
    368     else {
    369         SkFILEStream stream(fullpath.c_str());
    370         if (stream.getLength() > 0) {
    371             return find_name_and_style(&stream, name, style);
    372         }
    373     }
    374 
    375     if (isExpected) {
    376         SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
    377     }
    378     return false;
    379 }
    380 
    381 // used to record our notion of the pre-existing fonts
    382 struct FontInitRec {
    383     const char*         fFileName;
    384     const char* const*  fNames;     // null-terminated list
    385 };
    386 
    387 static const char* gSansNames[] = {
    388     "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
    389 };
    390 
    391 static const char* gSerifNames[] = {
    392     "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
    393     "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
    394 };
    395 
    396 static const char* gMonoNames[] = {
    397     "monospace", "courier", "courier new", "monaco", NULL
    398 };
    399 
    400 // deliberately empty, but we use the address to identify fallback fonts
    401 static const char* gFBNames[] = { NULL };
    402 
    403 /*  Fonts must be grouped by family, with the first font in a family having the
    404     list of names (even if that list is empty), and the following members having
    405     null for the list. The names list must be NULL-terminated
    406 */
    407 static const FontInitRec gSystemFonts[] = {
    408     { "DroidSans.ttf",              gSansNames  },
    409     { "DroidSans-Bold.ttf",         NULL        },
    410     { "DroidSerif-Regular.ttf",     gSerifNames },
    411     { "DroidSerif-Bold.ttf",        NULL        },
    412     { "DroidSerif-Italic.ttf",      NULL        },
    413     { "DroidSerif-BoldItalic.ttf",  NULL        },
    414     { "DroidSansMono.ttf",          gMonoNames  },
    415     /*  These are optional, and can be ignored if not found in the file system.
    416         These are appended to gFallbackFonts[] as they are seen, so we list
    417         them in the order we want them to be accessed by NextLogicalFont().
    418      */
    419     { "DroidSansArabic.ttf",        gFBNames    },
    420     { "DroidSansHebrew.ttf",        gFBNames    },
    421     { "DroidSansThai.ttf",          gFBNames    },
    422     { "MTLmr3m.ttf",                gFBNames    }, // Motoya Japanese Font
    423     { "MTLc3m.ttf",                 gFBNames    }, // Motoya Japanese Font
    424     { "DroidSansJapanese.ttf",      gFBNames    },
    425     { "DroidSansFallback.ttf",      gFBNames    }
    426 };
    427 
    428 #define DEFAULT_NAMES   gSansNames
    429 
    430 // these globals are assigned (once) by load_system_fonts()
    431 static FamilyRec* gDefaultFamily;
    432 static SkTypeface* gDefaultNormal;
    433 
    434 /*  This is sized conservatively, assuming that it will never be a size issue.
    435     It will be initialized in load_system_fonts(), and will be filled with the
    436     fontIDs that can be used for fallback consideration, in sorted order (sorted
    437     meaning element[0] should be used first, then element[1], etc. When we hit
    438     a fontID==0 in the array, the list is done, hence our allocation size is
    439     +1 the total number of possible system fonts. Also see NextLogicalFont().
    440  */
    441 static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
    442 
    443 /*  Called once (ensured by the sentinel check at the beginning of our body).
    444     Initializes all the globals, and register the system fonts.
    445  */
    446 static void load_system_fonts() {
    447     // check if we've already be called
    448     if (NULL != gDefaultNormal) {
    449         return;
    450     }
    451 
    452     const FontInitRec* rec = gSystemFonts;
    453     SkTypeface* firstInFamily = NULL;
    454     int fallbackCount = 0;
    455 
    456     for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
    457         // if we're the first in a new family, clear firstInFamily
    458         if (rec[i].fNames != NULL) {
    459             firstInFamily = NULL;
    460         }
    461 
    462         SkString name;
    463         SkTypeface::Style style;
    464 
    465         // we expect all the fonts, except the "fallback" fonts
    466         bool isExpected = (rec[i].fNames != gFBNames);
    467         if (!get_name_and_style(rec[i].fFileName, &name, &style, isExpected)) {
    468             continue;
    469         }
    470 
    471         SkTypeface* tf = SkNEW_ARGS(FileTypeface,
    472                                     (style,
    473                                      true,  // system-font (cannot delete)
    474                                      firstInFamily, // what family to join
    475                                      rec[i].fFileName) // filename
    476                                     );
    477 
    478         if (rec[i].fNames != NULL) {
    479             // see if this is one of our fallback fonts
    480             if (rec[i].fNames == gFBNames) {
    481             //    SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
    482             //             rec[i].fFileName, fallbackCount, tf->uniqueID());
    483                 gFallbackFonts[fallbackCount++] = tf->uniqueID();
    484             }
    485 
    486             firstInFamily = tf;
    487             FamilyRec* family = find_family(tf);
    488             const char* const* names = rec[i].fNames;
    489 
    490             // record the default family if this is it
    491             if (names == DEFAULT_NAMES) {
    492                 gDefaultFamily = family;
    493             }
    494             // add the names to map to this family
    495             while (*names) {
    496                 add_name(*names, family);
    497                 names += 1;
    498             }
    499         }
    500     }
    501 
    502     // do this after all fonts are loaded. This is our default font, and it
    503     // acts as a sentinel so we only execute load_system_fonts() once
    504     gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
    505     // now terminate our fallback list with the sentinel value
    506     gFallbackFonts[fallbackCount] = 0;
    507 }
    508 
    509 ///////////////////////////////////////////////////////////////////////////////
    510 
    511 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
    512     const char* name = ((FamilyTypeface*)face)->getUniqueString();
    513 
    514     stream->write8((uint8_t)face->style());
    515 
    516     if (NULL == name || 0 == *name) {
    517         stream->writePackedUInt(0);
    518 //        SkDebugf("--- fonthost serialize null\n");
    519     } else {
    520         uint32_t len = strlen(name);
    521         stream->writePackedUInt(len);
    522         stream->write(name, len);
    523 //      SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
    524     }
    525 }
    526 
    527 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
    528     load_system_fonts();
    529 
    530     int style = stream->readU8();
    531 
    532     int len = stream->readPackedUInt();
    533     if (len > 0) {
    534         SkString str;
    535         str.resize(len);
    536         stream->read(str.writable_str(), len);
    537 
    538         const FontInitRec* rec = gSystemFonts;
    539         for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
    540             if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
    541                 // backup until we hit the fNames
    542                 for (int j = i; j >= 0; --j) {
    543                     if (rec[j].fNames != NULL) {
    544                         return SkFontHost::CreateTypeface(NULL,
    545                                     rec[j].fNames[0], (SkTypeface::Style)style);
    546                     }
    547                 }
    548             }
    549         }
    550     }
    551     return NULL;
    552 }
    553 
    554 ///////////////////////////////////////////////////////////////////////////////
    555 
    556 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
    557                                        const char familyName[],
    558                                        SkTypeface::Style style) {
    559     load_system_fonts();
    560 
    561     SkAutoMutexAcquire  ac(gFamilyMutex);
    562 
    563     // clip to legal style bits
    564     style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
    565 
    566     SkTypeface* tf = NULL;
    567 
    568     if (NULL != familyFace) {
    569         tf = find_typeface(familyFace, style);
    570     } else if (NULL != familyName) {
    571 //        SkDebugf("======= familyName <%s>\n", familyName);
    572         tf = find_typeface(familyName, style);
    573     }
    574 
    575     if (NULL == tf) {
    576         tf = find_best_face(gDefaultFamily, style);
    577     }
    578 
    579     // we ref(), since the symantic is to return a new instance
    580     tf->ref();
    581     return tf;
    582 }
    583 
    584 bool SkFontHost::ValidFontID(uint32_t fontID) {
    585     SkAutoMutexAcquire  ac(gFamilyMutex);
    586 
    587     return find_from_uniqueID(fontID) != NULL;
    588 }
    589 
    590 SkStream* SkFontHost::OpenStream(uint32_t fontID) {
    591     SkAutoMutexAcquire  ac(gFamilyMutex);
    592 
    593     FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
    594     SkStream* stream = tf ? tf->openStream() : NULL;
    595 
    596     if (stream && stream->getLength() == 0) {
    597         stream->unref();
    598         stream = NULL;
    599     }
    600     return stream;
    601 }
    602 
    603 size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
    604                                int32_t* index) {
    605     SkAutoMutexAcquire  ac(gFamilyMutex);
    606 
    607     FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
    608     const char* src = tf ? tf->getFilePath() : NULL;
    609 
    610     if (src) {
    611         size_t size = strlen(src);
    612         if (path) {
    613             memcpy(path, src, SkMin32(size, length));
    614         }
    615         if (index) {
    616             *index = 0; // we don't have collections (yet)
    617         }
    618         return size;
    619     } else {
    620         return 0;
    621     }
    622 }
    623 
    624 uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) {
    625     load_system_fonts();
    626 
    627     /*  First see if fontID is already one of our fallbacks. If so, return
    628         its successor. If fontID is not in our list, then return the first one
    629         in our list. Note: list is zero-terminated, and returning zero means
    630         we have no more fonts to use for fallbacks.
    631      */
    632     const uint32_t* list = gFallbackFonts;
    633     for (int i = 0; list[i] != 0; i++) {
    634         if (list[i] == fontID) {
    635             return list[i+1];
    636         }
    637     }
    638     return list[0];
    639 }
    640 
    641 ///////////////////////////////////////////////////////////////////////////////
    642 
    643 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
    644     if (NULL == stream || stream->getLength() <= 0) {
    645         return NULL;
    646     }
    647 
    648     SkString name;
    649     SkTypeface::Style style;
    650 
    651     if (find_name_and_style(stream, &name, &style)) {
    652         return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream));
    653     } else {
    654         return NULL;
    655     }
    656 }
    657 
    658 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
    659     SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
    660     SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
    661     // since we created the stream, we let go of our ref() here
    662     stream->unref();
    663     return face;
    664 }
    665 
    666 ///////////////////////////////////////////////////////////////////////////////
    667 
    668 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
    669     if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
    670         return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
    671     else
    672         return 0;   // nothing to do
    673 }
    674 
    675