tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

0007-Bug-719872-Old-Android-FontHost.patch (22631B)


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