bug 684889 - refactor and clean up Android font-list implementation. r=jdaggett
authorJonathan Kew <jfkthame@gmail.com>
Fri, 23 Sep 2011 12:15:36 +0100
changeset 77411 6081c809fcf6ee052752e84c2ecade07e0397837
parent 77410 e38b3957d001fd3f4c9fee69a23e867e982a0134
child 77412 065af81cd739ed419f936680c1b2fc61572f5357
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersjdaggett
bugs684889
milestone9.0a1
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
@@ -39,26 +39,27 @@
 #define gfxToolkitPlatform gfxPlatformGtk
 #elif defined(MOZ_WIDGET_QT)
 #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"
+#include "gfxFT2FontList.h"
 #include <locale.h>
 #include "cairo-ft.h"
 #include FT_TRUETYPE_TAGS_H
 #include FT_TRUETYPE_TABLES_H
 #include "gfxFontUtils.h"
 #include "gfxHarfBuzzShaper.h"
 #include "gfxUnicodeProperties.h"
 #include "gfxAtoms.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,72 +867,33 @@ 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.
  */
 already_AddRefed<gfxFT2Font>
-gfxFT2Font::GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle, PRBool aNeedsBold)
+gfxFT2Font::GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle,
+                          PRBool aNeedsBold)
 {
+#ifdef ANDROID
+    FontEntry *fe = static_cast<FontEntry*>
+        (gfxPlatformFontList::PlatformFontList()->
+            FindFontForFamily(aName, aStyle, aNeedsBold));
+#else
     FontEntry *fe = static_cast<FontEntry*>
         (gfxToolkitPlatform::GetPlatform()->FindFontEntry(aName, *aStyle));
+#endif
     if (!fe) {
         NS_WARNING("Failed to find font entry for font!");
         return nsnull;
     }
 
     nsRefPtr<gfxFT2Font> font = GetOrMakeFont(fe, aStyle, aNeedsBold);
     return font.forget();
 }
--- 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();
 
@@ -130,19 +133,22 @@ public: // new functions
                PRBool aNeedsBold);
     virtual ~gfxFT2Font ();
 
     cairo_font_face_t *CairoFontFace();
 
     FontEntry *GetFontEntry();
 
     static already_AddRefed<gfxFT2Font>
-    GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle, PRBool aNeedsBold = PR_FALSE);
+    GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle,
+                  PRBool aNeedsBold = PR_FALSE);
+
     static already_AddRefed<gfxFT2Font>
-    GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle, PRBool aNeedsBold = PR_FALSE);
+    GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle,
+                  PRBool aNeedsBold = PR_FALSE);
 
     struct CachedGlyphData {
         CachedGlyphData()
             : glyphIndex(0xffffffffU) { }
 
         CachedGlyphData(PRUint32 gid)
             : glyphIndex(gid) { }
 
@@ -179,16 +185,17 @@ protected:
 
     void AddRange(gfxTextRun *aTextRun, const PRUnichar *str, PRUint32 offset, PRUint32 len);
 
     typedef nsBaseHashtableET<nsUint32HashKey, CachedGlyphData> CharGlyphMapEntryType;
     typedef nsTHashtable<CharGlyphMapEntryType> CharGlyphMap;
     CharGlyphMap mCharGlyphCache;
 };
 
+#ifndef ANDROID // not needed on Android, uses the standard gfxFontGroup directly
 class THEBES_API gfxFT2FontGroup : public gfxFontGroup {
 public: // new functions
     gfxFT2FontGroup (const nsAString& families,
                     const gfxFontStyle *aStyle,
                     gfxUserFontSet *aUserFontSet);
     virtual ~gfxFT2FontGroup ();
 
 protected: // from gfxFontGroup
@@ -213,11 +220,12 @@ protected: // new functions
     already_AddRefed<gfxFT2Font> WhichFontSupportsChar(const nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList,
                                                        PRUint32 aCh);
     already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
     already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);
 
     nsTArray<gfxTextRange> mRanges;
     nsString mString;
 };
+#endif // !ANDROID
 
 #endif /* GFX_FT2FONTS_H */
 
--- 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"