Bug 493280: restructure Windows font management based on cross-platform font-list classes. r=jdaggett sr=roc
authorJonathan Kew <jfkthame@gmail.com>
Wed, 07 Oct 2009 15:13:40 +0100
changeset 36949 99bb0c6877f02bb9e7f2d2cd55963cd6fca2582c
parent 36948 6ce98ed11af8a38561d23d132668dd0793408533
child 36950 1a3d81ba980abd84599311880d7c916ffdd9d5fa
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjdaggett, roc
bugs493280
milestone1.9.3a1pre
Bug 493280: restructure Windows font management based on cross-platform font-list classes. r=jdaggett sr=roc
gfx/thebes/public/gfxFT2Fonts.h
gfx/thebes/public/gfxFont.h
gfx/thebes/public/gfxWindowsFonts.h
gfx/thebes/public/gfxWindowsPlatform.h
gfx/thebes/src/Makefile.in
gfx/thebes/src/gfxFT2FontList.cpp
gfx/thebes/src/gfxFT2FontList.h
gfx/thebes/src/gfxFT2Fonts.cpp
gfx/thebes/src/gfxGDIFontList.cpp
gfx/thebes/src/gfxGDIFontList.h
gfx/thebes/src/gfxMacPlatformFontList.h
gfx/thebes/src/gfxMacPlatformFontList.mm
gfx/thebes/src/gfxPlatform.cpp
gfx/thebes/src/gfxPlatformFontList.cpp
gfx/thebes/src/gfxPlatformFontList.h
gfx/thebes/src/gfxPlatformMac.cpp
gfx/thebes/src/gfxWindowsFonts.cpp
gfx/thebes/src/gfxWindowsPlatform.cpp
--- a/gfx/thebes/public/gfxFT2Fonts.h
+++ b/gfx/thebes/public/gfxFT2Fonts.h
@@ -199,22 +199,22 @@ protected: // new functions
     void AddRange(gfxTextRun *aTextRun, gfxFT2Font *font, const PRUnichar *str, PRUint32 offset, PRUint32 len);
 
     static PRBool FontCallback (const nsAString & fontName, 
                                 const nsACString & genericName, 
                                 void *closure);
     PRBool mEnableKerning;
 
     void GetPrefFonts(const char *aLangGroup,
-                      nsTArray<nsRefPtr<FontEntry> >& aFontEntryList);
-    void GetCJKPrefFonts(nsTArray<nsRefPtr<FontEntry> >& aFontEntryList);
+                      nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList);
+    void GetCJKPrefFonts(nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList);
     void FamilyListToArrayList(const nsString& aFamilies,
                                const nsCString& aLangGroup,
-                               nsTArray<nsRefPtr<FontEntry> > *aFontEntryList);
-    already_AddRefed<gfxFT2Font> WhichFontSupportsChar(const nsTArray<nsRefPtr<FontEntry> >& aFontEntryList,
+                               nsTArray<nsRefPtr<gfxFontEntry> > *aFontEntryList);
+    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;
 };
 
--- a/gfx/thebes/public/gfxFont.h
+++ b/gfx/thebes/public/gfxFont.h
@@ -160,66 +160,77 @@ public:
     THEBES_INLINE_DECL_REFCOUNTING(gfxFontEntry)
 
     gfxFontEntry(const nsAString& aName, gfxFontFamily *aFamily = nsnull,
                  PRBool aIsStandardFace = PR_FALSE) : 
         mName(aName), mItalic(PR_FALSE), mFixedPitch(PR_FALSE),
         mIsProxy(PR_FALSE), mIsValid(PR_TRUE), 
         mIsBadUnderlineFont(PR_FALSE), mIsUserFont(PR_FALSE),
         mStandardFace(aIsStandardFace),
+        mSymbolFont(PR_FALSE),
         mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
         mCmapInitialized(PR_FALSE), mUserFontData(nsnull),
         mFamily(aFamily)
     { }
 
     gfxFontEntry(const gfxFontEntry& aEntry) : 
         mName(aEntry.mName), mItalic(aEntry.mItalic), 
         mFixedPitch(aEntry.mFixedPitch), mIsProxy(aEntry.mIsProxy), 
         mIsValid(aEntry.mIsValid), mIsBadUnderlineFont(aEntry.mIsBadUnderlineFont),
         mIsUserFont(aEntry.mIsUserFont),
         mStandardFace(aEntry.mStandardFace),
+        mSymbolFont(aEntry.mSymbolFont),
         mWeight(aEntry.mWeight), mCmapInitialized(aEntry.mCmapInitialized),
         mCharacterMap(aEntry.mCharacterMap), mUserFontData(aEntry.mUserFontData),
         mFamily(aEntry.mFamily)
     { }
 
     virtual ~gfxFontEntry();
 
     // unique name for the face, *not* the family
     const nsString& Name() const { return mName; }
 
-    PRUint16 Weight() { return mWeight; }
-    PRInt16 Stretch() { return mStretch; }
+    PRUint16 Weight() const { return mWeight; }
+    PRInt16 Stretch() const { return mStretch; }
 
-    PRBool IsUserFont() { return mIsUserFont; }
-    PRBool IsFixedPitch() { return mFixedPitch; }
-    PRBool IsItalic() { return mItalic; }
-    PRBool IsBold() { return mWeight >= 600; } // bold == weights 600 and above
+    PRBool IsUserFont() const { return mIsUserFont; }
+    PRBool IsFixedPitch() const { return mFixedPitch; }
+    PRBool IsItalic() const { return mItalic; }
+    PRBool IsBold() const { return mWeight >= 600; } // bold == weights 600 and above
+    PRBool IsSymbolFont() const { return mSymbolFont; }
 
     inline PRBool HasCharacter(PRUint32 ch) {
         if (mCharacterMap.test(ch))
             return PR_TRUE;
             
         return TestCharacterMap(ch);
     }
 
     virtual PRBool TestCharacterMap(PRUint32 aCh);
     virtual nsresult ReadCMAP();
 
+    virtual PRBool MatchesGenericFamily(const nsACString& aGeneric) const {
+        return PR_TRUE;
+    }
+    virtual PRBool SupportsLangGroup(const nsACString& aLangGroup) const {
+        return PR_TRUE;
+    }
+
     const nsString& FamilyName();
 
     nsString         mName;
 
     PRPackedBool     mItalic      : 1;
     PRPackedBool     mFixedPitch  : 1;
     PRPackedBool     mIsProxy     : 1;
     PRPackedBool     mIsValid     : 1;
     PRPackedBool     mIsBadUnderlineFont : 1;
     PRPackedBool     mIsUserFont  : 1;
     PRPackedBool     mStandardFace : 1;
+    PRPackedBool     mSymbolFont  : 1;
 
     PRUint16         mWeight;
     PRInt16          mStretch;
 
     PRPackedBool     mCmapInitialized;
     gfxSparseBitSet  mCharacterMap;
     gfxUserFontData* mUserFontData;
 
@@ -230,16 +241,17 @@ protected:
     friend class gfxFontFamily;
 
     gfxFontEntry() :
         mItalic(PR_FALSE), mFixedPitch(PR_FALSE),
         mIsProxy(PR_FALSE), mIsValid(PR_TRUE), 
         mIsBadUnderlineFont(PR_FALSE),
         mIsUserFont(PR_FALSE),
         mStandardFace(PR_FALSE),
+        mSymbolFont(PR_FALSE),
         mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
         mCmapInitialized(PR_FALSE),
         mUserFontData(nsnull),
         mFamily(nsnull)
     { }
 
     virtual nsresult GetFontTable(PRUint32 aTableTag, nsTArray<PRUint8>& aBuffer) {
         return NS_ERROR_FAILURE; // all platform subclasses should reimplement this!
--- a/gfx/thebes/public/gfxWindowsFonts.h
+++ b/gfx/thebes/public/gfxWindowsFonts.h
@@ -52,266 +52,27 @@
 
 #include <usp10.h>
 #include <cairo-win32.h>
 
 // xxx - used in FontEntry.  should be trimmed, moz code doesn't use
 //       exceptions.  use gfxSparseBitSet instead?
 #include <bitset>
 
-/**
- * List of different types of fonts we support on Windows.
- * These can generally be lumped in to 3 categories where we have to
- * do special things:  Really old fonts bitmap and vector fonts (device
- * and raster), Type 1 fonts, and TrueType/OpenType fonts.
- * 
- * This list is sorted in order from least prefered to most prefered.
- * We prefer Type1 fonts over OpenType fonts to avoid falling back to
- * things like Arial (opentype) when you ask for Helvetica (type1)
- **/
-enum gfxWindowsFontType {
-    GFX_FONT_TYPE_UNKNOWN = 0,
-    GFX_FONT_TYPE_DEVICE,
-    GFX_FONT_TYPE_RASTER,
-    GFX_FONT_TYPE_TRUETYPE,
-    GFX_FONT_TYPE_PS_OPENTYPE,
-    GFX_FONT_TYPE_TT_OPENTYPE,
-    GFX_FONT_TYPE_TYPE1
-};
-
-/**
- * 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), mIsBadUnderlineFontFamily(PR_FALSE) { }
-
-    FontEntry *FindFontEntry(const gfxFontStyle& aFontStyle);
-
-private:
-    friend class gfxWindowsPlatform;
-
-    void FindStyleVariations();
-
-    static int CALLBACK FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
-                                            const NEWTEXTMETRICEXW *nmetrics,
-                                            DWORD fontType, LPARAM data);
-
-protected:
-    PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
-                               PRBool anItalic, PRInt16 aStretch);
-
-public:
-    PRPackedBool mIsBadUnderlineFontFamily;
-};
-
-class FontEntry : public gfxFontEntry
-{
-public:
-    FontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
-              PRBool aItalic, PRUint16 aWeight, gfxUserFontData *aUserFontData) : 
-        gfxFontEntry(aFaceName), mFontType(aFontType),
-        mForceGDI(PR_FALSE), mUnknownCMAP(PR_FALSE),
-        mUnicodeFont(PR_FALSE), mSymbolFont(PR_FALSE),
-        mCharset(), mUnicodeRanges()
-    {
-        mUserFontData = aUserFontData;
-        mItalic = aItalic;
-        mWeight = aWeight;
-        if (IsType1())
-            mForceGDI = PR_TRUE;
-        mIsUserFont = aUserFontData != nsnull;
-    }
-
-    FontEntry(const FontEntry& aFontEntry) :
-        gfxFontEntry(aFontEntry),
-        mWindowsFamily(aFontEntry.mWindowsFamily),
-        mWindowsPitch(aFontEntry.mWindowsPitch),
-        mFontType(aFontEntry.mFontType),
-        mForceGDI(aFontEntry.mForceGDI),
-        mUnknownCMAP(aFontEntry.mUnknownCMAP),
-        mUnicodeFont(aFontEntry.mUnicodeFont),
-        mSymbolFont(aFontEntry.mSymbolFont),
-        mCharset(aFontEntry.mCharset),
-        mUnicodeRanges(aFontEntry.mUnicodeRanges)
-    {
-
-    }
-    static void InitializeFontEmbeddingProcs();
-
-    // create a font entry from downloaded font data
-    static FontEntry* LoadFont(const gfxProxyFontEntry &aProxyEntry,
-                               const PRUint8 *aFontData,
-                               PRUint32 aLength);
-
-    // create a font entry for a font with a given name
-    static FontEntry* CreateFontEntry(const nsAString& aName, 
-                                      gfxWindowsFontType aFontType, 
-                                      PRBool aItalic, PRUint16 aWeight, 
-                                      gfxUserFontData* aUserFontData, 
-                                      HDC hdc = 0, LOGFONTW *aLogFont = nsnull);
-
-    // create a font entry for a font referenced by its fullname
-    static FontEntry* LoadLocalFont(const gfxProxyFontEntry &aProxyEntry,
-                                    const nsAString& aFullname);
-
-    static void FillLogFont(LOGFONTW *aLogFont, const nsAString& aName, 
-                            gfxWindowsFontType aFontType, PRBool aItalic, 
-                            PRUint16 aWeight, gfxFloat aSize);
-
-    static gfxWindowsFontType DetermineFontType(const NEWTEXTMETRICW& metrics, 
-                                                DWORD fontType)
-    {
-        gfxWindowsFontType feType;
-        if (metrics.ntmFlags & NTM_TYPE1)
-            feType = GFX_FONT_TYPE_TYPE1;
-        else if (metrics.ntmFlags & NTM_PS_OPENTYPE)
-            feType = GFX_FONT_TYPE_PS_OPENTYPE;
-        else if (metrics.ntmFlags & NTM_TT_OPENTYPE)
-            feType = GFX_FONT_TYPE_TT_OPENTYPE;
-        else if (fontType == TRUETYPE_FONTTYPE)
-            feType = GFX_FONT_TYPE_TRUETYPE;
-        else if (fontType == RASTER_FONTTYPE)
-            feType = GFX_FONT_TYPE_RASTER;
-        else if (fontType == DEVICE_FONTTYPE)
-            feType = GFX_FONT_TYPE_DEVICE;
-        else
-            feType = GFX_FONT_TYPE_UNKNOWN;
-        
-        return feType;
-    }
-
-    PRBool IsType1() const {
-        return (mFontType == GFX_FONT_TYPE_TYPE1);
-    }
-
-    PRBool IsTrueType() const {
-        return (mFontType == GFX_FONT_TYPE_TRUETYPE ||
-                mFontType == GFX_FONT_TYPE_PS_OPENTYPE ||
-                mFontType == GFX_FONT_TYPE_TT_OPENTYPE);
-    }
-
-    PRBool IsCrappyFont() const {
-        /* return if it is a bitmap not a unicode font */
-        return (!mUnicodeFont || mSymbolFont || IsType1());
-    }
-
-    PRBool MatchesGenericFamily(const nsACString& aGeneric) const {
-        if (aGeneric.IsEmpty())
-            return PR_TRUE;
-
-        // Japanese 'Mincho' fonts do not belong to FF_MODERN even if
-        // they are fixed pitch because they have variable stroke width.
-        if (mWindowsFamily == FF_ROMAN && mWindowsPitch & FIXED_PITCH) {
-            return aGeneric.EqualsLiteral("monospace");
-        }
-
-        // Japanese 'Gothic' fonts do not belong to FF_SWISS even if
-        // they are variable pitch because they have constant stroke width.
-        if (mWindowsFamily == FF_MODERN && mWindowsPitch & VARIABLE_PITCH) {
-            return aGeneric.EqualsLiteral("sans-serif");
-        }
-
-        // All other fonts will be grouped correctly using family...
-        switch (mWindowsFamily) {
-        case FF_DONTCARE:
-            return PR_TRUE;
-        case FF_ROMAN:
-            return aGeneric.EqualsLiteral("serif");
-        case FF_SWISS:
-            return aGeneric.EqualsLiteral("sans-serif");
-        case FF_MODERN:
-            return aGeneric.EqualsLiteral("monospace");
-        case FF_SCRIPT:
-            return aGeneric.EqualsLiteral("cursive");
-        case FF_DECORATIVE:
-            return aGeneric.EqualsLiteral("fantasy");
-        }
-
-        return PR_FALSE;
-    }
-
-    PRBool SupportsLangGroup(const nsACString& aLangGroup) const {
-        if (aLangGroup.IsEmpty())
-            return PR_TRUE;
-
-        PRInt16 bit = -1;
-
-        /* map our langgroup names in to Windows charset bits */
-        if (aLangGroup.EqualsLiteral("x-western")) {
-            bit = ANSI_CHARSET;
-        } else if (aLangGroup.EqualsLiteral("ja")) {
-            bit = SHIFTJIS_CHARSET;
-        } else if (aLangGroup.EqualsLiteral("ko")) {
-            bit = HANGEUL_CHARSET;
-        } else if (aLangGroup.EqualsLiteral("ko-XXX")) {
-            bit = JOHAB_CHARSET;
-        } else if (aLangGroup.EqualsLiteral("zh-CN")) {
-            bit = GB2312_CHARSET;
-        } else if (aLangGroup.EqualsLiteral("zh-TW")) {
-            bit = CHINESEBIG5_CHARSET;
-        } else if (aLangGroup.EqualsLiteral("el")) {
-            bit = GREEK_CHARSET;
-        } else if (aLangGroup.EqualsLiteral("tr")) {
-            bit = TURKISH_CHARSET;
-        } else if (aLangGroup.EqualsLiteral("he")) {
-            bit = HEBREW_CHARSET;
-        } else if (aLangGroup.EqualsLiteral("ar")) {
-            bit = ARABIC_CHARSET;
-        } else if (aLangGroup.EqualsLiteral("x-baltic")) {
-            bit = BALTIC_CHARSET;
-        } else if (aLangGroup.EqualsLiteral("x-cyrillic")) {
-            bit = RUSSIAN_CHARSET;
-        } else if (aLangGroup.EqualsLiteral("th")) {
-            bit = THAI_CHARSET;
-        } else if (aLangGroup.EqualsLiteral("x-central-euro")) {
-            bit = EASTEUROPE_CHARSET;
-        } else if (aLangGroup.EqualsLiteral("x-symbol")) {
-            bit = SYMBOL_CHARSET;
-        }
-
-        if (bit != -1)
-            return mCharset[bit];
-
-        return PR_FALSE;
-    }
-
-    PRBool SupportsRange(PRUint8 range) {
-        return mUnicodeRanges[range];
-    }
-
-    PRBool TestCharacterMap(PRUint32 aCh);
-
-    PRUint8 mWindowsFamily;
-    PRUint8 mWindowsPitch;
-
-    gfxWindowsFontType mFontType;
-    PRPackedBool mForceGDI    : 1;
-    PRPackedBool mUnknownCMAP : 1;
-    PRPackedBool mUnicodeFont : 1;
-    PRPackedBool mSymbolFont  : 1;
-
-    std::bitset<256> mCharset;
-    std::bitset<128> mUnicodeRanges;
-};
+class GDIFontEntry;
 
 /**********************************************************************
  *
  * class gfxWindowsFont
  *
  **********************************************************************/
 
 class gfxWindowsFont : public gfxFont {
 public:
-    gfxWindowsFont(FontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
+    gfxWindowsFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
                    cairo_antialias_t anAntialiasOption = CAIRO_ANTIALIAS_DEFAULT);
     virtual ~gfxWindowsFont();
 
     virtual const gfxFont::Metrics& GetMetrics();
 
     HFONT GetHFONT() { return mFont; }
     cairo_font_face_t *CairoFontFace();
     cairo_scaled_font_t *CairoScaledFont();
@@ -331,20 +92,20 @@ public:
                                Spacing *aSpacing);
 
     virtual PRUint32 GetSpaceGlyph() {
         GetMetrics(); // ensure that the metrics are computed but don't recompute them
         return mSpaceGlyph;
     };
 
     PRBool IsValid() { GetMetrics(); return mIsValid; }
-    FontEntry *GetFontEntry();
+    GDIFontEntry *GetFontEntry();
 
     static already_AddRefed<gfxWindowsFont>
-    GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle,
+    GetOrMakeFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle,
                   PRBool aNeedsBold = PR_FALSE);
 
 protected:
     HFONT MakeHFONT();
     void FillLogFont(gfxFloat aSize);
 
     HFONT    mFont;
     gfxFloat mAdjustedSize;
@@ -385,56 +146,59 @@ public:
                                     const Parameters* aParams, PRUint32 aFlags);
     virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
                                     const Parameters* aParams, PRUint32 aFlags);
 
     const nsACString& GetGenericFamily() const {
         return mGenericFamily;
     }
 
-    const nsTArray<nsRefPtr<FontEntry> >& GetFontList() const {
-        return mFontEntries;
-    }
-    PRUint32 FontListLength() const {
-        return mFontEntries.Length();
-    }
-
-    FontEntry *GetFontEntryAt(PRInt32 i) {
-        return mFontEntries[i];
-    }
-
-    virtual gfxWindowsFont *GetFontAt(PRInt32 i);
-
-    void GroupFamilyListToArrayList(nsTArray<nsRefPtr<FontEntry> > *list,
+    void GroupFamilyListToArrayList(nsTArray<nsRefPtr<gfxFontEntry> > *list,
                                     nsTArray<PRPackedBool> *aNeedsBold);
     void FamilyListToArrayList(const nsString& aFamilies,
                                const nsCString& aLangGroup,
-                               nsTArray<nsRefPtr<FontEntry> > *list);
+                               nsTArray<nsRefPtr<gfxFontEntry> > *list);
 
-    void UpdateFontList();
+    virtual void UpdateFontList();
     virtual gfxFloat GetUnderlineOffset();
 
+    gfxWindowsFont* GetFontAt(PRInt32 aFontIndex) {
+        // If it turns out to be hard for all clients that cache font
+        // groups to call UpdateFontList at appropriate times, we could
+        // instead consider just calling UpdateFontList from someplace
+        // more central (such as here).
+        NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
+                     "Whoever was caching this font group should have "
+                     "called UpdateFontList on it");
+
+        return static_cast<gfxWindowsFont*>(static_cast<gfxFont*>(mFonts[aFontIndex]));
+    }
 
 protected:
     void InitFontList();
     void InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun, const char *aString, PRUint32 aLength);
     void InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength);
 
     void InitTextRunUniscribe(gfxContext *aContext, gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength);
 
     already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
     already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);
 
-    already_AddRefed<gfxWindowsFont> WhichFontSupportsChar(const nsTArray<nsRefPtr<FontEntry> >& fonts, PRUint32 ch);
-    void GetPrefFonts(const char *aLangGroup, nsTArray<nsRefPtr<FontEntry> >& array);
-    void GetCJKPrefFonts(nsTArray<nsRefPtr<FontEntry> >& array);
+    already_AddRefed<gfxWindowsFont> WhichFontSupportsChar(const nsTArray<nsRefPtr<gfxFontEntry> >& fonts, PRUint32 ch);
+    void GetPrefFonts(const char *aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> >& array);
+    void GetCJKPrefFonts(nsTArray<nsRefPtr<gfxFontEntry> >& array);
+
+    static PRBool FindWindowsFont(const nsAString& aName,
+                                  const nsACString& aGenericName,
+                                  void *closure);
+
+    PRBool HasFont(gfxFontEntry *aFontEntry);
 
 private:
 
     nsCString mGenericFamily;
-    nsTArray<nsRefPtr<FontEntry> > mFontEntries;
     nsTArray<PRPackedBool> mFontNeedsBold;
 
     const char *mItemLangGroup;  // used by pref-lang handling code
 
 };
 
 #endif /* GFX_WINDOWSFONTS_H */
--- a/gfx/thebes/public/gfxWindowsPlatform.h
+++ b/gfx/thebes/public/gfxWindowsPlatform.h
@@ -56,24 +56,26 @@
 #include "nsDataHashtable.h"
 
 #ifdef MOZ_FT2_FONTS
 typedef struct FT_LibraryRec_ *FT_Library;
 #endif
 
 #include <windows.h>
 
-class THEBES_API gfxWindowsPlatform : public gfxPlatform, private gfxFontInfoLoader {
+class THEBES_API gfxWindowsPlatform : public gfxPlatform {
 public:
     gfxWindowsPlatform();
     virtual ~gfxWindowsPlatform();
     static gfxWindowsPlatform *GetPlatform() {
         return (gfxWindowsPlatform*) gfxPlatform::GetPlatform();
     }
 
+    virtual gfxPlatformFontList* CreatePlatformFontList();
+
     already_AddRefed<gfxASurface> CreateOffscreenSurface(const gfxIntSize& size,
                                                          gfxASurface::gfxImageFormat imageFormat);
 
     enum RenderMode {
         /* Use GDI and windows surfaces */
         RENDER_GDI = 0,
 
         /* Use 32bpp image surfaces and call StretchDIBits */
@@ -99,18 +101,16 @@ public:
     void SetRenderMode(RenderMode rmode) { mRenderMode = rmode; }
 
     nsresult GetFontList(const nsACString& aLangGroup,
                          const nsACString& aGenericFamily,
                          nsTArray<nsString>& aListOfFonts);
 
     nsresult UpdateFontList();
 
-    void GetFontFamilyList(nsTArray<nsRefPtr<FontFamily> >& aFamilyArray);
-
     nsresult ResolveFontName(const nsAString& aFontName,
                              FontResolverCallback aCallback,
                              void *aClosure, PRBool& aAborted);
 
     nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
     gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
                                   const gfxFontStyle *aStyle,
@@ -129,100 +129,36 @@ public:
                                            const PRUint8 *aFontData,
                                            PRUint32 aLength);
 
     /**
      * Check whether format is supported on a platform or not (if unclear, returns true)
      */
     virtual PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags);
 
-    /* Given a string and a font we already have find the font that
-     * supports the most code points and most closely resembles aFont
-     *
-     * this involves looking at the fonts on your machine and seeing which
-     * code points they support as well as looking at things like the font
-     * family, style, weight, etc.
-     */
-    already_AddRefed<gfxFont>
-    FindFontForChar(PRUint32 aCh, gfxFont *aFont);
+    /* Find a FontFamily/FontEntry object that represents a font on your system given a name */
+    gfxFontFamily *FindFontFamily(const nsAString& aName);
+    gfxFontEntry *FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle);
 
-    /* Find a FontFamily/FontEntry object that represents a font on your system given a name */
-    FontFamily *FindFontFamily(const nsAString& aName);
-    FontEntry *FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle);
-
-    PRBool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> > *array);
-    void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> >& array);
+    PRBool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> > *array);
+    void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> >& array);
 
     void ClearPrefFonts() { mPrefFonts.Clear(); }
 
-    typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
-
 #ifdef MOZ_FT2_FONTS
     FT_Library GetFTLibrary();
-private:
-    void AppendFacesFromFontFile(const PRUnichar *aFileName);
-    void FindFonts();
 #endif
 
 protected:
     void InitDisplayCaps();
 
     RenderMode mRenderMode;
 
 private:
     void Init();
 
-    void InitBadUnderlineList();
-
-    static int CALLBACK FontEnumProc(const ENUMLOGFONTEXW *lpelfe,
-                                     const NEWTEXTMETRICEXW *metrics,
-                                     DWORD fontType, LPARAM data);
-    static int CALLBACK FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
-                                            const NEWTEXTMETRICEXW *nmetrics,
-                                            DWORD fontType, LPARAM data);
-
-    static PLDHashOperator FontGetStylesProc(nsStringHashKey::KeyType aKey,
-                                             nsRefPtr<FontFamily>& aFontFamily,
-                                             void* userArg);
-
-    static PLDHashOperator FontGetCMapDataProc(nsStringHashKey::KeyType aKey,
-                                               nsRefPtr<FontFamily>& aFontFamily,
-                                               void* userArg);
-
-    static int CALLBACK FontResolveProc(const ENUMLOGFONTEXW *lpelfe,
-                                        const NEWTEXTMETRICEXW *metrics,
-                                        DWORD fontType, LPARAM data);
-
-    static PLDHashOperator HashEnumFunc(nsStringHashKey::KeyType aKey,
-                                        nsRefPtr<FontFamily>& aData,
-                                        void* userArg);
-
-    static PLDHashOperator FindFontForCharProc(nsStringHashKey::KeyType aKey,
-                                               nsRefPtr<FontFamily>& aFontFamily,
-                                               void* userArg);
-
     virtual qcms_profile* GetPlatformCMSOutputProfile();
 
-    static int PrefChangedCallback(const char*, void*);
-
-    // gfxFontInfoLoader overrides, used to load in font cmaps
-    virtual void InitLoader();
-    virtual PRBool RunLoader();
-    virtual void FinishLoader();
-
-    FontTable mFonts;
-    FontTable mFontAliases;
-    FontTable mFontSubstitutes;
-    nsTArray<nsString> mNonExistingFonts;
-
-    // when system-wide font lookup fails for a character, cache it to skip future searches
-    gfxSparseBitSet mCodepointsWithNoFonts;
-    
-    nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<FontEntry> > > mPrefFonts;
-
-    // data used as part of the font cmap loading process
-    nsTArray<nsRefPtr<FontFamily> > mFontFamilies;
-    PRUint32 mStartIndex;
-    PRUint32 mIncrement;
-    PRUint32 mNumFamilies;
+    // TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList
+    nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
 };
 
 #endif /* GFX_WINDOWS_PLATFORM_H */
--- a/gfx/thebes/src/Makefile.in
+++ b/gfx/thebes/src/Makefile.in
@@ -51,20 +51,23 @@ CPPSRCS	+= 	gfxWindowsPlatform.cpp \
 		nsUnicodeRange.cpp \
 		$(NULL)
 
 ifdef WINCE
 CPPSRCS	+= gfxFT2Fonts.cpp \
 	   gfxFT2FontBase.cpp \
 	   gfxFT2Utils.cpp \
 	   gfxDDrawSurface.cpp \
+	   gfxFT2FontList.cpp \
 	   $(NULL)
 EXTRA_DSO_LDOPTS += ddraw.lib
 else
-CPPSRCS	+= gfxWindowsFonts.cpp 
+CPPSRCS	+= gfxWindowsFonts.cpp \
+	   gfxGDIFontList.cpp \
+	   $(NULL)
 endif
 
 CPPSRCS +=	gfxPDFSurface.cpp
 
 _OS_LIBS	= usp10 msimg32
 ifdef GNU_CXX
 _OS_LIBS	+= uuid
 endif
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/gfxFT2FontList.cpp
@@ -0,0 +1,286 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Stuart Parmenter <stuart@mozilla.com>
+ *   Masayuki Nakano <masayuki@d-toybox.com>
+ *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   John Daggett <jdaggett@mozilla.com>
+ *   Jonathan Kew <jfkthame@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * 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 "gfxFT2FontList.h"
+#include "gfxUserFontSet.h"
+#include "gfxFontUtils.h"
+
+#include "ft2build.h"
+#include FT_FREETYPE_H
+#include "gfxFT2Fonts.h"
+
+#include "nsIPref.h"  // for pref changes callback notification
+#include "nsServiceManagerUtils.h"
+#include "nsTArray.h"
+#include "nsUnicharUtils.h"
+
+#include "nsDirectoryServiceUtils.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsISimpleEnumerator.h"
+#include "nsIWindowsRegKey.h"
+
+#ifdef XP_WIN
+#include <windows.h>
+#endif
+
+#define ROUND(x) floor((x) + 0.5)
+
+#ifdef PR_LOGGING
+static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
+#endif /* PR_LOGGING */
+
+#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)
+{
+    if (aName.Length() >= LF_FACESIZE)
+        aName.Truncate(LF_FACESIZE - 1);
+    ToLowerCase(aName);
+}
+
+/***************************************************************
+ *
+ * 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.
+//
+// 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.
+
+gfxFT2FontList::gfxFT2FontList()
+{
+}
+
+void
+gfxFT2FontList::AppendFacesFromFontFile(const PRUnichar *aFileName)
+{
+    char fileName[MAX_PATH];
+    WideCharToMultiByte(CP_ACP, 0, aFileName, -1, fileName, MAX_PATH, NULL, NULL);
+    FT_Library ftLibrary = gfxWindowsPlatform::GetPlatform()->GetFTLibrary();
+    FT_Face dummy;
+    if (FT_Err_Ok == FT_New_Face(ftLibrary, fileName, -1, &dummy)) {
+        for (FT_Long i = 0; i < dummy->num_faces; i++) {
+            FT_Face face;
+            if (FT_Err_Ok != FT_New_Face(ftLibrary, fileName, i, &face))
+                continue;
+
+            FontEntry* fe = FontEntry::CreateFontEntryFromFace(face);
+            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);
+                }
+                family->AddFontEntry(fe);
+                family->SetHasStyles(PR_TRUE);
+#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);
+    }
+}
+
+void
+gfxFT2FontList::FindFonts()
+{
+    nsTArray<nsString> searchPaths(3);
+    nsTArray<nsString> fontPatterns(3);
+    fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.ttf"));
+    fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.ttc"));
+    fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.otf"));
+    wchar_t pathBuf[256];
+    SHGetSpecialFolderPathW(0, pathBuf, CSIDL_WINDOWS, 0);
+    searchPaths.AppendElement(pathBuf);
+    SHGetSpecialFolderPathW(0, pathBuf, CSIDL_FONTS, 0);
+    searchPaths.AppendElement(pathBuf);
+    nsCOMPtr<nsIFile> resDir;
+    NS_GetSpecialDirectory(NS_APP_RES_DIR, getter_AddRefs(resDir));
+    if (resDir) {
+        resDir->Append(NS_LITERAL_STRING("fonts"));
+        nsAutoString resPath;
+        resDir->GetPath(resPath);
+        searchPaths.AppendElement(resPath);
+    }
+    WIN32_FIND_DATAW results;
+    for (PRUint32 i = 0;  i < searchPaths.Length(); i++) {
+        const nsString& path(searchPaths[i]);
+        for (PRUint32 j = 0; j < fontPatterns.Length(); j++) { 
+            nsAutoString pattern(path);
+            pattern.Append(fontPatterns[j]);
+            HANDLE handle = FindFirstFileExW(pattern.get(),
+                                             FindExInfoStandard,
+                                             &results,
+                                             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()));
+                moreFiles = FindNextFile(handle, &results);
+            }
+            if (handle != INVALID_HANDLE_VALUE)
+                FindClose(handle);
+        }
+    }
+}
+
+void
+gfxFT2FontList::InitFontList()
+{
+    mFontFamilies.Clear();
+    mOtherFamilyNames.Clear();
+    mOtherFamilyNamesInitialized = PR_FALSE;
+    mPrefFonts.Clear();
+    CancelLoader();
+
+    // initialize ranges of characters for which system-wide font search should be skipped
+    mCodepointsWithNoFonts.reset();
+    mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
+    mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
+
+    FindFonts();
+
+    InitBadUnderlineList();
+}
+
+struct FullFontNameSearch {
+    FullFontNameSearch(const nsAString& aFullName)
+        : mFullName(aFullName), mFontEntry(nsnull)
+    { }
+
+    nsString     mFullName;
+    gfxFontEntry *mFontEntry;
+};
+
+// callback called for each family name, based on the assumption that the 
+// first part of the full name is the family name
+static PLDHashOperator
+FindFullName(nsStringHashKey::KeyType aKey,
+             nsRefPtr<gfxFontFamily>& aFontFamily,
+             void* userArg)
+{
+    FullFontNameSearch *data = reinterpret_cast<FullFontNameSearch*>(userArg);
+
+    // does the family name match up to the length of the family name?
+    const nsString& family = aFontFamily->Name();
+    
+    nsString fullNameFamily;
+    data->mFullName.Left(fullNameFamily, family.Length());
+
+    // if so, iterate over faces in this family to see if there is a match
+    if (family.Equals(fullNameFamily)) {
+        nsTArray<nsRefPtr<gfxFontEntry> >& fontList = aFontFamily->GetFontList();
+        int index, len = fontList.Length();
+        for (index = 0; index < len; index++) {
+            if (fontList[index]->Name().Equals(data->mFullName)) {
+                data->mFontEntry = fontList[index];
+                return PL_DHASH_STOP;
+            }
+        }
+    }
+
+    return PL_DHASH_NEXT;
+}
+
+gfxFontEntry* 
+gfxFT2FontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
+                                       const nsAString& aFontName)
+{
+    // walk over list of names
+    FullFontNameSearch data(aFontName);
+
+    mFontFamilies.Enumerate(FindFullName, &data);
+
+    return data.mFontEntry;
+}
+
+gfxFontEntry*
+gfxFT2FontList::GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold)
+{
+#ifdef XP_WIN
+    HGDIOBJ hGDI = ::GetStockObject(SYSTEM_FONT);
+    LOGFONTW logFont;
+    if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) {
+        nsAutoString resolvedName;
+        if (ResolveFontName(nsDependentString(logFont.lfFaceName), resolvedName)) {
+            return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
+        }
+    }
+#endif
+    /* TODO: what about Qt or other platforms that may use this? */
+    return nsnull;
+}
+
+gfxFontEntry*
+gfxFT2FontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
+                                 const PRUint8 *aFontData,
+                                 PRUint32 aLength)
+{
+    // The FT2 font needs the font data to persist, so we do NOT free it here
+    // but instead pass ownership to the font entry.
+    // Deallocation will happen later, when the font face is destroyed.
+    return FontEntry::CreateFontEntry(*aProxyEntry, aFontData, aLength);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/gfxFT2FontList.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Stuart Parmenter <stuart@mozilla.com>
+ *   Masayuki Nakano <masayuki@d-toybox.com>
+ *   John Daggett <jdaggett@mozilla.com>
+ *   Jonathan Kew <jfkthame@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * 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 ***** */
+
+#ifndef GFX_FT2FONTLIST_H
+#define GFX_FT2FONTLIST_H
+
+#include "gfxWindowsPlatform.h"
+#include "gfxPlatformFontList.h"
+
+#include <windows.h>
+#include <bitset>
+
+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);
+
+protected:
+    virtual void InitFontList();
+
+    void AppendFacesFromFontFile(const PRUnichar *aFileName);
+    void FindFonts();
+};
+
+#endif /* GFX_FT2FONTLIST_H */
--- a/gfx/thebes/src/gfxFT2Fonts.cpp
+++ b/gfx/thebes/src/gfxFT2Fonts.cpp
@@ -42,16 +42,17 @@
 #include <qfontinfo.h>
 #define gfxToolkitPlatform gfxQtPlatform
 #elif defined(XP_WIN)
 #ifdef WINCE
 #define SHGetSpecialFolderPathW SHGetSpecialFolderPath
 #endif
 #include "gfxWindowsPlatform.h"
 #define gfxToolkitPlatform gfxWindowsPlatform
+#include "gfxFT2FontList.h"
 #endif
 #include "gfxTypes.h"
 #include "gfxFT2Fonts.h"
 #include "gfxFT2FontBase.h"
 #include "gfxFT2Utils.h"
 #include <locale.h>
 #include "cairo-ft.h"
 #include FT_TRUETYPE_TAGS_H
@@ -480,33 +481,33 @@ AddFontNameToArray(const nsAString& aNam
     }
 
     return PR_TRUE;
 }
 
 void
 gfxFT2FontGroup::FamilyListToArrayList(const nsString& aFamilies,
                                        const nsCString& aLangGroup,
-                                       nsTArray<nsRefPtr<FontEntry> > *aFontEntryList)
+                                       nsTArray<nsRefPtr<gfxFontEntry> > *aFontEntryList)
 {
     nsAutoTArray<nsString, 15> fonts;
     ForEachFont(aFamilies, aLangGroup, AddFontNameToArray, &fonts);
 
     PRUint32 len = fonts.Length();
     for (PRUint32 i = 0; i < len; ++i) {
         const nsString& str = fonts[i];
-        nsRefPtr<FontEntry> fe = gfxToolkitPlatform::GetPlatform()->FindFontEntry(str, mStyle);
+        nsRefPtr<gfxFontEntry> fe = (gfxToolkitPlatform::GetPlatform()->FindFontEntry(str, mStyle));
         aFontEntryList->AppendElement(fe);
     }
 }
 
-void gfxFT2FontGroup::GetPrefFonts(const char *aLangGroup, nsTArray<nsRefPtr<FontEntry> >& aFontEntryList) {
+void gfxFT2FontGroup::GetPrefFonts(const char *aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList) {
     NS_ASSERTION(aLangGroup, "aLangGroup is null");
     gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
-    nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
+    nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
     /* this lookup has to depend on weight and style */
     nsCAutoString key(aLangGroup);
     key.Append("-");
     key.AppendInt(GetStyle()->style);
     key.Append("-");
     key.AppendInt(GetStyle()->weight);
     if (!platform->GetPrefFontEntries(key, &fonts)) {
         nsString fontString;
@@ -527,17 +528,17 @@ static PRInt32 GetCJKLangGroupIndex(cons
     for (i = 0; i < COUNT_OF_CJK_LANG_GROUP; i++) {
         if (!PL_strcasecmp(aLangGroup, sCJKLangGroup[i]))
             return i;
     }
     return -1;
 }
 
 // this function assigns to the array passed in.
-void gfxFT2FontGroup::GetCJKPrefFonts(nsTArray<nsRefPtr<FontEntry> >& aFontEntryList) {
+void gfxFT2FontGroup::GetCJKPrefFonts(nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList) {
     gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
 
     nsCAutoString key("x-internal-cjk-");
     key.AppendInt(mStyle.style);
     key.Append("-");
     key.AppendInt(mStyle.weight);
 
     if (!platform->GetPrefFontEntries(key, &aFontEntryList)) {
@@ -617,61 +618,61 @@ void gfxFT2FontGroup::GetCJKPrefFonts(ns
         GetPrefFonts(CJK_LANG_ZH_HK, aFontEntryList);
         GetPrefFonts(CJK_LANG_ZH_TW, aFontEntryList);
 
         platform->SetPrefFontEntries(key, aFontEntryList);
     }
 }
 
 already_AddRefed<gfxFT2Font>
-gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray<nsRefPtr<FontEntry> >& aFontEntryList, PRUint32 aCh)
+gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList, PRUint32 aCh)
 {
     for (PRUint32 i = 0; i < aFontEntryList.Length(); i++) {
-        nsRefPtr<FontEntry> fe = aFontEntryList[i];
+        gfxFontEntry *fe = aFontEntryList[i].get();
         if (fe->HasCharacter(aCh)) {
             nsRefPtr<gfxFT2Font> font =
-                gfxFT2Font::GetOrMakeFont(fe, &mStyle);
+                gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(fe), &mStyle);
             return font.forget();
         }
     }
     return nsnull;
 }
 
 already_AddRefed<gfxFont>
 gfxFT2FontGroup::WhichPrefFontSupportsChar(PRUint32 aCh)
 {
     if (aCh > 0xFFFF)
         return nsnull;
 
     nsRefPtr<gfxFT2Font> selectedFont;
 
     // check out the style's language group
-    nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
+    nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
     GetPrefFonts(mStyle.langGroup.get(), fonts);
     selectedFont = WhichFontSupportsChar(fonts, aCh);
 
     // otherwise search prefs
     if (!selectedFont) {
         PRUint32 unicodeRange = FindCharUnicodeRange(aCh);
 
         /* special case CJK */
         if (unicodeRange == kRangeSetCJK) {
             if (PR_LOG_TEST(gFontLog, PR_LOG_DEBUG)) {
                 PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: CJK"));
             }
 
-            nsAutoTArray<nsRefPtr<FontEntry>, 15> fonts;
+            nsAutoTArray<nsRefPtr<gfxFontEntry>, 15> fonts;
             GetCJKPrefFonts(fonts);
             selectedFont = WhichFontSupportsChar(fonts, aCh);
         } else {
             const char *langGroup = LangGroupFromUnicodeRange(unicodeRange);
             if (langGroup) {
                 PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: %s", langGroup));
 
-                nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
+                nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
                 GetPrefFonts(langGroup, fonts);
                 selectedFont = WhichFontSupportsChar(fonts, aCh);
             }
         }
     }
 
     if (selectedFont) {
         nsRefPtr<gfxFont> f = static_cast<gfxFont*>(selectedFont.get());
@@ -679,22 +680,32 @@ gfxFT2FontGroup::WhichPrefFontSupportsCh
     }
 
     return nsnull;
 }
 
 already_AddRefed<gfxFont>
 gfxFT2FontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
 {
+#ifdef XP_WIN
+    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
     nsRefPtr<gfxFont> selectedFont;
     nsRefPtr<gfxFT2Font> refFont = GetFontAt(0);
     gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
     selectedFont = platform->FindFontForChar(aCh, refFont);
     if (selectedFont)
         return selectedFont.forget();
+#endif
     return nsnull;
 }
 
 void gfxFT2FontGroup::CreateGlyphRunsFT(gfxTextRun *aTextRun)
 {
     ComputeRanges(mRanges, mString.get(), 0, mString.Length());
 
     PRUint32 offset = 0;
@@ -876,17 +887,18 @@ CreateScaledFont(FontEntry *aFontEntry, 
 /**
  * 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)
 {
-    FontEntry *fe = gfxToolkitPlatform::GetPlatform()->FindFontEntry(aName, *aStyle);
+    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);
     return font.forget();
 }
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/gfxGDIFontList.cpp
@@ -0,0 +1,961 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Stuart Parmenter <stuart@mozilla.com>
+ *   Masayuki Nakano <masayuki@d-toybox.com>
+ *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   John Daggett <jdaggett@mozilla.com>
+ *   Jonathan Kew <jfkthame@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * 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 "gfxGDIFontList.h"
+#include "gfxWindowsPlatform.h"
+#include "gfxUserFontSet.h"
+#include "gfxFontUtils.h"
+#include "gfxWindowsFonts.h"
+
+#include "nsIPref.h"  // for pref changes callback notification
+#include "nsServiceManagerUtils.h"
+#include "nsTArray.h"
+#include "nsUnicharUtils.h"
+
+#include "nsDirectoryServiceUtils.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsISimpleEnumerator.h"
+#include "nsIWindowsRegKey.h"
+
+#define ROUND(x) floor((x) + 0.5)
+
+#ifdef PR_LOGGING
+static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
+#endif /* PR_LOGGING */
+
+#define LOG(args) PR_LOG(gFontInfoLog, PR_LOG_DEBUG, args)
+#define LOG_ENABLED() PR_LOG_TEST(gFontInfoLog, PR_LOG_DEBUG)
+
+// font info loader constants
+static const PRUint32 kDelayBeforeLoadingFonts = 8 * 1000; // 8secs
+static const PRUint32 kIntervalBetweenLoadingFonts = 150; // 150ms
+
+static __inline void
+BuildKeyNameFromFontName(nsAString &aName)
+{
+    if (aName.Length() >= LF_FACESIZE)
+        aName.Truncate(LF_FACESIZE - 1);
+    ToLowerCase(aName);
+}
+
+// Implementation of gfxPlatformFontList for Win32 GDI,
+// using GDI font enumeration APIs to get the list of fonts
+
+// from t2embapi.h, included in Platform SDK 6.1 but not 6.0
+
+#ifndef __t2embapi__
+
+#define TTLOAD_PRIVATE                  0x00000001
+#define LICENSE_PREVIEWPRINT            0x0004
+#define E_NONE                          0x0000L
+
+typedef unsigned long( WINAPIV *READEMBEDPROC ) ( void*, void*, const unsigned long );
+
+typedef struct
+{
+    unsigned short usStructSize;    // size in bytes of structure client should set to sizeof(TTLOADINFO)
+    unsigned short usRefStrSize;    // size in wide characters of pusRefStr including NULL terminator
+    unsigned short *pusRefStr;      // reference or actual string.
+}TTLOADINFO;
+
+LONG WINAPI TTLoadEmbeddedFont
+(
+    HANDLE*  phFontReference,           // on completion, contains handle to identify embedded font installed
+                                        // on system
+    ULONG    ulFlags,                   // flags specifying the request 
+    ULONG*   pulPrivStatus,             // on completion, contains the embedding status
+    ULONG    ulPrivs,                   // allows for the reduction of licensing privileges
+    ULONG*   pulStatus,                 // on completion, may contain status flags for request 
+    READEMBEDPROC lpfnReadFromStream,   // callback function for doc/disk reads
+    LPVOID   lpvReadStream,             // the input stream tokin
+    LPWSTR   szWinFamilyName,           // the new 16 bit windows family name can be NULL
+    LPSTR    szMacFamilyName,           // the new 8 bit mac family name can be NULL
+    TTLOADINFO* pTTLoadInfo             // optional security
+);
+
+#endif // __t2embapi__
+
+typedef LONG( WINAPI *TTLoadEmbeddedFontProc ) (HANDLE* phFontReference, ULONG ulFlags, ULONG* pulPrivStatus, ULONG ulPrivs, ULONG* pulStatus, 
+                                             READEMBEDPROC lpfnReadFromStream, LPVOID lpvReadStream, LPWSTR szWinFamilyName, 
+                                             LPSTR szMacFamilyName, TTLOADINFO* pTTLoadInfo);
+
+typedef LONG( WINAPI *TTDeleteEmbeddedFontProc ) (HANDLE hFontReference, ULONG ulFlags, ULONG* pulStatus);
+
+
+static TTLoadEmbeddedFontProc TTLoadEmbeddedFontPtr = nsnull;
+static TTDeleteEmbeddedFontProc TTDeleteEmbeddedFontPtr = nsnull;
+
+class WinUserFontData : public gfxUserFontData {
+public:
+    WinUserFontData(HANDLE aFontRef, PRBool aIsCFF)
+        : mFontRef(aFontRef), mIsCFF(aIsCFF)
+    { }
+
+    virtual ~WinUserFontData()
+    {
+        if (mIsCFF) {
+            RemoveFontMemResourceEx(mFontRef);
+        } else {
+            ULONG pulStatus;
+            TTDeleteEmbeddedFontPtr(mFontRef, 0, &pulStatus);
+        }
+    }
+    
+    HANDLE mFontRef;
+    PRPackedBool mIsCFF;
+};
+
+BYTE 
+FontTypeToOutPrecision(PRUint8 fontType)
+{
+    BYTE ret;
+    switch (fontType) {
+    case GFX_FONT_TYPE_TT_OPENTYPE:
+    case GFX_FONT_TYPE_TRUETYPE:
+        ret = OUT_TT_ONLY_PRECIS;
+        break;
+    case GFX_FONT_TYPE_PS_OPENTYPE:
+        ret = OUT_PS_ONLY_PRECIS;
+        break;
+    case GFX_FONT_TYPE_TYPE1:
+        ret = OUT_OUTLINE_PRECIS;
+        break;
+    case GFX_FONT_TYPE_RASTER:
+        ret = OUT_RASTER_PRECIS;
+        break;
+    case GFX_FONT_TYPE_DEVICE:
+        ret = OUT_DEVICE_PRECIS;
+        break;
+    default:
+        ret = OUT_DEFAULT_PRECIS;
+    }
+    return ret;
+}
+
+/***************************************************************
+ *
+ * GDIFontEntry
+ *
+ */
+
+GDIFontEntry::GDIFontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
+                                   PRBool aItalic, PRUint16 aWeight, gfxUserFontData *aUserFontData) : 
+    gfxFontEntry(aFaceName), mFontType(aFontType),
+    mForceGDI(PR_FALSE), mUnknownCMAP(PR_FALSE),
+    mUnicodeFont(PR_FALSE),
+    mCharset(), mUnicodeRanges()
+{
+    mUserFontData = aUserFontData;
+    mItalic = aItalic;
+    mWeight = aWeight;
+    if (IsType1())
+        mForceGDI = PR_TRUE;
+    mIsUserFont = aUserFontData != nsnull;
+    InitLogFont(aFaceName, aFontType);
+}
+
+nsresult
+GDIFontEntry::ReadCMAP()
+{
+    // attempt this once, if errors occur leave a blank cmap
+    if (mCmapInitialized)
+        return NS_OK;
+    mCmapInitialized = PR_TRUE;
+
+    const PRUint32 kCmapTag = TRUETYPE_TAG('c','m','a','p');
+    nsAutoTArray<PRUint8,16384> buffer;
+    if (GetFontTable(kCmapTag, buffer) != NS_OK)
+        return NS_ERROR_FAILURE;
+    PRUint8 *cmap = buffer.Elements();
+
+    PRPackedBool  unicodeFont = PR_FALSE, symbolFont = PR_FALSE;
+    nsresult rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(),
+                                         mCharacterMap, unicodeFont, symbolFont);
+    mUnicodeFont = unicodeFont;
+    mSymbolFont = symbolFont;
+
+    PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-cmap) psname: %s, size: %d\n", 
+                                        NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
+    return rv;
+}
+
+nsresult
+GDIFontEntry::GetFontTable(PRUint32 aTableTag, nsTArray<PRUint8>& aBuffer)
+{
+    AutoDC dc;
+    AutoSelectFont font(dc.GetDC(), &mLogFont);
+    if (font.IsValid()) {
+        PRInt32 tableSize = ::GetFontData(dc.GetDC(), NS_SWAP32(aTableTag), 0, NULL, NULL);
+        if (tableSize != GDI_ERROR) {
+            if (aBuffer.SetLength(tableSize)) {
+                ::GetFontData(dc.GetDC(), NS_SWAP32(aTableTag), 0, aBuffer.Elements(), tableSize);
+                return NS_OK;
+            }
+            return NS_ERROR_OUT_OF_MEMORY;
+        }
+    }
+    return NS_ERROR_FAILURE;
+}
+
+void
+GDIFontEntry::FillLogFont(LOGFONTW *aLogFont, PRBool aItalic,
+                              PRUint16 aWeight, gfxFloat aSize)
+{
+    memcpy(aLogFont, &mLogFont, sizeof(LOGFONTW));
+
+    aLogFont->lfHeight = (LONG)-ROUND(aSize);
+
+    if (aLogFont->lfHeight == 0)
+        aLogFont->lfHeight = -1;
+
+    // always force lfItalic if we want it.  Font selection code will
+    // do its best to give us an italic font entry, but if no face exists
+    // it may give us a regular one based on weight.  Windows should
+    // do fake italic for us in that case.
+    aLogFont->lfItalic         = aItalic;
+    aLogFont->lfWeight         = aWeight;
+}
+
+PRBool 
+GDIFontEntry::TestCharacterMap(PRUint32 aCh)
+{
+    if (ReadCMAP() != NS_OK) {
+        // Type1 fonts aren't necessarily Unicode but
+        // this is the best guess we can make here
+        mUnicodeFont = IsType1();
+
+        // For fonts where we failed to read the character map,
+        // we can take a slow path to look up glyphs character by character
+        mUnknownCMAP = PR_TRUE;
+    }
+
+    if (mUnknownCMAP) {
+        if (aCh > 0xFFFF)
+            return PR_FALSE;
+
+        // previous code was using the group style
+        gfxFontStyle fakeStyle;  
+        if (mItalic)
+            fakeStyle.style = FONT_STYLE_ITALIC;
+        fakeStyle.weight = mWeight * 100;
+
+        nsRefPtr<gfxWindowsFont> font =
+            gfxWindowsFont::GetOrMakeFont(this, &fakeStyle);
+        if (!font->IsValid())
+            return PR_FALSE;
+
+        HDC dc = GetDC((HWND)nsnull);
+        SetGraphicsMode(dc, GM_ADVANCED);
+        HFONT hfont = font->GetHFONT();
+        HFONT oldFont = (HFONT)SelectObject(dc, hfont);
+
+        PRUnichar str[1] = { (PRUnichar)aCh };
+        WORD glyph[1];
+
+        PRBool hasGlyph = PR_FALSE;
+        if (IsType1()) {
+            // Type1 fonts and uniscribe APIs don't get along.  ScriptGetCMap will return E_HANDLE
+            DWORD ret = GetGlyphIndicesW(dc, str, 1, glyph, GGI_MARK_NONEXISTING_GLYPHS);
+            if (ret != GDI_ERROR && glyph[0] != 0xFFFF)
+                hasGlyph = PR_TRUE;
+        } else {
+            // ScriptGetCMap works better than GetGlyphIndicesW for things like bitmap/vector fonts
+            HRESULT rv = ScriptGetCMap(dc, font->ScriptCache(), str, 1, 0, glyph);
+            if (rv == S_OK)
+                hasGlyph = PR_TRUE;
+        }
+
+        SelectObject(dc, oldFont);
+        ReleaseDC(NULL, dc);
+
+        if (hasGlyph) {
+            mCharacterMap.set(aCh);
+            return PR_TRUE;
+        }
+    } else {
+        // font had a cmap so simply check that
+        return mCharacterMap.test(aCh);
+    }
+
+    return PR_FALSE;
+}
+
+void
+GDIFontEntry::InitLogFont(const nsAString& aName,
+                              gfxWindowsFontType aFontType)
+{
+#define CLIP_TURNOFF_FONTASSOCIATION 0x40
+    
+    mLogFont.lfHeight = -1;
+
+    // Fill in logFont structure
+    mLogFont.lfWidth          = 0;
+    mLogFont.lfEscapement     = 0;
+    mLogFont.lfOrientation    = 0;
+    mLogFont.lfUnderline      = FALSE;
+    mLogFont.lfStrikeOut      = FALSE;
+    mLogFont.lfCharSet        = DEFAULT_CHARSET;
+    mLogFont.lfOutPrecision   = FontTypeToOutPrecision(aFontType);
+    mLogFont.lfClipPrecision  = CLIP_TURNOFF_FONTASSOCIATION;
+    mLogFont.lfQuality        = DEFAULT_QUALITY;
+    mLogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+    // always force lfItalic if we want it.  Font selection code will
+    // do its best to give us an italic font entry, but if no face exists
+    // it may give us a regular one based on weight.  Windows should
+    // do fake italic for us in that case.
+    mLogFont.lfItalic         = mItalic;
+    mLogFont.lfWeight         = mWeight;
+
+    int len = PR_MIN(aName.Length(), LF_FACESIZE - 1);
+    memcpy(&mLogFont.lfFaceName, nsPromiseFlatString(aName).get(), len * 2);
+    mLogFont.lfFaceName[len] = '\0';
+}
+
+GDIFontEntry* 
+GDIFontEntry::CreateFontEntry(const nsAString& aName, gfxWindowsFontType aFontType, 
+                                  PRBool aItalic, PRUint16 aWeight, 
+                                  gfxUserFontData* aUserFontData)
+{
+    // jtdfix - need to set charset, unicode ranges, pitch/family
+
+    GDIFontEntry *fe = new GDIFontEntry(aName, aFontType, aItalic, aWeight,
+                                        aUserFontData);
+
+    // ReadCMAP may change the values of mUnicodeFont and mSymbolFont
+    if (NS_FAILED(fe->ReadCMAP())) {
+        // Type1 fonts aren't necessarily Unicode but
+        // this is the best guess we can make here
+        if (fe->IsType1())
+            fe->mUnicodeFont = PR_TRUE;
+        else
+            fe->mUnicodeFont = PR_FALSE;
+
+        // For fonts where we failed to read the character map,
+        // we can take a slow path to look up glyphs character by character
+        fe->mUnknownCMAP = PR_TRUE;
+    } 
+
+    return fe;
+}
+
+/***************************************************************
+ *
+ * GDIFontFamily
+ *
+ */
+
+int CALLBACK
+GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
+                                        const NEWTEXTMETRICEXW *nmetrics,
+                                        DWORD fontType, LPARAM data)
+{
+    const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
+    LOGFONTW logFont = lpelfe->elfLogFont;
+    GDIFontFamily *ff = reinterpret_cast<GDIFontFamily*>(data);
+
+    // Some fonts claim to support things > 900, but we don't so clamp the sizes
+    logFont.lfWeight = PR_MAX(PR_MIN(logFont.lfWeight, 900), 100);
+
+    gfxWindowsFontType feType = GDIFontEntry::DetermineFontType(metrics, fontType);
+
+    GDIFontEntry *fe = nsnull;
+    for (PRUint32 i = 0; i < ff->mAvailableFonts.Length(); ++i) {
+        fe = static_cast<GDIFontEntry*>(ff->mAvailableFonts[i].get());
+        if (feType > fe->mFontType) {
+            // if the new type is better than the old one, remove the old entries
+            ff->mAvailableFonts.RemoveElementAt(i);
+            --i;
+        } else if (feType < fe->mFontType) {
+            // otherwise if the new type is worse, skip it
+            return 1;
+        }
+    }
+
+    for (PRUint32 i = 0; i < ff->mAvailableFonts.Length(); ++i) {
+        fe = static_cast<GDIFontEntry*>(ff->mAvailableFonts[i].get());
+        // check if we already know about this face
+        if (fe->mWeight == logFont.lfWeight &&
+            fe->mItalic == (logFont.lfItalic == 0xFF)) {
+            // update the charset bit here since this could be different
+            fe->mCharset[metrics.tmCharSet] = 1;
+            return 1; 
+        }
+    }
+
+    fe = GDIFontEntry::CreateFontEntry(ff->mName, feType, (logFont.lfItalic == 0xFF),
+                                       (PRUint16) (logFont.lfWeight), nsnull);
+    if (!fe)
+        return 1;
+
+    ff->mAvailableFonts.AppendElement(fe);
+
+    // mark the charset bit
+    fe->mCharset[metrics.tmCharSet] = 1;
+
+    fe->mWindowsFamily = logFont.lfPitchAndFamily & 0xF0;
+    fe->mWindowsPitch = logFont.lfPitchAndFamily & 0x0F;
+
+    if (nmetrics->ntmFontSig.fsUsb[0] != 0x00000000 &&
+        nmetrics->ntmFontSig.fsUsb[1] != 0x00000000 &&
+        nmetrics->ntmFontSig.fsUsb[2] != 0x00000000 &&
+        nmetrics->ntmFontSig.fsUsb[3] != 0x00000000) {
+
+        // set the unicode ranges
+        PRUint32 x = 0;
+        for (PRUint32 i = 0; i < 4; ++i) {
+            DWORD range = nmetrics->ntmFontSig.fsUsb[i];
+            for (PRUint32 k = 0; k < 32; ++k) {
+                fe->mUnicodeRanges[x++] = (range & (1 << k)) != 0;
+            }
+        }
+    }
+
+#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(ff->Name()).get(), 
+             (logFont.lfItalic == 0xff) ? "italic" : "normal",
+             logFont.lfWeight, fe->Stretch()));
+    }
+#endif
+    return 1;
+}
+
+void
+GDIFontFamily::FindStyleVariations()
+{
+    if (mHasStyles)
+        return;
+    mHasStyles = PR_TRUE;
+
+    HDC hdc = GetDC(nsnull);
+    SetGraphicsMode(hdc, GM_ADVANCED);
+
+    LOGFONTW logFont;
+    memset(&logFont, 0, sizeof(LOGFONTW));
+    logFont.lfCharSet = DEFAULT_CHARSET;
+    logFont.lfPitchAndFamily = 0;
+    PRUint32 l = PR_MIN(mName.Length(), LF_FACESIZE - 1);
+    memcpy(logFont.lfFaceName,
+           nsPromiseFlatString(mName).get(),
+           l * sizeof(PRUnichar));
+    logFont.lfFaceName[l] = 0;
+
+    EnumFontFamiliesExW(hdc, &logFont,
+                        (FONTENUMPROCW)GDIFontFamily::FamilyAddStylesProc,
+                        (LPARAM)this, 0);
+#ifdef DEBUG
+    if (mAvailableFonts.Length() == 0) {
+        char msgBuf[256];
+        (void)sprintf(msgBuf, "no styles available in family \"%s\"",
+                      NS_ConvertUTF16toUTF8(mName).get());
+        NS_ASSERTION(mAvailableFonts.Length() != 0, msgBuf);
+    }
+#endif
+
+    ReleaseDC(nsnull, hdc);
+
+    if (mIsBadUnderlineFamily)
+        SetBadUnderlineFonts();
+}
+
+/***************************************************************
+ *
+ * gfxGDIFontList
+ *
+ */
+
+gfxGDIFontList::gfxGDIFontList()
+{
+    mFontSubstitutes.Init(50);
+
+    InitializeFontEmbeddingProcs();
+}
+
+static void
+RemoveCharsetFromFontSubstitute(nsAString &aName)
+{
+    PRInt32 comma = aName.FindChar(PRUnichar(','));
+    if (comma >= 0)
+        aName.Truncate(comma);
+}
+
+nsresult
+gfxGDIFontList::GetFontSubstitutes()
+{
+    // Create the list of FontSubstitutes
+    nsCOMPtr<nsIWindowsRegKey> regKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
+    if (!regKey)
+        return NS_ERROR_FAILURE;
+    NS_NAMED_LITERAL_STRING(kFontSubstitutesKey, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
+
+    nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
+                               kFontSubstitutesKey, nsIWindowsRegKey::ACCESS_READ);
+    if (NS_FAILED(rv))
+        return rv;
+
+    PRUint32 count;
+    rv = regKey->GetValueCount(&count);
+    if (NS_FAILED(rv) || count == 0)
+        return rv;
+    for (PRUint32 i = 0; i < count; i++) {
+        nsAutoString substituteName;
+        rv = regKey->GetValueName(i, substituteName);
+        if (NS_FAILED(rv) || substituteName.IsEmpty() || substituteName.CharAt(1) == PRUnichar('@'))
+            continue;
+        PRUint32 valueType;
+        rv = regKey->GetValueType(substituteName, &valueType);
+        if (NS_FAILED(rv) || valueType != nsIWindowsRegKey::TYPE_STRING)
+            continue;
+        nsAutoString actualFontName;
+        rv = regKey->ReadStringValue(substituteName, actualFontName);
+        if (NS_FAILED(rv))
+            continue;
+
+        RemoveCharsetFromFontSubstitute(substituteName);
+        BuildKeyNameFromFontName(substituteName);
+        RemoveCharsetFromFontSubstitute(actualFontName);
+        BuildKeyNameFromFontName(actualFontName);
+        gfxFontFamily *ff;
+        if (!actualFontName.IsEmpty() && (ff = mFontFamilies.GetWeak(actualFontName))) {
+            mFontSubstitutes.Put(substituteName, ff);
+        } else {
+            mNonExistingFonts.AppendElement(substituteName);
+        }
+    }
+    return NS_OK;
+}
+
+void
+gfxGDIFontList::InitFontList()
+{
+    gfxFontCache *fc = gfxFontCache::GetCache();
+    if (fc)
+        fc->AgeAllGenerations();
+
+    mFontFamilies.Clear();
+    mOtherFamilyNames.Clear();
+    mOtherFamilyNamesInitialized = PR_FALSE;
+    mPrefFonts.Clear();
+    mFontSubstitutes.Clear();
+    mNonExistingFonts.Clear();
+    CancelLoader();
+
+    // initialize ranges of characters for which system-wide font search should be skipped
+    mCodepointsWithNoFonts.reset();
+    mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
+    mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
+
+    // iterate over available families
+    LOGFONTW logfont;
+    memset(&logfont, 0, sizeof(logfont));
+    logfont.lfCharSet = DEFAULT_CHARSET;
+
+    AutoDC hdc;
+    int result = EnumFontFamiliesExW(hdc.GetDC(), &logfont,
+                                     (FONTENUMPROCW)&EnumFontFamExProc,
+                                     0, 0);
+
+    GetFontSubstitutes();
+
+    InitBadUnderlineList();
+
+    StartLoader(kDelayBeforeLoadingFonts, kIntervalBetweenLoadingFonts);
+}
+    
+int CALLBACK
+gfxGDIFontList::EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
+                                      NEWTEXTMETRICEXW *lpntme,
+                                      DWORD fontType,
+                                      LPARAM lParam)
+{
+    const LOGFONTW& lf = lpelfe->elfLogFont;
+
+    if (lf.lfFaceName[0] == '@') {
+        return 1;
+    }
+
+    nsAutoString name(lf.lfFaceName);
+    BuildKeyNameFromFontName(name);
+
+    gfxGDIFontList *fontList = PlatformFontList();
+
+    if (!fontList->mFontFamilies.GetWeak(name)) {
+        nsRefPtr<gfxFontFamily> family = new GDIFontFamily(nsDependentString(lf.lfFaceName));
+        fontList->mFontFamilies.Put(name, family);
+    }
+
+    return 1;
+}
+
+gfxFontEntry* 
+gfxGDIFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
+                                const nsAString& aFullname)
+{
+    LOGFONTW logFont;
+    memset(&logFont, 0, sizeof(LOGFONTW));
+    logFont.lfCharSet = DEFAULT_CHARSET;
+    PRUint32 namelen = PR_MIN(aFullname.Length(), LF_FACESIZE - 1);
+    ::memcpy(logFont.lfFaceName,
+             nsPromiseFlatString(aFullname).get(),
+             namelen * sizeof(PRUnichar));
+    logFont.lfFaceName[namelen] = 0;
+
+    AutoDC dc;
+    ::SetGraphicsMode(dc.GetDC(), GM_ADVANCED);
+
+    AutoSelectFont font(dc.GetDC(), &logFont);
+    if (!font.IsValid())
+        return nsnull;
+
+    // fetch fullname from name table (Windows takes swapped tag order)
+    const PRUint32 kNameTag = NS_SWAP32(TRUETYPE_TAG('n','a','m','e'));
+    nsAutoString fullName;
+
+    {
+        DWORD len = ::GetFontData(dc.GetDC(), kNameTag, 0, nsnull, 0);
+        if (len == GDI_ERROR || len == 0) // not a truetype font --
+            return nsnull;                // so just ignore
+    
+        nsAutoTArray<PRUint8,1024> nameData;
+        if (!nameData.AppendElements(len))
+            return nsnull;
+        PRUint8 *nameTable = nameData.Elements();
+    
+        DWORD newLen = ::GetFontData(dc.GetDC(), kNameTag, 0, nameTable, len);
+        if (newLen != len)
+            return nsnull;
+    
+        nsresult rv;
+        rv = gfxFontUtils::ReadCanonicalName(nameData, 
+                                             gfxFontUtils::NAME_ID_FULL,
+                                             fullName);
+        if (NS_FAILED(rv))
+            return nsnull;
+    }
+
+    // reject if different from canonical fullname
+    if (!aFullname.Equals(fullName))
+        return nsnull;
+
+    // create a new font entry
+    PRUint16 w = (aProxyEntry->mWeight == 0 ? 400 : aProxyEntry->mWeight);
+    PRBool isCFF = PR_FALSE; // jtdfix -- need to determine this
+    
+    gfxFontEntry *fe = GDIFontEntry::CreateFontEntry(aFullname, 
+        gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/, 
+        PRUint32(aProxyEntry->mItalic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL), 
+        w, nsnull);
+        
+    if (!fe)
+        return fe;
+
+    fe->mIsUserFont = PR_TRUE;
+    return fe;
+}
+
+void gfxGDIFontList::InitializeFontEmbeddingProcs()
+{
+    HMODULE fontlib = LoadLibraryW(L"t2embed.dll");
+    if (!fontlib)
+        return;
+    TTLoadEmbeddedFontPtr = (TTLoadEmbeddedFontProc) GetProcAddress(fontlib, "TTLoadEmbeddedFont");
+    TTDeleteEmbeddedFontPtr = (TTDeleteEmbeddedFontProc) GetProcAddress(fontlib, "TTDeleteEmbeddedFont");
+}
+
+// used to control stream read by Windows TTLoadEmbeddedFont API
+
+class EOTFontStreamReader {
+public:
+    EOTFontStreamReader(const PRUint8 *aFontData, PRUint32 aLength, PRUint8 *aEOTHeader, 
+                           PRUint32 aEOTHeaderLen, FontDataOverlay *aNameOverlay)
+        : mCurrentChunk(0), mChunkOffset(0)
+    {
+        NS_ASSERTION(aFontData, "null font data ptr passed in");
+        NS_ASSERTION(aEOTHeader, "null EOT header ptr passed in");
+        NS_ASSERTION(aNameOverlay, "null name overlay struct passed in");
+
+        if (aNameOverlay->overlaySrc) {
+            mNumChunks = 4;
+            // 0 : EOT header
+            mDataChunks[0].mData = aEOTHeader;
+            mDataChunks[0].mLength = aEOTHeaderLen;
+            // 1 : start of font data to overlayDest
+            mDataChunks[1].mData = aFontData;
+            mDataChunks[1].mLength = aNameOverlay->overlayDest;
+            // 2 : overlay data
+            mDataChunks[2].mData = aFontData + aNameOverlay->overlaySrc;
+            mDataChunks[2].mLength = aNameOverlay->overlaySrcLen;
+            // 3 : rest of font data
+            mDataChunks[3].mData = aFontData + aNameOverlay->overlayDest + aNameOverlay->overlaySrcLen;
+            mDataChunks[3].mLength = aLength - aNameOverlay->overlayDest - aNameOverlay->overlaySrcLen;
+        } else {
+            mNumChunks = 2;
+            // 0 : EOT header
+            mDataChunks[0].mData = aEOTHeader;
+            mDataChunks[0].mLength = aEOTHeaderLen;
+            // 1 : font data
+            mDataChunks[1].mData = aFontData;
+            mDataChunks[1].mLength = aLength;
+        }
+    }
+
+    ~EOTFontStreamReader() 
+    { 
+
+    }
+
+    struct FontDataChunk {
+        const PRUint8 *mData;
+        PRUint32       mLength;
+    };
+
+    PRUint32                mNumChunks;
+    FontDataChunk           mDataChunks[4];
+    PRUint32                mCurrentChunk;
+    PRUint32                mChunkOffset;
+
+    unsigned long Read(void *outBuffer, const unsigned long aBytesToRead)
+    {
+        PRUint32 bytesLeft = aBytesToRead;  // bytes left in the out buffer
+        PRUint8 *out = static_cast<PRUint8*> (outBuffer);
+
+        while (mCurrentChunk < mNumChunks && bytesLeft) {
+            FontDataChunk& currentChunk = mDataChunks[mCurrentChunk];
+            PRUint32 bytesToCopy = PR_MIN(bytesLeft, 
+                                          currentChunk.mLength - mChunkOffset);
+            memcpy(out, currentChunk.mData + mChunkOffset, bytesToCopy);
+            bytesLeft -= bytesToCopy;
+            mChunkOffset += bytesToCopy;
+            out += bytesToCopy;
+
+            NS_ASSERTION(mChunkOffset <= currentChunk.mLength, "oops, buffer overrun");
+
+            if (mChunkOffset == currentChunk.mLength) {
+                mCurrentChunk++;
+                mChunkOffset = 0;
+            }
+        }
+
+        return aBytesToRead - bytesLeft;
+    }
+
+    static unsigned long ReadEOTStream(void *aReadStream, void *outBuffer, 
+                                       const unsigned long aBytesToRead) 
+    {
+        EOTFontStreamReader *eotReader = 
+                               static_cast<EOTFontStreamReader*> (aReadStream);
+        return eotReader->Read(outBuffer, aBytesToRead);
+    }        
+        
+};
+
+gfxFontEntry* 
+gfxGDIFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, 
+                                 const PRUint8 *aFontData,
+                                 PRUint32 aLength)
+{
+    // MakePlatformFont is responsible for deleting the font data with NS_Free
+    // so we set up a stack object to ensure it is freed even if we take an
+    // early exit
+    struct FontDataDeleter {
+        FontDataDeleter(const PRUint8 *aFontData)
+            : mFontData(aFontData) { }
+        ~FontDataDeleter() { NS_Free((void*)mFontData); }
+        const PRUint8 *mFontData;
+    };
+    FontDataDeleter autoDelete(aFontData);
+
+    // if calls aren't available, bail
+    if (!TTLoadEmbeddedFontPtr || !TTDeleteEmbeddedFontPtr)
+        return nsnull;
+
+    PRBool isCFF = gfxFontUtils::IsCffFont(aFontData);
+        
+    nsresult rv;
+    HANDLE fontRef = nsnull;
+    PRBool isEmbedded = PR_FALSE;
+
+    nsAutoString uniqueName;
+    rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
+    if (NS_FAILED(rv))
+        return nsnull;
+
+    // for TTF fonts, first try using the t2embed library
+    if (!isCFF) {
+        // TrueType-style glyphs, use EOT library
+        nsAutoTArray<PRUint8,2048> eotHeader;
+        PRUint8 *buffer;
+        PRUint32 eotlen;
+
+        isEmbedded = PR_TRUE;
+        PRUint32 nameLen = PR_MIN(uniqueName.Length(), LF_FACESIZE - 1);
+        nsPromiseFlatString fontName(Substring(uniqueName, 0, nameLen));
+        
+        FontDataOverlay overlayNameData = {0, 0, 0};
+
+        rv = gfxFontUtils::MakeEOTHeader(aFontData, aLength, &eotHeader, 
+                                         &overlayNameData);
+        if (NS_FAILED(rv))
+            return nsnull;
+
+        // load in embedded font data
+        eotlen = eotHeader.Length();
+        buffer = reinterpret_cast<PRUint8*> (eotHeader.Elements());
+        
+        PRInt32 ret;
+        ULONG privStatus, pulStatus;
+        EOTFontStreamReader eotReader(aFontData, aLength, buffer, eotlen,
+                                      &overlayNameData);
+
+        ret = TTLoadEmbeddedFontPtr(&fontRef, TTLOAD_PRIVATE, &privStatus, 
+                                   LICENSE_PREVIEWPRINT, &pulStatus, 
+                                   EOTFontStreamReader::ReadEOTStream, 
+                                   &eotReader, (PRUnichar*)(fontName.get()), 0, 0);
+        if (ret != E_NONE)
+            fontRef = nsnull;
+    }
+
+    // load CFF fonts or fonts that failed with t2embed loader
+    if (fontRef == nsnull) {
+        // Postscript-style glyphs, swizzle name table, load directly
+        nsTArray<PRUint8> newFontData;
+
+        isEmbedded = PR_FALSE;
+        rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData);
+
+        if (NS_FAILED(rv))
+            return nsnull;
+        
+        DWORD numFonts = 0;
+
+        PRUint8 *fontData = reinterpret_cast<PRUint8*> (newFontData.Elements());
+        PRUint32 fontLength = newFontData.Length();
+        NS_ASSERTION(fontData, "null font data after renaming");
+
+        // http://msdn.microsoft.com/en-us/library/ms533942(VS.85).aspx
+        // "A font that is added by AddFontMemResourceEx is always private 
+        //  to the process that made the call and is not enumerable."
+        fontRef = AddFontMemResourceEx(fontData, fontLength, 
+                                       0 /* reserved */, &numFonts);
+        if (!fontRef)
+            return nsnull;
+
+        // only load fonts with a single face contained in the data
+        if (fontRef && numFonts != 1) {
+            RemoveFontMemResourceEx(fontRef);
+            return nsnull;
+        }
+    }
+
+    // make a new font entry using the unique name
+    WinUserFontData *winUserFontData = new WinUserFontData(fontRef, isCFF);
+    PRUint16 w = (aProxyEntry->mWeight == 0 ? 400 : aProxyEntry->mWeight);
+
+    GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(uniqueName, 
+        gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/, 
+        PRUint32(aProxyEntry->mItalic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL), 
+        w, winUserFontData);
+
+    if (!fe)
+        return fe;
+
+    fe->mIsUserFont = PR_TRUE;
+
+    // Uniscribe doesn't place CFF fonts loaded privately via AddFontMemResourceEx
+    if (isCFF)
+        fe->mForceGDI = PR_TRUE;
+ 
+    return fe;
+}
+
+gfxFontEntry*
+gfxGDIFontList::GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold)
+{
+    // this really shouldn't fail to find a font....
+    HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
+    LOGFONTW logFont;
+    if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) {
+        nsAutoString resolvedName;
+        if (ResolveFontName(nsDependentString(logFont.lfFaceName), resolvedName)) {
+            return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
+        }
+    }
+
+    // ...but just in case, try another approach as well
+    NONCLIENTMETRICSW ncm;
+    ncm.cbSize = sizeof(ncm);
+    BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 
+                                          sizeof(ncm), &ncm, 0);
+    if (status) {
+        nsAutoString resolvedName;
+        if (ResolveFontName(nsDependentString(ncm.lfMessageFont.lfFaceName), resolvedName)) {
+            return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
+        }
+    }
+
+    return nsnull;
+}
+
+
+PRBool 
+gfxGDIFontList::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
+{
+    nsAutoString keyName(aFontName);
+    BuildKeyNameFromFontName(keyName);
+
+    nsRefPtr<gfxFontFamily> ff;
+    if (mFontSubstitutes.Get(keyName, &ff)) {
+        aResolvedFontName = ff->Name();
+        return PR_TRUE;
+    }
+
+    if (mNonExistingFonts.Contains(keyName))
+        return PR_FALSE;
+
+    if (gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName))
+        return PR_TRUE;
+
+    return PR_FALSE;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/gfxGDIFontList.h
@@ -0,0 +1,353 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Stuart Parmenter <stuart@mozilla.com>
+ *   Masayuki Nakano <masayuki@d-toybox.com>
+ *   John Daggett <jdaggett@mozilla.com>
+ *   Jonathan Kew <jfkthame@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * 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 ***** */
+
+#ifndef GFX_GDIFONTLIST_H
+#define GFX_GDIFONTLIST_H
+
+#include "gfxWindowsPlatform.h"
+#include "gfxPlatformFontList.h"
+
+#include <windows.h>
+#include <bitset>
+
+class AutoDC // get the global device context, and auto-release it on destruction
+{
+public:
+    AutoDC() {
+        mDC = ::GetDC(NULL);
+    }
+
+    ~AutoDC() {
+        ::ReleaseDC(NULL, mDC);
+    }
+
+    HDC GetDC() {
+        return mDC;
+    }
+
+private:
+    HDC mDC;
+};
+
+class AutoSelectFont // select a font into the given DC, and auto-restore
+{
+public:
+    AutoSelectFont(HDC aDC, LOGFONTW *aLogFont) {
+        mFont = ::CreateFontIndirectW(aLogFont);
+        if (mFont) {
+            mDC = aDC;
+            mOldFont = (HFONT)::SelectObject(aDC, mFont);
+        } else {
+            mOldFont = NULL;
+        }
+    }
+
+    AutoSelectFont(HDC aDC, HFONT aFont) {
+        mDC = aDC;
+        mFont = aFont;
+        mOldFont = (HFONT)::SelectObject(aDC, aFont);
+    }
+
+    ~AutoSelectFont() {
+        if (mOldFont) {
+            ::SelectObject(mDC, mOldFont);
+        }
+    }
+
+    PRBool IsValid() const {
+        return mFont != NULL;
+    }
+
+    HFONT GetFont() const {
+        return mFont;
+    }
+
+private:
+    HDC mDC;
+    HFONT mFont;
+    HFONT mOldFont;
+};
+
+/**
+ * List of different types of fonts we support on Windows.
+ * These can generally be lumped in to 3 categories where we have to
+ * do special things:  Really old fonts bitmap and vector fonts (device
+ * and raster), Type 1 fonts, and TrueType/OpenType fonts.
+ * 
+ * This list is sorted in order from least prefered to most prefered.
+ * We prefer Type1 fonts over OpenType fonts to avoid falling back to
+ * things like Arial (opentype) when you ask for Helvetica (type1)
+ **/
+enum gfxWindowsFontType {
+    GFX_FONT_TYPE_UNKNOWN = 0,
+    GFX_FONT_TYPE_DEVICE,
+    GFX_FONT_TYPE_RASTER,
+    GFX_FONT_TYPE_TRUETYPE,
+    GFX_FONT_TYPE_PS_OPENTYPE,
+    GFX_FONT_TYPE_TT_OPENTYPE,
+    GFX_FONT_TYPE_TYPE1
+};
+
+// A single member of a font family (i.e. a single face, such as Times Italic)
+// represented as a LOGFONT that will resolve to the correct face.
+// This replaces FontEntry from gfxWindowsFonts.h/cpp.
+class GDIFontEntry : public gfxFontEntry
+{
+public:
+    LPLOGFONTW GetLogFont() { return &mLogFont; }
+
+    nsresult ReadCMAP();
+
+    void FillLogFont(LOGFONTW *aLogFont, PRBool aItalic,
+                     PRUint16 aWeight, gfxFloat aSize);
+
+    static gfxWindowsFontType DetermineFontType(const NEWTEXTMETRICW& metrics, 
+                                                DWORD fontType)
+    {
+        gfxWindowsFontType feType;
+        if (metrics.ntmFlags & NTM_TYPE1)
+            feType = GFX_FONT_TYPE_TYPE1;
+        else if (metrics.ntmFlags & NTM_PS_OPENTYPE)
+            feType = GFX_FONT_TYPE_PS_OPENTYPE;
+        else if (metrics.ntmFlags & NTM_TT_OPENTYPE)
+            feType = GFX_FONT_TYPE_TT_OPENTYPE;
+        else if (fontType == TRUETYPE_FONTTYPE)
+            feType = GFX_FONT_TYPE_TRUETYPE;
+        else if (fontType == RASTER_FONTTYPE)
+            feType = GFX_FONT_TYPE_RASTER;
+        else if (fontType == DEVICE_FONTTYPE)
+            feType = GFX_FONT_TYPE_DEVICE;
+        else
+            feType = GFX_FONT_TYPE_UNKNOWN;
+        
+        return feType;
+    }
+
+    PRBool IsType1() const {
+        return (mFontType == GFX_FONT_TYPE_TYPE1);
+    }
+
+    PRBool IsTrueType() const {
+        return (mFontType == GFX_FONT_TYPE_TRUETYPE ||
+                mFontType == GFX_FONT_TYPE_PS_OPENTYPE ||
+                mFontType == GFX_FONT_TYPE_TT_OPENTYPE);
+    }
+
+    PRBool IsCrappyFont() const {
+        /* return if it is a bitmap not a unicode font */
+        return (!mUnicodeFont || IsSymbolFont() || IsType1());
+    }
+
+    PRBool MatchesGenericFamily(const nsACString& aGeneric) const {
+        if (aGeneric.IsEmpty())
+            return PR_TRUE;
+
+        // Japanese 'Mincho' fonts do not belong to FF_MODERN even if
+        // they are fixed pitch because they have variable stroke width.
+        if (mWindowsFamily == FF_ROMAN && mWindowsPitch & FIXED_PITCH) {
+            return aGeneric.EqualsLiteral("monospace");
+        }
+
+        // Japanese 'Gothic' fonts do not belong to FF_SWISS even if
+        // they are variable pitch because they have constant stroke width.
+        if (mWindowsFamily == FF_MODERN && mWindowsPitch & VARIABLE_PITCH) {
+            return aGeneric.EqualsLiteral("sans-serif");
+        }
+
+        // All other fonts will be grouped correctly using family...
+        switch (mWindowsFamily) {
+        case FF_DONTCARE:
+            return PR_TRUE;
+        case FF_ROMAN:
+            return aGeneric.EqualsLiteral("serif");
+        case FF_SWISS:
+            return aGeneric.EqualsLiteral("sans-serif");
+        case FF_MODERN:
+            return aGeneric.EqualsLiteral("monospace");
+        case FF_SCRIPT:
+            return aGeneric.EqualsLiteral("cursive");
+        case FF_DECORATIVE:
+            return aGeneric.EqualsLiteral("fantasy");
+        }
+
+        return PR_FALSE;
+    }
+
+    PRBool SupportsLangGroup(const nsACString& aLangGroup) const {
+        if (aLangGroup.IsEmpty())
+            return PR_TRUE;
+
+        PRInt16 bit = -1;
+
+        /* map our langgroup names in to Windows charset bits */
+        if (aLangGroup.EqualsLiteral("x-western")) {
+            bit = ANSI_CHARSET;
+        } else if (aLangGroup.EqualsLiteral("ja")) {
+            bit = SHIFTJIS_CHARSET;
+        } else if (aLangGroup.EqualsLiteral("ko")) {
+            bit = HANGEUL_CHARSET;
+        } else if (aLangGroup.EqualsLiteral("ko-XXX")) {
+            bit = JOHAB_CHARSET;
+        } else if (aLangGroup.EqualsLiteral("zh-CN")) {
+            bit = GB2312_CHARSET;
+        } else if (aLangGroup.EqualsLiteral("zh-TW")) {
+            bit = CHINESEBIG5_CHARSET;
+        } else if (aLangGroup.EqualsLiteral("el")) {
+            bit = GREEK_CHARSET;
+        } else if (aLangGroup.EqualsLiteral("tr")) {
+            bit = TURKISH_CHARSET;
+        } else if (aLangGroup.EqualsLiteral("he")) {
+            bit = HEBREW_CHARSET;
+        } else if (aLangGroup.EqualsLiteral("ar")) {
+            bit = ARABIC_CHARSET;
+        } else if (aLangGroup.EqualsLiteral("x-baltic")) {
+            bit = BALTIC_CHARSET;
+        } else if (aLangGroup.EqualsLiteral("x-cyrillic")) {
+            bit = RUSSIAN_CHARSET;
+        } else if (aLangGroup.EqualsLiteral("th")) {
+            bit = THAI_CHARSET;
+        } else if (aLangGroup.EqualsLiteral("x-central-euro")) {
+            bit = EASTEUROPE_CHARSET;
+        } else if (aLangGroup.EqualsLiteral("x-symbol")) {
+            bit = SYMBOL_CHARSET;
+        }
+
+        if (bit != -1)
+            return mCharset[bit];
+
+        return PR_FALSE;
+    }
+
+    PRBool SupportsRange(PRUint8 range) {
+        return mUnicodeRanges[range];
+    }
+
+    PRBool TestCharacterMap(PRUint32 aCh);
+
+    // create a font entry for a font with a given name
+    static GDIFontEntry* CreateFontEntry(const nsAString& aName, 
+                                      gfxWindowsFontType aFontType, 
+                                      PRBool aItalic, PRUint16 aWeight, 
+                                      gfxUserFontData* aUserFontData);
+
+    // create a font entry for a font referenced by its fullname
+    static GDIFontEntry* LoadLocalFont(const gfxProxyFontEntry &aProxyEntry,
+                                    const nsAString& aFullname);
+
+    PRUint8 mWindowsFamily;
+    PRUint8 mWindowsPitch;
+
+    gfxWindowsFontType mFontType;
+    PRPackedBool mForceGDI    : 1;
+    PRPackedBool mUnknownCMAP : 1;
+    PRPackedBool mUnicodeFont : 1;
+
+    std::bitset<256> mCharset;
+    std::bitset<128> mUnicodeRanges;
+
+protected:
+    friend class gfxWindowsFont;
+
+    GDIFontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
+                     PRBool aItalic, PRUint16 aWeight, gfxUserFontData *aUserFontData);
+
+    void InitLogFont(const nsAString& aName, gfxWindowsFontType aFontType);
+
+    virtual nsresult GetFontTable(PRUint32 aTableTag, nsTArray<PRUint8>& aBuffer);
+
+    LOGFONTW mLogFont;
+};
+
+// a single font family, referencing one or more faces
+class GDIFontFamily : public gfxFontFamily
+{
+public:
+    GDIFontFamily(nsAString &aName) :
+        gfxFontFamily(aName) {}
+
+    virtual void FindStyleVariations();
+
+private:
+    static int CALLBACK FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
+                                            const NEWTEXTMETRICEXW *nmetrics,
+                                            DWORD fontType, LPARAM data);
+};
+
+class gfxGDIFontList : public gfxPlatformFontList {
+public:
+    static gfxGDIFontList* PlatformFontList() {
+        return static_cast<gfxGDIFontList*>(sPlatformFontList);
+    }
+
+    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);
+
+    virtual PRBool ResolveFontName(const nsAString& aFontName,
+                                   nsAString& aResolvedFontName);
+
+private:
+    friend class gfxWindowsPlatform;
+
+    gfxGDIFontList();
+
+    void InitializeFontEmbeddingProcs();
+
+    // initialize font lists
+    virtual void InitFontList();
+
+    nsresult GetFontSubstitutes();
+
+    static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
+                                          NEWTEXTMETRICEXW *lpntme,
+                                          DWORD fontType,
+                                          LPARAM lParam);
+
+    typedef nsDataHashtable<nsStringHashKey, nsRefPtr<gfxFontFamily> > FontTable;
+
+    FontTable mFontSubstitutes;
+    nsTArray<nsString> mNonExistingFonts;
+};
+
+#endif /* GFX_GDIFONTLIST_H */
--- a/gfx/thebes/src/gfxMacPlatformFontList.h
+++ b/gfx/thebes/src/gfxMacPlatformFontList.h
@@ -87,29 +87,29 @@ protected:
 #ifndef __LP64__
     PRPackedBool mUseLiGothicAtsuiHack;
 #endif
 };
 
 class gfxMacPlatformFontList : public gfxPlatformFontList {
 public:
     static gfxMacPlatformFontList* PlatformFontList() {
-        return (gfxMacPlatformFontList*)sPlatformFontList;
+        return static_cast<gfxMacPlatformFontList*>(sPlatformFontList);
     }
 
     static PRInt32 AppleWeightToCSSWeight(PRInt32 aAppleWeight);
 
     virtual gfxFontEntry* GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold);
 
     virtual PRBool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
     
-    virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry,
+    virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const PRUint8 *aFontData, PRUint32 aLength);
 
     void ClearPrefFonts() { mPrefFonts.Clear(); }
 
 private:
     friend class gfxPlatformMac;
 
     gfxMacPlatformFontList();
--- a/gfx/thebes/src/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/src/gfxMacPlatformFontList.mm
@@ -101,17 +101,22 @@ static void GetStringForNSString(const N
 }
 
 static NSString* GetNSStringForString(const nsAString& aSrc)
 {
     return [NSString stringWithCharacters:aSrc.BeginReading()
                      length:aSrc.Length()];
 }
 
+#ifdef PR_LOGGING
 static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
+#endif /* PR_LOGGING */
+
+#define LOG(args) PR_LOG(gFontInfoLog, PR_LOG_DEBUG, args)
+#define LOG_ENABLED() PR_LOG_TEST(gFontInfoLog, PR_LOG_DEBUG)
 
 /* MacOSFontEntry */
 #pragma mark-
 
 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
                                PRInt32 aWeight,
                                gfxFontFamily *aFamily,
                                PRBool aIsStandardFace)
@@ -389,19 +394,16 @@ gfxMacFontFamily::FindStyleVariations()
             NSRange range = [facename rangeOfString:@"ultralight" options:NSCaseInsensitiveSearch];
             if (range.location != NSNotFound) {
                 appKitWeight = kAppleUltraLightWeight;
             }
         }
 
         PRInt32 cssWeight = gfxMacPlatformFontList::AppleWeightToCSSWeight(appKitWeight) * 100;
 
-        PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit) family: %s, psname: %s, face: %s, apple-weight: %d, css-weight: %d, macTraits: %8.8x\n",
-            [family UTF8String], [psname UTF8String], [facename UTF8String], appKitWeight, cssWeight, macTraits));
-
         // make a nsString
         nsAutoString postscriptFontName;
         GetStringForNSString(psname, postscriptFontName);
 
         if ([facename isEqualToString:@"Regular"] ||
             [facename isEqualToString:@"Bold"] ||
             [facename isEqualToString:@"Italic"] ||
             [facename isEqualToString:@"Oblique"] ||
@@ -424,16 +426,29 @@ gfxMacFontFamily::FindStyleVariations()
         }
         if (macTraits & NSItalicFontMask) {
             fontEntry->mItalic = PR_TRUE;
         }
         if (macTraits & NSFixedPitchFontMask) {
             fontEntry->mFixedPitch = PR_TRUE;
         }
 
+#ifdef PR_LOGGING
+        if (LOG_ENABLED()) {
+            LOG(("(fontinit) added (%s) to family (%s)"
+                 " with style: %s weight: %d stretch: %d"
+                 " (apple-weight: %d macTraits: %8.8x)",
+                 NS_ConvertUTF16toUTF8(fontEntry->Name()).get(), 
+                 NS_ConvertUTF16toUTF8(Name()).get(), 
+                 fontEntry->IsItalic() ? "italic" : "normal",
+                 cssWeight, fontEntry->Stretch(),
+                 appKitWeight, macTraits));
+        }
+#endif
+
         // insert into font entry array of family
         AddFontEntry(fontEntry);
     }
 
     SortAvailableFonts();
     SetHasStyles(PR_TRUE);
 
     if (mIsBadUnderlineFamily) {
@@ -573,18 +588,22 @@ gfxMacPlatformFontList::InitFontList()
 
     mATSGeneration = currentGeneration;
     PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit) updating to generation: %d", mATSGeneration));
 
     mFontFamilies.Clear();
     mOtherFamilyNames.Clear();
     mOtherFamilyNamesInitialized = PR_FALSE;
     mPrefFonts.Clear();
+    CancelLoader();
+
+    // initialize ranges of characters for which system-wide font search should be skipped
     mCodepointsWithNoFonts.reset();
-    CancelLoader();
+    mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
+    mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
 
     // iterate over available families
     NSEnumerator *families = [[sFontManager availableFontFamilies]
                               objectEnumerator];  // returns "canonical", non-localized family name
 
     nsAutoString availableFamilyName;
 
     NSString *availableFamily = nil;
@@ -617,25 +636,20 @@ gfxMacPlatformFontList::InitFontList()
         EliminateDuplicateFaces(NS_LITERAL_STRING("Helvetica"));
 
         // Cocoa reports that Courier and Monaco are not fixed-pitch fonts
         // so explicitly tweak these settings
         SetFixedPitch(NS_LITERAL_STRING("Courier"));
         SetFixedPitch(NS_LITERAL_STRING("Monaco"));
     }
 
-    // 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
-
     InitBadUnderlineList();
 
     // start the delayed cmap loader
     StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps);
-
 }
 
 void
 gfxMacPlatformFontList::InitSingleFaceList()
 {
     nsAutoTArray<nsString, 10> singleFaceFonts;
     gfxFontUtils::GetPrefsFontList("font.single-face-list", singleFaceFonts);
 
@@ -749,17 +763,17 @@ gfxMacPlatformFontList::AppleWeightToCSS
         aAppleWeight = 1;
     else if (aAppleWeight > kAppleMaxWeight)
         aAppleWeight = kAppleMaxWeight;
     return gAppleWeightToCSSWeight[aAppleWeight];
 }
 
 gfxFontEntry*
 gfxMacPlatformFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
-                                    const nsAString& aFontName)
+                                        const nsAString& aFontName)
 {
     NSString *faceName = GetNSStringForString(aFontName);
 
     // first lookup a single face based on postscript name
     ATSFontRef fontRef = ::ATSFontFindFromPostScriptName(CFStringRef(faceName),
                                                          kATSOptionFlagsDefault);
 
     // if not found, lookup using full font name
@@ -812,24 +826,35 @@ public:
         if (mContainerRef)
             ::ATSFontDeactivate(mContainerRef, NULL, kATSOptionFlagsDefault);
     }
 
     ATSFontContainerRef     mContainerRef;
 };
 
 gfxFontEntry*
-gfxMacPlatformFontList::MakePlatformFont(const gfxFontEntry *aProxyEntry,
+gfxMacPlatformFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                          const PRUint8 *aFontData,
                                          PRUint32 aLength)
 {
     OSStatus err;
 
     NS_ASSERTION(aFontData, "MakePlatformFont called with null data");
 
+    // MakePlatformFont is responsible for deleting the font data with NS_Free
+    // so we set up a stack object to ensure it is freed even if we take an
+    // early exit
+    struct FontDataDeleter {
+        FontDataDeleter(const PRUint8 *aFontData)
+            : mFontData(aFontData) { }
+        ~FontDataDeleter() { NS_Free((void*)mFontData); }
+        const PRUint8 *mFontData;
+    };
+    FontDataDeleter autoDelete(aFontData);
+
     ATSFontRef fontRef;
     ATSFontContainerRef containerRef;
 
     // we get occasional failures when multiple fonts are activated in quick succession
     // if the ATS font cache is damaged; to work around this, we can retry the activation
     const PRUint32 kMaxRetries = 3;
     PRUint32 retryCount = 0;
     while (retryCount++ < kMaxRetries) {
@@ -839,56 +864,50 @@ gfxMacPlatformFontList::MakePlatformFont
                                           NULL,
                                           kATSOptionFlagsDoNotNotify,
                                           &containerRef);
         mATSGeneration = ::ATSGetGeneration();
 
         if (err != noErr) {
 #if DEBUG
             char warnBuf[1024];
-            const gfxProxyFontEntry *proxyEntry =
-                static_cast<const gfxProxyFontEntry*> (aProxyEntry);
             sprintf(warnBuf, "downloaded font error, ATSFontActivateFromMemory err: %d for (%s)",
                     PRInt32(err),
-                    NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
+                    NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get());
             NS_WARNING(warnBuf);
 #endif
             return nsnull;
         }
 
         // ignoring containers with multiple fonts, use the first face only for now
         err = ::ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1,
                                          &fontRef, NULL);
         if (err != noErr) {
 #if DEBUG
             char warnBuf[1024];
-            const gfxProxyFontEntry *proxyEntry =
-                static_cast<const gfxProxyFontEntry*> (aProxyEntry);
             sprintf(warnBuf, "downloaded font error, ATSFontFindFromContainer err: %d for (%s)",
                     PRInt32(err),
-                    NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
+                    NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get());
             NS_WARNING(warnBuf);
 #endif
             ::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
             return nsnull;
         }
 
         // now lookup the Postscript name; this may fail if the font cache is bad
         OSStatus err;
         NSString *psname = NULL;
         err = ::ATSFontGetPostScriptName(fontRef, kATSOptionFlagsDefault, (CFStringRef*) (&psname));
         if (err == noErr) {
             [psname release];
         } else {
 #ifdef DEBUG
             char warnBuf[1024];
-            const gfxProxyFontEntry *proxyEntry =
-                static_cast<const gfxProxyFontEntry*> (aProxyEntry);
             sprintf(warnBuf, "ATSFontGetPostScriptName err = %d for (%s), retries = %d", (PRInt32)err,
-                    NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get(), retryCount);
+                    NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get(), retryCount);
             NS_WARNING(warnBuf);
 #endif
             ::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
             // retry the activation a couple of times if this fails
             // (may be a transient failure due to ATS font cache issues)
             continue;
         }
 
@@ -927,20 +946,18 @@ gfxMacPlatformFontList::MakePlatformFont
 
         // if succeeded and font cmap is good, return the new font
         if (newFontEntry->mIsValid && NS_SUCCEEDED(newFontEntry->ReadCMAP()))
             return newFontEntry;
 
         // if something is funky about this font, delete immediately
 #if DEBUG
         char warnBuf[1024];
-        const gfxProxyFontEntry *proxyEntry =
-            static_cast<const gfxProxyFontEntry*> (aProxyEntry);
         sprintf(warnBuf, "downloaded font not loaded properly, removed face for (%s)",
-                NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
+                NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get());
         NS_WARNING(warnBuf);
 #endif
         delete newFontEntry;
 
         // We don't retry from here; the ATS font cache issue would have caused failure earlier
         // so if we get here, there's something else bad going on within our font data structures.
         // Currently, there should be no way to reach here, as fontentry creation cannot fail
         // except by memory allocation failure.
--- a/gfx/thebes/src/gfxPlatform.cpp
+++ b/gfx/thebes/src/gfxPlatform.cpp
@@ -65,16 +65,17 @@
 
 #include "cairo.h"
 #include "qcms.h"
 
 #include "plstr.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefBranch2.h"
+#include "nsCRT.h"
 
 gfxPlatform *gPlatform = nsnull;
 
 PRInt32 gfxPlatform::sDPI = -1;
 
 // These two may point to the same profile
 static qcms_profile *gCMSOutputProfile = nsnull;
 static qcms_profile *gCMSsRGBProfile = nsnull;
@@ -181,17 +182,17 @@ gfxPlatform::Init()
 #elif defined(XP_OS2)
     gPlatform = new gfxOS2Platform;
 #endif
     if (!gPlatform)
         return NS_ERROR_OUT_OF_MEMORY;
 
     nsresult rv;
 
-#if defined(XP_MACOSX) // temporary, until this is implemented on others
+#if defined(XP_MACOSX) || defined(XP_WIN) // temporary, until this is implemented on others
     rv = gfxPlatformFontList::Init();
     if (NS_FAILED(rv)) {
         NS_ERROR("Could not initialize gfxPlatformFontList");
         Shutdown();
         return rv;
     }
 #endif
 
@@ -231,17 +232,17 @@ gfxPlatform::Init()
 void
 gfxPlatform::Shutdown()
 {
     // These may be called before the corresponding subsystems have actually
     // started up. That's OK, they can handle it.
     gfxTextRunCache::Shutdown();
     gfxTextRunWordCache::Shutdown();
     gfxFontCache::Shutdown();
-#if defined(XP_MACOSX) // temporary, until this is implemented on others
+#if defined(XP_MACOSX) || defined(XP_WIN) // temporary, until this is implemented on others
     gfxPlatformFontList::Shutdown();
 #endif
 
     // Free the various non-null transforms and loaded profiles
     ShutdownCMS();
 
     /* Unregister our CMS Override callback. */
     nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
@@ -435,18 +436,37 @@ PRBool gfxPlatform::ForEachPrefFont(eFon
                 return PR_FALSE;
         }
     
         // fetch font.name-list.xxx value                   
         prefName.AssignLiteral("font.name-list.");
         prefName.Append(genericDotLang);
         rv = prefs->GetCharPref(prefName.get(), getter_Copies(nameListValue));
         if (NS_SUCCEEDED(rv) && !nameListValue.Equals(nameValue)) {
-            if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(nameListValue), aClosure))
-                return PR_FALSE;
+            const char kComma = ',';
+            const char *p, *p_end;
+            nsCAutoString list(nameListValue);
+            list.BeginReading(p);
+            list.EndReading(p_end);
+            while (p < p_end) {
+                while (nsCRT::IsAsciiSpace(*p)) {
+                    if (++p == p_end)
+                        break;
+                }
+                if (p == p_end)
+                    break;
+                const char *start = p;
+                while (++p != p_end && *p != kComma)
+                    /* nothing */ ;
+                nsCAutoString fontName(Substring(start, p));
+                fontName.CompressWhitespace(PR_FALSE, PR_TRUE);
+                if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(fontName), aClosure))
+                    return PR_FALSE;
+                p++;
+            }
         }
     }
 
     return PR_TRUE;
 }
 
 eFontPrefLang
 gfxPlatform::GetFontPrefLangFor(const char* aLang)
--- a/gfx/thebes/src/gfxPlatformFontList.cpp
+++ b/gfx/thebes/src/gfxPlatformFontList.cpp
@@ -242,19 +242,38 @@ struct FontListData {
 
 PLDHashOperator PR_CALLBACK
 gfxPlatformFontList::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
                                              nsRefPtr<gfxFontFamily>& aFamilyEntry,
                                              void *aUserArg)
 {
     FontListData *data = static_cast<FontListData*>(aUserArg);
 
-    nsAutoString localizedFamilyName;
-    aFamilyEntry->LocalizedName(localizedFamilyName);
-    data->mListOfFonts.AppendElement(localizedFamilyName);
+    // 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.langGroup = data->mLangGroup;
+    PRBool needsBold;
+    nsRefPtr<gfxFontEntry> aFontEntry = aFamilyEntry->FindFontForStyle(style, needsBold);
+    NS_ASSERTION(aFontEntry, "couldn't find any font entry in family");
+    if (!aFontEntry)
+        return PL_DHASH_NEXT;
+
+    /* skip symbol fonts */
+    if (aFontEntry->IsSymbolFont())
+        return PL_DHASH_NEXT;
+
+    if (aFontEntry->SupportsLangGroup(data->mLangGroup) &&
+        aFontEntry->MatchesGenericFamily(data->mGenericFamily)) {
+        nsAutoString localizedFamilyName;
+        aFamilyEntry->LocalizedName(localizedFamilyName);
+        data->mListOfFonts.AppendElement(localizedFamilyName);
+    }
+
     return PL_DHASH_NEXT;
 }
 
 void
 gfxPlatformFontList::GetFontList (const nsACString& aLangGroup,
                                  const nsACString& aGenericFamily,
                                  nsTArray<nsString>& aListOfFonts)
 {
@@ -412,16 +431,24 @@ gfxPlatformFontList::AddOtherFamilyName(
     if (!mOtherFamilyNames.GetWeak(key, &found)) {
         mOtherFamilyNames.Put(key, aFamilyEntry);
         PR_LOG(gFontListLog, PR_LOG_DEBUG, ("(fontlist-otherfamily) canonical family: %s, other family: %s\n", 
                                             NS_ConvertUTF16toUTF8(aFamilyEntry->Name()).get(), 
                                             NS_ConvertUTF16toUTF8(aOtherFamilyName).get()));
     }
 }
 
+PRBool
+gfxPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
+{
+    aFamilyName.Truncate();
+    ResolveFontName(aFontName, aFamilyName);
+    return !aFamilyName.IsEmpty();
+}
+
 void 
 gfxPlatformFontList::InitLoader()
 {
     GetFontFamilyList(mFontFamiliesToLoad);
     mStartIndex = 0;
     mNumFamilies = mFontFamiliesToLoad.Length();
 }
 
@@ -455,9 +482,8 @@ gfxPlatformFontList::RunLoader()
 }
 
 void 
 gfxPlatformFontList::FinishLoader()
 {
     mFontFamiliesToLoad.Clear();
     mNumFamilies = 0;
 }
-
--- a/gfx/thebes/src/gfxPlatformFontList.h
+++ b/gfx/thebes/src/gfxPlatformFontList.h
@@ -104,22 +104,23 @@ public:
                                          PRBool& aNeedsBold) = 0;
 
     // look up a font by name on the host platform
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName) = 0;
 
     // create a new platform font from downloaded data (@font-face)
     // this method is responsible to ensure aFontData is NS_Free()'d
-    virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry,
+    virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const PRUint8 *aFontData,
                                            PRUint32 aLength) = 0;
 
     // get the standard family name on the platform for a given font name
-    virtual PRBool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) = 0;
+    // (platforms may override, eg Mac)
+    virtual PRBool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
 protected:
     gfxPlatformFontList();
 
     static gfxPlatformFontList *sPlatformFontList;
 
     static PLDHashOperator FindFontForCharProc(nsStringHashKey::KeyType aKey,
                                                nsRefPtr<gfxFontFamily>& aFamilyEntry,
--- a/gfx/thebes/src/gfxPlatformMac.cpp
+++ b/gfx/thebes/src/gfxPlatformMac.cpp
@@ -184,24 +184,22 @@ gfxPlatformMac::LookupLocalFont(const gf
     return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry, 
                                                                     aFontName);
 }
 
 gfxFontEntry* 
 gfxPlatformMac::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                  const PRUint8 *aFontData, PRUint32 aLength)
 {
-    // Ownership of aFontData is passed in here.
-    // After activating the font via ATS, we can discard the data.
-    gfxFontEntry *fe =
-        gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry,
-                                                                  aFontData,
-                                                                  aLength);
-    NS_Free((void*)aFontData);
-    return fe;
+    // Ownership of aFontData is received here, and passed on to
+    // gfxPlatformFontList::MakePlatformFont(), which must ensure the data
+    // is released with NS_Free when no longer needed
+    return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry,
+                                                                     aFontData,
+                                                                     aLength);
 }
 
 PRBool
 gfxPlatformMac::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
 {
     // check for strange format flags
     NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
                  "strange font format hint set");
--- a/gfx/thebes/src/gfxWindowsFonts.cpp
+++ b/gfx/thebes/src/gfxWindowsFonts.cpp
@@ -43,16 +43,17 @@
 
 #include "prtypes.h"
 #include "gfxTypes.h"
 
 #include "gfxContext.h"
 #include "gfxWindowsFonts.h"
 #include "gfxWindowsSurface.h"
 #include "gfxWindowsPlatform.h"
+#include "gfxGDIFontList.h"
 
 #include "gfxFontTest.h"
 
 #include "cairo.h"
 #include "cairo-win32.h"
 
 #include <windows.h>
 
@@ -71,47 +72,16 @@
 #include <math.h>
 
 #include "prlog.h"
 #include "prinit.h"
 static PRLogModuleInfo *gFontLog = PR_NewLogModule("winfonts");
 
 #define ROUND(x) floor((x) + 0.5)
 
-BYTE 
-FontTypeToOutPrecision(PRUint8 fontType)
-{
-#ifdef WINCE
-    return OUT_DEFAULT_PRECIS;
-#else
-    BYTE ret;
-    switch (fontType) {
-    case GFX_FONT_TYPE_TT_OPENTYPE:
-    case GFX_FONT_TYPE_TRUETYPE:
-        ret = OUT_TT_ONLY_PRECIS;
-        break;
-    case GFX_FONT_TYPE_PS_OPENTYPE:
-        ret = OUT_PS_ONLY_PRECIS;
-        break;
-    case GFX_FONT_TYPE_TYPE1:
-        ret = OUT_OUTLINE_PRECIS;
-        break;
-    case GFX_FONT_TYPE_RASTER:
-        ret = OUT_RASTER_PRECIS;
-        break;
-    case GFX_FONT_TYPE_DEVICE:
-        ret = OUT_DEVICE_PRECIS;
-        break;
-    default:
-        ret = OUT_DEFAULT_PRECIS;
-    }
-    return ret;
-#endif
-}
-
 struct DCFromContext {
     DCFromContext(gfxContext *aContext) {
         dc = NULL;
         nsRefPtr<gfxASurface> aSurface = aContext->CurrentSurface();
         NS_ASSERTION(aSurface, "DCFromContext: null surface");
         if (aSurface &&
             (aSurface->GetType() == gfxASurface::SurfaceTypeWin32 ||
              aSurface->GetType() == gfxASurface::SurfaceTypeWin32Printing))
@@ -137,751 +107,21 @@ struct DCFromContext {
 
     HDC dc;
     PRBool needsRelease;
 };
 
 
 /**********************************************************************
  *
- * class FontFamily
- *
- **********************************************************************/
-static nsresult
-ReadCMAP(HDC hdc, FontEntry *aFontEntry)
-{
-    const PRUint32 kCMAP = NS_SWAP32(TRUETYPE_TAG('c','m','a','p'));
-
-    DWORD len = GetFontData(hdc, kCMAP, 0, nsnull, 0);
-    if (len == GDI_ERROR || len == 0) // not a truetype font --
-        return NS_ERROR_FAILURE;      // we'll treat it as a symbol font
-
-    nsAutoTArray<PRUint8,16384> buffer;
-    if (!buffer.AppendElements(len))
-        return NS_ERROR_OUT_OF_MEMORY;
-    PRUint8 *buf = buffer.Elements();
-
-    DWORD newLen = GetFontData(hdc, kCMAP, 0, buf, len);
-    NS_ENSURE_TRUE(newLen == len, NS_ERROR_FAILURE);
-
-    // can't pass bits as references...
-    PRPackedBool unicodeFont = aFontEntry->mUnicodeFont;
-    PRPackedBool symbolFont = aFontEntry->mSymbolFont;
-    nsresult rv = gfxFontUtils::ReadCMAP(buf, len, aFontEntry->mCharacterMap,
-                                         unicodeFont, symbolFont);
-    aFontEntry->mUnicodeFont = unicodeFont;
-    aFontEntry->mSymbolFont = symbolFont;
-
-    return rv;
-}
-
-struct FamilyAddStyleProcData {
-    HDC dc;
-    FontFamily *ff;
-};
-
-int CALLBACK 
-FontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
-                                const NEWTEXTMETRICEXW *nmetrics,
-                                DWORD fontType, LPARAM data)
-{
-    const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
-    LOGFONTW logFont = lpelfe->elfLogFont;
-
-    FamilyAddStyleProcData *faspd = reinterpret_cast<FamilyAddStyleProcData*>(data);
-    FontFamily *ff = faspd->ff;
-    HDC hdc = faspd->dc;
-
-    // Some fonts claim to support things > 900, but we don't so clamp the sizes
-    logFont.lfWeight = PR_MAX(PR_MIN(logFont.lfWeight, 900), 100);
-
-
-    gfxWindowsFontType feType = FontEntry::DetermineFontType(metrics, fontType);
-
-    FontEntry *fe = nsnull;
-    for (PRUint32 i = 0; i < ff->mAvailableFonts.Length(); ++i) {
-        fe = static_cast<FontEntry*>(ff->mAvailableFonts[i].get());
-        if (feType > fe->mFontType) {
-            // if the new type is better than the old one, remove the old entries
-            ff->mAvailableFonts.RemoveElementAt(i);
-            --i;
-        } else if (feType < fe->mFontType) {
-            // otherwise if the new type is worse, skip it
-            return 1;
-        }
-    }
-
-    for (PRUint32 i = 0; i < ff->mAvailableFonts.Length(); ++i) {
-        fe = static_cast<FontEntry*>(ff->mAvailableFonts[i].get());
-        // check if we already know about this face
-        if (fe->mWeight == logFont.lfWeight &&
-            fe->mItalic == (logFont.lfItalic == 0xFF)) {
-            // update the charset bit here since this could be different
-            fe->mCharset[metrics.tmCharSet] = 1;
-            return 1; 
-        }
-    }
-
-    logFont.lfCharSet = DEFAULT_CHARSET;
-    logFont.lfOutPrecision = FontTypeToOutPrecision(feType);
-    fe = FontEntry::CreateFontEntry(ff->mName, feType, (logFont.lfItalic == 0xFF), (PRUint16) (logFont.lfWeight), nsnull, hdc, &logFont);
-
-    if (!fe)
-        return 1;
-
-    ff->mAvailableFonts.AppendElement(fe);
-
-    // mark the charset bit
-    fe->mCharset[metrics.tmCharSet] = 1;
-
-    fe->mWindowsFamily = logFont.lfPitchAndFamily & 0xF0;
-    fe->mWindowsPitch = logFont.lfPitchAndFamily & 0x0F;
-
-    if (nmetrics->ntmFontSig.fsUsb[0] != 0x00000000 &&
-        nmetrics->ntmFontSig.fsUsb[1] != 0x00000000 &&
-        nmetrics->ntmFontSig.fsUsb[2] != 0x00000000 &&
-        nmetrics->ntmFontSig.fsUsb[3] != 0x00000000) {
-
-        // set the unicode ranges
-        PRUint32 x = 0;
-        for (PRUint32 i = 0; i < 4; ++i) {
-            DWORD range = nmetrics->ntmFontSig.fsUsb[i];
-            for (PRUint32 k = 0; k < 32; ++k) {
-                fe->mUnicodeRanges[x++] = (range & (1 << k)) != 0;
-            }
-        }
-    }
-
-    fe->mIsBadUnderlineFont = ff->mIsBadUnderlineFontFamily;
-
-    return 1;
-}
-
-// general cmap reading routines moved to gfxFontUtils.cpp
-void
-FontFamily::FindStyleVariations()
-{
-    if (mHasStyles)
-        return;
-    mHasStyles = PR_TRUE;
-
-    HDC hdc = GetDC(nsnull);
-    SetGraphicsMode(hdc, GM_ADVANCED);
-
-    LOGFONTW logFont;
-    memset(&logFont, 0, sizeof(LOGFONTW));
-    logFont.lfCharSet = DEFAULT_CHARSET;
-    logFont.lfPitchAndFamily = 0;
-    PRUint32 l = PR_MIN(mName.Length(), LF_FACESIZE - 1);
-    memcpy(logFont.lfFaceName,
-           nsPromiseFlatString(mName).get(),
-           l * sizeof(PRUnichar));
-    logFont.lfFaceName[l] = 0;
-
-    FamilyAddStyleProcData faspd;
-    faspd.dc = hdc;
-    faspd.ff = this;
-
-    EnumFontFamiliesExW(hdc, &logFont, (FONTENUMPROCW)FontFamily::FamilyAddStylesProc, (LPARAM)&faspd, 0);
-#ifdef DEBUG
-    if (mAvailableFonts.Length() == 0) {
-        char msgBuf[256];
-        (void)sprintf(msgBuf, "no styles available in family \"%s\"",
-                      NS_ConvertUTF16toUTF8(mName).get());
-        NS_ASSERTION(mAvailableFonts.Length() != 0, msgBuf);
-    }
-#endif
-
-    ReleaseDC(nsnull, hdc);
-
-    // Look for font families without bold variations and add a FontEntry
-    // with synthetic bold (weight 600) for them.
-    FontEntry *darkestItalic = nsnull;
-    FontEntry *darkestNonItalic = nsnull;
-    PRUint8 highestItalic = 0, highestNonItalic = 0;
-    for (PRUint32 i = 0; i < mAvailableFonts.Length(); i++) {
-        FontEntry *fe = static_cast<FontEntry*>(mAvailableFonts[i].get());
-        if (fe->mItalic) {
-            if (!darkestItalic || fe->mWeight > darkestItalic->mWeight)
-                darkestItalic = fe;
-        } else {
-            if (!darkestNonItalic || fe->mWeight > darkestNonItalic->mWeight)
-                darkestNonItalic = fe;
-        }
-    }
-
-    if (darkestItalic && darkestItalic->mWeight < 600) {
-        FontEntry *newEntry = new FontEntry(*darkestItalic);
-        newEntry->mWeight = 600;
-        mAvailableFonts.AppendElement(newEntry);
-    }
-    if (darkestNonItalic && darkestNonItalic->mWeight < 600) {
-        FontEntry *newEntry = new FontEntry(*darkestNonItalic);
-        newEntry->mWeight = 600;
-        mAvailableFonts.AppendElement(newEntry);
-    }
-}
-
-
-FontEntry *
-FontFamily::FindFontEntry(const gfxFontStyle& aFontStyle)
-{
-    PRBool needsBold;
-    return static_cast<FontEntry*> (FindFontForStyle(aFontStyle, needsBold));
-}
-
-PRBool
-FontFamily::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
-                                PRBool anItalic, PRInt16 aStretch)
-{
-    PRBool matchesSomething = PR_FALSE;
-
-    for (PRUint32 j = 0; j < 2; j++) {
-        // build up an array of weights that match the italicness we're looking for
-        for (PRUint32 i = 0; i < mAvailableFonts.Length(); i++) {
-            gfxFontEntry *fe = mAvailableFonts[i];
-            const PRUint8 weight = (fe->mWeight / 100);
-            if (fe->mItalic == anItalic) {
-                aFontsForWeights[weight] = fe;
-                matchesSomething = PR_TRUE;
-            }
-        }
-        if (matchesSomething)
-            break;
-        anItalic = !anItalic;
-    }
-
-    return matchesSomething;
-}
-
-// from t2embapi.h, included in Platform SDK 6.1 but not 6.0
-
-#ifndef __t2embapi__
-
-#define TTLOAD_PRIVATE                  0x00000001
-#define LICENSE_PREVIEWPRINT            0x0004
-#define E_NONE                          0x0000L
-
-typedef unsigned long( WINAPIV *READEMBEDPROC ) ( void*, void*, const unsigned long );
-
-typedef struct
-{
-    unsigned short usStructSize;    // size in bytes of structure client should set to sizeof(TTLOADINFO)
-    unsigned short usRefStrSize;    // size in wide characters of pusRefStr including NULL terminator
-    unsigned short *pusRefStr;      // reference or actual string.
-}TTLOADINFO;
-
-LONG WINAPI TTLoadEmbeddedFont
-(
-    HANDLE*  phFontReference,           // on completion, contains handle to identify embedded font installed
-                                        // on system
-    ULONG    ulFlags,                   // flags specifying the request 
-    ULONG*   pulPrivStatus,             // on completion, contains the embedding status
-    ULONG    ulPrivs,                   // allows for the reduction of licensing privileges
-    ULONG*   pulStatus,                 // on completion, may contain status flags for request 
-    READEMBEDPROC lpfnReadFromStream,   // callback function for doc/disk reads
-    LPVOID   lpvReadStream,             // the input stream tokin
-    LPWSTR   szWinFamilyName,           // the new 16 bit windows family name can be NULL
-    LPSTR    szMacFamilyName,           // the new 8 bit mac family name can be NULL
-    TTLOADINFO* pTTLoadInfo             // optional security
-);
-
-#endif // __t2embapi__
-
-typedef LONG( WINAPI *TTLoadEmbeddedFontProc ) (HANDLE* phFontReference, ULONG ulFlags, ULONG* pulPrivStatus, ULONG ulPrivs, ULONG* pulStatus, 
-                                             READEMBEDPROC lpfnReadFromStream, LPVOID lpvReadStream, LPWSTR szWinFamilyName, 
-                                             LPSTR szMacFamilyName, TTLOADINFO* pTTLoadInfo);
-
-typedef LONG( WINAPI *TTDeleteEmbeddedFontProc ) (HANDLE hFontReference, ULONG ulFlags, ULONG* pulStatus);
-
-
-static TTLoadEmbeddedFontProc TTLoadEmbeddedFontPtr = nsnull;
-static TTDeleteEmbeddedFontProc TTDeleteEmbeddedFontPtr = nsnull;
-
-void FontEntry::InitializeFontEmbeddingProcs()
-{
-    HMODULE fontlib = LoadLibraryW(L"t2embed.dll");
-    if (!fontlib)
-        return;
-    TTLoadEmbeddedFontPtr = (TTLoadEmbeddedFontProc) GetProcAddress(fontlib, "TTLoadEmbeddedFont");
-    TTDeleteEmbeddedFontPtr = (TTDeleteEmbeddedFontProc) GetProcAddress(fontlib, "TTDeleteEmbeddedFont");
-}
-
-class WinUserFontData : public gfxUserFontData {
-public:
-    WinUserFontData(HANDLE aFontRef, PRBool aIsEmbeddedFont)
-        : mFontRef(aFontRef), mIsEmbeddedFont(aIsEmbeddedFont)
-    { }
-
-    virtual ~WinUserFontData()
-    {
-        if (!mIsEmbeddedFont) {
-            RemoveFontMemResourceEx(mFontRef);
-        } else {
-            ULONG pulStatus;
-            TTDeleteEmbeddedFontPtr(mFontRef, 0, &pulStatus);
-        }
-    }
-    
-    HANDLE mFontRef;
-    PRPackedBool mIsEmbeddedFont;
-};
-
-// used to control stream read by Windows TTLoadEmbeddedFont API
-
-class EOTFontStreamReader {
-public:
-    EOTFontStreamReader(const PRUint8 *aFontData, PRUint32 aLength, PRUint8 *aEOTHeader, 
-                           PRUint32 aEOTHeaderLen, FontDataOverlay *aNameOverlay)
-        : mCurrentChunk(0), mChunkOffset(0)
-    {
-        NS_ASSERTION(aFontData, "null font data ptr passed in");
-        NS_ASSERTION(aEOTHeader, "null EOT header ptr passed in");
-        NS_ASSERTION(aNameOverlay, "null name overlay struct passed in");
-
-        if (aNameOverlay->overlaySrc) {
-            mNumChunks = 4;
-            // 0 : EOT header
-            mDataChunks[0].mData = aEOTHeader;
-            mDataChunks[0].mLength = aEOTHeaderLen;
-            // 1 : start of font data to overlayDest
-            mDataChunks[1].mData = aFontData;
-            mDataChunks[1].mLength = aNameOverlay->overlayDest;
-            // 2 : overlay data
-            mDataChunks[2].mData = aFontData + aNameOverlay->overlaySrc;
-            mDataChunks[2].mLength = aNameOverlay->overlaySrcLen;
-            // 3 : rest of font data
-            mDataChunks[3].mData = aFontData + aNameOverlay->overlayDest + aNameOverlay->overlaySrcLen;
-            mDataChunks[3].mLength = aLength - aNameOverlay->overlayDest - aNameOverlay->overlaySrcLen;
-        } else {
-            mNumChunks = 2;
-            // 0 : EOT header
-            mDataChunks[0].mData = aEOTHeader;
-            mDataChunks[0].mLength = aEOTHeaderLen;
-            // 1 : font data
-            mDataChunks[1].mData = aFontData;
-            mDataChunks[1].mLength = aLength;
-        }
-    }
-
-    ~EOTFontStreamReader() 
-    { 
-
-    }
-
-    struct FontDataChunk {
-        const PRUint8 *mData;
-        PRUint32       mLength;
-    };
-
-    PRUint32                mNumChunks;
-    FontDataChunk           mDataChunks[4];
-    PRUint32                mCurrentChunk;
-    PRUint32                mChunkOffset;
-
-    unsigned long Read(void *outBuffer, const unsigned long aBytesToRead)
-    {
-        PRUint32 bytesLeft = aBytesToRead;  // bytes left in the out buffer
-        PRUint8 *out = static_cast<PRUint8*> (outBuffer);
-
-        while (mCurrentChunk < mNumChunks && bytesLeft) {
-            FontDataChunk& currentChunk = mDataChunks[mCurrentChunk];
-            PRUint32 bytesToCopy = PR_MIN(bytesLeft, 
-                                          currentChunk.mLength - mChunkOffset);
-            memcpy(out, currentChunk.mData + mChunkOffset, bytesToCopy);
-            bytesLeft -= bytesToCopy;
-            mChunkOffset += bytesToCopy;
-            out += bytesToCopy;
-
-            NS_ASSERTION(mChunkOffset <= currentChunk.mLength, "oops, buffer overrun");
-
-            if (mChunkOffset == currentChunk.mLength) {
-                mCurrentChunk++;
-                mChunkOffset = 0;
-            }
-        }
-
-        return aBytesToRead - bytesLeft;
-    }
-
-    static unsigned long ReadEOTStream(void *aReadStream, void *outBuffer, 
-                                       const unsigned long aBytesToRead) 
-    {
-        EOTFontStreamReader *eotReader = 
-                               static_cast<EOTFontStreamReader*> (aReadStream);
-        return eotReader->Read(outBuffer, aBytesToRead);
-    }        
-        
-};
-
-/* static */
-FontEntry* 
-FontEntry::LoadFont(const gfxProxyFontEntry &aProxyEntry, 
-                    const PRUint8 *aFontData, 
-                    PRUint32 aLength)
-{
-    // if calls aren't available, bail
-    if (!TTLoadEmbeddedFontPtr || !TTDeleteEmbeddedFontPtr)
-        return nsnull;
-
-    PRBool isCFF = gfxFontUtils::IsCffFont(aFontData);
-        
-    nsresult rv;
-    HANDLE fontRef = nsnull;
-    PRBool isEmbedded = PR_FALSE;
-
-    nsAutoString uniqueName;
-    rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
-    if (NS_FAILED(rv))
-        return nsnull;
-
-    // for TTF fonts, first try using the t2embed library
-    if (!isCFF) {
-        // TrueType-style glyphs, use EOT library
-        nsAutoTArray<PRUint8,2048> eotHeader;
-        PRUint8 *buffer;
-        PRUint32 eotlen;
-
-        isEmbedded = PR_TRUE;
-        PRUint32 nameLen = PR_MIN(uniqueName.Length(), LF_FACESIZE - 1);
-        nsPromiseFlatString fontName(Substring(uniqueName, 0, nameLen));
-        
-        FontDataOverlay overlayNameData = {0, 0, 0};
-
-        rv = gfxFontUtils::MakeEOTHeader(aFontData, aLength, &eotHeader, 
-                                         &overlayNameData);
-        if (NS_FAILED(rv))
-            return nsnull;
-
-        // load in embedded font data
-        eotlen = eotHeader.Length();
-        buffer = reinterpret_cast<PRUint8*> (eotHeader.Elements());
-        
-        PRInt32 ret;
-        ULONG privStatus, pulStatus;
-        EOTFontStreamReader eotReader(aFontData, aLength, buffer, eotlen,
-                                      &overlayNameData);
-
-        ret = TTLoadEmbeddedFontPtr(&fontRef, TTLOAD_PRIVATE, &privStatus, 
-                                   LICENSE_PREVIEWPRINT, &pulStatus, 
-                                   EOTFontStreamReader::ReadEOTStream, 
-                                   &eotReader, (PRUnichar*)(fontName.get()), 0, 0);
-        if (ret != E_NONE)
-            fontRef = nsnull;
-    }
-
-    // load CFF fonts or fonts that failed with t2embed loader
-    if (fontRef == nsnull) {
-        // Postscript-style glyphs, swizzle name table, load directly
-        nsTArray<PRUint8> newFontData;
-
-        isEmbedded = PR_FALSE;
-        rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData);
-
-        if (NS_FAILED(rv))
-            return nsnull;
-        
-        DWORD numFonts = 0;
-
-        PRUint8 *fontData = reinterpret_cast<PRUint8*> (newFontData.Elements());
-        PRUint32 fontLength = newFontData.Length();
-        NS_ASSERTION(fontData, "null font data after renaming");
-
-        // http://msdn.microsoft.com/en-us/library/ms533942(VS.85).aspx
-        // "A font that is added by AddFontMemResourceEx is always private 
-        //  to the process that made the call and is not enumerable."
-        fontRef = AddFontMemResourceEx(fontData, fontLength, 
-                                       0 /* reserved */, &numFonts);
-        if (!fontRef)
-            return nsnull;
-
-        // only load fonts with a single face contained in the data
-        if (fontRef && numFonts != 1) {
-            RemoveFontMemResourceEx(fontRef);
-            return nsnull;
-        }
-    }
-
-    // make a new font entry using the unique name
-    WinUserFontData *winUserFontData = new WinUserFontData(fontRef, isEmbedded);
-    PRUint16 w = (aProxyEntry.mWeight == 0 ? 400 : aProxyEntry.mWeight);
-
-    FontEntry *fe = FontEntry::CreateFontEntry(uniqueName, 
-        gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/, 
-        PRUint32(aProxyEntry.mItalic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL), 
-        w, winUserFontData);
-
-    if (!fe)
-        return fe;
-
-    // Uniscribe doesn't place CFF fonts loaded privately via AddFontMemResourceEx
-    if (isCFF)
-        fe->mForceGDI = PR_TRUE;
- 
-    return fe;
-}
-
-class AutoReleaseDC {
-public:
-    AutoReleaseDC(HDC hdc) : mDC(hdc) {
-        SetGraphicsMode(hdc, GM_ADVANCED);
-    }
-    ~AutoReleaseDC() { ReleaseDC(nsnull, mDC); }
-    HDC mDC;
-};
-
-class AutoPushPopFont {
-public:
-    AutoPushPopFont(HDC hdc, HFONT aFont) : mDC(hdc), mFont(aFont) {
-        mOldFont = (HFONT)SelectObject(mDC, mFont);
-    }
-    ~AutoPushPopFont() { 
-        SelectObject(mDC, mOldFont);
-        DeleteObject(mFont); 
-    }
-    HDC   mDC;
-    HFONT mFont;
-    HFONT mOldFont;
-};
-
-/* static */
-FontEntry* 
-FontEntry::CreateFontEntry(const nsAString& aName, gfxWindowsFontType aFontType, 
-                           PRBool aItalic, PRUint16 aWeight, 
-                           gfxUserFontData* aUserFontData, 
-                           HDC hdc, LOGFONTW *aLogFont)
-{
-    LOGFONTW logFont;
-    PRBool needRelease = PR_FALSE;
-
-    // jtdfix - need to set charset, unicode ranges, pitch/family
-
-    FontEntry *fe;
-
-    fe = new FontEntry(aName, aFontType, aItalic, aWeight, aUserFontData);
-    if (!fe)
-        return nsnull;
-
-    if (!aLogFont) {
-        aLogFont = &logFont;
-        FontEntry::FillLogFont(aLogFont, aName, aFontType, aItalic, aWeight, 0);
-    }
-
-    if (!hdc) {
-        hdc = GetDC(nsnull);
-        SetGraphicsMode(hdc, GM_ADVANCED);
-        needRelease = PR_TRUE;
-    }
-    
-    HFONT font = CreateFontIndirectW(aLogFont);
-
-    if (font) {
-        AutoPushPopFont fontCleanup(hdc, font);
-        nsresult rv;
-
-        rv = ::ReadCMAP(hdc, fe);
-
-        if (NS_FAILED(rv)) {
-
-            // ReadCMAP can fail but only handle failure cases when the font
-            // did *not* have a cmap that appears to be malformed.  Uniscribe
-            // can crash with corrupt cmaps.
-            if (rv == NS_ERROR_GFX_CMAP_MALFORMED) {
-                delete fe;
-                return nsnull;
-            } else {
-
-                // ReadCMAP may change the values of mUnicodeFont and mSymbolFont
-    
-                // Type1 fonts aren't necessarily Unicode but
-                // this is the best guess we can make here
-                if (fe->IsType1())
-                    fe->mUnicodeFont = PR_TRUE;
-                else
-                    fe->mUnicodeFont = PR_FALSE;
-    
-                // For fonts where we failed to read the character map,
-                // we can take a slow path to look up glyphs character by character
-                fe->mUnknownCMAP = PR_TRUE;
-            }
-        } 
-    }
-
-    if (needRelease)
-        ReleaseDC(nsnull, hdc);
-
-    return fe;
-}
-
-/* static */
-FontEntry* 
-FontEntry::LoadLocalFont(const gfxProxyFontEntry &aProxyEntry,
-                         const nsAString& aFullname)
-{
-    // lookup name with CreateFontIndirect
-    HDC hdc = GetDC(nsnull);
-    AutoReleaseDC dcCleanup(hdc);
-    SetGraphicsMode(hdc, GM_ADVANCED);
-
-    LOGFONTW logFont;
-    memset(&logFont, 0, sizeof(LOGFONTW));
-    logFont.lfCharSet = DEFAULT_CHARSET;
-    PRUint32 namelen = PR_MIN(aFullname.Length(), LF_FACESIZE - 1);
-    memcpy(logFont.lfFaceName,
-           nsPromiseFlatString(aFullname).get(),
-           namelen * sizeof(PRUnichar));
-    logFont.lfFaceName[namelen] = 0;
-
-    HFONT font = CreateFontIndirectW(&logFont);
-    if (!font)
-        return nsnull;
-    
-    // fetch fullname from name table (Windows takes swapped tag order)
-    const PRUint32 kNameTag = NS_SWAP32(TRUETYPE_TAG('n','a','m','e'));
-    nsAutoString fullName;
-
-    {
-        AutoPushPopFont fontCleanup(hdc, font);
-    
-        DWORD len = GetFontData(hdc, kNameTag, 0, nsnull, 0);
-        if (len == GDI_ERROR || len == 0) // not a truetype font --
-            return nsnull;                // so just ignore
-    
-        nsAutoTArray<PRUint8,1024> nameData;
-        if (!nameData.AppendElements(len))
-            return nsnull;
-        PRUint8 *nameTable = nameData.Elements();
-    
-        DWORD newLen = GetFontData(hdc, kNameTag, 0, nameTable, len);
-        if (newLen != len)
-            return nsnull;
-    
-        nsresult rv;
-        
-        rv = gfxFontUtils::ReadCanonicalName(nameData, 
-                                             gfxFontUtils::NAME_ID_FULL,
-                                             fullName);
-        if (NS_FAILED(rv))
-            return nsnull;
-    }
-
-    // reject if different from canonical fullname
-    if (!aFullname.Equals(fullName))
-        return nsnull;
-
-    // create a new font entry
-    PRUint16 w = (aProxyEntry.mWeight == 0 ? 400 : aProxyEntry.mWeight);
-    PRBool isCFF = PR_FALSE; // jtdfix -- need to determine this
-    
-    FontEntry *fe = FontEntry::CreateFontEntry(aFullname, 
-        gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/, 
-        PRUint32(aProxyEntry.mItalic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL), 
-        w, nsnull);
-        
-    if (!fe)
-        return fe;
-
-    fe->mIsUserFont = PR_TRUE;
-    return fe;
-}
-
-void
-FontEntry::FillLogFont(LOGFONTW *aLogFont, const nsAString& aName,
-                       gfxWindowsFontType aFontType, PRBool aItalic,
-                       PRUint16 aWeight, gfxFloat aSize)
-{
-#define CLIP_TURNOFF_FONTASSOCIATION 0x40
-    
-    aLogFont->lfHeight = (LONG)-ROUND(aSize);
-
-    if (aLogFont->lfHeight == 0)
-        aLogFont->lfHeight = -1;
-
-    // Fill in logFont structure
-    aLogFont->lfWidth          = 0;
-    aLogFont->lfEscapement     = 0;
-    aLogFont->lfOrientation    = 0;
-    aLogFont->lfUnderline      = FALSE;
-    aLogFont->lfStrikeOut      = FALSE;
-    aLogFont->lfCharSet        = DEFAULT_CHARSET;
-    aLogFont->lfOutPrecision   = FontTypeToOutPrecision(aFontType);
-    aLogFont->lfClipPrecision  = CLIP_TURNOFF_FONTASSOCIATION;
-    aLogFont->lfQuality        = DEFAULT_QUALITY;
-    aLogFont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
-    // always force lfItalic if we want it.  Font selection code will
-    // do its best to give us an italic font entry, but if no face exists
-    // it may give us a regular one based on weight.  Windows should
-    // do fake italic for us in that case.
-    aLogFont->lfItalic         = aItalic;
-    aLogFont->lfWeight         = aWeight;
-
-    int len = PR_MIN(aName.Length(), LF_FACESIZE - 1);
-    memcpy(aLogFont->lfFaceName, nsPromiseFlatString(aName).get(), len * 2);
-    aLogFont->lfFaceName[len] = '\0';
-}
-
-
-PRBool 
-FontEntry::TestCharacterMap(PRUint32 aCh)
-{
-    if (mUnknownCMAP) {
-        if (aCh > 0xFFFF)
-            return PR_FALSE;
-
-        // previous code was using the group style
-        gfxFontStyle fakeStyle;  
-        if (mItalic)
-            fakeStyle.style = FONT_STYLE_ITALIC;
-        fakeStyle.weight = mWeight * 100;
-
-        nsRefPtr<gfxWindowsFont> font =
-            gfxWindowsFont::GetOrMakeFont(this, &fakeStyle);
-        if (!font->IsValid())
-            return PR_FALSE;
-
-        HDC dc = GetDC((HWND)nsnull);
-        SetGraphicsMode(dc, GM_ADVANCED);
-        HFONT hfont = font->GetHFONT();
-        HFONT oldFont = (HFONT)SelectObject(dc, hfont);
-
-        PRUnichar str[1] = { (PRUnichar)aCh };
-        WORD glyph[1];
-
-        PRBool hasGlyph = PR_FALSE;
-        if (IsType1()) {
-            // Type1 fonts and uniscribe APIs don't get along.  ScriptGetCMap will return E_HANDLE
-            DWORD ret = GetGlyphIndicesW(dc, str, 1, glyph, GGI_MARK_NONEXISTING_GLYPHS);
-            if (ret != GDI_ERROR && glyph[0] != 0xFFFF)
-                hasGlyph = PR_TRUE;
-        } else {
-            // ScriptGetCMap works better than GetGlyphIndicesW for things like bitmap/vector fonts
-            HRESULT rv = ScriptGetCMap(dc, font->ScriptCache(), str, 1, 0, glyph);
-            if (rv == S_OK)
-                hasGlyph = PR_TRUE;
-        }
-
-        SelectObject(dc, oldFont);
-        ReleaseDC(NULL, dc);
-
-        if (hasGlyph) {
-            mCharacterMap.set(aCh);
-            return PR_TRUE;
-        }
-    }
-
-    return PR_FALSE;
-}
-
-/**********************************************************************
- *
  * class gfxWindowsFont
  *
  **********************************************************************/
 
-gfxWindowsFont::gfxWindowsFont(FontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
+gfxWindowsFont::gfxWindowsFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
                                cairo_antialias_t anAntialiasOption)
     : gfxFont(aFontEntry, aFontStyle),
       mFont(nsnull), mAdjustedSize(0.0), mScriptCache(nsnull),
       mFontFace(nsnull), mScaledFont(nsnull),
       mMetrics(nsnull), mAntialiasOption(anAntialiasOption)
 {
     mFontEntry = aFontEntry;
     NS_ASSERTION(mFontEntry, "Unable to find font entry for font.  Something is whack.");
@@ -1095,17 +335,17 @@ gfxWindowsFont::ComputeMetrics()
     ReleaseDC((HWND)nsnull, dc);
 
     SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
 }
 
 void
 gfxWindowsFont::FillLogFont(gfxFloat aSize)
 {
-    FontEntry *fe = GetFontEntry();
+    GDIFontEntry *fe = GetFontEntry();
     PRBool isItalic;
 
     isItalic = (GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE));
     PRUint16 weight = fe->Weight();
 
     // if user font, disable italics/bold if defined to be italics/bold face
     // this avoids unwanted synthetic italics/bold
     if (fe->mIsUserFont) {
@@ -1119,18 +359,17 @@ gfxWindowsFont::FillLogFont(gfxFloat aSi
             GetStyle()->ComputeWeightAndOffset(&baseWeight, &weightDistance);
             if ((weightDistance == 0 && baseWeight >= 6) 
                 || (weightDistance > 0)) {
                 weight = 700; // set to get GDI to synthetic bold this face
             }
         }
     }
 
-    FontEntry::FillLogFont(&mLogFont, fe->Name(),  fe->mFontType, isItalic, 
-                           weight, aSize);
+    fe->FillLogFont(&mLogFont, isItalic, weight, aSize);
 }
 
 
 nsString
 gfxWindowsFont::GetUniqueName()
 {
     nsString uniqueName;
 
@@ -1190,20 +429,20 @@ gfxWindowsFont::Measure(gfxTextRun *aTex
                                      aRefContext, aSpacing);
         }
     }
 
     return gfxFont::Measure(aTextRun, aStart, aEnd,
                             aBoundingBoxType, aRefContext, aSpacing);
 }
 
-FontEntry*
+GDIFontEntry*
 gfxWindowsFont::GetFontEntry()
 {
-    return static_cast<FontEntry*> (mFontEntry.get()); 
+    return static_cast<GDIFontEntry*> (mFontEntry.get()); 
 }
 
 PRBool
 gfxWindowsFont::SetupCairoFont(gfxContext *aContext)
 {
     cairo_scaled_font_t *scaledFont = CairoScaledFont();
     if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
         // Don't cairo_set_scaled_font as that would propagate the error to
@@ -1221,17 +460,17 @@ gfxWindowsFont::SetupCairoFont(gfxContex
  **********************************************************************/
 
 /**
  * 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<gfxWindowsFont>
-gfxWindowsFont::GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle,
+gfxWindowsFont::GetOrMakeFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle,
                               PRBool aNeedsBold)
 {
     // because we know the FontEntry has the weight we really want, use it for matching
     // things in the cache so we don't end up with things like 402 in there.
     gfxFontStyle style(*aStyle);
 
     if (aFontEntry->mIsUserFont && !aFontEntry->IsBold()) {
         // determine whether synthetic bolding is needed
@@ -1275,32 +514,32 @@ AddFontNameToArray(const nsAString& aNam
             list->AppendElement(aName);
     }
 
     return PR_TRUE;
 }
 
 
 void
-gfxWindowsFontGroup::GroupFamilyListToArrayList(nsTArray<nsRefPtr<FontEntry> > *list,
+gfxWindowsFontGroup::GroupFamilyListToArrayList(nsTArray<nsRefPtr<gfxFontEntry> > *list,
                                                 nsTArray<PRPackedBool> *aNeedsBold)
 {
     nsAutoTArray<nsString, 15> fonts;
     ForEachFont(AddFontNameToArray, &fonts);
 
     PRUint32 len = fonts.Length();
     for (PRUint32 i = 0; i < len; ++i) {
-        nsRefPtr<FontEntry> fe;
+        nsRefPtr<gfxFontEntry> fe;
         
         // first, look up in the user font set
         gfxFontEntry *gfe;
         PRBool needsBold = PR_FALSE;
         if (mUserFontSet && (gfe = mUserFontSet->FindFontEntry(fonts[i], mStyle, needsBold))) {
             // assume for now platform font if not SVG
-            fe = static_cast<FontEntry*> (gfe);
+            fe = gfe;
         }
     
         // nothing in the user font set ==> check system fonts
         if (!fe) {
             fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(fonts[i], mStyle);
         }
 
         // if found, add to the list
@@ -1309,153 +548,154 @@ gfxWindowsFontGroup::GroupFamilyListToAr
             aNeedsBold->AppendElement(static_cast<PRPackedBool>(needsBold));
         }
     }
 }
 
 void
 gfxWindowsFontGroup::FamilyListToArrayList(const nsString& aFamilies,
                                            const nsCString& aLangGroup,
-                                           nsTArray<nsRefPtr<FontEntry> > *list)
+                                           nsTArray<nsRefPtr<gfxFontEntry> > *list)
 {
     nsAutoTArray<nsString, 15> fonts;
     ForEachFont(aFamilies, aLangGroup, AddFontNameToArray, &fonts);
 
     PRUint32 len = fonts.Length();
     for (PRUint32 i = 0; i < len; ++i) {
         const nsString& str = fonts[i];
-        nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(str, mStyle);
+        nsRefPtr<gfxFontEntry> fe =
+            gfxWindowsPlatform::GetPlatform()->FindFontEntry(str, mStyle);
         if (fe) {
             list->AppendElement(fe);
         }
     }
 }
 
 gfxWindowsFontGroup::gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet)
     : gfxFontGroup(aFamilies, aStyle, aUserFontSet)
 {
     InitFontList();
 }
 
 gfxWindowsFontGroup::~gfxWindowsFontGroup()
 {
 }
 
-gfxWindowsFont *
-gfxWindowsFontGroup::GetFontAt(PRInt32 i)
-{
-    // If it turns out to be hard for all clients that cache font
-    // groups to call UpdateFontList at appropriate times, we could
-    // instead consider just calling UpdateFontList from someplace
-    // more central (such as here).
-    NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
-                 "Whoever was caching this font group should have "
-                 "called UpdateFontList on it");
-
-    if (!mFonts[i]) {
-        nsRefPtr<gfxWindowsFont> font =
-            gfxWindowsFont::GetOrMakeFont(mFontEntries[i], &mStyle, mFontNeedsBold[i]);
-        mFonts[i] = font;
-    }
-
-    return static_cast<gfxWindowsFont*>(mFonts[i].get());
-}
-
 gfxFontGroup *
 gfxWindowsFontGroup::Copy(const gfxFontStyle *aStyle)
 {
     return new gfxWindowsFontGroup(mFamilies, aStyle, mUserFontSet);
 }
 
 void 
 gfxWindowsFontGroup::UpdateFontList()
 {
     // if user font set is set, check to see if font list needs updating
     if (mUserFontSet && mCurrGeneration != GetGeneration()) {
         // xxx - can probably improve this to detect when all fonts were found, so no need to update list
         mFonts.Clear();
-        mFontEntries.Clear();
         mFontNeedsBold.Clear();
         InitFontList();
         mCurrGeneration = GetGeneration();
     }
 
 }
 
+PRBool
+gfxWindowsFontGroup::FindWindowsFont(const nsAString& aName,
+                                     const nsACString& aGenericName,
+                                     void *closure)
+{
+    gfxWindowsFontGroup *fontGroup = (gfxWindowsFontGroup*) closure;
+    const gfxFontStyle *fontStyle = fontGroup->GetStyle();
+
+    PRBool needsBold;
+    gfxFontEntry *fe = nsnull;
+
+    // first, look up in the user font set
+    gfxUserFontSet *fs = fontGroup->GetUserFontSet();
+    gfxFontEntry *gfe;
+    if (fs && (gfe = fs->FindFontEntry(aName, *fontStyle, needsBold))) {
+        // assume for now platform font if not SVG
+        fe = gfe;
+    }
+
+    // nothing in the user font set ==> check system fonts
+    if (!fe) {
+        fe = gfxPlatformFontList::PlatformFontList()->FindFontForFamily(aName, fontStyle, needsBold);
+    }
+
+    if (fe && !fontGroup->HasFont(fe)) {
+        nsRefPtr<gfxWindowsFont> font = gfxWindowsFont::GetOrMakeFont(fe, fontStyle, needsBold);
+        if (font) {
+            fontGroup->mFonts.AppendElement(font);
+        }
+    }
+
+    return PR_TRUE;
+}
+
+PRBool
+gfxWindowsFontGroup::HasFont(gfxFontEntry *aFontEntry)
+{
+    for (PRUint32 i = 0; i < mFonts.Length(); ++i) {
+        if (aFontEntry == mFonts.ElementAt(i).get()->GetFontEntry())
+            return PR_TRUE;
+    }
+    return PR_FALSE;
+}
+
 void 
 gfxWindowsFontGroup::InitFontList()
 {
-    GroupFamilyListToArrayList(&mFontEntries, &mFontNeedsBold);
-
-    mFonts.AppendElements(mFontEntries.Length());
+    ForEachFont(FindWindowsFont, this);
 
-    // Ensure that the first font is usable. Precompute its metrics since
-    // we'll surely need them anyway.
-    while (mFontEntries.Length() > 0) {
-        nsRefPtr<gfxWindowsFont> font =
-            gfxWindowsFont::GetOrMakeFont(mFontEntries[0], &mStyle, mFontNeedsBold[0]);
-        if (!font->IsValid()) {
-            mFontEntries.RemoveElementAt(0);
-            mFonts.RemoveElementAt(0);
-            mFontNeedsBold.RemoveElementAt(0);
-            continue;
-        }
-        mFonts[0] = font;
-        break;
-    }
+    if (mFonts.Length() == 0) {
+        // If we get here, we most likely didn't have a default font for
+        // a specific langGroup.  Let's just pick the default Windows
+        // user font.
 
-    if (mFontEntries.Length() == 0) {
-        // It is pretty important that we have at least one font, so
-        // try a few system fonts that should be there.
-        nsAutoString str;
-        HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
-        LOGFONTW logFont;
-        if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) {
-            str.AppendLiteral("\"");
-            str.Append(nsDependentString(logFont.lfFaceName));
-            str.AppendLiteral("\"");
-        }
+        PRBool needsBold;
+        gfxFontEntry *defaultFont =
+            gfxPlatformFontList::PlatformFontList()->GetDefaultFont(&mStyle, needsBold);
+        NS_ASSERTION(defaultFont, "invalid default font returned by GetDefaultFont");
 
-        NONCLIENTMETRICSW ncm;
-        ncm.cbSize = sizeof(ncm);
-        BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 
-                                              sizeof(ncm), &ncm, 0);
-        if (status) {
-            str.AppendLiteral(",\"");
-            str.Append(nsDependentString(ncm.lfMessageFont.lfFaceName));
-            str.AppendLiteral("\"");
-        }
+        nsRefPtr<gfxWindowsFont> font = gfxWindowsFont::GetOrMakeFont(defaultFont, &mStyle);
 
-        FamilyListToArrayList(str, mStyle.langGroup, &mFontEntries);
-
-        // Keep length of mFonts in sync with length of mFontEntries.
-        // Maybe we should eagerly set up mFonts[0] like we do above,
-        // but if the resulting gfxWindowsFont is invalid then we can't
-        // do much anyway. In that case the font will return zero metrics,
-        // its mUnknownCMAP will be set to true, and HasCharacter will
-        // just report false for all characters, so the fact that the font
-        // is bogus should not cause problems.
-        mFonts.AppendElements(mFontEntries.Length());
-        mFontNeedsBold.AppendElements(mFontEntries.Length());
+        if (font) {
+            mFonts.AppendElement(font);
+        }
     }
 
     // force the underline offset to get recalculated
     mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET;
+
+    if (!mStyle.systemFont) {
+        for (PRUint32 i = 0; i < mFonts.Length(); ++i) {
+            gfxWindowsFont* font = static_cast<gfxWindowsFont*>(mFonts[i].get());
+            if (font->GetFontEntry()->mIsBadUnderlineFont) {
+                gfxFloat first = mFonts[0]->GetMetrics().underlineOffset;
+                gfxFloat bad = font->GetMetrics().underlineOffset;
+                mUnderlineOffset = PR_MIN(first, bad);
+                break;
+            }
+        }
+    }
 }
 
 gfxFloat 
 gfxWindowsFontGroup::GetUnderlineOffset()
 {
     if (mUnderlineOffset != UNDERLINE_OFFSET_NOT_SET)
         return mUnderlineOffset;
 
     // not yet initialized, need to calculate
     if (!mStyle.systemFont) {
-        for (PRUint32 i = 0; i < mFontEntries.Length(); ++i) {
-            if (mFontEntries[i]->mIsBadUnderlineFont) {
+        for (PRUint32 i = 0; i < mFonts.Length(); ++i) {
+            if (mFonts[i]->GetFontEntry()->mIsBadUnderlineFont) {
                 gfxFloat first = GetFontAt(0)->GetMetrics().underlineOffset;
                 gfxFloat bad = GetFontAt(i)->GetMetrics().underlineOffset;
                 mUnderlineOffset = PR_MIN(first, bad);
                 break;
             }
         }
     }
 
@@ -1629,17 +869,17 @@ SetupTextRunFromGlyphs(gfxTextRun *aRun,
     }
     return PR_TRUE;
 }
 
 void
 gfxWindowsFontGroup::InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun,
                                     const char *aString, PRUint32 aLength)
 {
-    nsRefPtr<gfxWindowsFont> font = GetFontAt(0);
+    nsRefPtr<gfxWindowsFont> font = static_cast<gfxWindowsFont*>(GetFontAt(0));
     DCFromContext dc(aContext);
     if (SetupDCFont(dc, font)) {
         nsAutoTArray<WCHAR,500> glyphArray;
         if (!glyphArray.SetLength(aLength))
             return;
 
         DWORD ret = GetGlyphIndicesA(dc, aString, aLength, (WORD*) glyphArray.Elements(),
                                      GGI_MARK_NONEXISTING_GLYPHS);
@@ -1653,17 +893,17 @@ gfxWindowsFontGroup::InitTextRunGDI(gfxC
     AppendASCIItoUTF16(cString, utf16);
     InitTextRunUniscribe(aContext, aRun, utf16.get(), aLength);
 }
 
 void
 gfxWindowsFontGroup::InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun,
                                     const PRUnichar *aString, PRUint32 aLength)
 {
-    nsRefPtr<gfxWindowsFont> font = GetFontAt(0);
+    nsRefPtr<gfxWindowsFont> font = static_cast<gfxWindowsFont*>(GetFontAt(0));
     DCFromContext dc(aContext);
     if (SetupDCFont(dc, font)) {
         nsAutoTArray<WCHAR,500> glyphArray;
         if (!glyphArray.SetLength(aLength))
             return;
 
         DWORD ret = GetGlyphIndicesW(dc, aString, aLength, (WORD*) glyphArray.Elements(),
                                      GGI_MARK_NONEXISTING_GLYPHS);
@@ -1895,16 +1135,30 @@ public:
                 }
 
                 SelectFont();
 
                 shapeDC = mDC;
                 continue;
             }
 
+            // http://msdn.microsoft.com/en-us/library/dd368564(VS.85).aspx:
+            // Uniscribe will return this if "the font corresponding to the
+            // DC does not support the script required by the run...".
+            // In this case, we'll set the script code to SCRIPT_UNDEFINED
+            // and try again, so that we'll at least get glyphs even though
+            // they won't necessarily have proper shaping.
+            // (We probably shouldn't have selected this font at all,
+            // but it's too late to fix that here.)
+            if (rv == USP_E_SCRIPT_NOT_IN_FONT) {
+                sa.eScript = SCRIPT_UNDEFINED;
+                NS_WARNING("Uniscribe says font does not support script needed");
+                continue;
+            }
+
             return rv;
         }
     }
 
     HRESULT ShapeGDI() {
         SelectFont();
 
         mNumGlyphs = mRangeLength;
@@ -1957,28 +1211,35 @@ public:
         return missing;
     }
 
 
     HRESULT PlaceUniscribe() {
         HRESULT rv;
         HDC placeDC = nsnull;
 
+        SCRIPT_ANALYSIS sa = mScriptItem->a;
+
         while (PR_TRUE) {
             rv = ScriptPlace(placeDC, mCurrentFont->ScriptCache(),
                              mGlyphs.Elements(), mNumGlyphs,
-                             mAttr.Elements(), &mScriptItem->a,
+                             mAttr.Elements(), &sa,
                              mAdvances.Elements(), mOffsets.Elements(), NULL);
 
             if (rv == E_PENDING) {
                 SelectFont();
                 placeDC = mDC;
                 continue;
             }
 
+            if (rv == USP_E_SCRIPT_NOT_IN_FONT) {
+                sa.eScript = SCRIPT_UNDEFINED;
+                continue;
+            }
+
             break;
         }
 
         return rv;
     }
 
     HRESULT PlaceGDI() {
         SelectFont();
@@ -2189,17 +1450,17 @@ public:
 
     nsTArray<gfxTextRange>& Ranges() { return mRanges; }
 
     void SetRange(PRUint32 i) {
         nsRefPtr<gfxWindowsFont> font;
         if (mRanges[i].font)
             font = static_cast<gfxWindowsFont*> (mRanges[i].font.get());
         else
-            font = mGroup->GetFontAt(0);
+            font = static_cast<gfxWindowsFont*> (mGroup->GetFontAt(0));
 
         SetCurrentFont(font);
 
         mRangeString = mItemString + mRanges[i].start;
         mRangeLength = mRanges[i].Length();
     }
 
 
@@ -2427,38 +1688,40 @@ private:
 
     SCRIPT_CONTROL mControl;
     SCRIPT_STATE   mState;
     nsTArray<SCRIPT_ITEM> mItems;
     int mNumItems;
 };
 
 already_AddRefed<gfxWindowsFont>
-gfxWindowsFontGroup::WhichFontSupportsChar(const nsTArray<nsRefPtr<FontEntry> >& fonts, PRUint32 ch) {
+gfxWindowsFontGroup::WhichFontSupportsChar(const nsTArray<nsRefPtr<gfxFontEntry> >& fonts,
+                                           PRUint32 ch) {
     for (PRUint32 i = 0; i < fonts.Length(); i++) {
-        nsRefPtr<FontEntry> fe = fonts[i];
+        GDIFontEntry* fe = static_cast<GDIFontEntry*>(fonts[i].get());
         if (fe->mSymbolFont && !mStyle.familyNameQuirks)
             continue;
         if (fe->HasCharacter(ch)) {
             nsRefPtr<gfxWindowsFont> font =
                 gfxWindowsFont::GetOrMakeFont(fe, &mStyle);
             // Check that the font is still usable.
             if (!font->IsValid())
                 continue;
             return font.forget();
         }
     }
     return nsnull;
 }
 
 // this function appends to the array passed in.
-void gfxWindowsFontGroup::GetPrefFonts(const char *aLangGroup, nsTArray<nsRefPtr<FontEntry> >& array) {
+void gfxWindowsFontGroup::GetPrefFonts(const char *aLangGroup,
+                                       nsTArray<nsRefPtr<gfxFontEntry> >& array) {
     NS_ASSERTION(aLangGroup, "aLangGroup is null");
     gfxWindowsPlatform *platform = gfxWindowsPlatform::GetPlatform();
-    nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
+    nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
     /* this lookup has to depend on weight and style */
     nsCAutoString key(aLangGroup);
     key.Append("-");
     key.AppendInt(GetStyle()->style);
     key.Append("-");
     key.AppendInt(GetStyle()->weight);
     if (!platform->GetPrefFontEntries(key, &fonts)) {
         nsString fontString;
@@ -2479,17 +1742,17 @@ static PRInt32 GetCJKLangGroupIndex(cons
     for (i = 0; i < COUNT_OF_CJK_LANG_GROUP; i++) {
         if (!PL_strcasecmp(aLangGroup, sCJKLangGroup[i]))
             return i;
     }
     return -1;
 }
 
 // this function assigns to the array passed in.
-void gfxWindowsFontGroup::GetCJKPrefFonts(nsTArray<nsRefPtr<FontEntry> >& array) {
+void gfxWindowsFontGroup::GetCJKPrefFonts(nsTArray<nsRefPtr<gfxFontEntry> >& array) {
     gfxWindowsPlatform *platform = gfxWindowsPlatform::GetPlatform();
 
     nsCAutoString key("x-internal-cjk-");
     key.AppendInt(mStyle.style);
     key.Append("-");
     key.AppendInt(mStyle.weight);
 
     if (!platform->GetPrefFontEntries(key, &array)) {
@@ -2558,47 +1821,47 @@ void gfxWindowsFontGroup::GetCJKPrefFont
 
 already_AddRefed<gfxFont> 
 gfxWindowsFontGroup::WhichPrefFontSupportsChar(PRUint32 aCh)
 {
     nsRefPtr<gfxWindowsFont> selectedFont;
 
     // check out the style's language group
     if (!selectedFont) {
-        nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
+        nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
         this->GetPrefFonts(mStyle.langGroup.get(), fonts);
         selectedFont = WhichFontSupportsChar(fonts, aCh);
     }
 
     // otherwise search prefs
     if (!selectedFont) {
         /* first check with the script properties to see what they think */
         if (mItemLangGroup) {
             PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: %s ", mItemLangGroup));
 
-            nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
+            nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
             this->GetPrefFonts(mItemLangGroup, fonts);
             selectedFont = WhichFontSupportsChar(fonts, aCh);
         } else if (aCh <= 0xFFFF) {
             PRUint32 unicodeRange = FindCharUnicodeRange(aCh);
 
             /* special case CJK */
             if (unicodeRange == kRangeSetCJK) {
                 if (PR_LOG_TEST(gFontLog, PR_LOG_DEBUG))
                     PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: CJK"));
 
-                nsAutoTArray<nsRefPtr<FontEntry>, 15> fonts;
+                nsAutoTArray<nsRefPtr<gfxFontEntry>, 15> fonts;
                 this->GetCJKPrefFonts(fonts);
                 selectedFont = WhichFontSupportsChar(fonts, aCh);
             } else {
                 const char *langGroup = LangGroupFromUnicodeRange(unicodeRange);
                 if (langGroup) {
                     PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: %s", langGroup));
 
-                    nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
+                    nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
                     this->GetPrefFonts(langGroup, fonts);
                     selectedFont = WhichFontSupportsChar(fonts, aCh);
                 }
             }
         }
     }
 
     if (selectedFont) {
@@ -2608,27 +1871,22 @@ gfxWindowsFontGroup::WhichPrefFontSuppor
 
     return nsnull;
 }
 
 
 already_AddRefed<gfxFont> 
 gfxWindowsFontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
 {
-    nsRefPtr<gfxFont> selectedFont;
-
-    // system font lookup
-    PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Looking for best match"));
-
-    nsRefPtr<gfxWindowsFont> refFont = GetFontAt(0);
-    gfxWindowsPlatform *platform = gfxWindowsPlatform::GetPlatform();
-    selectedFont = platform->FindFontForChar(aCh, refFont);
-
-    if (selectedFont) {
-        return selectedFont.forget();
+    gfxFontEntry *fe = gfxPlatformFontList::PlatformFontList()->FindFontForChar(aCh, GetFontAt(0));
+    if (fe) {
+        nsRefPtr<gfxWindowsFont> windowsFont = gfxWindowsFont::GetOrMakeFont(fe, &mStyle);
+        NS_ASSERTION(windowsFont, "failed to make font from font entry");
+        nsRefPtr<gfxFont> font = (gfxFont*) windowsFont;
+        return font.forget();
     }
 
     return nsnull;
 }
 
 
 void
 gfxWindowsFontGroup::InitTextRunUniscribe(gfxContext *aContext, gfxTextRun *aRun, const PRUnichar *aString,
--- a/gfx/thebes/src/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/src/gfxWindowsPlatform.cpp
@@ -55,18 +55,20 @@
 #include "plbase64.h"
 
 #ifdef MOZ_FT2_FONTS
 #include "ft2build.h"
 #include FT_FREETYPE_H
 #include "gfxFT2Fonts.h"
 #include "cairo-ft.h"
 #include "nsAppDirectoryServiceDefs.h"
+#include "gfxFT2FontList.h"
 #else
 #include "gfxWindowsFonts.h"
+#include "gfxGDIFontList.h"
 #endif
 
 /*XXX to get CAIRO_HAS_DDRAW_SURFACE */
 #include "cairo.h"
 
 #ifdef WINCE
 #include <shlwapi.h>
 
@@ -78,88 +80,45 @@
 #include "gfxUserFontSet.h"
 
 #include <string>
 
 #ifdef MOZ_FT2_FONTS
 static FT_Library gPlatformFTLibrary = NULL;
 #endif
 
-// font info loader constants
-static const PRUint32 kDelayBeforeLoadingCmaps = 8 * 1000; // 8secs
-static const PRUint32 kIntervalBetweenLoadingCmaps = 150; // 150ms
-static const PRUint32 kNumFontsPerSlice = 10; // read in info 10 fonts at a time
-
 static __inline void
 BuildKeyNameFromFontName(nsAString &aName)
 {
     if (aName.Length() >= LF_FACESIZE)
         aName.Truncate(LF_FACESIZE - 1);
     ToLowerCase(aName);
 }
 
-class gfxWindowsPlatformPrefObserver : public nsIObserver {
-public:
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIOBSERVER
-};
-
-NS_IMPL_ISUPPORTS1(gfxWindowsPlatformPrefObserver, nsIObserver)
-
-NS_IMETHODIMP
-gfxWindowsPlatformPrefObserver::Observe(nsISupports     *aSubject,
-                                        const char      *aTopic,
-                                        const PRUnichar *aData)
+gfxWindowsPlatform::gfxWindowsPlatform()
 {
-    NS_ASSERTION(!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID), "invalid topic");
-    // XXX this could be made to only clear out the cache for the prefs that were changed
-    // but it probably isn't that big a deal.
-    gfxWindowsPlatform::GetPlatform()->ClearPrefFonts();
-    return NS_OK;
-}
-
-gfxWindowsPlatform::gfxWindowsPlatform()
-    : mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0)
-{
-    mFonts.Init(200);
-    mFontAliases.Init(20);
-    mFontSubstitutes.Init(50);
-    mPrefFonts.Init(10);
+    mPrefFonts.Init(50);
 
 #ifdef MOZ_FT2_FONTS
     FT_Init_FreeType(&gPlatformFTLibrary);
-#else
-    FontEntry::InitializeFontEmbeddingProcs();
 #endif
 
-    UpdateFontList();
-
-    nsCOMPtr<nsIPrefBranch2> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
-
-    if (pref) {
-        gfxWindowsPlatformPrefObserver *observer = new gfxWindowsPlatformPrefObserver();
-        if (observer) {
-            pref->AddObserver("font.", observer, PR_FALSE);
-            pref->AddObserver("font.name-list.", observer, PR_FALSE);
-            pref->AddObserver("intl.accept_languages", observer, PR_FALSE);
-            // don't bother unregistering.  We'll get shutdown after the pref service
-        }
-    }
-
 /* Pick the default render mode differently between
  * desktop, Windows Mobile, and Windows CE.
  */
 #if defined(WINCE_WINDOWS_MOBILE)
     mRenderMode = RENDER_IMAGE_DDRAW16;
 #elif defined(WINCE)
     mRenderMode = RENDER_DDRAW_GL;
 #else
     mRenderMode = RENDER_GDI;
 #endif
 
+    nsCOMPtr<nsIPrefBranch2> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
+
     PRInt32 rmode;
     if (NS_SUCCEEDED(pref->GetIntPref("mozilla.widget.render-mode", &rmode))) {
         if (rmode >= 0 || rmode < RENDER_MODE_MAX) {
 #ifndef CAIRO_HAS_DDRAW_SURFACE
             if (rmode == RENDER_DDRAW || rmode == RENDER_DDRAW_GL)
                 rmode = RENDER_IMAGE_STRETCH24;
 #endif
             mRenderMode = (RenderMode) rmode;
@@ -168,16 +127,26 @@ gfxWindowsPlatform::gfxWindowsPlatform()
 }
 
 gfxWindowsPlatform::~gfxWindowsPlatform()
 {
     // not calling FT_Done_FreeType because cairo may still hold references to
     // these FT_Faces.  See bug 458169.
 }
 
+gfxPlatformFontList*
+gfxWindowsPlatform::CreatePlatformFontList()
+{
+#ifdef MOZ_FT2_FONTS
+    return new gfxFT2FontList();
+#else
+    return new gfxGDIFontList();
+#endif
+}
+ 
 already_AddRefed<gfxASurface>
 gfxWindowsPlatform::CreateOffscreenSurface(const gfxIntSize& size,
                                            gfxASurface::gfxImageFormat imageFormat)
 {
     gfxASurface *surf = nsnull;
 
 #ifdef CAIRO_HAS_DDRAW_SURFACE
     if (mRenderMode == RENDER_DDRAW || mRenderMode == RENDER_DDRAW_GL)
@@ -192,673 +161,105 @@ gfxWindowsPlatform::CreateOffscreenSurfa
     if (surf == nsnull)
         surf = new gfxImageSurface(size, imageFormat);
 
     NS_IF_ADDREF(surf);
 
     return surf;
 }
 
-int CALLBACK 
-gfxWindowsPlatform::FontEnumProc(const ENUMLOGFONTEXW *lpelfe,
-                                 const NEWTEXTMETRICEXW *nmetrics,
-                                 DWORD fontType, LPARAM data)
-{
-    FontTable *ht = reinterpret_cast<FontTable*>(data);
-
-    const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
-    const LOGFONTW& logFont = lpelfe->elfLogFont;
-
-    // Ignore vertical fonts
-    if (logFont.lfFaceName[0] == L'@')
-        return 1;
-
-    nsAutoString name(logFont.lfFaceName);
-    BuildKeyNameFromFontName(name);
-
-    nsRefPtr<FontFamily> ff;
-    if (!ht->Get(name, &ff)) {
-        ff = new FontFamily(nsDependentString(logFont.lfFaceName));
-        ht->Put(name, ff);
-    }
-
-    return 1;
-}
-
-
-// general cmap reading routines moved to gfxFontUtils.cpp
-
-struct FontListData {
-    FontListData(const nsACString& aLangGroup, const nsACString& aGenericFamily, nsTArray<nsString>& aListOfFonts) :
-        mLangGroup(aLangGroup), mGenericFamily(aGenericFamily), mStringArray(aListOfFonts) {}
-    const nsACString& mLangGroup;
-    const nsACString& mGenericFamily;
-    nsTArray<nsString>& mStringArray;
-};
-
-PLDHashOperator
-gfxWindowsPlatform::HashEnumFunc(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.langGroup = 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;
-
-
-#ifndef MOZ_FT2_FONTS
-    /* skip symbol fonts */
-    if (aFontEntry->mSymbolFont)
-        return PL_DHASH_NEXT;
-
-    if (aFontEntry->SupportsLangGroup(data->mLangGroup) &&
-        aFontEntry->MatchesGenericFamily(data->mGenericFamily))
-#endif
-    data->mStringArray.AppendElement(aFontFamily->Name());
-
-    return PL_DHASH_NEXT;
-}
-
 nsresult
 gfxWindowsPlatform::GetFontList(const nsACString& aLangGroup,
                                 const nsACString& aGenericFamily,
                                 nsTArray<nsString>& aListOfFonts)
 {
-    FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
-
-    mFonts.Enumerate(gfxWindowsPlatform::HashEnumFunc, &data);
-
-    aListOfFonts.Sort();
-    aListOfFonts.Compact();
+    gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, aGenericFamily, aListOfFonts);
 
     return NS_OK;
 }
 
 static void
 RemoveCharsetFromFontSubstitute(nsAString &aName)
 {
     PRInt32 comma = aName.FindChar(PRUnichar(','));
     if (comma >= 0)
         aName.Truncate(comma);
 }
 
-#ifdef MOZ_FT2_FONTS
-void gfxWindowsPlatform::AppendFacesFromFontFile(const PRUnichar *aFileName) {
-    char fileName[MAX_PATH];
-    WideCharToMultiByte(CP_ACP, 0, aFileName, -1, fileName, MAX_PATH, NULL, NULL);
-    FT_Face dummy;
-    if (FT_Err_Ok == FT_New_Face(GetFTLibrary(), fileName, -1, &dummy)) {
-        for (FT_Long i = 0; i < dummy->num_faces; i++) {
-            FT_Face face;
-            if (FT_Err_Ok != FT_New_Face(GetFTLibrary(), fileName, 
-                                         i, &face))
-                continue;
-
-            FontEntry* fe = FontEntry::CreateFontEntryFromFace(face);
-            if (fe) {
-                NS_ConvertUTF8toUTF16 name(face->family_name);
-                BuildKeyNameFromFontName(name);       
-                nsRefPtr<FontFamily> ff;
-                if (!mFonts.Get(name, &ff)) {
-                    ff = new FontFamily(name);
-                    mFonts.Put(name, ff);
-                }
-                ff->AddFontEntry(fe);
-                ff->SetHasStyles(PR_TRUE);
-            }
-        }
-        FT_Done_Face(dummy);
-    }
-}
-
-void
-gfxWindowsPlatform::FindFonts()
-{
-    nsTArray<nsString> searchPaths(3);
-    nsTArray<nsString> fontPatterns(3);
-    fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.ttf"));
-    fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.ttc"));
-    fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.otf"));
-    wchar_t pathBuf[256];
-    SHGetSpecialFolderPathW(0, pathBuf, CSIDL_WINDOWS, 0);
-    searchPaths.AppendElement(pathBuf);
-    SHGetSpecialFolderPathW(0, pathBuf, CSIDL_FONTS, 0);
-    searchPaths.AppendElement(pathBuf);
-    nsCOMPtr<nsIFile> resDir;
-    NS_GetSpecialDirectory(NS_APP_RES_DIR, getter_AddRefs(resDir));
-    if (resDir) {
-        resDir->Append(NS_LITERAL_STRING("fonts"));
-        nsAutoString resPath;
-        resDir->GetPath(resPath);
-        searchPaths.AppendElement(resPath);
-    }
-    WIN32_FIND_DATAW results;
-    for (PRUint32 i = 0;  i < searchPaths.Length(); i++) {
-        const nsString& path(searchPaths[i]);
-        for (PRUint32 j = 0; j < fontPatterns.Length(); j++) { 
-            nsAutoString pattern(path);
-            pattern.Append(fontPatterns[j]);
-            HANDLE handle = FindFirstFileExW(pattern.get(),
-                                             FindExInfoStandard,
-                                             &results,
-                                             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()));
-                moreFiles = FindNextFile(handle, &results);
-            }
-            if (handle != INVALID_HANDLE_VALUE)
-                FindClose(handle);
-        }
-    }
-}
-
-#endif
-
 
 nsresult
 gfxWindowsPlatform::UpdateFontList()
 {
-    gfxFontCache *fc = gfxFontCache::GetCache();
-    if (fc)
-        fc->AgeAllGenerations();
-    mFonts.Clear();
-    mFontAliases.Clear();
-    mNonExistingFonts.Clear();
-    mFontSubstitutes.Clear();
-    mPrefFonts.Clear();
-    mCodepointsWithNoFonts.reset();
-    CancelLoader();
-#ifdef MOZ_FT2_FONTS
-    FindFonts();
-#else    
-    LOGFONTW logFont;
-    logFont.lfCharSet = DEFAULT_CHARSET;
-    logFont.lfFaceName[0] = 0;
-    logFont.lfPitchAndFamily = 0;
-
-    // Use the screen DC here.. should we use something else for printing?
-    HDC dc = ::GetDC(nsnull);
-    EnumFontFamiliesExW(dc, &logFont, (FONTENUMPROCW)gfxWindowsPlatform::FontEnumProc, (LPARAM)&mFonts, 0);
-    ::ReleaseDC(nsnull, dc);
-#endif
-    // initialize the cmap loading process after font list has been initialized
-    StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps); 
-
-    // Create the list of FontSubstitutes
-    nsCOMPtr<nsIWindowsRegKey> regKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
-    if (!regKey)
-        return NS_ERROR_FAILURE;
-     NS_NAMED_LITERAL_STRING(kFontSubstitutesKey, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
-
-    nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
-                               kFontSubstitutesKey, nsIWindowsRegKey::ACCESS_READ);
-    if (NS_FAILED(rv))
-        return rv;
-
-    PRUint32 count;
-    rv = regKey->GetValueCount(&count);
-    if (NS_FAILED(rv) || count == 0)
-        return rv;
-    for (PRUint32 i = 0; i < count; i++) {
-        nsAutoString substituteName;
-        rv = regKey->GetValueName(i, substituteName);
-        if (NS_FAILED(rv) || substituteName.IsEmpty() ||
-            substituteName.CharAt(1) == PRUnichar('@'))
-            continue;
-        PRUint32 valueType;
-        rv = regKey->GetValueType(substituteName, &valueType);
-        if (NS_FAILED(rv) || valueType != nsIWindowsRegKey::TYPE_STRING)
-            continue;
-        nsAutoString actualFontName;
-        rv = regKey->ReadStringValue(substituteName, actualFontName);
-        if (NS_FAILED(rv))
-            continue;
-
-        RemoveCharsetFromFontSubstitute(substituteName);
-        BuildKeyNameFromFontName(substituteName);
-        RemoveCharsetFromFontSubstitute(actualFontName);
-        BuildKeyNameFromFontName(actualFontName);
-        nsRefPtr<FontFamily> ff;
-        if (!actualFontName.IsEmpty() && mFonts.Get(actualFontName, &ff))
-            mFontSubstitutes.Put(substituteName, ff);
-        else
-            mNonExistingFonts.AppendElement(substituteName);
-    }
-
-    // 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
-
-    InitBadUnderlineList();
+    gfxPlatformFontList::PlatformFontList()->UpdateFontList();
 
     return NS_OK;
 }
 
-struct FontFamilyListData {
-    FontFamilyListData(nsTArray<nsRefPtr<FontFamily> >& aFamilyArray) 
-        : mFamilyArray(aFamilyArray)
-    {}
-
-    static PLDHashOperator AppendFamily(nsStringHashKey::KeyType aKey,
-                                        nsRefPtr<FontFamily>& aFamilyEntry,
-                                        void *aUserArg)
-    {
-        FontFamilyListData *data = (FontFamilyListData*)aUserArg;
-        data->mFamilyArray.AppendElement(aFamilyEntry);
-        return PL_DHASH_NEXT;
-    }
-
-    nsTArray<nsRefPtr<FontFamily> >& mFamilyArray;
-};
-
-void
-gfxWindowsPlatform::GetFontFamilyList(nsTArray<nsRefPtr<FontFamily> >& aFamilyArray)
-{
-    FontFamilyListData data(aFamilyArray);
-    mFonts.Enumerate(FontFamilyListData::AppendFamily, &data);
-}
-
-static PRBool SimpleResolverCallback(const nsAString& aName, void* aClosure)
-{
-    nsString *result = static_cast<nsString*>(aClosure);
-    result->Assign(aName);
-    return PR_FALSE;
-}
-
-void
-gfxWindowsPlatform::InitBadUnderlineList()
-{
-// Only windows fonts have mIsBadUnderlineFontFamily flag
-#ifndef MOZ_FT2_FONTS
-    nsAutoTArray<nsString, 10> blacklist;
-    gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist);
-    PRUint32 numFonts = blacklist.Length();
-    for (PRUint32 i = 0; i < numFonts; i++) {
-        PRBool aborted;
-        nsAutoString resolved;
-        ResolveFontName(blacklist[i], SimpleResolverCallback, &resolved, aborted);
-        if (resolved.IsEmpty())
-            continue;
-        FontFamily *ff = FindFontFamily(resolved);
-        if (!ff)
-            continue;
-        ff->mIsBadUnderlineFontFamily = 1;
-    }
-#endif
-}
-
-nsresult
-gfxWindowsPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
-{
-    aFamilyName.Truncate();
-    PRBool aborted;
-    return ResolveFontName(aFontName, SimpleResolverCallback, &aFamilyName, aborted);
-}
-
 struct ResolveData {
     ResolveData(gfxPlatform::FontResolverCallback aCallback,
                 gfxWindowsPlatform *aCaller, const nsAString *aFontName,
                 void *aClosure) :
         mFoundCount(0), mCallback(aCallback), mCaller(aCaller),
         mFontName(aFontName), mClosure(aClosure) {}
     PRUint32 mFoundCount;
     gfxPlatform::FontResolverCallback mCallback;
     gfxWindowsPlatform *mCaller;
     const nsAString *mFontName;
     void *mClosure;
 };
 
 nsresult
 gfxWindowsPlatform::ResolveFontName(const nsAString& aFontName,
                                     FontResolverCallback aCallback,
-                                    void *aClosure,
-                                    PRBool& aAborted)
+                                    void *aClosure, PRBool& aAborted)
 {
-    if (aFontName.IsEmpty())
-        return NS_ERROR_FAILURE;
-
-    nsAutoString keyName(aFontName);
-    BuildKeyNameFromFontName(keyName);
-
-    nsRefPtr<FontFamily> ff;
-    if (mFonts.Get(keyName, &ff) ||
-        mFontSubstitutes.Get(keyName, &ff) ||
-        mFontAliases.Get(keyName, &ff)) {
-        aAborted = !(*aCallback)(ff->Name(), aClosure);
-        // XXX If the font has font link, we should add the linked font.
-        return NS_OK;
-    }
-
-    if (mNonExistingFonts.Contains(keyName)) {
+    nsAutoString resolvedName;
+    if (!gfxPlatformFontList::PlatformFontList()->
+             ResolveFontName(aFontName, resolvedName)) {
         aAborted = PR_FALSE;
         return NS_OK;
     }
-
-    LOGFONTW logFont;
-    logFont.lfCharSet = DEFAULT_CHARSET;
-    logFont.lfPitchAndFamily = 0;
-    PRInt32 len = aFontName.Length();
-    if (len >= LF_FACESIZE)
-        len = LF_FACESIZE - 1;
-    memcpy(logFont.lfFaceName,
-           nsPromiseFlatString(aFontName).get(), len * sizeof(PRUnichar));
-    logFont.lfFaceName[len] = 0;
-
-    HDC dc = ::GetDC(nsnull);
-    ResolveData data(aCallback, this, &keyName, aClosure);
-    aAborted = !EnumFontFamiliesExW(dc, &logFont,
-                                    (FONTENUMPROCW)gfxWindowsPlatform::FontResolveProc,
-                                    (LPARAM)&data, 0);
-    if (data.mFoundCount == 0)
-        mNonExistingFonts.AppendElement(keyName);
-    ::ReleaseDC(nsnull, dc);
-
+    aAborted = !(*aCallback)(resolvedName, aClosure);
     return NS_OK;
 }
 
-int CALLBACK 
-gfxWindowsPlatform::FontResolveProc(const ENUMLOGFONTEXW *lpelfe,
-                                    const NEWTEXTMETRICEXW *nmetrics,
-                                    DWORD fontType, LPARAM data)
-{
-    const LOGFONTW& logFont = lpelfe->elfLogFont;
-    // Ignore vertical fonts
-    if (logFont.lfFaceName[0] == L'@' || logFont.lfFaceName[0] == 0)
-        return 1;
-
-    ResolveData *rData = reinterpret_cast<ResolveData*>(data);
-
-    nsAutoString name(logFont.lfFaceName);
-
-    // Save the alias name to cache
-    nsRefPtr<FontFamily> ff;
-    nsAutoString keyName(name);
-    BuildKeyNameFromFontName(keyName);
-    if (!rData->mCaller->mFonts.Get(keyName, &ff)) {
-        // This case only occurs on failing to build
-        // the list of font substitue. In this case, the user should
-        // reboot the Windows. Probably, we don't have the good way for
-        // resolving in this time.
-        NS_WARNING("Cannot find actual font");
-        return 1;
-    }
-
-    rData->mFoundCount++;
-    rData->mCaller->mFontAliases.Put(*(rData->mFontName), ff);
-
-    return (rData->mCallback)(name, rData->mClosure);
-
-    // XXX If the font has font link, we should add the linked font.
-}
-
-PLDHashOperator
-gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
-                                        nsRefPtr<FontFamily>& aFontFamily,
-                                        void* userArg)
+nsresult
+gfxWindowsPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
-    FontSearch *data = (FontSearch*)userArg;
-
-#ifdef MOZ_FT2_FONTS
-    aFontFamily->FindFontForChar(data);
-#else
-    const PRUint32 ch = data->mCh;
-
-    nsRefPtr<FontEntry> fe = aFontFamily->FindFontEntry(*data->mFontToMatch->GetStyle());
-    NS_ASSERTION(fe, "couldn't find any font entry in family");
-    if (!fe)
-        return PL_DHASH_NEXT;
-
-    // initialize rank to 1 so that any match is better than the initial
-    // value of data->mMatchRank (zero); therefore the first font that
-    // passes the mCharacterMap.test() will become the mBestMatch until
-    // a better entry is found
-    PRInt32 rank = 1;
-
-    // skip over non-unicode and bitmap fonts and fonts that don't have
-    // the code point we're looking for
-    if (fe->IsCrappyFont() || !fe->mCharacterMap.test(ch))
-        return PL_DHASH_NEXT;
-
-    // fonts that claim to support the range are more
-    // likely to be "better fonts" than ones that don't... (in theory)
-    if (fe->SupportsRange(gfxFontUtils::CharRangeBit(ch)))
-        rank += 1;
-
-    if (fe->SupportsLangGroup(data->mFontToMatch->GetStyle()->langGroup))
-        rank += 2;
-
-    FontEntry* mfe = static_cast<FontEntry*>(data->mFontToMatch->GetFontEntry());
-
-    if (fe->mWindowsFamily == mfe->mWindowsFamily)
-        rank += 3;
-    if (fe->mWindowsPitch == mfe->mWindowsPitch)
-        rank += 3;
-
-    /* italic */
-    const PRBool italic = (data->mFontToMatch->GetStyle()->style != FONT_STYLE_NORMAL);
-    if (fe->mItalic != italic)
-        rank += 3;
-
-    /* weight */
-    PRInt8 baseWeight, weightDistance;
-    data->mFontToMatch->GetStyle()->ComputeWeightAndOffset(&baseWeight, &weightDistance);
-    if (fe->mWeight == (baseWeight * 100) + (weightDistance * 100))
-        rank += 2;
-    else if (fe->mWeight == data->mFontToMatch->GetFontEntry()->mWeight)
-        rank += 1;
-
-    if (rank > data->mMatchRank ||
-        (rank == data->mMatchRank && Compare(fe->Name(), data->mBestMatch->Name()) > 0)) {
-        data->mBestMatch = fe;
-        data->mMatchRank = rank;
-    }
-#endif
-
-    return PL_DHASH_NEXT;
-}
-
-already_AddRefed<gfxFont>
-gfxWindowsPlatform::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(gfxWindowsPlatform::FindFontForCharProc, &data);
-
-    if (data.mBestMatch) {
-#ifdef MOZ_FT2_FONTS
-        nsRefPtr<gfxFT2Font> font =
-            gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()), 
-                                      aFont->GetStyle()); 
-        gfxFont* ret = font.forget().get();
-        return already_AddRefed<gfxFont>(ret);
-#else
-        nsRefPtr<gfxWindowsFont> font =
-            gfxWindowsFont::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()),
-                                          aFont->GetStyle());
-        if (font->IsValid()) {
-            gfxFont* ret = font.forget().get();
-            return already_AddRefed<gfxFont>(ret);
-        }
-#endif
-        return nsnull;
-    }
-    // no match? add to set of non-matching codepoints
-    mCodepointsWithNoFonts.set(aCh);
-    return nsnull;
+    gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
+    return NS_OK;
 }
 
 gfxFontGroup *
 gfxWindowsPlatform::CreateFontGroup(const nsAString &aFamilies,
                                     const gfxFontStyle *aStyle,
                                     gfxUserFontSet *aUserFontSet)
 {
 #ifdef MOZ_FT2_FONTS
     return new gfxFT2FontGroup(aFamilies, aStyle);
 #else
     return new gfxWindowsFontGroup(aFamilies, aStyle, aUserFontSet);
 #endif
 }
 
-
-struct FullFontNameSearch {
-    FullFontNameSearch(const nsAString& aFullName)
-        : mFound(PR_FALSE), mFullName(aFullName), mDC(nsnull), mFontEntry(nsnull)
-    { }
-
-    PRPackedBool mFound;
-    nsString     mFullName;
-    nsString     mFamilyName;
-    HDC          mDC;
-    gfxFontEntry *mFontEntry;
-};
-
-#ifndef MOZ_FT2_FONTS
-// callback called for each face within a single family
-// match against elfFullName
-
-static int CALLBACK 
-FindFullNameForFace(const ENUMLOGFONTEXW *lpelfe,
-                    const NEWTEXTMETRICEXW *nmetrics,
-                    DWORD fontType, LPARAM userArg)
-{
-    FullFontNameSearch *data = reinterpret_cast<FullFontNameSearch*>(userArg);
-
-    // does the full name match?
-    if (!data->mFullName.Equals(nsDependentString(lpelfe->elfFullName)))
-        return 1;  // continue
-
-    // found match, create a new font entry
-    data->mFound = PR_TRUE;
-
-    const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
-    LOGFONTW logFont = lpelfe->elfLogFont;
-
-    // Some fonts claim to support things > 900, but we don't so clamp the sizes
-    logFont.lfWeight = PR_MAX(PR_MIN(logFont.lfWeight, 900), 100);
-
-    gfxWindowsFontType feType = FontEntry::DetermineFontType(metrics, fontType);
-
-    data->mFontEntry = FontEntry::CreateFontEntry(data->mFamilyName, feType, (logFont.lfItalic == 0xFF), (PRUint16) (logFont.lfWeight), nsnull, data->mDC, &logFont);
-
-    return 0;  // stop iteration
-}
-#endif
-
-// callback called for each family name, based on the assumption that the 
-// first part of the full name is the family name
-
-static PLDHashOperator
-FindFullName(nsStringHashKey::KeyType aKey,
-             nsRefPtr<FontFamily>& aFontFamily,
-             void* userArg)
-{
-    FullFontNameSearch *data = reinterpret_cast<FullFontNameSearch*>(userArg);
-
-    // does the family name match up to the length of the family name?
-    const nsString& family = aFontFamily->Name();
-    
-    nsString fullNameFamily;
-    data->mFullName.Left(fullNameFamily, family.Length());
-
-    // if so, iterate over faces in this family to see if there is a match
-    if (family.Equals(fullNameFamily)) {
-#ifdef MOZ_FT2_FONTS
-        int len = aFontFamily->GetFontList().Length();
-        int index = 0;
-        for (; index < len && 
-                 !aFontFamily->GetFontList()[index]->Name().Equals(data->mFullName); index++);
-        if (index < len) {
-            data->mFound = PR_TRUE;
-            data->mFontEntry = aFontFamily->GetFontList()[index];
-        }
-#else
-        HDC hdc;
-        
-        if (!data->mDC) {
-            data->mDC= GetDC(nsnull);
-            SetGraphicsMode(data->mDC, GM_ADVANCED);
-        }
-        hdc = data->mDC;
-
-        LOGFONTW logFont;
-        memset(&logFont, 0, sizeof(LOGFONTW));
-        logFont.lfCharSet = DEFAULT_CHARSET;
-        logFont.lfPitchAndFamily = 0;
-        PRUint32 l = PR_MIN(family.Length(), LF_FACESIZE - 1);
-        memcpy(logFont.lfFaceName,
-               nsPromiseFlatString(family).get(),
-               l * sizeof(PRUnichar));
-        logFont.lfFaceName[l] = 0;
-        data->mFamilyName.Assign(family);
-
-        EnumFontFamiliesExW(hdc, &logFont, (FONTENUMPROCW)FindFullNameForFace, (LPARAM)data, 0);
-#endif
-    }
-
-    if (data->mFound)
-        return PL_DHASH_STOP;
-
-    return PL_DHASH_NEXT;
-}
-
 gfxFontEntry* 
 gfxWindowsPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                     const nsAString& aFontName)
 {
-#ifdef MOZ_FT2_FONTS
-    // walk over list of names
-    FullFontNameSearch data(aFontName);
-
-    // find fonts that support the character
-    mFonts.Enumerate(FindFullName, &data);
-
-    if (data.mDC)
-        ReleaseDC(nsnull, data.mDC);
-    
-    return data.mFontEntry;
-#else
-    return FontEntry::LoadLocalFont(*aProxyEntry, aFontName);
-#endif
+    return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry, 
+                                                                    aFontName);
 }
 
 gfxFontEntry* 
 gfxWindowsPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                      const PRUint8 *aFontData, PRUint32 aLength)
 {
-#ifdef MOZ_FT2_FONTS
-    // The FT2 font needs the font data to persist, so we do NOT free it here
-    // but instead pass ownership to the font entry.
-    // Deallocation will happen later, when the font face is destroyed.
-    return FontEntry::CreateFontEntry(*aProxyEntry, aFontData, aLength);
-#else
-    // With GDI, we can free the downloaded data after activating the font
-    gfxFontEntry *fe = FontEntry::LoadFont(*aProxyEntry, aFontData, aLength);
-    NS_Free((void*)aFontData);
-    return fe;
-#endif    
+    return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry,
+                                                                     aFontData,
+                                                                     aLength);
 }
 
 PRBool
 gfxWindowsPlatform::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
 {
     // check for strange format flags
     NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
                  "strange font format hint set");
@@ -874,39 +275,31 @@ gfxWindowsPlatform::IsFontFormatSupporte
     if (aFormatFlags != 0) {
         return PR_FALSE;
     }
 
     // no format hint set, need to look at data
     return PR_TRUE;
 }
 
-FontFamily *
+gfxFontFamily *
 gfxWindowsPlatform::FindFontFamily(const nsAString& aName)
 {
-    nsAutoString name(aName);
-    BuildKeyNameFromFontName(name);
-
-    nsRefPtr<FontFamily> ff;
-    if (!mFonts.Get(name, &ff) &&
-        !mFontSubstitutes.Get(name, &ff) &&
-        !mFontAliases.Get(name, &ff)) {
-        return nsnull;
-    }
-    return ff.get();
+    return gfxPlatformFontList::PlatformFontList()->FindFamily(aName);
 }
 
-FontEntry *
+gfxFontEntry *
 gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle)
 {
-    nsRefPtr<FontFamily> ff = FindFontFamily(aName);
+    nsRefPtr<gfxFontFamily> ff = FindFontFamily(aName);
     if (!ff)
         return nsnull;
 
-    return ff->FindFontEntry(aFontStyle);
+    PRBool aNeedsBold;
+    return ff->FindFontForStyle(aFontStyle, aNeedsBold);
 }
 
 qcms_profile*
 gfxWindowsPlatform::GetPlatformCMSOutputProfile()
 {
 #ifndef MOZ_FT2_FONTS
     WCHAR str[1024+1];
     DWORD size = 1024;
@@ -933,60 +326,27 @@ gfxWindowsPlatform::GetPlatformCMSOutput
 #endif
     return profile;
 #else
     return nsnull;
 #endif
 }
 
 PRBool
-gfxWindowsPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> > *array)
+gfxWindowsPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> > *array)
 {
     return mPrefFonts.Get(aKey, array);
 }
 
 void
-gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> >& array)
+gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> >& array)
 {
     mPrefFonts.Put(aKey, array);
 }
 
-void 
-gfxWindowsPlatform::InitLoader()
-{
-    GetFontFamilyList(mFontFamilies);
-    mStartIndex = 0;
-    mNumFamilies = mFontFamilies.Length();
-}
-
-PRBool 
-gfxWindowsPlatform::RunLoader()
-{
-    PRUint32 i, endIndex = ( mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies );
-
-#ifndef MOZ_FT2_FONTS
-    // for each font family, load in various font info
-    for (i = mStartIndex; i < endIndex; i++) {
-        // load the cmaps for all variations
-        mFontFamilies[i]->FindStyleVariations();
-    }
-#endif
-    mStartIndex += mIncrement;
-    if (mStartIndex < mNumFamilies)
-        return PR_FALSE;
-    return PR_TRUE;
-}
-
-void 
-gfxWindowsPlatform::FinishLoader()
-{
-    mFontFamilies.Clear();
-    mNumFamilies = 0;
-}
-
 #ifdef MOZ_FT2_FONTS
 FT_Library
 gfxWindowsPlatform::GetFTLibrary()
 {
     return gPlatformFTLibrary;
 }
 #endif