tor-browser

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

0004-Bug-777614-Re-apply-bug-719872-Fix-crash-on-Android-.patch (22087B)


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