Bug 910754 - Re-apply bug 921670 - Import the old Android FontHost to provide fonts for skia-npapi r=snorp
authorGeorge Wright <george@mozilla.com>
Fri, 14 Feb 2014 16:10:48 -0500
changeset 169781 29fcbc4e91f3d86c3ae02f602026a45cacb5260b
parent 169780 14e857f528b21289b151d8bc4d97b98bd53d0bfe
child 169782 c53990676a372365120bc8657fe203a0a361710e
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerssnorp
bugs910754, 921670
milestone30.0a1
Bug 910754 - Re-apply bug 921670 - Import the old Android FontHost to provide fonts for skia-npapi r=snorp
gfx/skia/moz.build
gfx/skia/src/ports/SkFontHost_android_old.cpp
gfx/skia/trunk/src/ports/SkFontHost_android_old.cpp
gfx/skia/trunk/src/ports/SkFontHost_cairo.cpp
--- a/gfx/skia/moz.build
+++ b/gfx/skia/moz.build
@@ -692,27 +692,29 @@ SOURCES += [
     'trunk/src/utils/SkSHA1.cpp',
     'trunk/src/utils/SkThreadPool.cpp',
     'trunk/src/utils/SkUnitMappers.cpp',
     ]
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk'):
     SOURCES += [
         'trunk/src/images/SkImageRef_ashmem.cpp',
         'trunk/src/ports/SkDebug_android.cpp',
+        'trunk/src/ports/SkFontHost_android_old.cpp',
         'trunk/src/ports/SkFontHost_cairo.cpp',
         'trunk/src/ports/SkFontHost_FreeType.cpp',
         'trunk/src/ports/SkFontHost_FreeType_common.cpp',
         'trunk/src/ports/SkOSFile_posix.cpp',
         'trunk/src/ports/SkPurgeableMemoryBlock_android.cpp',
         'trunk/src/ports/SkTime_Unix.cpp',
         'trunk/src/ports/SkTLS_pthread.cpp',
         'trunk/src/utils/android/ashmem.cpp',
         'trunk/src/utils/SkThreadUtils_pthread.cpp',
         'trunk/src/utils/SkThreadUtils_pthread_other.cpp',
     ]
+    DEFINES['SK_FONTHOST_CAIRO_STANDALONE'] = 0
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     SOURCES += [
         'trunk/src/ports/SkDebug_stdio.cpp',
         'trunk/src/ports/SkFontHost_mac.cpp',
         'trunk/src/ports/SkOSFile_posix.cpp',
         'trunk/src/ports/SkPurgeableMemoryBlock_mac.cpp',
         'trunk/src/ports/SkTime_Unix.cpp',
         'trunk/src/ports/SkTLS_pthread.cpp',
deleted file mode 100644
--- a/gfx/skia/src/ports/SkFontHost_android_old.cpp
+++ /dev/null
@@ -1,604 +0,0 @@
-
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#include "SkFontDescriptor.h"
-#include "SkFontHost.h"
-#include "SkFontHost_FreeType_common.h"
-#include "SkDescriptor.h"
-#include "SkStream.h"
-#include "SkPaint.h"
-#include "SkString.h"
-#include "SkStream.h"
-#include "SkThread.h"
-#include "SkTSearch.h"
-#include <stdio.h>
-
-#define FONT_CACHE_MEMORY_BUDGET    (768 * 1024)
-
-#ifndef SK_FONT_FILE_PREFIX
-    #define SK_FONT_FILE_PREFIX          "/fonts/"
-#endif
-
-bool find_name_and_attributes(SkStream* stream, SkString* name, SkTypeface::Style* style,
-                                           bool* isFixedWidth);
-
-static void GetFullPathForSysFonts(SkString* full, const char name[]) {
-    full->set(getenv("ANDROID_ROOT"));
-    full->append(SK_FONT_FILE_PREFIX);
-    full->append(name);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-struct FamilyRec;
-
-/*  This guy holds a mapping of a name -> family, used for looking up fonts.
-    Since it is stored in a stretchy array that doesn't preserve object
-    semantics, we don't use constructor/destructors, but just have explicit
-    helpers to manage our internal bookkeeping.
-*/
-struct NameFamilyPair {
-    const char* fName;      // we own this
-    FamilyRec*  fFamily;    // we don't own this, we just reference it
-
-    void construct(const char name[], FamilyRec* family) {
-        fName = strdup(name);
-        fFamily = family;   // we don't own this, so just record the referene
-    }
-
-    void destruct() {
-        free((char*)fName);
-        // we don't own family, so just ignore our reference
-    }
-};
-
-// we use atomic_inc to grow this for each typeface we create
-static int32_t gUniqueFontID;
-
-// this is the mutex that protects these globals
-static SkMutex gFamilyMutex;
-static FamilyRec* gFamilyHead;
-static SkTDArray<NameFamilyPair> gNameList;
-
-struct FamilyRec {
-    FamilyRec*  fNext;
-    SkTypeface* fFaces[4];
-
-    FamilyRec()
-    {
-        fNext = gFamilyHead;
-        memset(fFaces, 0, sizeof(fFaces));
-        gFamilyHead = this;
-    }
-};
-
-static SkTypeface* find_best_face(const FamilyRec* family,
-                                  SkTypeface::Style style) {
-    SkTypeface* const* faces = family->fFaces;
-
-    if (faces[style] != NULL) { // exact match
-        return faces[style];
-    }
-    // look for a matching bold
-    style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
-    if (faces[style] != NULL) {
-        return faces[style];
-    }
-    // look for the plain
-    if (faces[SkTypeface::kNormal] != NULL) {
-        return faces[SkTypeface::kNormal];
-    }
-    // look for anything
-    for (int i = 0; i < 4; i++) {
-        if (faces[i] != NULL) {
-            return faces[i];
-        }
-    }
-    // should never get here, since the faces list should not be empty
-    SkASSERT(!"faces list is empty");
-    return NULL;
-}
-
-static FamilyRec* find_family(const SkTypeface* member) {
-    FamilyRec* curr = gFamilyHead;
-    while (curr != NULL) {
-        for (int i = 0; i < 4; i++) {
-            if (curr->fFaces[i] == member) {
-                return curr;
-            }
-        }
-        curr = curr->fNext;
-    }
-    return NULL;
-}
-
-/*  Returns the matching typeface, or NULL. If a typeface is found, its refcnt
-    is not modified.
- */
-static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
-    FamilyRec* curr = gFamilyHead;
-    while (curr != NULL) {
-        for (int i = 0; i < 4; i++) {
-            SkTypeface* face = curr->fFaces[i];
-            if (face != NULL && face->uniqueID() == uniqueID) {
-                return face;
-            }
-        }
-        curr = curr->fNext;
-    }
-    return NULL;
-}
-
-/*  Remove reference to this face from its family. If the resulting family
-    is empty (has no faces), return that family, otherwise return NULL
-*/
-static FamilyRec* remove_from_family(const SkTypeface* face) {
-    FamilyRec* family = find_family(face);
-    SkASSERT(family->fFaces[face->style()] == face);
-    family->fFaces[face->style()] = NULL;
-
-    for (int i = 0; i < 4; i++) {
-        if (family->fFaces[i] != NULL) {    // family is non-empty
-            return NULL;
-        }
-    }
-    return family;  // return the empty family
-}
-
-// maybe we should make FamilyRec be doubly-linked
-static void detach_and_delete_family(FamilyRec* family) {
-    FamilyRec* curr = gFamilyHead;
-    FamilyRec* prev = NULL;
-
-    while (curr != NULL) {
-        FamilyRec* next = curr->fNext;
-        if (curr == family) {
-            if (prev == NULL) {
-                gFamilyHead = next;
-            } else {
-                prev->fNext = next;
-            }
-            SkDELETE(family);
-            return;
-        }
-        prev = curr;
-        curr = next;
-    }
-    SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
-}
-
-static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
-    NameFamilyPair* list = gNameList.begin();
-    int             count = gNameList.count();
-
-    int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
-
-    if (index >= 0) {
-        return find_best_face(list[index].fFamily, style);
-    }
-    return NULL;
-}
-
-static SkTypeface* find_typeface(const SkTypeface* familyMember,
-                                 SkTypeface::Style style) {
-    const FamilyRec* family = find_family(familyMember);
-    return family ? find_best_face(family, style) : NULL;
-}
-
-static void add_name(const char name[], FamilyRec* family) {
-    SkAutoAsciiToLC tolc(name);
-    name = tolc.lc();
-
-    NameFamilyPair* list = gNameList.begin();
-    int             count = gNameList.count();
-
-    int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
-
-    if (index < 0) {
-        list = gNameList.insert(~index);
-        list->construct(name, family);
-    }
-}
-
-static void remove_from_names(FamilyRec* emptyFamily)
-{
-#ifdef SK_DEBUG
-    for (int i = 0; i < 4; i++) {
-        SkASSERT(emptyFamily->fFaces[i] == NULL);
-    }
-#endif
-
-    SkTDArray<NameFamilyPair>& list = gNameList;
-
-    // must go backwards when removing
-    for (int i = list.count() - 1; i >= 0; --i) {
-        NameFamilyPair* pair = &list[i];
-        if (pair->fFamily == emptyFamily) {
-            pair->destruct();
-            list.remove(i);
-        }
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-class FamilyTypeface : public SkTypeface_FreeType {
-public:
-    FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember,
-                   bool isFixedWidth)
-    : SkTypeface_FreeType(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) {
-        fIsSysFont = sysFont;
-
-        SkAutoMutexAcquire  ac(gFamilyMutex);
-
-        FamilyRec* rec = NULL;
-        if (familyMember) {
-            rec = find_family(familyMember);
-            SkASSERT(rec);
-        } else {
-            rec = SkNEW(FamilyRec);
-        }
-        rec->fFaces[style] = this;
-    }
-
-    virtual ~FamilyTypeface() {
-        SkAutoMutexAcquire  ac(gFamilyMutex);
-
-        // remove us from our family. If the family is now empty, we return
-        // that and then remove that family from the name list
-        FamilyRec* family = remove_from_family(this);
-        if (NULL != family) {
-            remove_from_names(family);
-            detach_and_delete_family(family);
-        }
-    }
-
-    bool isSysFont() const { return fIsSysFont; }
-
-    virtual const char* getUniqueString() const = 0;
-    virtual const char* getFilePath() const = 0;
-
-protected:
-    virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
-
-private:
-    bool    fIsSysFont;
-
-    typedef SkTypeface INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-class StreamTypeface : public FamilyTypeface {
-public:
-    StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
-                   SkStream* stream, bool isFixedWidth)
-    : INHERITED(style, sysFont, familyMember, isFixedWidth) {
-        SkASSERT(stream);
-        stream->ref();
-        fStream = stream;
-    }
-    virtual ~StreamTypeface() {
-        fStream->unref();
-    }
-
-    // overrides
-    virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
-        *ttcIndex = 0;
-        // we just ref our existing stream, since the caller will call unref()
-        // when they are through
-        fStream->ref();
-        // must rewind each time, since the caller assumes a "new" stream
-        fStream->rewind();
-        return fStream;
-    }
-    virtual const char* getUniqueString() const { return NULL; }
-    virtual const char* getFilePath() const { return NULL; }
-
-private:
-    SkStream* fStream;
-
-    typedef FamilyTypeface INHERITED;
-};
-
-class FileTypeface : public FamilyTypeface {
-public:
-    FileTypeface(Style style, bool sysFont, SkTypeface* familyMember,
-                 const char path[], bool isFixedWidth)
-    : INHERITED(style, sysFont, familyMember, isFixedWidth) {
-        SkString fullpath;
-
-        if (sysFont) {
-            GetFullPathForSysFonts(&fullpath, path);
-            path = fullpath.c_str();
-        }
-        fPath.set(path);
-    }
-
-    // overrides
-    virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
-        *ttcIndex = 0;
-        SkStream* stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
-
-        // check for failure
-        if (stream->getLength() <= 0) {
-            SkDELETE(stream);
-            stream = NULL;
-        }
-        return stream;
-    }
-    virtual const char* getUniqueString() const {
-        const char* str = strrchr(fPath.c_str(), '/');
-        if (str) {
-            str += 1;   // skip the '/'
-        }
-        return str;
-    }
-    virtual const char* getFilePath() const {
-        return fPath.c_str();
-    }
-
-private:
-    SkString fPath;
-
-    typedef FamilyTypeface INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-static bool get_name_and_style(const char path[], SkString* name,
-                               SkTypeface::Style* style,
-                               bool* isFixedWidth, bool isExpected) {
-    SkString        fullpath;
-    GetFullPathForSysFonts(&fullpath, path);
-
-    SkFILEStream stream(fullpath.c_str());
-    if (stream.getLength() > 0) {
-        find_name_and_attributes(&stream, name, style, isFixedWidth);
-        return true;
-    }
-    else {
-        SkFILEStream stream(fullpath.c_str());
-        if (stream.getLength() > 0) {
-            find_name_and_attributes(&stream, name, style, isFixedWidth);
-            return true;
-        }
-    }
-
-    if (isExpected) {
-        SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
-    }
-    return false;
-}
-
-// used to record our notion of the pre-existing fonts
-struct FontInitRec {
-    const char*         fFileName;
-    const char* const*  fNames;     // null-terminated list
-};
-
-static const char* gSansNames[] = {
-    "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
-};
-
-static const char* gSerifNames[] = {
-    "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
-    "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
-};
-
-static const char* gMonoNames[] = {
-    "monospace", "courier", "courier new", "monaco", NULL
-};
-
-// deliberately empty, but we use the address to identify fallback fonts
-static const char* gFBNames[] = { NULL };
-
-/*  Fonts must be grouped by family, with the first font in a family having the
-    list of names (even if that list is empty), and the following members having
-    null for the list. The names list must be NULL-terminated
-*/
-static const FontInitRec gSystemFonts[] = {
-    { "DroidSans.ttf",              gSansNames  },
-    { "DroidSans-Bold.ttf",         NULL        },
-    { "DroidSerif-Regular.ttf",     gSerifNames },
-    { "DroidSerif-Bold.ttf",        NULL        },
-    { "DroidSerif-Italic.ttf",      NULL        },
-    { "DroidSerif-BoldItalic.ttf",  NULL        },
-    { "DroidSansMono.ttf",          gMonoNames  },
-    /*  These are optional, and can be ignored if not found in the file system.
-        These are appended to gFallbackFonts[] as they are seen, so we list
-        them in the order we want them to be accessed by NextLogicalFont().
-     */
-    { "DroidSansArabic.ttf",        gFBNames    },
-    { "DroidSansHebrew.ttf",        gFBNames    },
-    { "DroidSansThai.ttf",          gFBNames    },
-    { "MTLmr3m.ttf",                gFBNames    }, // Motoya Japanese Font
-    { "MTLc3m.ttf",                 gFBNames    }, // Motoya Japanese Font
-    { "DroidSansJapanese.ttf",      gFBNames    },
-    { "DroidSansFallback.ttf",      gFBNames    }
-};
-
-#define DEFAULT_NAMES   gSansNames
-
-// these globals are assigned (once) by load_system_fonts()
-static FamilyRec* gDefaultFamily;
-static SkTypeface* gDefaultNormal;
-
-/*  This is sized conservatively, assuming that it will never be a size issue.
-    It will be initialized in load_system_fonts(), and will be filled with the
-    fontIDs that can be used for fallback consideration, in sorted order (sorted
-    meaning element[0] should be used first, then element[1], etc. When we hit
-    a fontID==0 in the array, the list is done, hence our allocation size is
-    +1 the total number of possible system fonts. Also see NextLogicalFont().
- */
-static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
-
-/*  Called once (ensured by the sentinel check at the beginning of our body).
-    Initializes all the globals, and register the system fonts.
- */
-static void load_system_fonts() {
-    // check if we've already be called
-    if (NULL != gDefaultNormal) {
-        return;
-    }
-
-    const FontInitRec* rec = gSystemFonts;
-    SkTypeface* firstInFamily = NULL;
-    int fallbackCount = 0;
-
-    for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
-        // if we're the first in a new family, clear firstInFamily
-        if (rec[i].fNames != NULL) {
-            firstInFamily = NULL;
-        }
-
-        bool isFixedWidth;
-        SkString name;
-        SkTypeface::Style style;
-
-        // we expect all the fonts, except the "fallback" fonts
-        bool isExpected = (rec[i].fNames != gFBNames);
-        if (!get_name_and_style(rec[i].fFileName, &name, &style,
-                                &isFixedWidth, isExpected)) {
-            continue;
-        }
-
-        SkTypeface* tf = SkNEW_ARGS(FileTypeface,
-                                    (style,
-                                     true,  // system-font (cannot delete)
-                                     firstInFamily, // what family to join
-                                     rec[i].fFileName,
-                                     isFixedWidth) // filename
-                                    );
-
-        if (rec[i].fNames != NULL) {
-            // see if this is one of our fallback fonts
-            if (rec[i].fNames == gFBNames) {
-            //    SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
-            //             rec[i].fFileName, fallbackCount, tf->uniqueID());
-                gFallbackFonts[fallbackCount++] = tf->uniqueID();
-            }
-
-            firstInFamily = tf;
-            FamilyRec* family = find_family(tf);
-            const char* const* names = rec[i].fNames;
-
-            // record the default family if this is it
-            if (names == DEFAULT_NAMES) {
-                gDefaultFamily = family;
-            }
-            // add the names to map to this family
-            while (*names) {
-                add_name(*names, family);
-                names += 1;
-            }
-        }
-    }
-
-    // do this after all fonts are loaded. This is our default font, and it
-    // acts as a sentinel so we only execute load_system_fonts() once
-    gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
-    // now terminate our fallback list with the sentinel value
-    gFallbackFonts[fallbackCount] = 0;
-}
-
-void FamilyTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
-                                         bool* isLocalStream) const {
-    {
-        SkAutoMutexAcquire ac(gFamilyMutex);
-        //desc->setFamilyName(find_family_name(this));
-        desc->setFontFileName(this->getUniqueString());
-    }
-    *isLocalStream = !this->isSysFont();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
-                                       const char familyName[],
-                                       SkTypeface::Style style) {
-    load_system_fonts();
-
-    SkAutoMutexAcquire  ac(gFamilyMutex);
-
-    // clip to legal style bits
-    style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
-
-    SkTypeface* tf = NULL;
-
-    if (NULL != familyFace) {
-        tf = find_typeface(familyFace, style);
-    } else if (NULL != familyName) {
-//        SkDebugf("======= familyName <%s>\n", familyName);
-        tf = find_typeface(familyName, style);
-    }
-
-    if (NULL == tf) {
-        tf = find_best_face(gDefaultFamily, style);
-    }
-
-    // we ref(), since the symantic is to return a new instance
-    tf->ref();
-    return tf;
-}
-
-SkTypeface* SkAndroidNextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
-    load_system_fonts();
-
-    /*  First see if fontID is already one of our fallbacks. If so, return
-        its successor. If fontID is not in our list, then return the first one
-        in our list. Note: list is zero-terminated, and returning zero means
-        we have no more fonts to use for fallbacks.
-     */
-    const uint32_t* list = gFallbackFonts;
-    for (int i = 0; list[i] != 0; i++) {
-        if (list[i] == currFontID) {
-            return find_from_uniqueID(list[i+1]);
-        }
-    }
-    return find_from_uniqueID(list[0]);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
-    if (NULL == stream || stream->getLength() <= 0) {
-        return NULL;
-    }
-
-    bool isFixedWidth;
-    SkString name;
-    SkTypeface::Style style;
-    find_name_and_attributes(stream, &name, &style, &isFixedWidth);
-
-    if (!name.isEmpty()) {
-        return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth));
-    } else {
-        return NULL;
-    }
-}
-
-SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
-    SkStream* stream = SkNEW_ARGS(SkFILEStream, (path));
-    SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
-    // since we created the stream, we let go of our ref() here
-    stream->unref();
-    return face;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#include "SkFontMgr.h"
-
-SkFontMgr* SkFontMgr::Factory() {
-    // todo
-    return NULL;
-}
-
new file mode 100644
--- /dev/null
+++ b/gfx/skia/trunk/src/ports/SkFontHost_android_old.cpp
@@ -0,0 +1,589 @@
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "SkFontDescriptor.h"
+#include "SkFontHost.h"
+#include "SkFontHost_FreeType_common.h"
+#include "SkDescriptor.h"
+#include "SkStream.h"
+#include "SkPaint.h"
+#include "SkString.h"
+#include "SkStream.h"
+#include "SkThread.h"
+#include "SkTSearch.h"
+#include <stdio.h>
+
+#define FONT_CACHE_MEMORY_BUDGET    (768 * 1024)
+
+#ifndef SK_FONT_FILE_PREFIX
+    #define SK_FONT_FILE_PREFIX          "/fonts/"
+#endif
+
+bool find_name_and_attributes(SkStream* stream, SkString* name, SkTypeface::Style* style,
+                                           bool* isFixedWidth);
+
+static void GetFullPathForSysFonts(SkString* full, const char name[]) {
+    full->set(getenv("ANDROID_ROOT"));
+    full->append(SK_FONT_FILE_PREFIX);
+    full->append(name);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct FamilyRec;
+
+/*  This guy holds a mapping of a name -> family, used for looking up fonts.
+    Since it is stored in a stretchy array that doesn't preserve object
+    semantics, we don't use constructor/destructors, but just have explicit
+    helpers to manage our internal bookkeeping.
+*/
+struct NameFamilyPair {
+    const char* fName;      // we own this
+    FamilyRec*  fFamily;    // we don't own this, we just reference it
+
+    void construct(const char name[], FamilyRec* family) {
+        fName = strdup(name);
+        fFamily = family;   // we don't own this, so just record the referene
+    }
+
+    void destruct() {
+        free((char*)fName);
+        // we don't own family, so just ignore our reference
+    }
+};
+
+// we use atomic_inc to grow this for each typeface we create
+static int32_t gUniqueFontID;
+
+// this is the mutex that protects these globals
+static SkMutex gFamilyMutex;
+static FamilyRec* gFamilyHead;
+static SkTDArray<NameFamilyPair> gNameList;
+
+struct FamilyRec {
+    FamilyRec*  fNext;
+    SkTypeface* fFaces[4];
+
+    FamilyRec()
+    {
+        fNext = gFamilyHead;
+        memset(fFaces, 0, sizeof(fFaces));
+        gFamilyHead = this;
+    }
+};
+
+static SkTypeface* find_best_face(const FamilyRec* family,
+                                  SkTypeface::Style style) {
+    SkTypeface* const* faces = family->fFaces;
+
+    if (faces[style] != NULL) { // exact match
+        return faces[style];
+    }
+    // look for a matching bold
+    style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
+    if (faces[style] != NULL) {
+        return faces[style];
+    }
+    // look for the plain
+    if (faces[SkTypeface::kNormal] != NULL) {
+        return faces[SkTypeface::kNormal];
+    }
+    // look for anything
+    for (int i = 0; i < 4; i++) {
+        if (faces[i] != NULL) {
+            return faces[i];
+        }
+    }
+    // should never get here, since the faces list should not be empty
+    SkASSERT(!"faces list is empty");
+    return NULL;
+}
+
+static FamilyRec* find_family(const SkTypeface* member) {
+    FamilyRec* curr = gFamilyHead;
+    while (curr != NULL) {
+        for (int i = 0; i < 4; i++) {
+            if (curr->fFaces[i] == member) {
+                return curr;
+            }
+        }
+        curr = curr->fNext;
+    }
+    return NULL;
+}
+
+/*  Returns the matching typeface, or NULL. If a typeface is found, its refcnt
+    is not modified.
+ */
+static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
+    FamilyRec* curr = gFamilyHead;
+    while (curr != NULL) {
+        for (int i = 0; i < 4; i++) {
+            SkTypeface* face = curr->fFaces[i];
+            if (face != NULL && face->uniqueID() == uniqueID) {
+                return face;
+            }
+        }
+        curr = curr->fNext;
+    }
+    return NULL;
+}
+
+/*  Remove reference to this face from its family. If the resulting family
+    is empty (has no faces), return that family, otherwise return NULL
+*/
+static FamilyRec* remove_from_family(const SkTypeface* face) {
+    FamilyRec* family = find_family(face);
+    SkASSERT(family->fFaces[face->style()] == face);
+    family->fFaces[face->style()] = NULL;
+
+    for (int i = 0; i < 4; i++) {
+        if (family->fFaces[i] != NULL) {    // family is non-empty
+            return NULL;
+        }
+    }
+    return family;  // return the empty family
+}
+
+// maybe we should make FamilyRec be doubly-linked
+static void detach_and_delete_family(FamilyRec* family) {
+    FamilyRec* curr = gFamilyHead;
+    FamilyRec* prev = NULL;
+
+    while (curr != NULL) {
+        FamilyRec* next = curr->fNext;
+        if (curr == family) {
+            if (prev == NULL) {
+                gFamilyHead = next;
+            } else {
+                prev->fNext = next;
+            }
+            SkDELETE(family);
+            return;
+        }
+        prev = curr;
+        curr = next;
+    }
+    SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
+}
+
+static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
+    NameFamilyPair* list = gNameList.begin();
+    int             count = gNameList.count();
+
+    int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
+
+    if (index >= 0) {
+        return find_best_face(list[index].fFamily, style);
+    }
+    return NULL;
+}
+
+static SkTypeface* find_typeface(const SkTypeface* familyMember,
+                                 SkTypeface::Style style) {
+    const FamilyRec* family = find_family(familyMember);
+    return family ? find_best_face(family, style) : NULL;
+}
+
+static void add_name(const char name[], FamilyRec* family) {
+    SkAutoAsciiToLC tolc(name);
+    name = tolc.lc();
+
+    NameFamilyPair* list = gNameList.begin();
+    int             count = gNameList.count();
+
+    int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
+
+    if (index < 0) {
+        list = gNameList.insert(~index);
+        list->construct(name, family);
+    }
+}
+
+static void remove_from_names(FamilyRec* emptyFamily)
+{
+#ifdef SK_DEBUG
+    for (int i = 0; i < 4; i++) {
+        SkASSERT(emptyFamily->fFaces[i] == NULL);
+    }
+#endif
+
+    SkTDArray<NameFamilyPair>& list = gNameList;
+
+    // must go backwards when removing
+    for (int i = list.count() - 1; i >= 0; --i) {
+        NameFamilyPair* pair = &list[i];
+        if (pair->fFamily == emptyFamily) {
+            pair->destruct();
+            list.remove(i);
+        }
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class FamilyTypeface : public SkTypeface_FreeType {
+public:
+    FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember,
+                   bool isFixedWidth)
+    : SkTypeface_FreeType(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) {
+        fIsSysFont = sysFont;
+
+        SkAutoMutexAcquire  ac(gFamilyMutex);
+
+        FamilyRec* rec = NULL;
+        if (familyMember) {
+            rec = find_family(familyMember);
+            SkASSERT(rec);
+        } else {
+            rec = SkNEW(FamilyRec);
+        }
+        rec->fFaces[style] = this;
+    }
+
+    virtual ~FamilyTypeface() {
+        SkAutoMutexAcquire  ac(gFamilyMutex);
+
+        // remove us from our family. If the family is now empty, we return
+        // that and then remove that family from the name list
+        FamilyRec* family = remove_from_family(this);
+        if (NULL != family) {
+            remove_from_names(family);
+            detach_and_delete_family(family);
+        }
+    }
+
+    bool isSysFont() const { return fIsSysFont; }
+
+    virtual const char* getUniqueString() const = 0;
+    virtual const char* getFilePath() const = 0;
+
+protected:
+    virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
+
+private:
+    bool    fIsSysFont;
+
+    typedef SkTypeface INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class StreamTypeface : public FamilyTypeface {
+public:
+    StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
+                   SkStream* stream, bool isFixedWidth)
+    : INHERITED(style, sysFont, familyMember, isFixedWidth) {
+        SkASSERT(stream);
+        stream->ref();
+        fStream = stream;
+    }
+    virtual ~StreamTypeface() {
+        fStream->unref();
+    }
+
+    // overrides
+    virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
+        *ttcIndex = 0;
+        // we just ref our existing stream, since the caller will call unref()
+        // when they are through
+        fStream->ref();
+        // must rewind each time, since the caller assumes a "new" stream
+        fStream->rewind();
+        return fStream;
+    }
+    virtual const char* getUniqueString() const { return NULL; }
+    virtual const char* getFilePath() const { return NULL; }
+
+private:
+    SkStream* fStream;
+
+    typedef FamilyTypeface INHERITED;
+};
+
+class FileTypeface : public FamilyTypeface {
+public:
+    FileTypeface(Style style, bool sysFont, SkTypeface* familyMember,
+                 const char path[], bool isFixedWidth)
+    : INHERITED(style, sysFont, familyMember, isFixedWidth) {
+        SkString fullpath;
+
+        if (sysFont) {
+            GetFullPathForSysFonts(&fullpath, path);
+            path = fullpath.c_str();
+        }
+        fPath.set(path);
+    }
+
+    // overrides
+    virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
+        *ttcIndex = 0;
+        SkStream* stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
+
+        // check for failure
+        if (stream->getLength() <= 0) {
+            SkDELETE(stream);
+            stream = NULL;
+        }
+        return stream;
+    }
+    virtual const char* getUniqueString() const {
+        const char* str = strrchr(fPath.c_str(), '/');
+        if (str) {
+            str += 1;   // skip the '/'
+        }
+        return str;
+    }
+    virtual const char* getFilePath() const {
+        return fPath.c_str();
+    }
+
+private:
+    SkString fPath;
+
+    typedef FamilyTypeface INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static bool get_name_and_style(const char path[], SkString* name,
+                               SkTypeface::Style* style,
+                               bool* isFixedWidth, bool isExpected) {
+    SkString        fullpath;
+    GetFullPathForSysFonts(&fullpath, path);
+
+    SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(fullpath.c_str()));
+    if (stream.get()) {
+        find_name_and_attributes(stream, name, style, isFixedWidth);
+        return true;
+    }
+
+    if (isExpected) {
+        SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
+    }
+    return false;
+}
+
+// used to record our notion of the pre-existing fonts
+struct FontInitRec {
+    const char*         fFileName;
+    const char* const*  fNames;     // null-terminated list
+};
+
+static const char* gSansNames[] = {
+    "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
+};
+
+static const char* gSerifNames[] = {
+    "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
+    "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
+};
+
+static const char* gMonoNames[] = {
+    "monospace", "courier", "courier new", "monaco", NULL
+};
+
+// deliberately empty, but we use the address to identify fallback fonts
+static const char* gFBNames[] = { NULL };
+
+/*  Fonts must be grouped by family, with the first font in a family having the
+    list of names (even if that list is empty), and the following members having
+    null for the list. The names list must be NULL-terminated
+*/
+static const FontInitRec gSystemFonts[] = {
+    { "DroidSans.ttf",              gSansNames  },
+    { "DroidSans-Bold.ttf",         NULL        },
+    { "DroidSerif-Regular.ttf",     gSerifNames },
+    { "DroidSerif-Bold.ttf",        NULL        },
+    { "DroidSerif-Italic.ttf",      NULL        },
+    { "DroidSerif-BoldItalic.ttf",  NULL        },
+    { "DroidSansMono.ttf",          gMonoNames  },
+    /*  These are optional, and can be ignored if not found in the file system.
+        These are appended to gFallbackFonts[] as they are seen, so we list
+        them in the order we want them to be accessed by NextLogicalFont().
+     */
+    { "DroidSansArabic.ttf",        gFBNames    },
+    { "DroidSansHebrew.ttf",        gFBNames    },
+    { "DroidSansThai.ttf",          gFBNames    },
+    { "MTLmr3m.ttf",                gFBNames    }, // Motoya Japanese Font
+    { "MTLc3m.ttf",                 gFBNames    }, // Motoya Japanese Font
+    { "DroidSansJapanese.ttf",      gFBNames    },
+    { "DroidSansFallback.ttf",      gFBNames    }
+};
+
+#define DEFAULT_NAMES   gSansNames
+
+// these globals are assigned (once) by load_system_fonts()
+static FamilyRec* gDefaultFamily;
+static SkTypeface* gDefaultNormal;
+
+/*  This is sized conservatively, assuming that it will never be a size issue.
+    It will be initialized in load_system_fonts(), and will be filled with the
+    fontIDs that can be used for fallback consideration, in sorted order (sorted
+    meaning element[0] should be used first, then element[1], etc. When we hit
+    a fontID==0 in the array, the list is done, hence our allocation size is
+    +1 the total number of possible system fonts. Also see NextLogicalFont().
+ */
+static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
+
+/*  Called once (ensured by the sentinel check at the beginning of our body).
+    Initializes all the globals, and register the system fonts.
+ */
+static void load_system_fonts() {
+    // check if we've already be called
+    if (NULL != gDefaultNormal) {
+        return;
+    }
+
+    const FontInitRec* rec = gSystemFonts;
+    SkTypeface* firstInFamily = NULL;
+    int fallbackCount = 0;
+
+    for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
+        // if we're the first in a new family, clear firstInFamily
+        if (rec[i].fNames != NULL) {
+            firstInFamily = NULL;
+        }
+
+        bool isFixedWidth;
+        SkString name;
+        SkTypeface::Style style;
+
+        // we expect all the fonts, except the "fallback" fonts
+        bool isExpected = (rec[i].fNames != gFBNames);
+        if (!get_name_and_style(rec[i].fFileName, &name, &style,
+                                &isFixedWidth, isExpected)) {
+            continue;
+        }
+
+        SkTypeface* tf = SkNEW_ARGS(FileTypeface,
+                                    (style,
+                                     true,  // system-font (cannot delete)
+                                     firstInFamily, // what family to join
+                                     rec[i].fFileName,
+                                     isFixedWidth) // filename
+                                    );
+
+        if (rec[i].fNames != NULL) {
+            // see if this is one of our fallback fonts
+            if (rec[i].fNames == gFBNames) {
+            //    SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
+            //             rec[i].fFileName, fallbackCount, tf->uniqueID());
+                gFallbackFonts[fallbackCount++] = tf->uniqueID();
+            }
+
+            firstInFamily = tf;
+            FamilyRec* family = find_family(tf);
+            const char* const* names = rec[i].fNames;
+
+            // record the default family if this is it
+            if (names == DEFAULT_NAMES) {
+                gDefaultFamily = family;
+            }
+            // add the names to map to this family
+            while (*names) {
+                add_name(*names, family);
+                names += 1;
+            }
+        }
+    }
+
+    // do this after all fonts are loaded. This is our default font, and it
+    // acts as a sentinel so we only execute load_system_fonts() once
+    gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
+    // now terminate our fallback list with the sentinel value
+    gFallbackFonts[fallbackCount] = 0;
+}
+
+void FamilyTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
+                                         bool* isLocalStream) const {
+    {
+        SkAutoMutexAcquire ac(gFamilyMutex);
+        //desc->setFamilyName(find_family_name(this));
+        desc->setFontFileName(this->getUniqueString());
+    }
+    *isLocalStream = !this->isSysFont();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
+                                       const char familyName[],
+                                       SkTypeface::Style style) {
+    load_system_fonts();
+
+    SkAutoMutexAcquire  ac(gFamilyMutex);
+
+    // clip to legal style bits
+    style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
+
+    SkTypeface* tf = NULL;
+
+    if (NULL != familyFace) {
+        tf = find_typeface(familyFace, style);
+    } else if (NULL != familyName) {
+//        SkDebugf("======= familyName <%s>\n", familyName);
+        tf = find_typeface(familyName, style);
+    }
+
+    if (NULL == tf) {
+        tf = find_best_face(gDefaultFamily, style);
+    }
+
+    // we ref(), since the symantic is to return a new instance
+    tf->ref();
+    return tf;
+}
+
+SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
+                                         const SkPaintOptionsAndroid& options) {
+    load_system_fonts();
+
+    /*  First see if fontID is already one of our fallbacks. If so, return
+        its successor. If fontID is not in our list, then return the first one
+        in our list. Note: list is zero-terminated, and returning zero means
+        we have no more fonts to use for fallbacks.
+     */
+    const uint32_t* list = gFallbackFonts;
+    for (int i = 0; list[i] != 0; i++) {
+        if (list[i] == currFontID) {
+            return find_from_uniqueID(list[i+1]);
+        }
+    }
+    return find_from_uniqueID(list[0]);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
+    if (NULL == stream || stream->getLength() <= 0) {
+        return NULL;
+    }
+
+    bool isFixedWidth;
+    SkString name;
+    SkTypeface::Style style;
+    find_name_and_attributes(stream, &name, &style, &isFixedWidth);
+
+    if (!name.isEmpty()) {
+        return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth));
+    } else {
+        return NULL;
+    }
+}
+
+SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
+    SkStream* stream = SkNEW_ARGS(SkFILEStream, (path));
+    SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
+    // since we created the stream, we let go of our ref() here
+    stream->unref();
+    return face;
+}
+
--- a/gfx/skia/trunk/src/ports/SkFontHost_cairo.cpp
+++ b/gfx/skia/trunk/src/ports/SkFontHost_cairo.cpp
@@ -15,16 +15,20 @@
 #include "SkFontHost.h"
 #include "SkPath.h"
 #include "SkScalerContext.h"
 #include "SkTypefaceCache.h"
 
 #include <ft2build.h>
 #include FT_FREETYPE_H
 
+#ifndef SK_FONTHOST_CAIRO_STANDALONE
+#define SK_FONTHOST_CAIRO_STANDALONE 1
+#endif
+
 static cairo_user_data_key_t kSkTypefaceKey;
 
 class SkScalerContext_CairoFT : public SkScalerContext_FreeType_Base {
 public:
     SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc);
     virtual ~SkScalerContext_CairoFT();
 
 protected:
@@ -162,17 +166,17 @@ SkTypeface* SkCreateTypefaceFromCairoFon
     } else {
         typeface = SkCairoFTTypeface::CreateTypeface(fontFace, style, isFixedWidth);
         SkTypefaceCache::Add(typeface, style);
     }
 
     return typeface;
 }
 
-#ifdef SK_FONTHOST_DOES_NOT_USE_FONTMGR
+#if defined(SK_FONTHOST_DOES_NOT_USE_FONTMGR) && SK_FONTHOST_CAIRO_STANDALONE
 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
                                      const char famillyName[],
                                      SkTypeface::Style style)
 {
     SkDEBUGFAIL("SkFontHost::FindTypeface unimplemented");
     return NULL;
 }
 
@@ -372,23 +376,16 @@ SkUnichar SkScalerContext_CairoFT::gener
             return charCode;
         }
         charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
     }
 
     return 0;
 }
 
-#ifdef SK_BUILD_FOR_ANDROID
-SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
-                                         const SkPaintOptionsAndroid& options) {
-    return NULL;
-}
-#endif
-
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "SkFontMgr.h"
 
 SkFontMgr* SkFontMgr::Factory() {
     // todo
     return NULL;
 }