bug 684889 - refactor and clean up Android font-list implementation. r=jdaggett
☠☠ backed out by 6c12bf7c3616 ☠ ☠
authorJonathan Kew <jfkthame@gmail.com>
Fri, 23 Sep 2011 09:53:13 +0100
changeset 78717 864c08bd7c63049a15d501dc40827ee606f1e8ba
parent 78716 1431db818666e15b9319e039cce5aa0e041f6176
child 78718 f4b1fa7a0f3147b20e67701f124c8b9ddfe0c447
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs684889
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 684889 - refactor and clean up Android font-list implementation. r=jdaggett
dom/ipc/PContent.ipdl
gfx/thebes/gfxAndroidPlatform.cpp
gfx/thebes/gfxAndroidPlatform.h
gfx/thebes/gfxFT2FontList.cpp
gfx/thebes/gfxFT2FontList.h
gfx/thebes/gfxFT2Fonts.cpp
gfx/thebes/gfxFT2Fonts.h
gfx/thebes/gfxFont.cpp
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -78,19 +78,23 @@ struct StorageClone
 // cloned (see nsDOMStorage2::Clone)
 union StorageConstructData
 {
     null_t;
     StorageClone;
 };
 
 struct FontListEntry {
-    nsCString familyName;
+    nsString  familyName;
+    nsString  faceName;
     nsCString filepath;
-    PRUint32  index;
+    PRUint16  weight;
+    PRInt16   stretch;
+    PRUint8   italic;
+    PRUint8   index;
 };
 
 rpc protocol PContent
 {
     manages PAudio;
     manages PBrowser;
     manages PCrashReporter;
     manages PTestShell;
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -30,64 +30,34 @@
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
-#include "mozilla/dom/ContentChild.h"
-#include "nsXULAppAPI.h"
-
-#include <android/log.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
 
 #include "gfxAndroidPlatform.h"
 
-#include "cairo.h"
-#include "cairo-ft.h"
-
+#include "gfxFT2FontList.h"
 #include "gfxImageSurface.h"
 
-#include "nsUnicharUtils.h"
-
-#include "nsMathUtils.h"
-#include "nsTArray.h"
-
-#include "qcms.h"
+#include "cairo.h"
 
 #include "ft2build.h"
 #include FT_FREETYPE_H
-#include "gfxFT2Fonts.h"
-#include "gfxPlatformFontList.h"
-#include "gfxFT2FontList.h"
-#include "mozilla/scache/StartupCache.h"
-#include "nsXPCOMStrings.h"
-
-using namespace mozilla;
-using namespace dom;
 
 static FT_Library gPlatformFTLibrary = NULL;
 
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoFonts" , ## args)
 
 gfxAndroidPlatform::gfxAndroidPlatform()
 {
     FT_Init_FreeType(&gPlatformFTLibrary);
-
-    mFonts.Init(200);
-    mFontAliases.Init(20);
-    mFontSubstitutes.Init(50);
-    mPrefFonts.Init(10);
-
-    UpdateFontList();
 }
 
 gfxAndroidPlatform::~gfxAndroidPlatform()
 {
     cairo_debug_reset_static_data();
 
     FT_Done_FreeType(gPlatformFTLibrary);
     gPlatformFTLibrary = NULL;
@@ -101,480 +71,61 @@ gfxAndroidPlatform::CreateOffscreenSurfa
     if (contentType == gfxImageSurface::CONTENT_COLOR)
         newSurface = new gfxImageSurface (size, GetOffscreenFormat());
     else
         newSurface = new gfxImageSurface (size, gfxASurface::FormatFromContent(contentType));
 
     return newSurface.forget();
 }
 
-struct FontListData {
-    FontListData(nsIAtom *aLangGroup, const nsACString& aGenericFamily, nsTArray<nsString>& aListOfFonts) :
-        mLangGroup(aLangGroup), mGenericFamily(aGenericFamily), mStringArray(aListOfFonts) {}
-    nsIAtom *mLangGroup;
-    const nsACString& mGenericFamily;
-    nsTArray<nsString>& mStringArray;
-};
-
-static PLDHashOperator
-FontListHashEnumFunc(nsStringHashKey::KeyType aKey,
-                     nsRefPtr<FontFamily>& aFontFamily,
-                     void* userArg)
-{
-    FontListData *data = (FontListData*)userArg;
-
-    // use the first variation for now.  This data should be the same
-    // for all the variations and should probably be moved up to
-    // the Family
-    gfxFontStyle style;
-    style.language = data->mLangGroup;
-    nsRefPtr<FontEntry> aFontEntry = aFontFamily->FindFontEntry(style);
-    NS_ASSERTION(aFontEntry, "couldn't find any font entry in family");
-    if (!aFontEntry)
-        return PL_DHASH_NEXT;
-
-
-    data->mStringArray.AppendElement(aFontFamily->Name());
-
-    return PL_DHASH_NEXT;
-}
-
 nsresult
 gfxAndroidPlatform::GetFontList(nsIAtom *aLangGroup,
                                 const nsACString& aGenericFamily,
                                 nsTArray<nsString>& aListOfFonts)
 {
-    FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
-
-    mFonts.Enumerate(FontListHashEnumFunc, &data);
-
-    aListOfFonts.Sort();
-    aListOfFonts.Compact();
-
+    gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup,
+                                                         aGenericFamily,
+                                                         aListOfFonts);
     return NS_OK;
 }
 
-class FontNameCache {
-public:
-    typedef nsAutoTArray<PRUint32, 8> IndexList;
-    PLDHashTableOps ops;
-    FontNameCache() : mWriteNeeded(PR_FALSE) {
-        ops = (PLDHashTableOps) {
-            PL_DHashAllocTable,
-            PL_DHashFreeTable,
-            StringHash,
-            HashMatchEntry,
-            MoveEntry,
-            PL_DHashClearEntryStub,
-            PL_DHashFinalizeStub,
-            NULL};
-        if (!PL_DHashTableInit(&mMap, &ops, nsnull,
-                               sizeof(FNCMapEntry), 0)) {
-            mMap.ops = nsnull;
-            LOG("initializing the map failed");
-        }
-        NS_ABORT_IF_FALSE(XRE_GetProcessType() == GeckoProcessType_Default,
-                          "StartupCacheFontNameCache should only be used in chrome procsess");
-        mCache = mozilla::scache::StartupCache::GetSingleton();
-        Init();
-    }
-
-    void Init()
-    {
-        if (!mMap.ops || !mCache)
-            return;
-        nsCAutoString prefName("font.cache");
-        PRUint32 size;
-        char* buf;
-        if (NS_FAILED(mCache->GetBuffer(prefName.get(), &buf, &size)))
-            return;
-
-        LOG("got: %s from the cache", nsDependentCString(buf, size).get());
-        char* entry = strtok(buf, ";");
-        while (entry) {
-            nsCString faceList, filename, indexes;
-            PRUint32 timestamp, fileSize;
-            filename.Assign(entry);
-            entry = strtok(NULL, ";");
-            if (!entry)
-                break;
-            faceList.Assign(entry);
-            entry = strtok(NULL, ";");
-            if (!entry)
-                break;
-            char* endptr;
-            timestamp = strtoul(entry, &endptr, 10);
-            if (*endptr != '\0')
-                break;
-            entry = strtok(NULL, ";");
-            if (!entry)
-                break;
-            fileSize = strtoul(entry, &endptr, 10);
-            if (*endptr != '\0')
-                break;
-            entry = strtok(NULL, ";");
-            if (!entry)
-                break;
-            indexes.Assign(entry);
-            FNCMapEntry* mapEntry =
-                static_cast<FNCMapEntry*>
-                (PL_DHashTableOperate(&mMap, filename.get(), PL_DHASH_ADD));
-            if (mapEntry) {
-                mapEntry->mFilename = filename;
-                mapEntry->mTimestamp = timestamp;
-                mapEntry->mFilesize = fileSize;
-                mapEntry->mFaces.AssignWithConversion(faceList);
-                mapEntry->mIndexes = indexes;
-            }
-            entry = strtok(NULL, ";");
-        }
-        free(buf);
-    }
-
-    virtual void
-    GetInfoForFile(nsCString& aFileName, nsAString& aFaceList,
-                   PRUint32 *aTimestamp, PRUint32 *aFileSize,
-                   IndexList &aIndexList)
-    {
-        if (!mMap.ops)
-            return;
-        PLDHashEntryHdr *hdr = PL_DHashTableOperate(&mMap, aFileName.get(), PL_DHASH_LOOKUP);
-        if (!hdr)
-            return;
-        FNCMapEntry* entry = static_cast<FNCMapEntry*>(hdr);
-        if (entry && entry->mTimestamp && entry->mFilesize) {
-            *aTimestamp = entry->mTimestamp;
-            *aFileSize = entry->mFilesize;
-            char* indexes = const_cast<char*>(entry->mIndexes.get());
-            char* endptr = indexes + 1;
-            unsigned long index = strtoul(indexes, &endptr, 10);
-            while (indexes < endptr && indexes[0] != '\0') {
-                aIndexList.AppendElement(index);
-                indexes = endptr + 1;
-            }
-            aFaceList.Assign(entry->mFaces);
-        }
-    }
-
-    virtual void
-    CacheFileInfo(nsCString& aFileName, nsAString& aFaceList,
-                  PRUint32 aTimestamp, PRUint32 aFileSize,
-                  IndexList &aIndexList)
-    {
-        if (!mMap.ops)
-            return;
-        FNCMapEntry* entry =
-            static_cast<FNCMapEntry*>
-            (PL_DHashTableOperate(&mMap, aFileName.get(), PL_DHASH_ADD));
-        if (entry) {
-            entry->mFilename = aFileName;
-            entry->mTimestamp = aTimestamp;
-            entry->mFilesize = aFileSize;
-            entry->mFaces.Assign(aFaceList);
-            for (PRUint32 i = 0; i < aIndexList.Length(); i++) {
-                entry->mIndexes.AppendInt(aIndexList[i]);
-                entry->mIndexes.Append(",");
-            }
-        }
-        mWriteNeeded = PR_TRUE;
-    }
-    ~FontNameCache() {
-        if (!mMap.ops)
-            return;
-
-        if (!mWriteNeeded || !mCache) {
-            PL_DHashTableFinish(&mMap);
-            return;
-        }
-
-        nsCAutoString buf;
-        PL_DHashTableEnumerate(&mMap, WriteOutMap, &buf);
-        PL_DHashTableFinish(&mMap);
-        nsCAutoString prefName("font.cache");
-        mCache->PutBuffer(prefName.get(), buf.get(), buf.Length() + 1);
-    }
-private:
-    mozilla::scache::StartupCache* mCache;
-    PLDHashTable mMap;
-    PRBool mWriteNeeded;
-
-    static PLDHashOperator WriteOutMap(PLDHashTable *aTable,
-                                       PLDHashEntryHdr *aHdr,
-                                       PRUint32 aNumber, void *aData)
-    {
-        nsCAutoString* buf = (nsCAutoString*)aData;
-        FNCMapEntry* entry = static_cast<FNCMapEntry*>(aHdr);
-
-        buf->Append(entry->mFilename);
-        buf->Append(";");
-        buf->AppendWithConversion(entry->mFaces);
-        buf->Append(";");
-        buf->AppendInt(entry->mTimestamp);
-        buf->Append(";");
-        buf->AppendInt(entry->mFilesize);
-        buf->Append(";");
-        buf->Append(entry->mIndexes);
-        buf->Append(";");
-
-        return PL_DHASH_NEXT;
-    }
-
-    typedef struct : public PLDHashEntryHdr {
-    public:
-        nsCString mFilename;
-        PRUint32 mTimestamp;
-        PRUint32 mFilesize;
-        nsString mFaces;
-        nsCString mIndexes;
-    } FNCMapEntry;
-
-
-    static PLDHashNumber StringHash(PLDHashTable *table, const void *key) {
-        PLDHashNumber h = 0;
-        for (const char *s = reinterpret_cast<const char*>(key); *s; ++s)
-            h = PR_ROTATE_LEFT32(h, 4) ^ NS_ToLower(*s);
-        return h;
-    }
-
-    static PRBool HashMatchEntry(PLDHashTable *table,
-                                 const PLDHashEntryHdr *aHdr, const void *key)
-    {
-        const FNCMapEntry* entry =
-            static_cast<const FNCMapEntry*>(aHdr);
-        return entry->mFilename.Equals((char*)key);
-    }
-
-    static void MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *aFrom,
-                          PLDHashEntryHdr *aTo)
-    {
-        FNCMapEntry* to =
-            static_cast<FNCMapEntry*>(aTo);
-        const FNCMapEntry* from =
-            static_cast<const FNCMapEntry*>(aFrom);
-        to->mFilename.Assign(from->mFilename);
-        to->mTimestamp = from->mTimestamp;
-        to->mFilesize = from->mFilesize;
-        to->mFaces.Assign(from->mFaces);
-        to->mIndexes.Assign(from->mIndexes);
-    }
-
-};
-
-void
-gfxAndroidPlatform::AppendFacesFromFontFile(const char *aFileName, FontNameCache* aFontCache, InfallibleTArray<FontListEntry>* aFontList)
-{
-    nsString faceList;
-    PRUint32 timestamp = 0;
-    PRUint32 filesize = 0;
-    FontNameCache::IndexList indexList;
-    nsCString fileName(aFileName);
-    if (aFontCache)
-        aFontCache->GetInfoForFile(fileName, faceList, &timestamp, &filesize, indexList);
-    struct stat s;
-    int stat_ret = stat(aFileName, &s);
-    if (!faceList.IsEmpty() && indexList.Length() && 0 == stat_ret &&
-        s.st_mtime == timestamp && s.st_size == filesize) {
-        PRInt32 beginning = 0;
-        PRInt32 end = faceList.Find(",", PR_TRUE, beginning, -1);
-        for (PRUint32 i = 0; i < indexList.Length() && end != kNotFound; i++) {
-            nsDependentSubstring name(faceList, beginning, end);
-            ToLowerCase(name);
-            FontListEntry fle(NS_ConvertUTF16toUTF8(name), fileName,
-                              indexList[i]);
-            aFontList->AppendElement(fle);
-            beginning = end + 1;
-            end = faceList.Find(",", PR_TRUE, beginning, -1);
-        }
-        return;
-    }
-
-    faceList.AssignLiteral("");
-    timestamp = s.st_mtime;
-    filesize = s.st_size;
-    FT_Face dummy;
-    if (FT_Err_Ok == FT_New_Face(GetFTLibrary(), aFileName, -1, &dummy)) {
-        for (FT_Long i = 0; i < dummy->num_faces; i++) {
-            FT_Face face;
-            if (FT_Err_Ok != FT_New_Face(GetFTLibrary(), aFileName,
-                                         i, &face))
-                continue;
-            nsDependentCString name(face->family_name);
-            ToLowerCase(name);
-
-            nsRefPtr<FontFamily> ff;
-            faceList.AppendWithConversion(name);
-            faceList.AppendLiteral(",");
-            indexList.AppendElement(i);
-            ToLowerCase(name);
-            FontListEntry fle(name, fileName, i);
-            aFontList->AppendElement(fle);
-        }
-        FT_Done_Face(dummy);
-        if (aFontCache && 0 == stat_ret)
-            aFontCache->CacheFileInfo(fileName, faceList, timestamp, filesize, indexList);
-    }
-}
-
-void
-gfxAndroidPlatform::FindFontsInDirectory(const nsCString& aFontsDir,
-                                         FontNameCache* aFontCache)
-{
-    static const char* sStandardFonts[] = {
-        "DroidSans.ttf",
-        "DroidSans-Bold.ttf",
-        "DroidSerif-Regular.ttf",
-        "DroidSerif-Bold.ttf",
-        "DroidSerif-Italic.ttf",
-        "DroidSerif-BoldItalic.ttf",
-        "DroidSansMono.ttf",
-        "DroidSansArabic.ttf",
-        "DroidSansHebrew.ttf",
-        "DroidSansThai.ttf",
-        "MTLmr3m.ttf",
-        "MTLc3m.ttf",
-        "DroidSansJapanese.ttf",
-        "DroidSansFallback.ttf"
-    };
-
-    DIR *d = opendir(aFontsDir.get());
-    struct dirent *ent = NULL;
-    while(d && (ent = readdir(d)) != NULL) {
-        int namelen = strlen(ent->d_name);
-        if (namelen > 4 &&
-            strcasecmp(ent->d_name + namelen - 4, ".ttf") == 0)
-        {
-            bool isStdFont = false;
-            for (unsigned int i = 0; i < NS_ARRAY_LENGTH(sStandardFonts) && !isStdFont; i++) {
-                isStdFont = strcmp(sStandardFonts[i], ent->d_name) == 0;
-            }
-            if (!isStdFont) {
-                nsCString s(aFontsDir);
-                s.Append(nsDependentCString(ent->d_name));
-
-                AppendFacesFromFontFile(s.get(), aFontCache, &mFontList);
-            }
-        }
-    }
-    closedir(d);
-    for (unsigned int i = 0; i < NS_ARRAY_LENGTH(sStandardFonts); i++) {
-        nsCString s(aFontsDir);
-        s.Append(nsDependentCString(sStandardFonts[i]));
-
-        AppendFacesFromFontFile(s.get(), aFontCache, &mFontList);
-    }
-}
-
 void
 gfxAndroidPlatform::GetFontList(InfallibleTArray<FontListEntry>* retValue)
 {
-    if (XRE_GetProcessType() != GeckoProcessType_Default) {
-        mozilla::dom::ContentChild::GetSingleton()->SendReadFontList(retValue);
-        return;
-    }
-
-    if (mFontList.Length() > 0) {
-        *retValue = mFontList;
-        return;
-    }
-
-    // ANDROID_ROOT is the root of the android system, typically /system
-    // font files are in /$ANDROID_ROOT/fonts/
-    FontNameCache fnc;
-    FindFontsInDirectory(NS_LITERAL_CSTRING("/system/fonts/"), &fnc);
-    char *androidRoot = PR_GetEnv("ANDROID_ROOT");
-    if (androidRoot && strcmp(androidRoot, "/system")) {
-        nsCString root(androidRoot);
-        root.Append("/fonts/");
-        FindFontsInDirectory(root, &fnc);
-    }
-
-    *retValue = mFontList;
+    gfxFT2FontList::PlatformFontList()->GetFontList(retValue);
 }
 
 nsresult
 gfxAndroidPlatform::UpdateFontList()
 {
-    gfxFontCache *fc = gfxFontCache::GetCache();
-    if (fc)
-        fc->AgeAllGenerations();
-    mFonts.Clear();
-    mFontAliases.Clear();
-    mFontSubstitutes.Clear();
-    mPrefFonts.Clear();
-    mCodepointsWithNoFonts.reset();
-
-    InfallibleTArray<FontListEntry> fontList;
-    GetFontList(&fontList);
-    for (PRUint32 i = 0; i < fontList.Length(); i++) {
-        NS_ConvertUTF8toUTF16 name(fontList[i].familyName());
-        nsRefPtr<FontFamily> ff;
-        if (!mFonts.Get(name, &ff)) {
-            ff = new FontFamily(name);
-            mFonts.Put(name, ff);
-        }
-        ff->AddFontFileAndIndex(fontList[i].filepath(), fontList[i].index());
-    }
-
-    // initialize the cmap loading process after font list has been initialized
-    //StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps);
-
-    // initialize ranges of characters for which system-wide font search should be skipped
-    mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
-    mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
-
+    gfxPlatformFontList::PlatformFontList()->UpdateFontList();
     return NS_OK;
 }
 
 nsresult
 gfxAndroidPlatform::ResolveFontName(const nsAString& aFontName,
                                     FontResolverCallback aCallback,
                                     void *aClosure,
                                     PRBool& aAborted)
 {
-    if (aFontName.IsEmpty())
-        return NS_ERROR_FAILURE;
-
     nsAutoString resolvedName;
-    gfxPlatformFontList* platformFontList = gfxPlatformFontList::PlatformFontList();
-    if (platformFontList) {
-        if (!platformFontList->ResolveFontName(aFontName, resolvedName)) {
-            aAborted = PR_FALSE;
-            return NS_OK;
-        }
+    if (!gfxPlatformFontList::PlatformFontList()->
+             ResolveFontName(aFontName, resolvedName)) {
+        aAborted = PR_FALSE;
+        return NS_OK;
     }
-
-    nsAutoString keyName(aFontName);
-    ToLowerCase(keyName);
-
-    nsRefPtr<FontFamily> ff;
-    if (mFonts.Get(keyName, &ff) ||
-        mFontSubstitutes.Get(keyName, &ff) ||
-        mFontAliases.Get(keyName, &ff))
-    {
-        aAborted = !(*aCallback)(ff->Name(), aClosure);
-    } else {
-        aAborted = PR_FALSE;
-    }
-
+    aAborted = !(*aCallback)(resolvedName, aClosure);
     return NS_OK;
 }
 
-static PRBool SimpleResolverCallback(const nsAString& aName, void* aClosure)
-{
-    nsString *result = static_cast<nsString*>(aClosure);
-    result->Assign(aName);
-    return PR_FALSE;
-}
-
 nsresult
 gfxAndroidPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
-    aFamilyName.Truncate();
-    PRBool aborted;
-    return ResolveFontName(aFontName, SimpleResolverCallback, &aFamilyName, aborted);
+    gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
+    return NS_OK;
 }
 
 gfxPlatformFontList*
 gfxAndroidPlatform::CreatePlatformFontList()
 {
     gfxPlatformFontList* list = new gfxFT2FontList();
     if (NS_SUCCEEDED(list->InitFontList())) {
         return list;
@@ -606,99 +157,26 @@ gfxAndroidPlatform::IsFontFormatSupporte
     return PR_TRUE;
 }
 
 gfxFontGroup *
 gfxAndroidPlatform::CreateFontGroup(const nsAString &aFamilies,
                                const gfxFontStyle *aStyle,
                                gfxUserFontSet* aUserFontSet)
 {
-    return new gfxFT2FontGroup(aFamilies, aStyle, aUserFontSet);
+    return new gfxFontGroup(aFamilies, aStyle, aUserFontSet);
 }
 
 FT_Library
 gfxAndroidPlatform::GetFTLibrary()
 {
     return gPlatformFTLibrary;
 }
 
-FontFamily *
-gfxAndroidPlatform::FindFontFamily(const nsAString& aName)
-{
-    nsAutoString name(aName);
-    ToLowerCase(name);
-
-    nsRefPtr<FontFamily> ff;
-    if (!mFonts.Get(name, &ff) &&
-        !mFontSubstitutes.Get(name, &ff) &&
-        !mFontAliases.Get(name, &ff)) {
-        return nsnull;
-    }
-    return ff.get();
-}
-
-FontEntry *
-gfxAndroidPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle)
-{
-    nsRefPtr<FontFamily> ff = FindFontFamily(aName);
-    if (!ff)
-        return nsnull;
-
-    return ff->FindFontEntry(aFontStyle);
-}
-
-static PLDHashOperator
-FindFontForCharProc(nsStringHashKey::KeyType aKey,
-                    nsRefPtr<FontFamily>& aFontFamily,
-                    void* aUserArg)
-{
-    FontSearch *data = (FontSearch*)aUserArg;
-    aFontFamily->FindFontForChar(data);
-    return PL_DHASH_NEXT;
-}
-
-already_AddRefed<gfxFont>
-gfxAndroidPlatform::FindFontForChar(PRUint32 aCh, gfxFont *aFont)
-{
-    // is codepoint with no matching font? return null immediately
-    if (mCodepointsWithNoFonts.test(aCh)) {
-        return nsnull;
-    }
-
-    FontSearch data(aCh, aFont);
-
-    // find fonts that support the character
-    mFonts.Enumerate(FindFontForCharProc, &data);
-
-    if (data.mBestMatch) {
-        nsRefPtr<gfxFT2Font> font =
-            gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()),
-                                      aFont->GetStyle());
-        gfxFont* ret = font.forget().get();
-        return already_AddRefed<gfxFont>(ret);
-    }
-
-    // no match? add to set of non-matching codepoints
-    mCodepointsWithNoFonts.set(aCh);
-
-    return nsnull;
-}
-
 gfxFontEntry* 
 gfxAndroidPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                      const PRUint8 *aFontData, PRUint32 aLength)
 {
     return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry,
                                                                      aFontData,
                                                                      aLength);
 }
 
-PRBool
-gfxAndroidPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> > *aFontEntryList)
-{
-    return mPrefFonts.Get(aKey, aFontEntryList);
-}
-
-void
-gfxAndroidPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList)
-{
-    mPrefFonts.Put(aKey, aFontEntryList);
-}
--- a/gfx/thebes/gfxAndroidPlatform.h
+++ b/gfx/thebes/gfxAndroidPlatform.h
@@ -34,93 +34,61 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef GFX_PLATFORM_ANDROID_H
 #define GFX_PLATFORM_ANDROID_H
 
-#include "gfxFontUtils.h"
 #include "gfxFT2Fonts.h"
 #include "gfxPlatform.h"
-#include "nsDataHashtable.h"
+#include "gfxUserFontSet.h"
 #include "nsTArray.h"
 
 typedef struct FT_LibraryRec_ *FT_Library;
 
-class FontFamily;
-class FontEntry;
-namespace mozilla {
-    namespace dom {
-        class FontListEntry;
-    };
-};
-
-using namespace mozilla;
-using namespace dom;
-
-class FontNameCache;
-
 class THEBES_API gfxAndroidPlatform : public gfxPlatform {
 public:
     gfxAndroidPlatform();
     virtual ~gfxAndroidPlatform();
 
     static gfxAndroidPlatform *GetPlatform() {
         return (gfxAndroidPlatform*) gfxPlatform::GetPlatform();
     }
 
+    virtual already_AddRefed<gfxASurface>
+    CreateOffscreenSurface(const gfxIntSize& size,
+                           gfxASurface::gfxContentType contentType);
+
+    virtual gfxImageFormat GetOffscreenFormat() { return gfxASurface::ImageFormatRGB16_565; }
+
+    // to support IPC font list (sharing between chrome and content)
     void GetFontList(InfallibleTArray<FontListEntry>* retValue);
 
-    already_AddRefed<gfxASurface> CreateOffscreenSurface(const gfxIntSize& size,
-                                                         gfxASurface::gfxContentType contentType);
-
+    // platform implementations of font functions
     virtual PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags);
     virtual gfxPlatformFontList* CreatePlatformFontList();
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
-                                     const PRUint8 *aFontData, PRUint32 aLength);
-
-    nsresult GetFontList(nsIAtom *aLangGroup,
-                         const nsACString& aGenericFamily,
-                         nsTArray<nsString>& aListOfFonts);
+                                           const PRUint8 *aFontData, PRUint32 aLength);
 
-    nsresult UpdateFontList();
+    virtual nsresult GetFontList(nsIAtom *aLangGroup,
+                                 const nsACString& aGenericFamily,
+                                 nsTArray<nsString>& aListOfFonts);
 
-    nsresult ResolveFontName(const nsAString& aFontName,
-                             FontResolverCallback aCallback,
-                             void *aClosure, PRBool& aAborted);
+    virtual nsresult UpdateFontList();
 
-    nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
-
-    gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
-                                  const gfxFontStyle *aStyle,
-                                  gfxUserFontSet* aUserFontSet);
+    virtual nsresult ResolveFontName(const nsAString& aFontName,
+                                     FontResolverCallback aCallback,
+                                     void *aClosure, PRBool& aAborted);
 
-    FontFamily *FindFontFamily(const nsAString& aName);
-    FontEntry *FindFontEntry(const nsAString& aFamilyName, const gfxFontStyle& aFontStyle);
-    already_AddRefed<gfxFont> FindFontForChar(PRUint32 aCh, gfxFont *aFont);
-    PRBool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> > *aFontEntryList);
-    void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList);
+    virtual nsresult GetStandardFamilyName(const nsAString& aFontName,
+                                           nsAString& aFamilyName);
+
+    virtual gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
+                                          const gfxFontStyle *aStyle,
+                                          gfxUserFontSet* aUserFontSet);
 
     FT_Library GetFTLibrary();
-
-    virtual gfxImageFormat GetOffscreenFormat() { return gfxASurface::ImageFormatRGB16_565; }
-
-protected:
-    void AppendFacesFromFontFile(const char *aFileName, FontNameCache* aFontCache, InfallibleTArray<FontListEntry>* retValue);
-    void FindFontsInDirectory(const nsCString& aFontsDir, FontNameCache* aFontCache);
-
-    typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
-
-    FontTable mFonts;
-    FontTable mFontAliases;
-    FontTable mFontSubstitutes;
-    InfallibleTArray<FontListEntry> mFontList;
-
-    // when system-wide font lookup fails for a character, cache it to skip future searches
-    gfxSparseBitSet mCodepointsWithNoFonts;
-    
-    nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
 };
 
 #endif /* GFX_PLATFORM_ANDROID_H */
 
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -34,16 +34,26 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#ifdef ANDROID
+#include "mozilla/dom/ContentChild.h"
+#include "nsXULAppAPI.h"
+
+#include "gfxAndroidPlatform.h"
+#include <dirent.h>
+#include <android/log.h>
+#define ALOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gecko" , ## args)
+#endif
+
 #include "gfxFT2FontList.h"
 #include "gfxUserFontSet.h"
 #include "gfxFontUtils.h"
 
 #include "ft2build.h"
 #include FT_FREETYPE_H
 #include "gfxFT2Fonts.h"
 
@@ -51,120 +61,430 @@
 #include "nsTArray.h"
 #include "nsUnicharUtils.h"
 
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsISimpleEnumerator.h"
 
+#include "mozilla/scache/StartupCache.h"
+#include <sys/stat.h>
+
 #ifdef XP_WIN
 #include "nsIWindowsRegKey.h"
 #include <windows.h>
 #endif
 
-#define ROUND(x) floor((x) + 0.5)
-
 #ifdef PR_LOGGING
 static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
 #endif /* PR_LOGGING */
 
-#ifdef ANDROID
-#include "gfxAndroidPlatform.h"
-#include <dirent.h>
-#include <android/log.h>
-#define ALOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gecko" , ## args)
-
-#endif
 #define LOG(args) PR_LOG(gFontInfoLog, PR_LOG_DEBUG, args)
 #define LOG_ENABLED() PR_LOG_TEST(gFontInfoLog, PR_LOG_DEBUG)
 
 static __inline void
 BuildKeyNameFromFontName(nsAString &aName)
 {
 #ifdef XP_WIN
     if (aName.Length() >= LF_FACESIZE)
         aName.Truncate(LF_FACESIZE - 1);
 #endif
     ToLowerCase(aName);
 }
 
+#define CACHE_KEY "font.cached-list"
+
+class FontNameCache {
+public:
+    FontNameCache()
+        : mWriteNeeded(PR_FALSE)
+    {
+        mOps = (PLDHashTableOps) {
+            PL_DHashAllocTable,
+            PL_DHashFreeTable,
+            StringHash,
+            HashMatchEntry,
+            MoveEntry,
+            PL_DHashClearEntryStub,
+            PL_DHashFinalizeStub,
+            NULL
+        };
+
+        if (!PL_DHashTableInit(&mMap, &mOps, nsnull,
+                               sizeof(FNCMapEntry), 0))
+        {
+            mMap.ops = nsnull;
+            LOG(("initializing the map failed"));
+        }
+
+        NS_ABORT_IF_FALSE(XRE_GetProcessType() == GeckoProcessType_Default,
+                          "StartupCacheFontNameCache should only be used in chrome process");
+        mCache = mozilla::scache::StartupCache::GetSingleton();
+
+        Init();
+    }
+
+    ~FontNameCache()
+    {
+        if (!mMap.ops) {
+            return;
+        }
+        if (!mWriteNeeded || !mCache) {
+            PL_DHashTableFinish(&mMap);
+            return;
+        }
+
+        nsCAutoString buf;
+        PL_DHashTableEnumerate(&mMap, WriteOutMap, &buf);
+        PL_DHashTableFinish(&mMap);
+        mCache->PutBuffer(CACHE_KEY, buf.get(), buf.Length() + 1);
+    }
+
+    void Init()
+    {
+        if (!mMap.ops || !mCache) {
+            return;
+        }
+        PRUint32 size;
+        char* buf;
+        if (NS_FAILED(mCache->GetBuffer(CACHE_KEY, &buf, &size))) {
+            return;
+        }
+
+        LOG(("got: %s from the cache", nsDependentCString(buf, size).get()));
+
+        const char* beginning = buf;
+        const char* end = strchr(beginning, ';');
+        while (end) {
+            nsCString filename(beginning, end - beginning);
+            beginning = end + 1;
+            if (!(end = strchr(beginning, ';'))) {
+                break;
+            }
+            nsCString faceList(beginning, end - beginning);
+            beginning = end + 1;
+            if (!(end = strchr(beginning, ';'))) {
+                break;
+            }
+            PRUint32 timestamp = strtoul(beginning, NULL, 10);
+            beginning = end + 1;
+            if (!(end = strchr(beginning, ';'))) {
+                break;
+            }
+            PRUint32 filesize = strtoul(beginning, NULL, 10);
+
+            FNCMapEntry* mapEntry =
+                static_cast<FNCMapEntry*>
+                (PL_DHashTableOperate(&mMap, filename.get(), PL_DHASH_ADD));
+            if (mapEntry) {
+                mapEntry->mFilename.Assign(filename);
+                mapEntry->mTimestamp = timestamp;
+                mapEntry->mFilesize = filesize;
+                mapEntry->mFaces.Assign(faceList);
+                // entries from the startupcache are marked "non-existing"
+                // until we have confirmed that the file still exists
+                mapEntry->mFileExists = PR_FALSE;
+            }
+
+            beginning = end + 1;
+            end = strchr(beginning, ';');
+        }
+
+        // Should we use free() or delete[] here? See bug 684700.
+        free(buf);
+    }
+
+    virtual void
+    GetInfoForFile(nsCString& aFileName, nsCString& aFaceList,
+                   PRUint32 *aTimestamp, PRUint32 *aFilesize)
+    {
+        if (!mMap.ops) {
+            return;
+        }
+        PLDHashEntryHdr *hdr =
+            PL_DHashTableOperate(&mMap, aFileName.get(), PL_DHASH_LOOKUP);
+        if (!hdr) {
+            return;
+        }
+        FNCMapEntry* entry = static_cast<FNCMapEntry*>(hdr);
+        if (entry && entry->mTimestamp && entry->mFilesize) {
+            *aTimestamp = entry->mTimestamp;
+            *aFilesize = entry->mFilesize;
+            aFaceList.Assign(entry->mFaces);
+            // this entry does correspond to an existing file
+            // (although it might not be up-to-date, in which case
+            // it will get overwritten via CacheFileInfo)
+            entry->mFileExists = PR_TRUE;
+        }
+    }
+
+    virtual void
+    CacheFileInfo(nsCString& aFileName, nsCString& aFaceList,
+                  PRUint32 aTimestamp, PRUint32 aFilesize)
+    {
+        if (!mMap.ops) {
+            return;
+        }
+        FNCMapEntry* entry =
+            static_cast<FNCMapEntry*>
+            (PL_DHashTableOperate(&mMap, aFileName.get(), PL_DHASH_ADD));
+        if (entry) {
+            entry->mFilename.Assign(aFileName);
+            entry->mTimestamp = aTimestamp;
+            entry->mFilesize = aFilesize;
+            entry->mFaces.Assign(aFaceList);
+            entry->mFileExists = PR_TRUE;
+        }
+        mWriteNeeded = PR_TRUE;
+    }
+
+private:
+    mozilla::scache::StartupCache* mCache;
+    PLDHashTable mMap;
+    PRBool mWriteNeeded;
+
+    PLDHashTableOps mOps;
+
+    static PLDHashOperator WriteOutMap(PLDHashTable *aTable,
+                                       PLDHashEntryHdr *aHdr,
+                                       PRUint32 aNumber, void *aData)
+    {
+        FNCMapEntry* entry = static_cast<FNCMapEntry*>(aHdr);
+        if (!entry->mFileExists) {
+            // skip writing entries for files that are no longer present
+            return PL_DHASH_NEXT;
+        }
+
+        nsCAutoString* buf = reinterpret_cast<nsCAutoString*>(aData);
+        buf->Append(entry->mFilename);
+        buf->Append(';');
+        buf->Append(entry->mFaces);
+        buf->Append(';');
+        buf->AppendInt(entry->mTimestamp);
+        buf->Append(';');
+        buf->AppendInt(entry->mFilesize);
+        buf->Append(';');
+        return PL_DHASH_NEXT;
+    }
+
+    typedef struct : public PLDHashEntryHdr {
+    public:
+        nsCString mFilename;
+        PRUint32  mTimestamp;
+        PRUint32  mFilesize;
+        nsCString mFaces;
+        PRBool    mFileExists;
+    } FNCMapEntry;
+
+    static PLDHashNumber StringHash(PLDHashTable *table, const void *key)
+    {
+        return HashString(reinterpret_cast<const char*>(key));
+    }
+
+    static PRBool HashMatchEntry(PLDHashTable *table,
+                                 const PLDHashEntryHdr *aHdr, const void *key)
+    {
+        const FNCMapEntry* entry =
+            static_cast<const FNCMapEntry*>(aHdr);
+        return entry->mFilename.Equals(reinterpret_cast<const char*>(key));
+    }
+
+    static void MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *aFrom,
+                          PLDHashEntryHdr *aTo)
+    {
+        FNCMapEntry* to = static_cast<FNCMapEntry*>(aTo);
+        const FNCMapEntry* from = static_cast<const FNCMapEntry*>(aFrom);
+        to->mFilename.Assign(from->mFilename);
+        to->mTimestamp = from->mTimestamp;
+        to->mFilesize = from->mFilesize;
+        to->mFaces.Assign(from->mFaces);
+        to->mFileExists = from->mFileExists;
+    }
+};
+
 /***************************************************************
  *
  * gfxFT2FontList
  *
  */
 
-// For Mobile, we use gfxFT2Fonts, and we build the font list by directly scanning
-// the system's Fonts directory for OpenType and TrueType files.
+// For Mobile, we use gfxFT2Fonts, and we build the font list by directly
+// scanning the system's Fonts directory for OpenType and TrueType files.
 //
-// FontEntry is currently defined in gfxFT2Fonts.h, but will probably be moved here
-// as part of the Freetype/Linux font restructuring for Harfbuzz integration.
-//
-// TODO: investigate startup performance - we might be able to improve by avoiding
-// the creation of FT_Faces here, and just reading names directly from the file;
-// or even consider caching a mapping from font family name to (list of) filenames,
-// so that we don't have to scan all the files before we can do any font lookups.
+// FontEntry is currently defined in gfxFT2Fonts.h, but should probably be
+// moved here for consistency with other platform implementations, and
+// because it logically "belongs" to the fontlist that manages the families
+// and entries.
 
 gfxFT2FontList::gfxFT2FontList()
 {
 }
 
 void
-gfxFT2FontList::AppendFacesFromFontFile(const PRUnichar *aFileName)
+gfxFT2FontList::AppendFacesFromCachedFaceList(nsCString& aFileName,
+                                              PRBool aStdFile,
+                                              nsCString& aFaceList)
 {
-    AppendFacesFromFontFile(NS_ConvertUTF16toUTF8(aFileName).get());
+    const char *beginning = aFaceList.get();
+    const char *end = strchr(beginning, ',');
+    while (end) {
+        nsString familyName =
+            NS_ConvertUTF8toUTF16(beginning, end - beginning);
+        ToLowerCase(familyName);
+        beginning = end + 1;
+        if (!(end = strchr(beginning, ','))) {
+            break;
+        }
+        nsString faceName =
+            NS_ConvertUTF8toUTF16(beginning, end - beginning);
+        beginning = end + 1;
+        if (!(end = strchr(beginning, ','))) {
+            break;
+        }
+        PRUint32 index = strtoul(beginning, NULL, 10);
+        beginning = end + 1;
+        if (!(end = strchr(beginning, ','))) {
+            break;
+        }
+        PRBool italic = (*beginning != '0');
+        beginning = end + 1;
+        if (!(end = strchr(beginning, ','))) {
+            break;
+        }
+        PRUint32 weight = strtoul(beginning, NULL, 10);
+        beginning = end + 1;
+        if (!(end = strchr(beginning, ','))) {
+            break;
+        }
+        PRInt32 stretch = strtol(beginning, NULL, 10);
+
+        FontListEntry fle(familyName, faceName, aFileName,
+                          weight, stretch, italic, index);
+        AppendFaceFromFontListEntry(fle, aStdFile);
+
+        beginning = end + 1;
+        end = strchr(beginning, ',');
+    }
+}
+
+static void
+AppendToFaceList(nsCString& aFaceList,
+                 nsAString& aFamilyName, FontEntry* aFontEntry)
+{
+    aFaceList.Append(NS_ConvertUTF16toUTF8(aFamilyName));
+    aFaceList.Append(',');
+    aFaceList.Append(NS_ConvertUTF16toUTF8(aFontEntry->Name()));
+    aFaceList.Append(',');
+    aFaceList.AppendInt(aFontEntry->mFTFontIndex);
+    aFaceList.Append(',');
+    aFaceList.Append(aFontEntry->IsItalic() ? '1' : '0');
+    aFaceList.Append(',');
+    aFaceList.AppendInt(aFontEntry->Weight());
+    aFaceList.Append(',');
+    aFaceList.AppendInt(aFontEntry->Stretch());
+    aFaceList.Append(',');
 }
 
 void
-gfxFT2FontList::AppendFacesFromFontFile(const char *aFileName)
+gfxFT2FontList::AppendFacesFromFontFile(nsCString& aFileName,
+                                        PRBool aStdFile,
+                                        FontNameCache *aCache)
 {
+    nsCString faceList;
+    PRUint32 filesize = 0, timestamp = 0;
+    if (aCache) {
+        aCache->GetInfoForFile(aFileName, faceList, &timestamp, &filesize);
+    }
+
+    struct stat s;
+    int statRetval = stat(aFileName.get(), &s);
+    if (!faceList.IsEmpty() && 0 == statRetval &&
+        s.st_mtime == timestamp && s.st_size == filesize)
+    {
+        LOG(("using cached font info for %s", aFileName.get()));
+        AppendFacesFromCachedFaceList(aFileName, aStdFile, faceList);
+        return;
+    }
+
 #ifdef XP_WIN
     FT_Library ftLibrary = gfxWindowsPlatform::GetPlatform()->GetFTLibrary();
 #elif defined(ANDROID)
     FT_Library ftLibrary = gfxAndroidPlatform::GetPlatform()->GetFTLibrary();
 #endif
     FT_Face dummy;
-    if (FT_Err_Ok == FT_New_Face(ftLibrary, aFileName, -1, &dummy)) {
+    if (FT_Err_Ok == FT_New_Face(ftLibrary, aFileName.get(), -1, &dummy)) {
+        LOG(("reading font info via FreeType for %s", aFileName.get()));
+        nsCString faceList;
+        timestamp = s.st_mtime;
+        filesize = s.st_size;
         for (FT_Long i = 0; i < dummy->num_faces; i++) {
             FT_Face face;
-            if (FT_Err_Ok != FT_New_Face(ftLibrary, aFileName, i, &face))
+            if (FT_Err_Ok != FT_New_Face(ftLibrary, aFileName.get(), i, &face)) {
                 continue;
+            }
 
-            FontEntry* fe = FontEntry::CreateFontEntryFromFace(face);
+            FontEntry* fe = FontEntry::CreateFontEntry(face, aFileName.get(), i);
             if (fe) {
                 NS_ConvertUTF8toUTF16 name(face->family_name);
                 BuildKeyNameFromFontName(name);       
                 gfxFontFamily *family = mFontFamilies.GetWeak(name);
                 if (!family) {
                     family = new gfxFontFamily(name);
                     mFontFamilies.Put(name, family);
-                    if (mBadUnderlineFamilyNames.Contains(name))
+                    if (mBadUnderlineFamilyNames.Contains(name)) {
                         family->SetBadUnderlineFamily();
+                    }
                 }
+                fe->mStandardFace = aStdFile;
                 family->AddFontEntry(fe);
-                family->SetHasStyles(PR_TRUE);
-                if (family->IsBadUnderlineFamily())
+                if (family->IsBadUnderlineFamily()) {
                     fe->mIsBadUnderlineFont = PR_TRUE;
+                }
+                AppendToFaceList(faceList, name, fe);
 #ifdef PR_LOGGING
                 if (LOG_ENABLED()) {
                     LOG(("(fontinit) added (%s) to family (%s)"
                          " with style: %s weight: %d stretch: %d",
                          NS_ConvertUTF16toUTF8(fe->Name()).get(), 
                          NS_ConvertUTF16toUTF8(family->Name()).get(), 
                          fe->IsItalic() ? "italic" : "normal",
                          fe->Weight(), fe->Stretch()));
                 }
 #endif
             }
         }
         FT_Done_Face(dummy);
+        if (aCache && 0 == statRetval && !faceList.IsEmpty()) {
+            aCache->CacheFileInfo(aFileName, faceList, timestamp, filesize);
+        }
     }
 }
 
+// Called on each family after all fonts are added to the list;
+// this will sort faces to give priority to "standard" font files
+// if aUserArg is non-null (i.e. we're using it as a boolean flag)
+static PLDHashOperator
+FinalizeFamilyMemberList(nsStringHashKey::KeyType aKey,
+                         nsRefPtr<gfxFontFamily>& aFamily,
+                         void* aUserArg)
+{
+    gfxFontFamily *family = aFamily.get();
+    PRBool sortFaces = (aUserArg != nsnull);
+
+    family->SetHasStyles(PR_TRUE);
+
+    if (sortFaces) {
+        family->SortAvailableFonts();
+    }
+    family->CheckForSimpleFamily();
+
+    return PL_DHASH_NEXT;
+}
+
 void
 gfxFT2FontList::FindFonts()
 {
 #ifdef XP_WIN
     nsTArray<nsString> searchPaths(3);
     nsTArray<nsString> fontPatterns(3);
     fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.ttf"));
     fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.ttc"));
@@ -194,53 +514,168 @@ gfxFT2FontList::FindFonts()
                                              FindExSearchNameMatch,
                                              NULL,
                                              0);
             PRBool moreFiles = handle != INVALID_HANDLE_VALUE;
             while (moreFiles) {
                 nsAutoString filePath(path);
                 filePath.AppendLiteral("\\");
                 filePath.Append(results.cFileName);
-                AppendFacesFromFontFile(static_cast<const PRUnichar*>(filePath.get()));
+                AppendFacesFromFontFile(NS_ConvertUTF16toUTF8(filePath));
                 moreFiles = FindNextFile(handle, &results);
             }
             if (handle != INVALID_HANDLE_VALUE)
                 FindClose(handle);
         }
     }
 #elif defined(ANDROID)
     gfxFontCache *fc = gfxFontCache::GetCache();
     if (fc)
         fc->AgeAllGenerations();
     mPrefFonts.Clear();
     mCodepointsWithNoFonts.reset();
 
-    DIR *d = opendir("/system/fonts");
-    struct dirent *ent = NULL;
-    while(d && (ent = readdir(d)) != NULL) {
-        int namelen = strlen(ent->d_name);
-        if (namelen > 4 &&
-            strcasecmp(ent->d_name + namelen - 4, ".ttf") == 0)
-        {
-            nsCString s("/system/fonts");
-            s.Append("/");
-            s.Append(nsDependentCString(ent->d_name));
-
-            AppendFacesFromFontFile(nsPromiseFlatCString(s).get());
-        }
-    }
-    if (d) {
-      closedir(d);
-    }
     mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
     mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
 
+    if (XRE_GetProcessType() != GeckoProcessType_Default) {
+        // Content process: ask the Chrome process to give us the list
+        InfallibleTArray<FontListEntry> fonts;
+        mozilla::dom::ContentChild::GetSingleton()->SendReadFontList(&fonts);
+        for (PRUint32 i = 0, n = fonts.Length(); i < n; ++i) {
+            AppendFaceFromFontListEntry(fonts[i], PR_FALSE);
+        }
+        // Passing null for userdata tells Finalize that it does not need
+        // to sort faces (because they were already sorted by chrome,
+        // so we just maintain the existing order)
+        mFontFamilies.Enumerate(FinalizeFamilyMemberList, nsnull);
+        LOG(("got font list from chrome process: %d faces in %d families",
+            fonts.Length(), mFontFamilies.Count()));
+        return;
+    }
+
+    // Chrome process: get the cached list (if any)
+    FontNameCache fnc;
+
+    // ANDROID_ROOT is the root of the android system, typically /system;
+    // font files are in /$ANDROID_ROOT/fonts/
+    nsCString root;
+    char *androidRoot = PR_GetEnv("ANDROID_ROOT");
+    if (androidRoot) {
+        root = androidRoot;
+    } else {
+        root = NS_LITERAL_CSTRING("/system");
+    }
+    root.Append("/fonts");
+
+    static const char* sStandardFonts[] = {
+        "DroidSans.ttf",
+        "DroidSans-Bold.ttf",
+        "DroidSerif-Regular.ttf",
+        "DroidSerif-Bold.ttf",
+        "DroidSerif-Italic.ttf",
+        "DroidSerif-BoldItalic.ttf",
+        "DroidSansMono.ttf",
+        "DroidSansArabic.ttf",
+        "DroidSansHebrew.ttf",
+        "DroidSansThai.ttf",
+        "MTLmr3m.ttf",
+        "MTLc3m.ttf",
+        "DroidSansJapanese.ttf",
+        "DroidSansFallback.ttf"
+    };
+
+    DIR *d = opendir(root.get());
+    if (!d) {
+        // if we can't find/read the font directory, we are doomed!
+        NS_RUNTIMEABORT("Could not read the system fonts directory");
+    }
+
+    struct dirent *ent = NULL;
+    while ((ent = readdir(d)) != NULL) {
+        int namelen = strlen(ent->d_name);
+        if (namelen <= 4) {
+            // cannot be a usable font filename
+            continue;
+        }
+        const char *ext = ent->d_name + namelen - 4;
+        if (strcasecmp(ext, ".ttf") == 0 ||
+            strcasecmp(ext, ".otf") == 0 ||
+            strcasecmp(ext, ".ttc") == 0)
+        {
+            bool isStdFont = false;
+            for (unsigned int i = 0;
+                 i < NS_ARRAY_LENGTH(sStandardFonts) && !isStdFont; i++)
+            {
+                isStdFont = strcmp(sStandardFonts[i], ent->d_name) == 0;
+            }
+
+            nsCString s(root);
+            s.Append('/');
+            s.Append(ent->d_name, namelen);
+
+            // Add the face(s) from this file to our font list;
+            // note that if we have cached info for this file in fnc,
+            // and the file is unchanged, we won't actually need to read it.
+            // If the file is new/changed, this will update the FontNameCache.
+            AppendFacesFromFontFile(s, isStdFont, &fnc);
+        }
+    }
+    closedir(d);
+
+    // Finalize the families by sorting faces into standard order
+    // and marking "simple" families.
+    // Passing non-null userData here says that we want faces to be sorted.
+    mFontFamilies.Enumerate(FinalizeFamilyMemberList, this);
 #endif // XP_WIN && ANDROID
 }
 
+void
+gfxFT2FontList::AppendFaceFromFontListEntry(const FontListEntry& aFLE,
+                                            PRBool aStdFile)
+{
+    FontEntry* fe = FontEntry::CreateFontEntry(aFLE);
+    if (fe) {
+        fe->mStandardFace = aStdFile;
+        nsAutoString name(aFLE.familyName());
+        gfxFontFamily *family = mFontFamilies.GetWeak(name);
+        if (!family) {
+            family = new gfxFontFamily(name);
+            mFontFamilies.Put(name, family);
+            if (mBadUnderlineFamilyNames.Contains(name)) {
+                family->SetBadUnderlineFamily();
+            }
+        }
+        family->AddFontEntry(fe);
+        if (family->IsBadUnderlineFamily()) {
+            fe->mIsBadUnderlineFont = PR_TRUE;
+        }
+    }
+}
+
+static PLDHashOperator
+AddFamilyToFontList(nsStringHashKey::KeyType aKey,
+                    nsRefPtr<gfxFontFamily>& aFamily,
+                    void* aUserArg)
+{
+    InfallibleTArray<FontListEntry>* fontlist =
+        reinterpret_cast<InfallibleTArray<FontListEntry>*>(aUserArg);
+
+    FontFamily *family = static_cast<FontFamily*>(aFamily.get());
+    family->AddFacesToFontList(fontlist);
+
+    return PL_DHASH_NEXT;
+}
+
+void
+gfxFT2FontList::GetFontList(InfallibleTArray<FontListEntry>* retValue)
+{
+    mFontFamilies.Enumerate(AddFamilyToFontList, retValue);
+}
+
 nsresult
 gfxFT2FontList::InitFontList()
 {
     // reset font lists
     gfxPlatformFontList::InitFontList();
     
     FindFonts();
 
--- a/gfx/thebes/gfxFT2FontList.h
+++ b/gfx/thebes/gfxFT2FontList.h
@@ -42,34 +42,56 @@
 #define GFX_FT2FONTLIST_H
 
 #ifdef XP_WIN
 #include "gfxWindowsPlatform.h"
 #include <windows.h>
 #endif
 #include "gfxPlatformFontList.h"
 
-#include <bitset>
+namespace mozilla {
+    namespace dom {
+        class FontListEntry;
+    };
+};
+using mozilla::dom::FontListEntry;
+
+class FontNameCache;
 
 class gfxFT2FontList : public gfxPlatformFontList
 {
 public:
     gfxFT2FontList();
 
     virtual gfxFontEntry* GetDefaultFont(const gfxFontStyle* aStyle,
                                          PRBool& aNeedsBold);
 
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
 
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const PRUint8 *aFontData,
                                            PRUint32 aLength);
 
+    void GetFontList(InfallibleTArray<FontListEntry>* retValue);
+
+    static gfxFT2FontList* PlatformFontList() {
+        return static_cast<gfxFT2FontList*>(gfxPlatformFontList::PlatformFontList());
+    }
+
 protected:
     virtual nsresult InitFontList();
 
-    void AppendFacesFromFontFile(const PRUnichar *aFileName);
-    void AppendFacesFromFontFile(const char *aFileName);
+    void AppendFaceFromFontListEntry(const FontListEntry& aFLE,
+                                     PRBool isStdFile);
+
+    void AppendFacesFromFontFile(nsCString& aFileName,
+                                 PRBool isStdFile = PR_FALSE,
+                                 FontNameCache *aCache = nsnull);
+
+    void AppendFacesFromCachedFaceList(nsCString& aFileName,
+                                       PRBool isStdFile,
+                                       nsCString& aFaceList);
+
     void FindFonts();
 };
 
 #endif /* GFX_FT2FONTLIST_H */
--- a/gfx/thebes/gfxFT2Fonts.cpp
+++ b/gfx/thebes/gfxFT2Fonts.cpp
@@ -41,16 +41,17 @@
 #include <qfontinfo.h>
 #include "gfxQtPlatform.h"
 #define gfxToolkitPlatform gfxQtPlatform
 #elif defined(XP_WIN)
 #include "gfxWindowsPlatform.h"
 #define gfxToolkitPlatform gfxWindowsPlatform
 #include "gfxFT2FontList.h"
 #elif defined(ANDROID)
+#include "mozilla/dom/ContentChild.h"
 #include "gfxAndroidPlatform.h"
 #define gfxToolkitPlatform gfxAndroidPlatform
 #endif
 
 #include "gfxTypes.h"
 #include "gfxFT2Fonts.h"
 #include "gfxFT2FontBase.h"
 #include "gfxFT2Utils.h"
@@ -66,37 +67,74 @@
 #include "nsUnicodeRange.h"
 #include "nsCRT.h"
 
 #include "prlog.h"
 #include "prinit.h"
 
 #include "mozilla/Preferences.h"
 
-using namespace mozilla;
-
 static PRLogModuleInfo *gFontLog = PR_NewLogModule("ft2fonts");
 
-static const char *sCJKLangGroup[] = {
-    "ja",
-    "ko",
-    "zh-cn",
-    "zh-hk",
-    "zh-tw"
-};
-#define COUNT_OF_CJK_LANG_GROUP 5
-
 // rounding and truncation functions for a Freetype floating point number
 // (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer
 // part and low 6 bits for the fractional part.
 #define MOZ_FT_ROUND(x) (((x) + 32) & ~63) // 63 = 2^6 - 1
 #define MOZ_FT_TRUNC(x) ((x) >> 6)
 #define CONVERT_DESIGN_UNITS_TO_PIXELS(v, s) \
         MOZ_FT_TRUNC(MOZ_FT_ROUND(FT_MulFix((v) , (s))))
 
+static cairo_scaled_font_t *
+CreateScaledFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle)
+{
+    cairo_scaled_font_t *scaledFont = NULL;
+
+    cairo_matrix_t sizeMatrix;
+    cairo_matrix_t identityMatrix;
+
+    // XXX deal with adjusted size
+    cairo_matrix_init_scale(&sizeMatrix, aStyle->size, aStyle->size);
+    cairo_matrix_init_identity(&identityMatrix);
+
+    // synthetic oblique by skewing via the font matrix
+    PRBool needsOblique =
+        !aFontEntry->mItalic &&
+            (aStyle->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE));
+
+    if (needsOblique) {
+        const double kSkewFactor = 0.25;
+
+        cairo_matrix_t style;
+        cairo_matrix_init(&style,
+                          1,                //xx
+                          0,                //yx
+                          -1 * kSkewFactor,  //xy
+                          1,                //yy
+                          0,                //x0
+                          0);               //y0
+        cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
+    }
+
+    cairo_font_options_t *fontOptions = cairo_font_options_create();
+
+#ifdef MOZ_GFX_OPTIMIZE_MOBILE
+    cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF);
+#endif
+
+    scaledFont = cairo_scaled_font_create(aFontEntry->CairoFontFace(),
+                                          &sizeMatrix,
+                                          &identityMatrix, fontOptions);
+    cairo_font_options_destroy(fontOptions);
+
+    NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS,
+                 "Failed to make scaled font");
+
+    return scaledFont;
+}
+
 /**
  * FontEntry
  */
 
 FontEntry::~FontEntry()
 {
     // Do nothing for mFTFace here since FTFontDestroyFunc is called by cairo.
     mFTFace = nsnull;
@@ -105,19 +143,22 @@ FontEntry::~FontEntry()
     if (mFontFace) {
         cairo_font_face_destroy(mFontFace);
         mFontFace = nsnull;
     }
 #endif
 }
 
 gfxFont*
-FontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, PRBool aNeedsBold) {
-    already_AddRefed<gfxFT2Font> font = gfxFT2Font::GetOrMakeFont(this, aFontStyle, aNeedsBold);
-    return font.get();
+FontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, PRBool aNeedsBold)
+{
+    cairo_scaled_font_t *scaledFont = CreateScaledFont(this, aFontStyle);
+    gfxFont *font = new gfxFT2Font(scaledFont, this, aFontStyle, aNeedsBold);
+    cairo_scaled_font_destroy(scaledFont);
+    return font;
 }
 
 /* static */
 FontEntry*
 FontEntry::CreateFontEntry(const gfxProxyFontEntry &aProxyEntry,
                            const PRUint8 *aFontData,
                            PRUint32 aLength)
 {
@@ -127,17 +168,17 @@ FontEntry::CreateFontEntry(const gfxProx
     FT_Face face;
     FT_Error error =
         FT_New_Memory_Face(gfxToolkitPlatform::GetPlatform()->GetFTLibrary(),
                            aFontData, aLength, 0, &face);
     if (error != FT_Err_Ok) {
         NS_Free((void*)aFontData);
         return nsnull;
     }
-    FontEntry* fe = FontEntry::CreateFontEntryFromFace(face, aFontData);
+    FontEntry* fe = FontEntry::CreateFontEntry(face, nsnull, 0, aFontData);
     if (fe) {
         fe->mItalic = aProxyEntry.mItalic;
         fe->mWeight = aProxyEntry.mWeight;
         fe->mStretch = aProxyEntry.mStretch;
     }
     return fe;
 }
 
@@ -164,17 +205,32 @@ private:
 static void
 FTFontDestroyFunc(void *data)
 {
     FTUserFontData *userFontData = static_cast<FTUserFontData*>(data);
     delete userFontData;
 }
 
 /* static */ FontEntry*
-FontEntry::CreateFontEntryFromFace(FT_Face aFace, const PRUint8 *aFontData) {
+FontEntry::CreateFontEntry(const FontListEntry& aFLE)
+{
+    FontEntry *fe = new FontEntry(aFLE.faceName());
+    fe->mFilename = aFLE.filepath();
+    fe->mFTFontIndex = aFLE.index();
+    fe->mWeight = aFLE.weight();
+    fe->mStretch = aFLE.stretch();
+    fe->mItalic = aFLE.italic();
+    return fe;
+}
+
+/* static */ FontEntry*
+FontEntry::CreateFontEntry(FT_Face aFace,
+                           const char* aFilename, PRUint8 aIndex,
+                           const PRUint8 *aFontData)
+{
     static cairo_user_data_key_t key;
 
     if (!aFace->family_name) {
         FT_Done_Face(aFace);
         return nsnull;
     }
     // Construct font name from family name and style name, regular fonts
     // do not have the modifier by convention.
@@ -186,16 +242,18 @@ FontEntry::CreateFontEntryFromFace(FT_Fa
     FontEntry *fe = new FontEntry(fontName);
     fe->mItalic = aFace->style_flags & FT_STYLE_FLAG_ITALIC;
     fe->mFTFace = aFace;
 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
     fe->mFontFace = cairo_ft_font_face_create_for_ft_face(aFace, FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
 #else
     fe->mFontFace = cairo_ft_font_face_create_for_ft_face(aFace, 0);
 #endif
+    fe->mFilename = aFilename;
+    fe->mFTFontIndex = aIndex;
     FTUserFontData *userFontData = new FTUserFontData(aFace, aFontData);
     cairo_font_face_set_user_data(fe->mFontFace, &key,
                                   userFontData, FTFontDestroyFunc);
 
     TT_OS2 *os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(aFace, ft_sfnt_os2));
     PRUint16 os2weight = 0;
     if (os2 && os2->version != 0xffff) {
         // Technically, only 100 to 900 are valid, but some fonts
@@ -297,47 +355,35 @@ FontEntry::GetFontTable(PRUint32 aTableT
 
 FontEntry *
 FontFamily::FindFontEntry(const gfxFontStyle& aFontStyle)
 {
     PRBool needsBold = PR_FALSE;
     return static_cast<FontEntry*>(FindFontForStyle(aFontStyle, needsBold));
 }
 
-void FontFamily::AddFontFileAndIndex(nsCString aFilename, PRUint32 aIndex)
+void
+FontFamily::AddFacesToFontList(InfallibleTArray<FontListEntry>* aFontList)
 {
-    SetHasStyles(PR_FALSE);
-    mFilenames.AppendElement(new FileAndIndex(aFilename, aIndex));
-}
-    
-
-
-void
-FontFamily::FindStyleVariations()
-{
-    if (mHasStyles) {
-        return;
+    for (int i = 0, n = mAvailableFonts.Length(); i < n; ++i) {
+        const FontEntry *fe =
+            static_cast<const FontEntry*>(mAvailableFonts[i].get());
+        if (!fe) {
+            continue;
+        }
+        
+        aFontList->AppendElement(FontListEntry(Name(), fe->Name(),
+                                               fe->mFilename,
+                                               fe->Weight(), fe->Stretch(),
+                                               fe->IsItalic(),
+                                               fe->mFTFontIndex));
     }
-    mHasStyles = PR_TRUE;
-
-    for (int i = 0; i < mFilenames.Length(); i++) {
-        FT_Face face;
-        gfxToolkitPlatform* platform = gfxToolkitPlatform::GetPlatform();
-        if (FT_Err_Ok == FT_New_Face(platform->GetFTLibrary(),
-                                     mFilenames[i].filename.get(), 
-                                     mFilenames[i].index, &face)) {
-            FontEntry* fe = FontEntry::CreateFontEntryFromFace(face);
-            if (fe)
-                AddFontEntry(fe);
-        }
-    }
-    mFilenames.Clear();
-    SetHasStyles(PR_TRUE);
 }
 
+#ifndef ANDROID // not needed on Android, we use the generic gfxFontGroup
 /**
  * gfxFT2FontGroup
  */
 
 PRBool
 gfxFT2FontGroup::FontCallback(const nsAString& fontName,
                               const nsACString& genericName,
                               PRBool aUseFontSet,
@@ -646,17 +692,17 @@ gfxFT2FontGroup::WhichPrefFontSupportsCh
     }
 
     return nsnull;
 }
 
 already_AddRefed<gfxFont>
 gfxFT2FontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
 {
-#ifdef XP_WIN
+#if defined(XP_WIN) || defined(ANDROID)
     FontEntry *fe = static_cast<FontEntry*>
         (gfxPlatformFontList::PlatformFontList()->FindFontForChar(aCh, GetFontAt(0)));
     if (fe) {
         nsRefPtr<gfxFT2Font> f = gfxFT2Font::GetOrMakeFont(fe, &mStyle);
         nsRefPtr<gfxFont> font = f.get();
         return font.forget();
     }
 #else
@@ -665,16 +711,18 @@ gfxFT2FontGroup::WhichSystemFontSupports
     gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
     selectedFont = platform->FindFontForChar(aCh, refFont);
     if (selectedFont)
         return selectedFont.forget();
 #endif
     return nsnull;
 }
 
+#endif // !ANDROID
+
 /**
  * gfxFT2Font
  */
 
 PRBool
 gfxFT2Font::InitTextRun(gfxContext *aContext,
                         gfxTextRun *aTextRun,
                         const PRUnichar *aString,
@@ -819,80 +867,36 @@ gfxFT2Font::~gfxFT2Font()
 }
 
 cairo_font_face_t *
 gfxFT2Font::CairoFontFace()
 {
     return GetFontEntry()->CairoFontFace();
 }
 
-static cairo_scaled_font_t *
-CreateScaledFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle)
-{
-    cairo_scaled_font_t *scaledFont = NULL;
-
-    cairo_matrix_t sizeMatrix;
-    cairo_matrix_t identityMatrix;
-
-    // XXX deal with adjusted size
-    cairo_matrix_init_scale(&sizeMatrix, aStyle->size, aStyle->size);
-    cairo_matrix_init_identity(&identityMatrix);
-
-    // synthetic oblique by skewing via the font matrix
-    PRBool needsOblique = (!aFontEntry->mItalic && (aStyle->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)));
-
-    if (needsOblique) {
-        const double kSkewFactor = 0.25;
-
-        cairo_matrix_t style;
-        cairo_matrix_init(&style,
-                          1,                //xx
-                          0,                //yx
-                          -1 * kSkewFactor,  //xy
-                          1,                //yy
-                          0,                //x0
-                          0);               //y0
-        cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
-    }
-
-    cairo_font_options_t *fontOptions = cairo_font_options_create();
-
-#ifdef MOZ_GFX_OPTIMIZE_MOBILE
-    cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF);
-#endif
-
-    scaledFont = cairo_scaled_font_create(aFontEntry->CairoFontFace(),
-                                          &sizeMatrix,
-                                          &identityMatrix, fontOptions);
-    cairo_font_options_destroy(fontOptions);
-
-    NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS,
-                 "Failed to make scaled font");
-
-    return scaledFont;
-}
-
 /**
  * Look up the font in the gfxFont cache. If we don't find it, create one.
  * In either case, add a ref, append it to the aFonts array, and return it ---
  * except for OOM in which case we do nothing and return null.
  */
+#ifndef ANDROID // this is only for gfxFT2FontGroup, which is not used on Android
 already_AddRefed<gfxFT2Font>
 gfxFT2Font::GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle, PRBool aNeedsBold)
 {
     FontEntry *fe = static_cast<FontEntry*>
         (gfxToolkitPlatform::GetPlatform()->FindFontEntry(aName, *aStyle));
     if (!fe) {
         NS_WARNING("Failed to find font entry for font!");
         return nsnull;
     }
 
     nsRefPtr<gfxFT2Font> font = GetOrMakeFont(fe, aStyle, aNeedsBold);
     return font.forget();
 }
+#endif
 
 already_AddRefed<gfxFT2Font>
 gfxFT2Font::GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle, PRBool aNeedsBold)
 {
     nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(aFontEntry, aStyle);
     if (!font) {
         cairo_scaled_font_t *scaledFont = CreateScaledFont(aFontEntry, aStyle);
         font = new gfxFT2Font(scaledFont, aFontEntry, aStyle, aNeedsBold);
--- a/gfx/thebes/gfxFT2Fonts.h
+++ b/gfx/thebes/gfxFT2Fonts.h
@@ -42,48 +42,41 @@
 #include "cairo.h"
 #include "gfxTypes.h"
 #include "gfxFont.h"
 #include "gfxFT2FontBase.h"
 #include "gfxContext.h"
 #include "gfxFontUtils.h"
 #include "gfxUserFontSet.h"
 
-typedef struct FT_FaceRec_* FT_Face;
+namespace mozilla {
+    namespace dom {
+        class FontListEntry;
+    };
+};
+using mozilla::dom::FontListEntry;
 
-class FileAndIndex {
-public:
-    FileAndIndex(nsCString aFilename, PRUint32 aIndex) :
-        filename(aFilename), index(aIndex) {}
-    FileAndIndex(FileAndIndex* fai) :
-        filename(fai->filename), index(fai->index) {}
-    nsCString filename;
-    PRUint32 index;
-};
+typedef struct FT_FaceRec_* FT_Face;
 
 /**
  * FontFamily is a class that describes one of the fonts on the users system.  It holds
  * each FontEntry (maps more directly to a font face) which holds font type, charset info
  * and character map info.
  */
 class FontEntry;
 class FontFamily : public gfxFontFamily
 {
 public:
     FontFamily(const nsAString& aName) :
         gfxFontFamily(aName) { }
 
     FontEntry *FindFontEntry(const gfxFontStyle& aFontStyle);
-    virtual void FindStyleVariations();
-    void AddFontFileAndIndex(nsCString aFilename, PRUint32 aIndex);
 
-private:
-    // mFilenames are queus of font files that
-    // need to be lazily processed into font entries
-    nsTArray<FileAndIndex> mFilenames;
+    // Append this family's faces to the IPC fontlist
+    void AddFacesToFontList(InfallibleTArray<FontListEntry>* aFontList);
 };
 
 class FontEntry : public gfxFontEntry
 {
 public:
     FontEntry(const nsAString& aFaceName) :
         gfxFontEntry(aFaceName)
     {
@@ -93,22 +86,32 @@ public:
     }
 
     ~FontEntry();
 
     const nsString& GetName() const {
         return Name();
     }
 
+    // create a font entry for a downloaded font
     static FontEntry* 
     CreateFontEntry(const gfxProxyFontEntry &aProxyEntry,
                     const PRUint8 *aFontData, PRUint32 aLength);
 
+    // create a font entry representing an installed font, identified by
+    // a FontListEntry; the freetype and cairo faces will not be instantiated
+    // until actually needed
+    static FontEntry*
+    CreateFontEntry(const FontListEntry& aFLE);
+
+    // create a font entry for a given freetype face; if it is an installed font,
+    // also record the filename and index
     static FontEntry* 
-    CreateFontEntryFromFace(FT_Face aFace, const PRUint8 *aFontData = nsnull);
+    CreateFontEntry(FT_Face aFace, const char *aFilename, PRUint8 aIndex,
+                    const PRUint8 *aFontData = nsnull);
         // aFontData is NS_Malloc'ed data that aFace depends on, to be freed
         // after the face is destroyed; null if there is no such buffer
 
     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, PRBool aNeedsBold);
 
     cairo_font_face_t *CairoFontFace();
     nsresult ReadCMAP();
 
@@ -129,18 +132,21 @@ public: // new functions
                const gfxFontStyle *aFontStyle,
                PRBool aNeedsBold);
     virtual ~gfxFT2Font ();
 
     cairo_font_face_t *CairoFontFace();
 
     FontEntry *GetFontEntry();
 
+#ifndef ANDROID
     static already_AddRefed<gfxFT2Font>
     GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle, PRBool aNeedsBold = PR_FALSE);
+#endif
+
     static already_AddRefed<gfxFT2Font>
     GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle, PRBool aNeedsBold = PR_FALSE);
 
     struct CachedGlyphData {
         CachedGlyphData()
             : glyphIndex(0xffffffffU) { }
 
         CachedGlyphData(PRUint32 gid)
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -535,25 +535,31 @@ gfxFontFamily::FindFontForStyle(const gf
     }
 
     return matchFE;
 }
 
 void
 gfxFontFamily::CheckForSimpleFamily()
 {
-    if (mAvailableFonts.Length() > 4 || mAvailableFonts.Length() == 0) {
+    PRUint32 count = mAvailableFonts.Length();
+    if (count > 4 || count == 0) {
         return; // can't be "simple" if there are >4 faces;
                 // if none then the family is unusable anyway
     }
 
+    if (count == 1) {
+        mIsSimpleFamily = PR_TRUE;
+        return;
+    }
+
     PRInt16 firstStretch = mAvailableFonts[0]->Stretch();
 
     gfxFontEntry *faces[4] = { 0 };
-    for (PRUint8 i = 0; i < mAvailableFonts.Length(); ++i) {
+    for (PRUint8 i = 0; i < count; ++i) {
         gfxFontEntry *fe = mAvailableFonts[i];
         if (fe->Stretch() != firstStretch) {
             return; // font-stretch doesn't match, don't treat as simple family
         }
         PRUint8 faceIndex = (fe->IsItalic() ? kItalicMask : 0) |
                             (fe->Weight() >= 600 ? kBoldMask : 0);
         if (faces[faceIndex]) {
             return; // two faces resolve to the same slot; family isn't "simple"