bug 493280 (part 1) refactor Mac font selection code and make 64-bit clean, r=joshmoz,jdaggett sr=roc
authorJonathan Kew <jfkthame@gmail.com>
Sun, 16 Aug 2009 14:52:12 +0100
changeset 31590 9d372f843f7273bca6fa06d6c42421b42bf3e415
parent 31589 dbd2e6a737675c45e636854571b3f8bbd6e47c21
child 31591 3d7ab97c7a3c5bc04a6d61f37d3c46c55851a57b
push id8601
push userjkew@mozilla.com
push dateSun, 16 Aug 2009 14:04:01 +0000
treeherdermozilla-central@9d372f843f72 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoshmoz, jdaggett, roc
bugs493280
milestone1.9.3a1pre
bug 493280 (part 1) refactor Mac font selection code and make 64-bit clean, r=joshmoz,jdaggett sr=roc
gfx/thebes/public/gfxAtsuiFonts.h
gfx/thebes/public/gfxCoreTextFonts.h
gfx/thebes/public/gfxFT2Fonts.h
gfx/thebes/public/gfxFont.h
gfx/thebes/public/gfxFontUtils.h
gfx/thebes/public/gfxPlatform.h
gfx/thebes/public/gfxPlatformMac.h
gfx/thebes/public/gfxUserFontSet.h
gfx/thebes/public/gfxWindowsFonts.h
gfx/thebes/src/Makefile.in
gfx/thebes/src/gfxAtsuiFonts.cpp
gfx/thebes/src/gfxCoreTextFonts.cpp
gfx/thebes/src/gfxFT2Fonts.cpp
gfx/thebes/src/gfxFont.cpp
gfx/thebes/src/gfxFontUtils.cpp
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/gfxQuartzFontCache.h
gfx/thebes/src/gfxQuartzFontCache.mm
gfx/thebes/src/gfxTextRunCache.cpp
gfx/thebes/src/gfxUserFontSet.cpp
gfx/thebes/src/gfxWindowsFonts.cpp
gfx/thebes/src/gfxWindowsPlatform.cpp
--- a/gfx/thebes/public/gfxAtsuiFonts.h
+++ b/gfx/thebes/public/gfxAtsuiFonts.h
@@ -10,23 +10,24 @@
  * 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 thebes gfx code.
  *
  * The Initial Developer of the Original Code is Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2006
+ * Portions created by the Initial Developer are Copyright (C) 2006-2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Vladimir Vukicevic <vladimir@pobox.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
@@ -48,17 +49,16 @@
 #include "gfxFontUtils.h"
 #include "gfxPlatform.h"
 
 #include <Carbon/Carbon.h>
 
 class gfxAtsuiFontGroup;
 
 class MacOSFontEntry;
-class MacOSFamilyEntry;
 
 class gfxAtsuiFont : public gfxFont {
 public:
 
     gfxAtsuiFont(MacOSFontEntry *aFontEntry,
                  const gfxFontStyle *fontStyle, PRBool aNeedsBold);
 
     virtual ~gfxAtsuiFont();
@@ -163,19 +163,19 @@ public:
     // search through pref fonts for a character, return nsnull if no matching pref font
     already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
 
     already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);
 
     void UpdateFontList();
 
 protected:
-    static PRBool FindATSUFont(const nsAString& aName,
-                               const nsACString& aGenericName,
-                               void *closure);
+    static PRBool FindATSFont(const nsAString& aName,
+                              const nsACString& aGenericName,
+                              void *closure);
 
     PRUint32 GuessMaximumStringLength();
 
     /**
      * @param aRun the text run to fill in
      * @param aString the complete text including all wrapper characters
      * @param aLength the length of aString
      * @param aLayoutStart the first character of aString that should be
@@ -198,17 +198,17 @@ protected:
 
     /**
      * Function to reinitialize our mFonts array and any other data
      * that depends on mFonts.
      */
     void InitFontList();
     
     // cache the most recent pref font to avoid general pref font lookup
-    nsRefPtr<MacOSFamilyEntry>    mLastPrefFamily;
+    nsRefPtr<gfxFontFamily>       mLastPrefFamily;
     nsRefPtr<gfxAtsuiFont>        mLastPrefFont;
     eFontPrefLang                 mLastPrefLang;       // lang group for last pref font
     PRBool                        mLastPrefFirstFont;  // is this the first font in the list of pref fonts for this lang group?
     eFontPrefLang                 mPageLang;
 };
 
 #endif /* not __LP64__ */
 
--- a/gfx/thebes/public/gfxCoreTextFonts.h
+++ b/gfx/thebes/public/gfxCoreTextFonts.h
@@ -10,17 +10,17 @@
  * 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 thebes gfx code.
  *
  * The Initial Developer of the Original Code is Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2006-2008
+ * Portions created by the Initial Developer are Copyright (C) 2006-2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Vladimir Vukicevic <vladimir@pobox.com>
  *   Masayuki Nakano <masayuki@d-toybox.com>
  *   John Daggett <jdaggett@mozilla.com>
  *   Jonathan Kew <jfkthame@gmail.com>
  *
@@ -47,17 +47,16 @@
 #include "gfxFontUtils.h"
 #include "gfxPlatform.h"
 
 #include <Carbon/Carbon.h>
 
 class gfxCoreTextFontGroup;
 
 class MacOSFontEntry;
-class MacOSFamilyEntry;
 
 class gfxCoreTextFont : public gfxFont {
 public:
 
     gfxCoreTextFont(MacOSFontEntry *aFontEntry,
                     const gfxFontStyle *fontStyle, PRBool aNeedsBold);
 
     virtual ~gfxCoreTextFont();
@@ -215,16 +214,16 @@ protected:
 
     nsresult SetGlyphsFromRun(gfxTextRun *aTextRun,
                               CTRunRef aCTRun,
                               const PRPackedBool *aUnmatched,
                               PRInt32 aLayoutStart,
                               PRInt32 aLayoutLength);
 
     // cache the most recent pref font to avoid general pref font lookup
-    nsRefPtr<MacOSFamilyEntry>    mLastPrefFamily;
+    nsRefPtr<gfxFontFamily>       mLastPrefFamily;
     nsRefPtr<gfxCoreTextFont>     mLastPrefFont;
     eFontPrefLang                 mLastPrefLang;       // lang group for last pref font
     PRBool                        mLastPrefFirstFont;  // is this the first font in the list of pref fonts for this lang group?
     eFontPrefLang                 mPageLang;
 };
 
 #endif /* GFX_CORETEXTFONTS_H */
--- a/gfx/thebes/public/gfxFT2Fonts.h
+++ b/gfx/thebes/public/gfxFT2Fonts.h
@@ -61,17 +61,16 @@ public:
         gfxFontFamily(aName) { }
 
     FontEntry *FindFontEntry(const gfxFontStyle& aFontStyle);
 
 protected:
     virtual PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], const gfxFontStyle& aFontStyle);
 
 public:
-    nsTArray<nsRefPtr<FontEntry> > mFaces;
     nsString mName;
 };
 
 class FontEntry : public gfxFontEntry
 {
 public:
     FontEntry(const nsAString& aFaceName) :
         gfxFontEntry(aFaceName)
--- a/gfx/thebes/public/gfxFont.h
+++ b/gfx/thebes/public/gfxFont.h
@@ -10,23 +10,24 @@
  * 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 Foundation code.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2005
+ * Portions created by the Initial Developer are Copyright (C) 2005-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
@@ -56,16 +57,17 @@
 #ifdef DEBUG
 #include <stdio.h>
 #endif
 
 class gfxContext;
 class gfxTextRun;
 class nsIAtom;
 class gfxFont;
+class gfxFontFamily;
 class gfxFontGroup;
 class gfxUserFontSet;
 class gfxUserFontData;
 
 // We should eliminate these synonyms when it won't cause many merge conflicts.
 #define FONT_STYLE_NORMAL              NS_FONT_STYLE_NORMAL
 #define FONT_STYLE_ITALIC              NS_FONT_STYLE_ITALIC
 #define FONT_STYLE_OBLIQUE             NS_FONT_STYLE_OBLIQUE
@@ -152,97 +154,221 @@ struct THEBES_API gfxFontStyle {
             (sizeAdjust == other.sizeAdjust);
     }
 };
 
 class gfxFontEntry {
 public:
     THEBES_INLINE_DECL_REFCOUNTING(gfxFontEntry)
 
-    gfxFontEntry(const nsAString& aName) : 
+    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),
         mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
-        mCmapInitialized(PR_FALSE), mUserFontData(nsnull)
+        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),
         mWeight(aEntry.mWeight), mCmapInitialized(aEntry.mCmapInitialized),
-        mCharacterMap(aEntry.mCharacterMap), mUserFontData(aEntry.mUserFontData)
+        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; }
 
-    PRInt32 Weight() { return mWeight; }
+    PRUint16 Weight() { return mWeight; }
+    PRInt16 Stretch() { return mStretch; }
 
     PRBool IsUserFont() { return mIsUserFont; }
     PRBool IsFixedPitch() { return mFixedPitch; }
     PRBool IsItalic() { return mItalic; }
     PRBool IsBold() { return mWeight >= 600; } // bold == weights 600 and above
 
     inline PRBool HasCharacter(PRUint32 ch) {
         if (mCharacterMap.test(ch))
             return PR_TRUE;
             
         return TestCharacterMap(ch);
     }
 
     virtual PRBool TestCharacterMap(PRUint32 aCh);
-    virtual nsresult ReadCMAP() { return 0; }
+    virtual nsresult ReadCMAP();
+
+    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;
 
     PRUint16         mWeight;
-    PRUint16         mStretch;
+    PRInt16          mStretch;
 
     PRPackedBool     mCmapInitialized;
     gfxSparseBitSet  mCharacterMap;
     gfxUserFontData* mUserFontData;
+
+protected:
+    friend class gfxPlatformFontList;
+    friend class gfxMacPlatformFontList;
+    friend class gfxFcFontEntry;
+    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),
+        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!
+    }
+
+    gfxFontFamily *mFamily;
 };
 
 
+// used when picking fallback font
+struct FontSearch {
+    FontSearch(const PRUint32 aCharacter, gfxFont *aFont) :
+        mCh(aCharacter), mFontToMatch(aFont), mMatchRank(0) {
+    }
+    const PRUint32         mCh;
+    gfxFont*               mFontToMatch;
+    PRInt32                mMatchRank;
+    nsRefPtr<gfxFontEntry> mBestMatch;
+};
+
+// helper class for adding other family names back into font cache
+class AddOtherFamilyNameFunctor;
+
 class gfxFontFamily {
 public:
     THEBES_INLINE_DECL_REFCOUNTING(gfxFontFamily)
 
     gfxFontFamily(const nsAString& aName) :
-        mName(aName) { }
+        mName(aName), mOtherFamilyNamesInitialized(PR_FALSE), mHasOtherFamilyNames(PR_FALSE),
+        mIsSimpleFamily(PR_FALSE),
+        mHasStyles(PR_FALSE)
+        { }
 
     virtual ~gfxFontFamily() { }
 
     const nsString& Name() { return mName; }
 
+    virtual void LocalizedName(nsAString& aLocalizedName);
+    virtual PRBool HasOtherFamilyNames();
+    
+    nsTArray<nsRefPtr<gfxFontEntry> >& GetFontList() { return mAvailableFonts; }
+    
+    void AddFontEntry(nsRefPtr<gfxFontEntry> aFontEntry) {
+        mAvailableFonts.AppendElement(aFontEntry);
+    }
+
+    // note that the styles for this family have been added
+    void SetHasStyles(PRBool aHasStyles) { mHasStyles = aHasStyles; }
+
     // choose a specific face to match a style using CSS font matching
     // rules (weight matching occurs here)
+    // may return a face that doesn't precisely match (e.g. normal face when no italic face exists)
+    // aNeedsBold is set to true when bolder face couldn't be found, false otherwise
     gfxFontEntry *FindFontForStyle(const gfxFontStyle& aFontStyle, 
                                    PRBool& aNeedsBold);
 
+    // iterates over faces looking for a match with a given characters
+    // used as part of the font fallback process
+    void FindFontForChar(FontSearch *aMatchData);
+
+    // read in other family names, if any, and use functor to add each into cache
+    virtual void ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor);
+
+    // find faces belonging to this family (temporary, for Windows FontFamily to override)
+    virtual void FindStyleVariations() { }
+
+    // search for a specific face using the Postscript name
+    gfxFontEntry* FindFont(const nsAString& aPostscriptName);
+
+    // read in cmaps for all the faces
+    void ReadCMAP() {
+        PRUint32 i, numFonts = mAvailableFonts.Length();
+        // called from RunLoader BEFORE CheckForSimpleFamily so that there cannot
+        // be any NULL entries in mAvailableFonts
+        for (i = 0; i < numFonts; i++)
+            mAvailableFonts[i]->ReadCMAP();
+    }
+
+    // set whether this font family is in "bad" underline offset blacklist.
+    void SetBadUnderlineFont(PRBool aIsBadUnderlineFont) {
+        PRUint32 i, numFonts = mAvailableFonts.Length();
+        // this is only used when initially setting up the family,
+        // so CheckForSimpleFamily has not yet been called and there cannot
+        // be any NULL entries in mAvailableFonts
+        for (i = 0; i < numFonts; i++)
+            mAvailableFonts[i]->mIsBadUnderlineFont = aIsBadUnderlineFont;
+    }
+
+    // sort available fonts to put preferred (standard) faces towards the end
+    void SortAvailableFonts();
+
+    // check whether the family fits into the simple 4-face model,
+    // so we can use simplified style-matching;
+    // if so set the mIsSimpleFamily flag (defaults to False before we've checked)
+    void CheckForSimpleFamily();
+
 protected:
-    // fills in an array with weights of faces that match style, returns
-   // number of weights in array
-    virtual PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], 
-                                       const gfxFontStyle& aFontStyle) 
-    { return PR_FALSE; }
+    // fills in an array with weights of faces that match style,
+    // returns whether any matching entries found
+    virtual PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
+                                       PRBool anItalic, PRInt16 aStretch);
+
+    PRBool ReadOtherFamilyNamesForFace(AddOtherFamilyNameFunctor& aOtherFamilyFunctor,
+                                       gfxFontEntry *aFontEntry,
+                                       PRBool useFullName);
 
     nsString mName;
+    nsTArray<nsRefPtr<gfxFontEntry> >  mAvailableFonts;
+    PRPackedBool mOtherFamilyNamesInitialized;
+    PRPackedBool mHasOtherFamilyNames;
+    PRPackedBool mIsSimpleFamily;
+    PRPackedBool mHasStyles;
+
+    enum {
+        // for "simple" families, the faces are stored in mAvailableFonts
+        // with fixed positions:
+        kRegularFaceIndex    = 0,
+        kBoldFaceIndex       = 1,
+        kItalicFaceIndex     = 2,
+        kBoldItalicFaceIndex = 3,
+        // mask values for selecting face with bold and/or italic attributes
+        kBoldMask   = 0x01,
+        kItalicMask = 0x02
+    };
 };
 
 struct gfxTextRange {
     gfxTextRange(PRUint32 aStart,  PRUint32 aEnd) : start(aStart), end(aEnd) { }
     PRUint32 Length() const { return end - start; }
     nsRefPtr<gfxFont> font;
     PRUint32 start, end;
 };
--- a/gfx/thebes/public/gfxFontUtils.h
+++ b/gfx/thebes/public/gfxFontUtils.h
@@ -10,22 +10,23 @@
  * 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 Foundation code.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2005
+ * Portions created by the Initial Developer are Copyright (C) 2005-2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <stuart@mozilla.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
@@ -48,16 +49,17 @@
 
 #include "nsITimer.h"
 #include "nsCOMPtr.h"
 #include "nsIRunnable.h"
 #include "nsThreadUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
+#include "nsIStreamBufferAccess.h"
 
 /* Bug 341128 - w32api defines min/max which causes problems with <bitset> */
 #ifdef __MINGW32__
 #undef min
 #undef max
 #endif
 
 #include <bitset>
@@ -287,40 +289,173 @@ public:
             mBlocks[i] = nsnull;    
     }
     
     nsTArray< nsAutoPtr<Block> > mBlocks;
 };
 
 #define TRUETYPE_TAG(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
 
+namespace mozilla {
+
+// Byte-swapping types and name table structure definitions moved from
+// gfxFontUtils.cpp to .h file so that gfxFont.cpp can also refer to them
+#pragma pack(1)
+
+struct AutoSwap_PRUint16 {
+#ifdef __SUNPRO_CC
+    AutoSwap_PRUint16& operator = (const PRUint16 aValue)
+      { this->value = NS_SWAP16(aValue); return *this; }
+#else
+    AutoSwap_PRUint16(PRUint16 aValue) { value = NS_SWAP16(aValue); }
+#endif
+    operator PRUint16() const { return NS_SWAP16(value); }
+    operator PRUint32() const { return NS_SWAP16(value); }
+    operator PRUint64() const { return NS_SWAP16(value); }
+    PRUint16 value;
+};
+
+struct AutoSwap_PRInt16 {
+#ifdef __SUNPRO_CC
+    AutoSwap_PRInt16& operator = (const PRInt16 aValue)
+      { this->value = NS_SWAP16(aValue); return *this; }
+#else
+    AutoSwap_PRInt16(PRInt16 aValue) { value = NS_SWAP16(aValue); }
+#endif
+    operator PRInt16() const { return NS_SWAP16(value); }
+    operator PRUint32() const { return NS_SWAP16(value); }
+    PRInt16  value;
+};
+
+struct AutoSwap_PRUint32 {
+#ifdef __SUNPRO_CC
+    AutoSwap_PRUint32& operator = (const PRUint32 aValue)
+      { this->value = NS_SWAP32(aValue); return *this; }
+#else
+    AutoSwap_PRUint32(PRUint32 aValue) { value = NS_SWAP32(aValue); }
+#endif
+    operator PRUint32() const { return NS_SWAP32(value); }
+    PRUint32  value;
+};
+
+struct AutoSwap_PRUint64 {
+#ifdef __SUNPRO_CC
+    AutoSwap_PRUint64& operator = (const PRUint64 aValue)
+      { this->value = NS_SWAP64(aValue); return *this; }
+#else
+    AutoSwap_PRUint64(PRUint64 aValue) { value = NS_SWAP64(aValue); }
+#endif
+    operator PRUint64() const { return NS_SWAP64(value); }
+    PRUint64  value;
+};
+
+#pragma pack()
+
+} // namespace mozilla
+
 // used for overlaying name changes without touching original font data
 struct FontDataOverlay {
     // overlaySrc != 0 ==> use overlay
     PRUint32  overlaySrc;    // src offset from start of font data
     PRUint32  overlaySrcLen; // src length
     PRUint32  overlayDest;   // dest offset from start of font data
 };
     
 class THEBES_API gfxFontUtils {
 
 public:
+    // these are public because gfxFont.cpp also looks into the name table
+    enum {
+        NAME_ID_FAMILY = 1,
+        NAME_ID_STYLE = 2,
+        NAME_ID_UNIQUE = 3,
+        NAME_ID_FULL = 4,
+        NAME_ID_VERSION = 5,
+        NAME_ID_POSTSCRIPT = 6,
+        NAME_ID_PREFERRED_FAMILY = 16,
+        NAME_ID_PREFERRED_STYLE = 17,
+
+        PLATFORM_ALL = -1,
+        PLATFORM_ID_UNICODE = 0,           // Mac OS uses this typically
+        PLATFORM_ID_MAC = 1,
+        PLATFORM_ID_ISO = 2,
+        PLATFORM_ID_MICROSOFT = 3,
+
+        ENCODING_ID_MAC_ROMAN = 0,         // traditional Mac OS script manager encodings
+        ENCODING_ID_MAC_JAPANESE = 1,      // (there are others defined, but some were never
+        ENCODING_ID_MAC_TRAD_CHINESE = 2,  // implemented by Apple, and I have never seen them
+        ENCODING_ID_MAC_KOREAN = 3,        // used in font names)
+        ENCODING_ID_MAC_ARABIC = 4,
+        ENCODING_ID_MAC_HEBREW = 5,
+        ENCODING_ID_MAC_GREEK = 6,
+        ENCODING_ID_MAC_CYRILLIC = 7,
+        ENCODING_ID_MAC_DEVANAGARI = 9,
+        ENCODING_ID_MAC_GURMUKHI = 10,
+        ENCODING_ID_MAC_GUJARATI = 11,
+        ENCODING_ID_MAC_SIMP_CHINESE = 25,
+
+        ENCODING_ID_MICROSOFT_SYMBOL = 0,  // Microsoft platform encoding IDs
+        ENCODING_ID_MICROSOFT_UNICODEBMP = 1,
+        ENCODING_ID_MICROSOFT_SHIFTJIS = 2,
+        ENCODING_ID_MICROSOFT_PRC = 3,
+        ENCODING_ID_MICROSOFT_BIG5 = 4,
+        ENCODING_ID_MICROSOFT_WANSUNG = 5,
+        ENCODING_ID_MICROSOFT_JOHAB  = 6,
+        ENCODING_ID_MICROSOFT_UNICODEFULL = 10,
+
+        LANG_ALL = -1,
+        LANG_ID_MAC_ENGLISH = 0,      // many others are defined, but most don't affect
+        LANG_ID_MAC_HEBREW = 10,      // the charset; should check all the central/eastern
+        LANG_ID_MAC_JAPANESE = 11,    // european codes, though
+        LANG_ID_MAC_ARABIC = 12,
+        LANG_ID_MAC_ICELANDIC = 15,
+        LANG_ID_MAC_TURKISH = 17,
+        LANG_ID_MAC_TRAD_CHINESE = 19,
+        LANG_ID_MAC_URDU = 20,
+        LANG_ID_MAC_KOREAN = 23,
+        LANG_ID_MAC_POLISH = 25,
+        LANG_ID_MAC_FARSI = 31,
+        LANG_ID_MAC_SIMP_CHINESE = 33,
+        LANG_ID_MAC_ROMANIAN = 37,
+        LANG_ID_MAC_CZECH = 38,
+        LANG_ID_MAC_SLOVAK = 39,
+
+        LANG_ID_MICROSOFT_EN_US = 0x0409         // with Microsoft platformID, EN US lang code
+    };
+
+    // name table has a header, followed by name records, followed by string data
+    struct NameHeader {
+        mozilla::AutoSwap_PRUint16    format;       // Format selector (=0).
+        mozilla::AutoSwap_PRUint16    count;        // Number of name records.
+        mozilla::AutoSwap_PRUint16    stringOffset; // Offset to start of string storage
+                                                    // (from start of table)
+    };
+
+    struct NameRecord {
+        mozilla::AutoSwap_PRUint16    platformID;   // Platform ID
+        mozilla::AutoSwap_PRUint16    encodingID;   // Platform-specific encoding ID
+        mozilla::AutoSwap_PRUint16    languageID;   // Language ID
+        mozilla::AutoSwap_PRUint16    nameID;       // Name ID.
+        mozilla::AutoSwap_PRUint16    length;       // String length (in bytes).
+        mozilla::AutoSwap_PRUint16    offset;       // String offset from start of storage
+                                                    // (in bytes).
+    };
 
     // for reading big-endian font data on either big or little-endian platforms
     
     static inline PRUint16
     ReadShortAt(const PRUint8 *aBuf, PRUint32 aIndex)
     {
         return (aBuf[aIndex] << 8) | aBuf[aIndex + 1];
     }
     
     static inline PRUint16
     ReadShortAt16(const PRUint16 *aBuf, PRUint32 aIndex)
     {
-        const PRUint8 *buf = (PRUint8*) aBuf;
+        const PRUint8 *buf = reinterpret_cast<const PRUint8*>(aBuf);
         PRUint32 index = aIndex << 1;
         return (buf[index] << 8) | buf[index+1];
     }
     
     static inline PRUint32
     ReadLongAt(const PRUint8 *aBuf, PRUint32 aIndex)
     {
         return ((aBuf[aIndex] << 24) | (aBuf[aIndex + 1] << 16) | 
@@ -358,46 +493,35 @@ public:
                         PRBool *aIsCFF = nsnull);
     
     // create a new name table and build a new font with that name table
     // appended on the end, returns true on success
     static nsresult
     RenameFont(const nsAString& aName, const PRUint8 *aFontData, 
                PRUint32 aFontDataLength, nsTArray<PRUint8> *aNewFont);
     
-    // constansts used with name table read methods
-    enum {
-        PLATFORM_ALL = -1,
-        PLATFORM_UNICODE = 0,
-        PLATFORM_MACINTOSH = 1,
-        PLATFORM_MICROSOFT = 3,
-        
-        NAME_LANG_ALL = -1,
-        
-        // name record id's
-        NAME_ID_FAMILY = 1,
-        NAME_ID_STYLE = 2,
-        NAME_ID_UNIQUE = 3,
-        NAME_ID_FULL = 4,  // used as key to GDI CreateFontIndirect
-        NAME_ID_VERSION = 5,
-        NAME_ID_POSTSCRIPT = 6,
-        NAME_ID_PREFERRED_FAMILY = 16       
-    };
-
     // read all names matching aNameID, returning in aNames array
     static nsresult
     ReadNames(nsTArray<PRUint8>& aNameTable, PRUint32 aNameID, 
               PRInt32 aPlatformID, nsTArray<nsString>& aNames);
       
     // reads English or first name matching aNameID, returning in aName
     // platform based on OS
     static nsresult
     ReadCanonicalName(nsTArray<PRUint8>& aNameTable, PRUint32 aNameID, 
                       nsString& aName);
       
+    // convert a name from the raw name table data into an nsString,
+    // provided we know how; return PR_TRUE if successful, or PR_FALSE
+    // if we can't handle the encoding
+    static PRBool
+    DecodeFontName(const PRUint8 *aBuf, PRInt32 aLength, 
+                   PRUint32 aPlatformCode, PRUint32 aScriptCode,
+                   PRUint32 aLangCode, nsAString& dest);
+
     static inline bool IsJoiner(PRUint32 ch) {
         return (ch == 0x200C ||
                 ch == 0x200D ||
                 ch == 0x2060);
     }
 
     static inline bool IsInvalid(PRUint32 ch) {
         return (ch == 0xFFFD);
@@ -412,16 +536,34 @@ public:
     // generate a unique font name
     static nsresult MakeUniqueUserFontName(nsAString& aName);
 
 protected:
     static nsresult
     ReadNames(nsTArray<PRUint8>& aNameTable, PRUint32 aNameID, 
               PRInt32 aLangID, PRInt32 aPlatformID, nsTArray<nsString>& aNames);
 
+    // convert opentype name-table platform/encoding/language values to a charset name
+    // we can use to convert the name data to unicode, or "" if data is UTF16BE
+    static const char*
+    GetCharsetForFontName(PRUint16 aPlatform, PRUint16 aScript, PRUint16 aLanguage);
+
+    struct MacFontNameCharsetMapping {
+        PRUint16    mEncoding;
+        PRUint16    mLanguage;
+        const char *mCharsetName;
+
+        bool operator<(const MacFontNameCharsetMapping& rhs) const {
+            return (mEncoding < rhs.mEncoding) ||
+                   ((mEncoding == rhs.mEncoding) && (mLanguage < rhs.mLanguage));
+        }
+    };
+    static const MacFontNameCharsetMapping gMacFontNameCharsets[];
+    static const char* gISOFontNameCharsets[];
+    static const char* gMSFontNameCharsets[];
 };
 
 // helper class for loading in font info spaced out at regular intervals
 
 class gfxFontInfoLoader {
 public:
 
     // state transitions:
@@ -499,17 +641,17 @@ protected:
 
     // Run - called at intervals, return true to indicate done
     virtual PRBool RunLoader() = 0;
 
     // Finish - cleanup after done
     virtual void FinishLoader() = 0;
 
     static void LoaderTimerCallback(nsITimer *aTimer, void *aThis) {
-        gfxFontInfoLoader *loader = (gfxFontInfoLoader*) aThis;
+        gfxFontInfoLoader *loader = static_cast<gfxFontInfoLoader*>(aThis);
         loader->LoaderTimerFire();
     }
 
     // start the timer, interval callbacks
     void LoaderTimerFire() {
         if (mState == stateTimerOnDelay) {
             mState = stateTimerOnInterval;
             mTimer->SetDelay(mInterval);
--- a/gfx/thebes/public/gfxPlatform.h
+++ b/gfx/thebes/public/gfxPlatform.h
@@ -55,16 +55,17 @@
 
 class gfxImageSurface;
 class gfxFont;
 class gfxFontGroup;
 struct gfxFontStyle;
 class gfxUserFontSet;
 class gfxFontEntry;
 class gfxProxyFontEntry;
+class gfxPlatformFontList;
 class nsIURI;
 
 // pref lang id's for font prefs
 // !!! needs to match the list of pref font.default.xx entries listed in all.js !!!
 
 enum eFontPrefLang {
     eFontPrefLang_Western     =  0,
     eFontPrefLang_CentEuro    =  1,
@@ -159,16 +160,24 @@ public:
                                  nsTArray<nsString>& aListOfFonts);
 
     /**
      * Rebuilds the any cached system font lists
      */
     virtual nsresult UpdateFontList();
 
     /**
+     * Create the platform font-list object (gfxPlatformFontList concrete subclass)
+     */
+    virtual gfxPlatformFontList *CreatePlatformFontList() {
+        NS_NOTREACHED("oops, this platform doesn't have a gfxPlatformFontList implementation");
+        return nsnull;
+    }
+
+    /**
      * Font name resolver, this returns actual font name(s) by the callback
      * function. If the font doesn't exist, the callback function is not called.
      * If the callback function returns PR_FALSE, the aAborted value is set to
      * PR_TRUE, otherwise, PR_FALSE.
      */
     typedef PRBool (*FontResolverCallback) (const nsAString& aName,
                                             void *aClosure);
     virtual nsresult ResolveFontName(const nsAString& aFontName,
--- a/gfx/thebes/public/gfxPlatformMac.h
+++ b/gfx/thebes/public/gfxPlatformMac.h
@@ -70,16 +70,18 @@ public:
 
     gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
                                   const gfxFontStyle *aStyle,
                                   gfxUserFontSet *aUserFontSet);
 
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
 
+    virtual gfxPlatformFontList* CreatePlatformFontList();
+
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            nsISupports *aLoader,
                                            const PRUint8 *aFontData,
                                            PRUint32 aLength);
 
     PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags);
 
     nsresult GetFontList(const nsACString& aLangGroup,
@@ -92,16 +94,24 @@ public:
     
     // Returns the OS X version as returned from Gestalt(gestaltSystemVersion, ...)
     // Ex: Mac OS X 10.4.x ==> 0x104x 
     PRInt32 OSXVersion();
 
     // lower threshold on font anti-aliasing
     PRUint32 GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; }
 
+    // whether we are using CoreText rather than ATSUI for shaping
+    PRBool UsingCoreText()
+#ifdef __LP64__
+        { return PR_TRUE; }
+#else
+        { return mUseCoreText; }
+#endif
+
     // record Unicode cluster boundaries in the text run
     static void SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString);
 
     // map a Unicode range (based on char code) to a font language for Preferences
     static eFontPrefLang GetFontPrefLangFor(PRUint8 aUnicodeRange);
 
 private:
     void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], PRUint32 &aLen, 
--- a/gfx/thebes/public/gfxUserFontSet.h
+++ b/gfx/thebes/public/gfxUserFontSet.h
@@ -77,21 +77,21 @@ public:
     gfxUserFontData() { }
     virtual ~gfxUserFontData() { }
 };
 
 // initially contains a set of proxy font entry objects, replaced with
 // platform/user fonts as downloaded
 
 class gfxMixedFontFamily : public gfxFontFamily {
+public:
+    friend class gfxUserFontSet;
 
-public:
     gfxMixedFontFamily(const nsAString& aName)
-        : gfxFontFamily(aName)
-    { }
+        : gfxFontFamily(aName) { }
 
     virtual ~gfxMixedFontFamily() { }
 
     void AddFontEntry(gfxFontEntry *aFontEntry) {
         nsRefPtr<gfxFontEntry> fe = aFontEntry;
         mAvailableFonts.AppendElement(fe);
     }
 
@@ -125,23 +125,16 @@ public:
         PRUint32 numFonts = mAvailableFonts.Length();
         for (PRUint32 i = 0; i < numFonts; i++) {
             gfxFontEntry *fe = mAvailableFonts[i];
             if (fe->mIsProxy)
                 return PR_FALSE;
         }
         return PR_TRUE;
     }
-
-    nsTArray<nsRefPtr<gfxFontEntry> >  mAvailableFonts;
-
-protected:
-    PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], 
-                               const gfxFontStyle& aFontStyle);
-
 };
 
 class gfxProxyFontEntry;
 
 class THEBES_API gfxUserFontSet {
 
 public:
 
@@ -229,27 +222,27 @@ protected:
     nsRefPtrHashtable<nsStringHashKey, gfxMixedFontFamily> mFontFamilies;
 
     PRUint64        mGeneration;
 };
 
 // acts a placeholder until the real font is downloaded
 
 class gfxProxyFontEntry : public gfxFontEntry {
+    friend class gfxUserFontSet;
 
 public:
     gfxProxyFontEntry(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, 
                       gfxMixedFontFamily *aFamily,
                       PRUint32 aWeight, 
                       PRUint32 aStretch, 
                       PRUint32 aItalicStyle, 
                       gfxSparseBitSet *aUnicodeRanges);
 
     virtual ~gfxProxyFontEntry();
 
     PRPackedBool                           mIsLoading;
     nsTArray<gfxFontFaceSrc>               mSrcList;
     PRUint32                               mSrcIndex; // index of loading src item
-    gfxMixedFontFamily*                    mFamily;
 };
 
 
 #endif /* GFX_USER_FONT_SET_H */
--- a/gfx/thebes/public/gfxWindowsFonts.h
+++ b/gfx/thebes/public/gfxWindowsFonts.h
@@ -78,38 +78,35 @@ enum gfxWindowsFontType {
  * 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), mHasStyles(PR_FALSE) { }
+        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[], const gfxFontStyle& aFontStyle);
+    PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
+                               PRBool anItalic, PRInt16 aStretch);
 
 public:
-    nsTArray<nsRefPtr<FontEntry> > mVariations;
     PRPackedBool mIsBadUnderlineFontFamily;
-
-private:
-    PRPackedBool mHasStyles;
 };
 
 class FontEntry : public gfxFontEntry
 {
 public:
     FontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
               PRBool aItalic, PRUint16 aWeight, gfxUserFontData *aUserFontData) : 
         gfxFontEntry(aFaceName), mFontType(aFontType),
--- a/gfx/thebes/src/Makefile.in
+++ b/gfx/thebes/src/Makefile.in
@@ -12,16 +12,17 @@ LIBXUL_LIBRARY	= 1
 EXPORT_LIBRARY	= 1
 
 REQUIRES = \
 	cairo \
 	string \
 	pref \
 	xpcom \
 	unicharutil \
+	uconv \
 	$(LCMS_REQUIRES) \
 	qcms \
 	$(NULL)
 
 CPPSRCS	= \
 	gfxASurface.cpp \
 	gfxAlphaRecovery.cpp \
 	gfxBlur.cpp \
@@ -30,16 +31,17 @@ CPPSRCS	= \
 	gfxFont.cpp \
 	gfxFontMissingGlyphs.cpp \
 	gfxFontTest.cpp \
 	gfxFontUtils.cpp \
 	gfxMatrix.cpp \
 	gfxPath.cpp \
 	gfxPattern.cpp \
 	gfxPlatform.cpp \
+	gfxPlatformFontList.cpp \
 	gfxRect.cpp \
 	gfxSkipChars.cpp \
 	gfxTextRunCache.cpp \
 	gfxTextRunWordCache.cpp \
 	gfxUserFontSet.cpp \
 	$(NULL)
 
 EXTRA_DSO_LDOPTS += \
@@ -155,17 +157,17 @@ CPPSRCS	+= \
 #CPPSRCS +=	gfxPDFSurface.cpp
 CPPSRCS +=      nsUnicodeRange.cpp
 CPPSRCS +=      gfxQuartzNativeDrawing.cpp
 
 ifdef MOZ_CORETEXT
 CPPSRCS += gfxCoreTextFonts.cpp
 endif
 
-CMMSRCS = gfxQuartzFontCache.mm
+CMMSRCS = gfxMacPlatformFontList.mm
 
 # Always link with OpenGL/AGL
 EXTRA_DSO_LDOPTS += -framework OpenGL -framework AGL -framework QuickTime
 endif
 
 EXTRA_DSO_LDOPTS += $(TK_LIBS)
 
 DEFINES += -DIMPL_THEBES
--- a/gfx/thebes/src/gfxAtsuiFonts.cpp
+++ b/gfx/thebes/src/gfxAtsuiFonts.cpp
@@ -10,23 +10,24 @@
  * 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) 2006
+ * Portions created by the Initial Developer are Copyright (C) 2006-2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Vladimir Vukicevic <vladimir@pobox.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
@@ -54,17 +55,17 @@
 #include "gfxAtsuiFonts.h"
 
 #include "gfxFontTest.h"
 #include "gfxFontUtils.h"
 
 #include "cairo-quartz.h"
 
 #include "gfxQuartzSurface.h"
-#include "gfxQuartzFontCache.h"
+#include "gfxMacPlatformFontList.h"
 #include "gfxUserFontSet.h"
 
 #include "nsUnicodeRange.h"
 
 // Uncomment this to dump all text runs created to stdout
 // #define DUMP_TEXT_RUNS
 
 #ifdef DUMP_TEXT_RUNS
@@ -502,17 +503,17 @@ gfxAtsuiFont::HasMirroringInfo()
 PRBool gfxAtsuiFont::TestCharacterMap(PRUint32 aCh) {
     if (!mIsValid) return PR_FALSE;
     return GetFontEntry()->TestCharacterMap(aCh);
 }
 
 MacOSFontEntry*
 gfxAtsuiFont::GetFontEntry()
 {
-    return static_cast< MacOSFontEntry*> (mFontEntry.get());
+    return static_cast<MacOSFontEntry*> (mFontEntry.get());
 }
 
 /**
  * Look up the font in the gfxFont cache. If we don't find it, create one.
  * In either case, add a ref and return it ---
  * except for OOM in which case we do nothing and return null.
  */
  
@@ -544,39 +545,39 @@ gfxAtsuiFontGroup::gfxAtsuiFontGroup(con
     : gfxFontGroup(families, aStyle, aUserFontSet)
 {
     mPageLang = gfxPlatform::GetFontPrefLangFor(mStyle.langGroup.get());
 
     InitFontList();
 }
 
 PRBool
-gfxAtsuiFontGroup::FindATSUFont(const nsAString& aName,
-                                const nsACString& aGenericName,
-                                void *closure)
+gfxAtsuiFontGroup::FindATSFont(const nsAString& aName,
+                               const nsACString& aGenericName,
+                               void *aClosure)
 {
-    gfxAtsuiFontGroup *fontGroup = (gfxAtsuiFontGroup*) closure;
+    gfxAtsuiFontGroup *fontGroup = static_cast<gfxAtsuiFontGroup*>(aClosure);
     const gfxFontStyle *fontStyle = fontGroup->GetStyle();
 
 
     PRBool needsBold;
     MacOSFontEntry *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 = static_cast<MacOSFontEntry*> (gfe);
     }
     
     // nothing in the user font set ==> check system fonts
     if (!fe) {
-        gfxQuartzFontCache *fc = gfxQuartzFontCache::SharedFontCache();
-        fe = fc->FindFontForFamily(aName, fontStyle, needsBold);
+        fe = static_cast<MacOSFontEntry*>
+            (gfxMacPlatformFontList::PlatformFontList()->FindFontForFamily(aName, fontStyle, needsBold));
     }
 
     if (fe && !fontGroup->HasFont(fe->GetFontRef())) {
         nsRefPtr<gfxAtsuiFont> font = GetOrMakeFont(fe, fontStyle, needsBold);
         if (font) {
             fontGroup->mFonts.AppendElement(font);
         }
     }
@@ -799,27 +800,27 @@ gfxAtsuiFontGroup::HasFont(ATSFontRef aF
     for (PRUint32 i = 0; i < mFonts.Length(); ++i) {
         if (aFontRef == static_cast<gfxAtsuiFont *>(mFonts.ElementAt(i).get())->GetATSFontRef())
             return PR_TRUE;
     }
     return PR_FALSE;
 }
 
 struct PrefFontCallbackData {
-    PrefFontCallbackData(nsTArray<nsRefPtr<MacOSFamilyEntry> >& aFamiliesArray) 
+    PrefFontCallbackData(nsTArray<nsRefPtr<gfxFontFamily> >& aFamiliesArray) 
         : mPrefFamilies(aFamiliesArray)
     {}
 
-    nsTArray<nsRefPtr<MacOSFamilyEntry> >& mPrefFamilies;
+    nsTArray<nsRefPtr<gfxFontFamily> >& mPrefFamilies;
 
     static PRBool AddFontFamilyEntry(eFontPrefLang aLang, const nsAString& aName, void *aClosure)
     {
-        PrefFontCallbackData *prefFontData = (PrefFontCallbackData*) aClosure;
+        PrefFontCallbackData *prefFontData = static_cast<PrefFontCallbackData*>(aClosure);
         
-        MacOSFamilyEntry *family = gfxQuartzFontCache::SharedFontCache()->FindFamily(aName);
+        gfxFontFamily *family = gfxMacPlatformFontList::PlatformFontList()->FindFamily(aName);
         if (family) {
             prefFontData->mPrefFamilies.AppendElement(family);
         }
         return PR_TRUE;
     }
 };
 
 
@@ -846,77 +847,79 @@ gfxAtsuiFontGroup::WhichPrefFontSupports
     // based on char lang and page lang, set up list of pref lang fonts to check
     eFontPrefLang prefLangs[kMaxLenPrefLangList];
     PRUint32 i, numLangs = 0;
 
     gfxPlatformMac *macPlatform = gfxPlatformMac::GetPlatform();
     macPlatform->GetLangPrefs(prefLangs, numLangs, charLang, mPageLang);
 
     for (i = 0; i < numLangs; i++) {
-        nsAutoTArray<nsRefPtr<MacOSFamilyEntry>, 5> families;
+        nsAutoTArray<nsRefPtr<gfxFontFamily>, 5> families;
         eFontPrefLang currentLang = prefLangs[i];
         
-        gfxQuartzFontCache *fc = gfxQuartzFontCache::SharedFontCache();
+        gfxMacPlatformFontList *fc = gfxMacPlatformFontList::PlatformFontList();
 
         // get the pref families for a single pref lang
         if (!fc->GetPrefFontFamilyEntries(currentLang, &families)) {
             eFontPrefLang prefLangsToSearch[1] = { currentLang };
             PrefFontCallbackData prefFontData(families);
             gfxPlatform::ForEachPrefFont(prefLangsToSearch, 1, PrefFontCallbackData::AddFontFamilyEntry,
                                            &prefFontData);
             fc->SetPrefFontFamilyEntries(currentLang, families);
         }
 
         // find the first pref font that includes the character
         PRUint32  i, numPrefs;
         numPrefs = families.Length();
         for (i = 0; i < numPrefs; i++) {
             // look up the appropriate face
-            MacOSFamilyEntry *family = families[i];
+            gfxFontFamily *family = families[i];
             if (!family) continue;
             
             // if a pref font is used, it's likely to be used again in the same text run.
             // the style doesn't change so the face lookup can be cached rather than calling
             // GetOrMakeFont repeatedly.  speeds up FindFontForChar lookup times for subsequent
             // pref font lookups
             if (family == mLastPrefFamily && mLastPrefFont->TestCharacterMap(aCh)) {
                 font = mLastPrefFont;
                 NS_ADDREF(font);
                 return font;
             }
             
             PRBool needsBold;
-            MacOSFontEntry *fe = family->FindFont(&mStyle, needsBold);
+            MacOSFontEntry *fe =
+                static_cast<MacOSFontEntry*>(family->FindFontForStyle(mStyle, needsBold));
             // if ch in cmap, create and return a gfxFont
             if (fe && fe->TestCharacterMap(aCh)) {
                 nsRefPtr<gfxAtsuiFont> prefFont = GetOrMakeFont(fe, &mStyle, needsBold);
                 if (!prefFont) continue;
                 mLastPrefFamily = family;
                 mLastPrefFont = prefFont;
                 mLastPrefLang = charLang;
                 mLastPrefFirstFont = (i == 0);
-                nsRefPtr<gfxFont> font2 = (gfxFont*) prefFont;
+                nsRefPtr<gfxFont> font2 = prefFont.get();
                 return font2.forget();
             }
 
         }
     }
 
     return nsnull;
 }
 
 already_AddRefed<gfxFont> 
 gfxAtsuiFontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
 {
     MacOSFontEntry *fe;
 
-    fe = gfxQuartzFontCache::SharedFontCache()->FindFontForChar(aCh, GetFontAt(0));
+    fe = static_cast<MacOSFontEntry*>
+        (gfxMacPlatformFontList::PlatformFontList()->FindFontForChar(aCh, GetFontAt(0)));
     if (fe) {
         nsRefPtr<gfxAtsuiFont> atsuiFont = GetOrMakeFont(fe, &mStyle, PR_FALSE); // ignore bolder considerations in system fallback case...
-        nsRefPtr<gfxFont> font = (gfxFont*) atsuiFont; 
+        nsRefPtr<gfxFont> font = atsuiFont.get(); 
         return font.forget();
     }
 
     return nsnull;
 }
 
 void
 gfxAtsuiFontGroup::UpdateFontList()
@@ -1503,18 +1506,18 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRu
                 memset(closure.mUnmatchedChars.get() + runStart - aLayoutStart,
                        PR_TRUE, matchedLength);
             }
             
         } else {
         
             if (matchedFont != firstFont) {
                 // create a new sub-style and add it to the layout
-                ATSUStyle subStyle = SetLayoutRangeToFont(layout, mainStyle, runStart, matchedLength,
-                                                          FMGetFontFromATSFontRef(matchedFont->GetATSFontRef()));
+                ATSUStyle subStyle = SetLayoutRangeToFont(layout, mainStyle, runStart,
+                                                          matchedLength, matchedFont->GetATSFontRef());
                 stylesToDispose.AppendElement(subStyle);
             }
 
             // add a glyph run for the matched substring
             aRun->AddGlyphRun(matchedFont, aOffsetInTextRun + runStart - aLayoutStart, PR_TRUE);
         }
         
         runStart += matchedLength;
@@ -1545,33 +1548,34 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRu
     }
     gCallbackClosure = nsnull;
     return !closure.mOverrunningGlyphs;
 }
 
 void
 gfxAtsuiFontGroup::InitFontList()
 {
-    ForEachFont(FindATSUFont, this);
+    ForEachFont(FindATSFont, this);
 
     if (mFonts.Length() == 0) {
         // XXX this will generate a list of the lang groups for which we have no
         // default fonts for on the mac; we should fix this!
         // Known:
         // ja x-beng x-devanagari x-tamil x-geor x-ethi x-gujr x-mlym x-armn
         // x-orya x-telu x-knda x-sinh
 
         //fprintf (stderr, "gfxAtsuiFontGroup: %s [%s] -> %d fonts found\n", NS_ConvertUTF16toUTF8(families).get(), mStyle.langGroup.get(), mFonts.Length());
 
         // If we get here, we most likely didn't have a default font for
         // a specific langGroup.  Let's just pick the default OSX
         // user font.
 
         PRBool needsBold;
-        MacOSFontEntry *defaultFont = gfxQuartzFontCache::SharedFontCache()->GetDefaultFont(&mStyle, needsBold);
+        MacOSFontEntry *defaultFont = static_cast<MacOSFontEntry*>
+            (gfxMacPlatformFontList::PlatformFontList()->GetDefaultFont(&mStyle, needsBold));
         NS_ASSERTION(defaultFont, "invalid default font returned by GetDefaultFont");
 
         nsRefPtr<gfxAtsuiFont> font = GetOrMakeFont(defaultFont, &mStyle, needsBold);
 
         if (font) {
             mFonts.AppendElement(font);
         }
     }
--- a/gfx/thebes/src/gfxCoreTextFonts.cpp
+++ b/gfx/thebes/src/gfxCoreTextFonts.cpp
@@ -53,17 +53,17 @@
 #include "gfxCoreTextFonts.h"
 
 #include "gfxFontTest.h"
 #include "gfxFontUtils.h"
 
 #include "cairo-quartz.h"
 
 #include "gfxQuartzSurface.h"
-#include "gfxQuartzFontCache.h"
+#include "gfxMacPlatformFontList.h"
 #include "gfxUserFontSet.h"
 
 #include "nsUnicodeRange.h"
 
 // Uncomment this to dump all text runs created to the log (if enabled)
 //#define DUMP_TEXT_RUNS
 
 #ifdef DUMP_TEXT_RUNS
@@ -584,22 +584,21 @@ gfxCoreTextFontGroup::gfxCoreTextFontGro
 
         //fprintf (stderr, "gfxCoreTextFontGroup: %s [%s] -> %d fonts found\n", NS_ConvertUTF16toUTF8(families).get(), aStyle->langGroup.get(), mFonts.Length());
 
         // If we get here, we most likely didn't have a default font for
         // a specific langGroup.  Let's just pick the default OSX
         // user font.
 
         PRBool needsBold;
-        MacOSFontEntry *defaultFont =
-            gfxQuartzFontCache::SharedFontCache()->GetDefaultFont(aStyle, needsBold);
+        MacOSFontEntry *defaultFont = static_cast<MacOSFontEntry*>
+            (gfxMacPlatformFontList::PlatformFontList()->GetDefaultFont(aStyle, needsBold));
         NS_ASSERTION(defaultFont, "invalid default font returned by GetDefaultFont");
 
         nsRefPtr<gfxCoreTextFont> font = GetOrMakeCTFont(defaultFont, aStyle, needsBold);
-
         if (font) {
             mFonts.AppendElement(font);
         }
     }
 
     mPageLang = gfxPlatform::GetFontPrefLangFor(mStyle.langGroup.get());
 
     if (!mStyle.systemFont) {
@@ -613,37 +612,37 @@ gfxCoreTextFontGroup::gfxCoreTextFontGro
             }
         }
     }
 }
 
 PRBool
 gfxCoreTextFontGroup::FindCTFont(const nsAString& aName,
                                  const nsACString& aGenericName,
-                                 void *closure)
+                                 void *aClosure)
 {
-    gfxCoreTextFontGroup *fontGroup = (gfxCoreTextFontGroup*) closure;
+    gfxCoreTextFontGroup *fontGroup = static_cast<gfxCoreTextFontGroup*>(aClosure);
     const gfxFontStyle *fontStyle = fontGroup->GetStyle();
 
 
     PRBool needsBold;
     MacOSFontEntry *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 = static_cast<MacOSFontEntry*> (gfe);
     }
 
     // nothing in the user font set ==> check system fonts
     if (!fe) {
-        gfxQuartzFontCache *fc = gfxQuartzFontCache::SharedFontCache();
-        fe = fc->FindFontForFamily(aName, fontStyle, needsBold);
+        fe = static_cast<MacOSFontEntry*>
+            (gfxMacPlatformFontList::PlatformFontList()->FindFontForFamily(aName, fontStyle, needsBold));
     }
 
     if (fe && !fontGroup->HasFont(fe->GetFontRef())) {
         nsRefPtr<gfxCoreTextFont> font = GetOrMakeCTFont(fe, fontStyle, needsBold);
         if (font) {
             fontGroup->mFonts.AppendElement(font);
         }
     }
@@ -1216,27 +1215,27 @@ gfxCoreTextFontGroup::HasFont(ATSFontRef
     for (PRUint32 i = 0; i < mFonts.Length(); ++i) {
         if (aFontRef == static_cast<gfxCoreTextFont *>(mFonts.ElementAt(i).get())->GetATSFont())
             return PR_TRUE;
     }
     return PR_FALSE;
 }
 
 struct PrefFontCallbackData {
-    PrefFontCallbackData(nsTArray<nsRefPtr<MacOSFamilyEntry> >& aFamiliesArray)
+    PrefFontCallbackData(nsTArray<nsRefPtr<gfxFontFamily> >& aFamiliesArray)
         : mPrefFamilies(aFamiliesArray)
     {}
 
-    nsTArray<nsRefPtr<MacOSFamilyEntry> >& mPrefFamilies;
+    nsTArray<nsRefPtr<gfxFontFamily> >& mPrefFamilies;
 
     static PRBool AddFontFamilyEntry(eFontPrefLang aLang, const nsAString& aName, void *aClosure)
     {
-        PrefFontCallbackData *prefFontData = (PrefFontCallbackData*) aClosure;
+        PrefFontCallbackData *prefFontData = static_cast<PrefFontCallbackData*>(aClosure);
 
-        MacOSFamilyEntry *family = gfxQuartzFontCache::SharedFontCache()->FindFamily(aName);
+        gfxFontFamily *family = gfxMacPlatformFontList::PlatformFontList()->FindFamily(aName);
         if (family) {
             prefFontData->mPrefFamilies.AppendElement(family);
         }
         return PR_TRUE;
     }
 };
 
 
@@ -1264,77 +1263,77 @@ gfxCoreTextFontGroup::WhichPrefFontSuppo
     // based on char lang and page lang, set up list of pref lang fonts to check
     eFontPrefLang prefLangs[kMaxLenPrefLangList];
     PRUint32 i, numLangs = 0;
 
     gfxPlatformMac *macPlatform = gfxPlatformMac::GetPlatform();
     macPlatform->GetLangPrefs(prefLangs, numLangs, charLang, mPageLang);
 
     for (i = 0; i < numLangs; i++) {
-        nsAutoTArray<nsRefPtr<MacOSFamilyEntry>, 5> families;
+        nsAutoTArray<nsRefPtr<gfxFontFamily>, 5> families;
         eFontPrefLang currentLang = prefLangs[i];
 
-        gfxQuartzFontCache *fc = gfxQuartzFontCache::SharedFontCache();
+        gfxMacPlatformFontList *fc = gfxMacPlatformFontList::PlatformFontList();
 
         // get the pref families for a single pref lang
         if (!fc->GetPrefFontFamilyEntries(currentLang, &families)) {
             eFontPrefLang prefLangsToSearch[1] = { currentLang };
             PrefFontCallbackData prefFontData(families);
             gfxPlatform::ForEachPrefFont(prefLangsToSearch, 1, PrefFontCallbackData::AddFontFamilyEntry,
                                            &prefFontData);
             fc->SetPrefFontFamilyEntries(currentLang, families);
         }
 
         // find the first pref font that includes the character
         PRUint32  i, numPrefs;
         numPrefs = families.Length();
         for (i = 0; i < numPrefs; i++) {
             // look up the appropriate face
-            MacOSFamilyEntry *family = families[i];
+            gfxFontFamily *family = families[i];
             if (!family) continue;
 
             // if a pref font is used, it's likely to be used again in the same text run.
             // the style doesn't change so the face lookup can be cached rather than calling
             // GetOrMakeCTFont repeatedly.  speeds up FindFontForChar lookup times for subsequent
             // pref font lookups
             if (family == mLastPrefFamily && mLastPrefFont->TestCharacterMap(aCh)) {
                 font = mLastPrefFont;
                 NS_ADDREF(font);
                 return font;
             }
 
             PRBool needsBold;
-            MacOSFontEntry *fe = family->FindFont(&mStyle, needsBold);
+            MacOSFontEntry *fe =
+                static_cast<MacOSFontEntry*>(family->FindFontForStyle(mStyle, needsBold));
             // if ch in cmap, create and return a gfxFont
             if (fe && fe->TestCharacterMap(aCh)) {
                 nsRefPtr<gfxCoreTextFont> prefFont = GetOrMakeCTFont(fe, &mStyle, needsBold);
                 if (!prefFont) continue;
                 mLastPrefFamily = family;
                 mLastPrefFont = prefFont;
                 mLastPrefLang = charLang;
                 mLastPrefFirstFont = (i == 0);
-                nsRefPtr<gfxFont> font2 = (gfxFont*) prefFont;
+                nsRefPtr<gfxFont> font2 = prefFont.get();
                 return font2.forget();
             }
 
         }
     }
 
     return nsnull;
 }
 
 already_AddRefed<gfxFont>
 gfxCoreTextFontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
 {
-    MacOSFontEntry *fe;
-
-    fe = gfxQuartzFontCache::SharedFontCache()->FindFontForChar(aCh, GetFontAt(0));
+    MacOSFontEntry *fe = static_cast<MacOSFontEntry*>
+        (gfxMacPlatformFontList::PlatformFontList()->FindFontForChar(aCh, GetFontAt(0)));
     if (fe) {
         nsRefPtr<gfxCoreTextFont> ctFont = GetOrMakeCTFont(fe, &mStyle, PR_FALSE); // ignore bolder considerations in system fallback case...
-        nsRefPtr<gfxFont> font = (gfxFont*) ctFont;
+        nsRefPtr<gfxFont> font = ctFont.get();
         return font.forget();
     }
 
     return nsnull;
 }
 
 void
 gfxCoreTextFontGroup::UpdateFontList()
--- a/gfx/thebes/src/gfxFT2Fonts.cpp
+++ b/gfx/thebes/src/gfxFT2Fonts.cpp
@@ -174,34 +174,34 @@ FontEntry::CairoFontFace()
 FontEntry *
 FontFamily::FindFontEntry(const gfxFontStyle& aFontStyle)
 {
     PRBool needsBold = PR_FALSE;
     return static_cast<FontEntry*>(FindFontForStyle(aFontStyle, needsBold));
 }
 
 PRBool
-FontFamily::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], const gfxFontStyle& aFontStyle)
+FontFamily::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
+                                PRBool anItalic, PRInt16 aStretch)
 {
-    PRBool italic = (aFontStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
     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 < mFaces.Length(); i++) {
-            FontEntry *fe = mFaces[i];
+        for (PRUint32 i = 0; i < mAvailableFonts.Length(); i++) {
+            gfxFontEntry *fe = mAvailableFonts[i];
             const PRUint8 weight = (fe->mWeight / 100);
-            if (fe->mItalic == italic) {
+            if (fe->mItalic == anItalic) {
                 aFontsForWeights[weight] = fe;
                 matchesSomething = PR_TRUE;
             }
         }
         if (matchesSomething)
             break;
-        italic = !italic;
+        anItalic = !anItalic;
     }
 
     return matchesSomething;
 }
 
 /**
  * gfxFT2FontGroup
  */
--- a/gfx/thebes/src/gfxFont.cpp
+++ b/gfx/thebes/src/gfxFont.cpp
@@ -10,23 +10,24 @@
  * 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 Foundation code.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2005
+ * Portions created by the Initial Developer are Copyright (C) 2005-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
@@ -45,26 +46,29 @@
 #include "gfxFont.h"
 #include "gfxPlatform.h"
 
 #include "prtypes.h"
 #include "gfxTypes.h"
 #include "gfxContext.h"
 #include "gfxFontMissingGlyphs.h"
 #include "gfxUserFontSet.h"
+#include "gfxPlatformFontList.h"
 #include "nsMathUtils.h"
 #include "nsBidiUtils.h"
 
 #include "cairo.h"
 #include "gfxFontTest.h"
 
 #include "nsCRT.h"
 
 gfxFontCache *gfxFontCache::gGlobalCache = nsnull;
 
+static PRLogModuleInfo *gFontSelection = PR_NewLogModule("fontSelectionLog");
+
 #ifdef DEBUG_roc
 #define DEBUG_TEXT_RUN_STORAGE_METRICS
 #endif
 
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
 static PRUint32 gTextRunStorageHighWaterMark = 0;
 static PRUint32 gTextRunStorage = 0;
 static PRUint32 gFontCount = 0;
@@ -78,58 +82,187 @@ static PRUint32 gGlyphExtentsSetupFallBa
 
 gfxFontEntry::~gfxFontEntry() 
 {
     if (mUserFontData)
         delete mUserFontData;
 }
 
 
-PRBool gfxFontEntry::TestCharacterMap(PRUint32 aCh) {
-    if (!mCmapInitialized) ReadCMAP();
+PRBool gfxFontEntry::TestCharacterMap(PRUint32 aCh)
+{
+    if (!mCmapInitialized) {
+        ReadCMAP();
+    }
     return mCharacterMap.test(aCh);
 }
 
 
-gfxFontEntry *gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle, PRBool& aNeedsBold)
+nsresult gfxFontEntry::ReadCMAP()
+{
+    mCmapInitialized = PR_TRUE;
+    return NS_OK;
+}
+
+
+const nsString& gfxFontEntry::FamilyName()
 {
-    gfxFontEntry *weightList[10] = { 0 };
+    NS_ASSERTION(mFamily, "gfxFontEntry is not a member of a family");
+    return mFamily->Name();
+}
+
+// we consider faces with mStandardFace == PR_TRUE to be "greater than" those with PR_FALSE,
+// because during style matching, later entries will replace earlier ones
+class FontEntryStandardFaceComparator {
+  public:
+    PRBool Equals(const nsRefPtr<gfxFontEntry>& a, const nsRefPtr<gfxFontEntry>& b) const {
+        return a->mStandardFace == b->mStandardFace;
+    }
+    PRBool LessThan(const nsRefPtr<gfxFontEntry>& a, const nsRefPtr<gfxFontEntry>& b) const {
+        return (a->mStandardFace == PR_FALSE && b->mStandardFace == PR_TRUE);
+    }
+};
+
+void
+gfxFontFamily::SortAvailableFonts()
+{
+    mAvailableFonts.Sort(FontEntryStandardFaceComparator());
+}
+
+PRBool
+gfxFontFamily::HasOtherFamilyNames()
+{
+    // need to read in other family names to determine this
+    if (!mOtherFamilyNamesInitialized) {
+        AddOtherFamilyNameFunctor addOtherNames(gfxPlatformFontList::PlatformFontList());
+        ReadOtherFamilyNames(addOtherNames);  // sets mHasOtherFamilyNames
+    }
+    return mHasOtherFamilyNames;
+}
+
+gfxFontEntry*
+gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle, PRBool& aNeedsBold)
+{
+    if (!mHasStyles)
+        FindStyleVariations(); // collect faces for the family, if not already done
+
+    NS_ASSERTION(mAvailableFonts.Length() > 0, "font family with no faces!");
 
     aNeedsBold = PR_FALSE;
 
-    PRBool foundWeights = FindWeightsForStyle(weightList, aFontStyle);
-    if (!foundWeights)
-        return nsnull;
-
     PRInt8 baseWeight, weightDistance;
     aFontStyle.ComputeWeightAndOffset(&baseWeight, &weightDistance);
+    PRBool wantBold = baseWeight >= 6;
+    if ((wantBold && weightDistance < 0) || (!wantBold && weightDistance > 0)) {
+        wantBold = !wantBold;
+    }
+
+    // If the family has only one face, we simply return it; no further checking needed
+    if (mAvailableFonts.Length() == 1) {
+        gfxFontEntry *fe = mAvailableFonts[0];
+        aNeedsBold = wantBold && !fe->IsBold();
+        return fe;
+    }
+
+    PRBool wantItalic = (aFontStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
+
+    // Most families are "simple", having just Regular/Bold/Italic/BoldItalic,
+    // or some subset of these. In this case, we have exactly 4 entries in mAvailableFonts,
+    // stored in the above order; note that some of the entries may be NULL.
+    // We can then pick the required entry based on whether the request is for
+    // bold or non-bold, italic or non-italic, without running the more complex
+    // matching algorithm used for larger families with many weights and/or widths.
+
+    if (mIsSimpleFamily) {
+        // Family has no more than the "standard" 4 faces, at fixed indexes;
+        // calculate which one we want.
+        // Note that we cannot simply return it as not all 4 faces are necessarily present.
+        PRUint8 faceIndex = (wantItalic ? kItalicMask : 0) |
+                            (wantBold ? kBoldMask : 0);
+
+        // if the desired style is available, return it directly
+        gfxFontEntry *fe = mAvailableFonts[faceIndex];
+        if (fe) {
+            // no need to set aNeedsBold here as we matched the boldness request
+            return fe;
+        }
+
+        // order to check fallback faces in a simple family, depending on requested style
+        static const PRUint8 simpleFallbacks[4][3] = {
+            { kBoldFaceIndex, kItalicFaceIndex, kBoldItalicFaceIndex },   // fallbacks for Regular
+            { kRegularFaceIndex, kBoldItalicFaceIndex, kItalicFaceIndex },// Bold
+            { kBoldItalicFaceIndex, kRegularFaceIndex, kBoldFaceIndex },  // Italic
+            { kItalicFaceIndex, kBoldFaceIndex, kRegularFaceIndex }       // BoldItalic
+        };
+        const PRUint8 *order = simpleFallbacks[faceIndex];
+
+        for (PRUint8 trial = 0; trial < 3; ++trial) {
+            // check remaining faces in order of preference to find the first that actually exists
+            fe = mAvailableFonts[order[trial]];
+            if (fe) {
+                PR_LOG(gFontSelection, PR_LOG_DEBUG,
+                       ("(FindFontForStyle) name: %s, sty: %02x, wt: %d, sz: %.1f -> %s (trial %d)\n", 
+                        NS_ConvertUTF16toUTF8(mName).get(),
+                        aFontStyle.style, aFontStyle.weight, aFontStyle.size,
+                        NS_ConvertUTF16toUTF8(fe->Name()).get(), trial));
+                aNeedsBold = wantBold && !fe->IsBold();
+                return fe;
+            }
+        }
+
+        // this can't happen unless we have totally broken the font-list manager!
+        NS_NOTREACHED("no face found in simple font family!");
+        return nsnull;
+    }
+
+    // This is a large/rich font family, so we do full style- and weight-matching:
+    // first collect a list of weights that are the best match for the requested
+    // font-stretch and font-style, then pick the best weight match among those
+    // available.
+
+    gfxFontEntry *weightList[10] = { 0 };
+    PRBool foundWeights = FindWeightsForStyle(weightList, wantItalic, aFontStyle.stretch);
+    if (!foundWeights) {
+        PR_LOG(gFontSelection, PR_LOG_DEBUG,
+               ("(FindFontForStyle) name: %s, sty: %02x, wt: %d, sz: %.1f -> null\n", 
+                NS_ConvertUTF16toUTF8(mName).get(),
+                aFontStyle.style, aFontStyle.weight, aFontStyle.size));
+        return nsnull;
+    }
 
     // 500 isn't quite bold so we want to treat it as 400 if we don't
     // have a 500 weight
     if (baseWeight == 5 && weightDistance == 0) {
         // If we have a 500 weight then use it
-        if (weightList[5])
+        if (weightList[5]) {
+            PR_LOG(gFontSelection, PR_LOG_DEBUG,
+                   ("(FindFontForStyle) name: %s, sty: %02x, wt: %d, sz: %.1f -> %s using wt 500\n", 
+                    NS_ConvertUTF16toUTF8(mName).get(),
+                    aFontStyle.style, aFontStyle.weight, aFontStyle.size,
+                    NS_ConvertUTF16toUTF8(weightList[5]->Name()).get()));
             return weightList[5];
+        }
 
         // Otherwise treat as 400
         baseWeight = 4;
     }
 
     PRInt8 matchBaseWeight = 0;
     PRInt8 direction = (baseWeight > 5) ? 1 : -1;
     for (PRInt8 i = baseWeight; ; i += direction) {
         if (weightList[i]) {
             matchBaseWeight = i;
             break;
         }
 
         // if we've reached one side without finding a font,
         // go the other direction until we find a match
-        if (i == 1 || i == 9)
+        if (i == 1 || i == 9) {
             direction = -direction;
+        }
     }
 
     gfxFontEntry *matchFE;
     const PRInt8 absDistance = abs(weightDistance);
     direction = (weightDistance >= 0) ? 1 : -1;
     PRInt8 i, wghtSteps = 0;
 
     // account for synthetic bold in lighter case
@@ -148,23 +281,317 @@ gfxFontEntry *gfxFontFamily::FindFontFor
         if (wghtSteps > absDistance)
             break;
     }
 
     if (weightDistance > 0 && wghtSteps <= absDistance) {
         aNeedsBold = PR_TRUE;
     }
 
-    if (!matchFE)
+    if (!matchFE) {
         matchFE = weightList[matchBaseWeight];
-
+    }
+
+    PR_LOG(gFontSelection, PR_LOG_DEBUG,
+           ("(FindFontForStyle) name: %s, sty: %02x, wt: %d, sz: %.1f -> %s\n", 
+            NS_ConvertUTF16toUTF8(mName).get(),
+            aFontStyle.style, aFontStyle.weight, aFontStyle.size,
+            NS_ConvertUTF16toUTF8(matchFE->Name()).get()));
     NS_ASSERTION(matchFE, "we should always be able to return something here");
     return matchFE;
 }
 
+void
+gfxFontFamily::CheckForSimpleFamily()
+{
+    if (mAvailableFonts.Length() > 4) {
+        return; // can't be "simple" if there are >4 faces
+    }
+
+    PRInt16 firstStretch = mAvailableFonts[0]->Stretch();
+
+    gfxFontEntry *faces[4] = { 0 };
+    for (PRUint8 i = 0; i < mAvailableFonts.Length(); ++i) {
+        gfxFontEntry *fe = mAvailableFonts[i];
+        if (fe->Stretch() != firstStretch) {
+            return; // font-stretch doesn't match, don't treat as simple family
+        }
+        PRUint8 faceIndex = (fe->IsItalic() ? kItalicMask : 0) |
+                            (fe->Weight() >= 600 ? kBoldMask : 0);
+        if (faces[faceIndex]) {
+            return; // two faces resolve to the same slot; family isn't "simple"
+        }
+        faces[faceIndex] = fe;
+    }
+
+    // we have successfully slotted the available faces into the standard
+    // 4-face framework
+    mAvailableFonts.SetLength(4);
+    for (PRUint8 i = 0; i < 4; ++i) {
+        if (mAvailableFonts[i].get() != faces[i]) {
+            mAvailableFonts[i].swap(faces[i]);
+        }
+    }
+
+    mIsSimpleFamily = PR_TRUE;
+}
+
+static inline PRUint32
+StyleDistance(gfxFontEntry *aFontEntry,
+              PRBool anItalic, PRInt16 aStretch)
+{
+    // Compute a measure of the "distance" between the requested style
+    // and the given fontEntry,
+    // considering italicness and font-stretch but not weight.
+
+    // TODO (refine CSS spec...): discuss priority of italic vs stretch;
+    // whether penalty for stretch mismatch should depend on actual difference in values;
+    // whether a sign mismatch in stretch should increase the effective distance
+
+    return (aFontEntry->IsItalic() != anItalic ? 1 : 0) +
+           (aFontEntry->mStretch != aStretch ? 10 : 0);
+}
+
+PRBool
+gfxFontFamily::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
+                                   PRBool anItalic, PRInt16 aStretch)
+{
+    PRUint32 foundWeights = 0;
+    PRUint32 bestMatchDistance = 0xffffffff;
+
+    for (PRUint32 i = 0; i < mAvailableFonts.Length(); i++) {
+        // this is not called for "simple" families, and therefore it does not
+        // need to check the mAvailableFonts entries for NULL
+        gfxFontEntry *fe = mAvailableFonts[i];
+        PRUint32 distance = StyleDistance(fe, anItalic, aStretch);
+        if (distance <= bestMatchDistance) {
+            PRInt8 wt = fe->mWeight / 100;
+            NS_ASSERTION(wt >= 1 && wt < 10, "invalid weight in fontEntry");
+            if (!aFontsForWeights[wt]) {
+                // record this as a possible candidate for weight matching
+                aFontsForWeights[wt] = fe;
+                ++foundWeights;
+            } else {
+                PRUint32 prevDistance = StyleDistance(aFontsForWeights[wt], anItalic, aStretch);
+                if (prevDistance >= distance) {
+                    // replacing a weight we already found, so don't increment foundWeights
+                    aFontsForWeights[wt] = fe;
+                }
+            }
+            bestMatchDistance = distance;
+        }
+    }
+
+    NS_ASSERTION(foundWeights > 0, "Font family containing no faces?");
+
+    if (foundWeights == 1) {
+        // no need to cull entries if we only found one weight
+        return PR_TRUE;
+    }
+
+    // we might have recorded some faces that were a partial style match, but later found
+    // others that were closer; in this case, we need to cull the poorer matches from the
+    // weight list we'll return
+    for (PRUint32 i = 0; i < 10; ++i) {
+        if (aFontsForWeights[i] &&
+            StyleDistance(aFontsForWeights[i], anItalic, aStretch) > bestMatchDistance)
+        {
+            aFontsForWeights[i] = 0;
+        }
+    }
+
+    return (foundWeights > 0);
+}
+
+
+void gfxFontFamily::LocalizedName(nsAString& aLocalizedName)
+{
+    // just return the primary name; subclasses should override
+    aLocalizedName = mName;
+}
+
+
+void
+gfxFontFamily::FindFontForChar(FontSearch *aMatchData)
+{
+    // xxx - optimization point - keep a bit vector with the union of supported unicode ranges
+    // by all fonts for this family and bail immediately if the character is not in any of
+    // this family's cmaps
+
+    // iterate over fonts
+    PRUint32 numFonts = mAvailableFonts.Length();
+    for (PRUint32 i = 0; i < numFonts; i++) {
+        gfxFontEntry *fe = mAvailableFonts[i];
+        if (!fe)
+            continue;
+
+        PRInt32 rank = 0;
+
+        if (fe->TestCharacterMap(aMatchData->mCh)) {
+            rank += 20;
+        }
+
+        // if we didn't match any characters don't bother wasting more time with this face.
+        if (rank == 0)
+            continue;
+            
+        // omitting from original windows code -- family name, lang group, pitch
+        // not available in current FontEntry implementation
+
+        if (aMatchData->mFontToMatch) { 
+            const gfxFontStyle *style = aMatchData->mFontToMatch->GetStyle();
+            
+            // italics
+            if (fe->IsItalic() && 
+                    (style->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0) {
+                rank += 5;
+            }
+            
+            // weight
+            PRInt8 baseWeight, weightDistance;
+            style->ComputeWeightAndOffset(&baseWeight, &weightDistance);
+
+            // xxx - not entirely correct, the one unit of weight distance reflects 
+            // the "next bolder/lighter face"
+            PRInt32 targetWeight = (baseWeight * 100) + (weightDistance * 100);
+
+            PRInt32 entryWeight = fe->Weight();
+            if (entryWeight == targetWeight) {
+                rank += 5;
+            } else {
+                PRUint32 diffWeight = abs(entryWeight - targetWeight);
+                if (diffWeight <= 100)  // favor faces close in weight
+                    rank += 2;
+            }
+        } else {
+            // if no font to match, prefer non-bold, non-italic fonts
+            if (!fe->IsItalic() && !fe->IsBold())
+                rank += 5;
+        }
+        
+        // xxx - add whether AAT font with morphing info for specific lang groups
+        
+        if (rank > aMatchData->mMatchRank
+            || (rank == aMatchData->mMatchRank &&
+                Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0)) 
+        {
+            aMatchData->mBestMatch = fe;
+            aMatchData->mMatchRank = rank;
+        }
+    }
+}
+
+
+// returns true if other names were found, false otherwise
+PRBool
+gfxFontFamily::ReadOtherFamilyNamesForFace(AddOtherFamilyNameFunctor& aOtherFamilyFunctor,
+                                           gfxFontEntry *aFontEntry,
+                                           PRBool useFullName = PR_FALSE)
+{
+    const PRUint32 kNAME = TRUETYPE_TAG('n','a','m','e');
+
+    nsAutoTArray<PRUint8,8192> buffer;
+    if (aFontEntry->GetFontTable(kNAME, buffer) != NS_OK)
+        return PR_FALSE;
+
+    const PRUint8 *nameData = buffer.Elements();
+    PRUint32 dataLength = buffer.Length();
+    const gfxFontUtils::NameHeader *nameHeader =
+        reinterpret_cast<const gfxFontUtils::NameHeader*>(nameData);
+
+    PRUint32 nameCount = nameHeader->count;
+    if (nameCount * sizeof(gfxFontUtils::NameRecord) > dataLength) {
+        NS_WARNING("invalid font (name records)");
+        return PR_FALSE;
+    }
+    
+    const gfxFontUtils::NameRecord *nameRecord =
+        reinterpret_cast<const gfxFontUtils::NameRecord*>(nameData + sizeof(gfxFontUtils::NameHeader));
+    PRUint32 stringsBase = PRUint32(nameHeader->stringOffset);
+
+    PRBool foundNames = PR_FALSE;
+    for (PRUint32 i = 0; i < nameCount; i++, nameRecord++) {
+        PRUint32 nameLen = nameRecord->length;
+        PRUint32 nameOff = nameRecord->offset;  // offset from base of string storage
+
+        if (stringsBase + nameOff + nameLen > dataLength) {
+            NS_WARNING("invalid font (name table strings)");
+            return PR_FALSE;
+        }
+
+        PRUint16 nameID = nameRecord->nameID;
+        if ((useFullName && nameID == gfxFontUtils::NAME_ID_FULL) ||
+            (!useFullName && (nameID == gfxFontUtils::NAME_ID_FAMILY ||
+                              nameID == gfxFontUtils::NAME_ID_PREFERRED_FAMILY))) {
+            nsAutoString otherFamilyName;
+            PRBool ok = gfxFontUtils::DecodeFontName(nameData + stringsBase + nameOff,
+                                                     nameLen,
+                                                     PRUint32(nameRecord->platformID),
+                                                     PRUint32(nameRecord->encodingID),
+                                                     PRUint32(nameRecord->languageID),
+                                                     otherFamilyName);
+            // add if not same as canonical family name
+            if (ok && otherFamilyName != mName) {
+                aOtherFamilyFunctor(this, otherFamilyName);
+                foundNames = PR_TRUE;
+            }
+        }
+    }
+
+    return foundNames;
+}
+
+
+void
+gfxFontFamily::ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor)
+{
+    if (mOtherFamilyNamesInitialized) 
+        return;
+    mOtherFamilyNamesInitialized = PR_TRUE;
+
+    // read in other family names for the first face in the list
+    PRUint32 numFonts = mAvailableFonts.Length();
+    PRUint32 i;
+    for (i = 0; i < numFonts; ++i) {
+        if (!mAvailableFonts[i])
+            continue;
+        mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aOtherFamilyFunctor,
+                                                           mAvailableFonts[i].get());
+        break;
+    }
+
+    // read in other names for the first face in the list with the assumption
+    // that if extra names don't exist in that face then they don't exist in
+    // other faces for the same font
+    if (mHasOtherFamilyNames) {
+        // read in names for all faces, needed to catch cases where fonts have
+        // family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
+        for ( ; i < numFonts; i++) {
+            if (!mAvailableFonts[i])
+                continue;
+            ReadOtherFamilyNamesForFace(aOtherFamilyFunctor, mAvailableFonts[i].get());
+        }
+    }
+}
+
+
+gfxFontEntry*
+gfxFontFamily::FindFont(const nsAString& aPostscriptName)
+{
+    // find the font using a simple linear search
+    PRUint32 numFonts = mAvailableFonts.Length();
+    for (PRUint32 i = 0; i < numFonts; i++) {
+        gfxFontEntry *fe = mAvailableFonts[i].get();
+        if (fe && fe->Name() == aPostscriptName)
+            return fe;
+    }
+    return nsnull;
+}
+
+
 nsresult
 gfxFontCache::Init()
 {
     NS_ASSERTION(!gGlobalCache, "Where did this come from?");
     gGlobalCache = new gfxFontCache();
     return gGlobalCache ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
@@ -2197,17 +2624,16 @@ gfxTextRun::SetLineBreaks(PRUint32 aStar
 }
 
 PRUint32
 gfxTextRun::FindFirstGlyphRunContaining(PRUint32 aOffset)
 {
     NS_ASSERTION(aOffset <= mCharacterCount, "Bad offset looking for glyphrun");
     if (aOffset == mCharacterCount)
         return mGlyphRuns.Length();
-
     PRUint32 start = 0;
     PRUint32 end = mGlyphRuns.Length();
     while (end - start > 1) {
         PRUint32 mid = (start + end)/2;
         if (mGlyphRuns[mid].mCharacterOffset <= aOffset) {
             start = mid;
         } else {
             end = mid;
@@ -2282,28 +2708,26 @@ gfxTextRun::SanitizeGlyphRuns()
 {
     if (mGlyphRuns.Length() <= 1)
         return;
 
     // If any glyph run starts with ligature-continuation characters, we need to advance it
     // to the first "real" character to avoid drawing partial ligature glyphs from wrong font
     // (seen with U+FEFF in reftest 474417-1, as Core Text eliminates the glyph, which makes
     // it appear as if a ligature has been formed)
-    PRInt32 i;
-    for (i = mGlyphRuns.Length() - 1; i >= 0; --i) {
+    PRInt32 i, last = mGlyphRuns.Length() - 1;
+    for (i = last; i >= 0; --i) {
         GlyphRun& run = mGlyphRuns[i];
         while (mCharacterGlyphs[run.mCharacterOffset].IsLigatureContinuation() &&
                run.mCharacterOffset < mCharacterCount) {
             run.mCharacterOffset++;
         }
         // if the run has become empty, eliminate it
-        if ((i < mGlyphRuns.Length() - 1 &&
-             run.mCharacterOffset >= mGlyphRuns[i+1].mCharacterOffset) ||
-            (i == mGlyphRuns.Length() - 1 &&
-             run.mCharacterOffset == mCharacterCount)) {
+        if ((i < last && run.mCharacterOffset >= mGlyphRuns[i+1].mCharacterOffset) ||
+            (i == last && run.mCharacterOffset == mCharacterCount)) {
             mGlyphRuns.RemoveElementAt(i);
         }
     }
 }
 
 PRUint32
 gfxTextRun::CountMissingGlyphs()
 {
--- a/gfx/thebes/src/gfxFontUtils.cpp
+++ b/gfx/thebes/src/gfxFontUtils.cpp
@@ -10,22 +10,23 @@
  * 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 thebes gfx code.
  *
  * The Initial Developer of the Original Code is Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2007
+ * Portions created by the Initial Developer are Copyright (C) 2007-2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <stuart@mozilla.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
@@ -42,16 +43,17 @@
 
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "nsIPrefLocalizedString.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIStreamBufferAccess.h"
 #include "nsIUUIDGenerator.h"
 #include "nsMemory.h"
+#include "nsICharsetConverterManager.h"
 
 #include "plbase64.h"
 
 #ifdef XP_MACOSX
 #include <CoreFoundation/CoreFoundation.h>
 #endif
 
 #define NO_RANGE_FOUND 126 // bit 126 in the font unicode ranges is required to be 0
@@ -221,17 +223,16 @@ static const struct UnicodeRangeTableEnt
     { 107, 0x10800, 0x1083F, "Cypriot Syllabary" },
     { 108, 0x10A00, 0x10A5F, "Kharoshthi" },
     { 109, 0x1D300, 0x1D35F, "Tai Xuan Jing Symbols" },
     { 110, 0x12000, 0x123FF, "Cuneiform" },
     { 110, 0x12400, 0x1247F, "Cuneiform Numbers and Punctuation" },
     { 111, 0x1D360, 0x1D37F, "Counting Rod Numerals" }
 };
 
-
 nsresult
 gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBitSet& aCharacterMap) 
 {
     enum {
         OffsetFormat = 0,
         OffsetReserved = 2,
         OffsetTableLength = 4,
         OffsetLanguage = 8,
@@ -287,17 +288,17 @@ gfxFontUtils::ReadCMAPTableFormat4(PRUin
     NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetLanguage) == 0, NS_ERROR_FAILURE);
 #endif
 
     PRUint16 segCountX2 = ReadShortAt(aBuf, OffsetSegCountX2);
     NS_ENSURE_TRUE(tablelen >= 16 + (segCountX2 * 4), NS_ERROR_FAILURE);
 
     const PRUint16 segCount = segCountX2 / 2;
 
-    const PRUint16 *endCounts = (PRUint16*)(aBuf + 14);
+    const PRUint16 *endCounts = reinterpret_cast<const PRUint16*>(aBuf + 14);
     const PRUint16 *startCounts = endCounts + 1 /* skip one uint16 for reservedPad */ + segCount;
     const PRUint16 *idDeltas = startCounts + segCount;
     const PRUint16 *idRangeOffsets = idDeltas + segCount;
     for (PRUint16 i = 0; i < segCount; i++) {
         const PRUint16 endCount = ReadShortAt16(endCounts, i);
         const PRUint16 startCount = ReadShortAt16(startCounts, i);
         const PRUint16 idRangeOffset = ReadShortAt16(idRangeOffsets, i);
         if (idRangeOffset == 0) {
@@ -328,29 +329,29 @@ gfxFontUtils::ReadCMAPTableFormat4(PRUin
     return NS_OK;
 }
 
 // Windows requires fonts to have a format-4 cmap with a Microsoft ID (3).  On the Mac, fonts either have
 // a format-4 cmap with Microsoft platform/encoding id or they have one with a platformID == Unicode (0)
 // For fonts with two format-4 tables, the first one (Unicode platform) is preferred on the Mac.
 
 #if defined(XP_MACOSX)
-    #define acceptablePlatform(p)       ((p) == PLATFORM_UNICODE || (p) == PLATFORM_MICROSOFT)
-    #define acceptableFormat4(p,e,k)      ( ((p) == PLATFORM_MICROSOFT && (e) == EncodingIDMicrosoft && (k) != 4) || \
-                                            ((p) == PLATFORM_UNICODE) )
-    #define isSymbol(p,e)               ((p) == PLATFORM_MICROSOFT && (e) == EncodingIDSymbol)
+    #define acceptablePlatform(p)    ((p) == PLATFORM_ID_UNICODE || (p) == PLATFORM_ID_MICROSOFT)
+    #define acceptableFormat4(p,e,k) ( ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft && (k) != 4) || \
+                                       ((p) == PLATFORM_ID_UNICODE) )
+    #define isSymbol(p,e)            ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDSymbol)
 #else
-    #define acceptablePlatform(p)       ((p) == PLATFORM_MICROSOFT)
-    #define acceptableFormat4(p,e,k)      ((e) == EncodingIDMicrosoft)
-    #define isSymbol(p,e)               ((e) == EncodingIDSymbol)
+    #define acceptablePlatform(p)    ((p) == PLATFORM_ID_MICROSOFT)
+    #define acceptableFormat4(p,e,k) ((e) == EncodingIDMicrosoft)
+    #define isSymbol(p,e)            ((e) == EncodingIDSymbol)
 #endif
 
 #define acceptableUCS4Encoding(p, e) \
-    ((platformID == PLATFORM_MICROSOFT && encodingID == EncodingIDUCS4ForMicrosoftPlatform) || \
-     (platformID == PLATFORM_UNICODE   && encodingID == EncodingIDUCS4ForUnicodePlatform))
+    ((platformID == PLATFORM_ID_MICROSOFT && encodingID == EncodingIDUCS4ForMicrosoftPlatform) || \
+     (platformID == PLATFORM_ID_UNICODE   && encodingID == EncodingIDUCS4ForUnicodePlatform))
 
 nsresult
 gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap, 
                        PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont)
 {
     enum {
         OffsetVersion = 0,
         OffsetNumTables = 2,
@@ -489,17 +490,17 @@ nsresult gfxFontUtils::MakeUniqueUserFon
 
     NS_ASSERTION(sizeof(guid) * 2 <= MAX_B64_LEN, "size of nsID has changed!");
 
     nsresult rv = uuidgen->GenerateUUIDInPlace(&guid);
     NS_ENSURE_SUCCESS(rv, rv);
 
     char guidB64[MAX_B64_LEN] = {0};
 
-    if (!PL_Base64Encode((char *)(&guid), sizeof(guid), guidB64))
+    if (!PL_Base64Encode(reinterpret_cast<char*>(&guid), sizeof(guid), guidB64))
         return NS_ERROR_FAILURE;
 
     // all b64 characters except for '/' are allowed in Postscript names, so convert / ==> -
     char *p;
     for (p = guidB64; *p; p++) {
         if (*p == '/')
             *p = '-';
     }
@@ -507,66 +508,21 @@ nsresult gfxFontUtils::MakeUniqueUserFon
     aName.Assign(NS_LITERAL_STRING("uf"));
     aName.AppendASCII(guidB64);
     return NS_OK;
 }
 
 
 // TrueType/OpenType table handling code
 
+using namespace mozilla; // for the AutoSwap_* types
+
 // need byte aligned structs
 #pragma pack(1)
 
-struct AutoSwap_PRUint16 {
-#ifdef __SUNPRO_CC
-    AutoSwap_PRUint16& operator = (const PRUint16 aValue)
-      { this->value = NS_SWAP16(aValue); return *this; }
-#else
-    AutoSwap_PRUint16(PRUint16 aValue) { value = NS_SWAP16(aValue); }
-#endif
-    operator PRUint16() const { return NS_SWAP16(value); }
-    operator PRUint32() const { return NS_SWAP16(value); }
-    operator PRUint64() const { return NS_SWAP16(value); }
-    PRUint16 value;
-};
-
-struct AutoSwap_PRInt16 {
-#ifdef __SUNPRO_CC
-    AutoSwap_PRInt16& operator = (const PRInt16 aValue)
-      { this->value = NS_SWAP16(aValue); return *this; }
-#else
-    AutoSwap_PRInt16(PRInt16 aValue) { value = NS_SWAP16(aValue); }
-#endif
-    operator PRInt16() const { return NS_SWAP16(value); }
-    operator PRUint32() const { return NS_SWAP16(value); }
-    PRInt16  value;
-};
-
-struct AutoSwap_PRUint32 {
-#ifdef __SUNPRO_CC
-    AutoSwap_PRUint32& operator = (const PRUint32 aValue)
-      { this->value = NS_SWAP32(aValue); return *this; }
-#else
-    AutoSwap_PRUint32(PRUint32 aValue) { value = NS_SWAP32(aValue); }
-#endif
-    operator PRUint32() const { return NS_SWAP32(value); }
-    PRUint32  value;
-};
-
-struct AutoSwap_PRUint64 {
-#ifdef __SUNPRO_CC
-    AutoSwap_PRUint64& operator = (const PRUint64 aValue)
-      { this->value = NS_SWAP64(aValue); return *this; }
-#else
-    AutoSwap_PRUint64(PRUint64 aValue) { value = NS_SWAP64(aValue); }
-#endif
-    operator PRUint64() const { return NS_SWAP64(value); }
-    PRUint64  value;
-};
-
 struct SFNTHeader {
     AutoSwap_PRUint32    sfntVersion;            // Fixed, 0x00010000 for version 1.0.
     AutoSwap_PRUint16    numTables;              // Number of tables.
     AutoSwap_PRUint16    searchRange;            // (Maximum power of 2 <= numTables) x 16.
     AutoSwap_PRUint16    entrySelector;          // Log2(maximum power of 2 <= numTables).
     AutoSwap_PRUint16    rangeShift;             // NumTables x 16-searchRange.        
 };
 
@@ -597,38 +553,16 @@ struct HeadTable {
     AutoSwap_PRInt16     yMax;                  // For all glyph bounding boxes.
     AutoSwap_PRUint16    macStyle;              // Bit 0: Bold (if set to 1);
     AutoSwap_PRUint16    lowestRecPPEM;         // Smallest readable size in pixels.
     AutoSwap_PRInt16     fontDirectionHint;
     AutoSwap_PRInt16     indexToLocFormat;
     AutoSwap_PRInt16     glyphDataFormat;
 };
 
-// name table has a header, followed by name records, followed by string data
-struct NameHeader {
-    AutoSwap_PRUint16    format;                 // Format selector (=0).
-    AutoSwap_PRUint16    count;                  // Number of name records.
-    AutoSwap_PRUint16    stringOffset;           // Offset to start of string storage (from start of table)
-};
-
-struct NameRecord {
-    AutoSwap_PRUint16    platformID;             // Platform ID
-    AutoSwap_PRUint16    encodingID;             // Platform-specific encoding ID
-    AutoSwap_PRUint16    languageID;             // Language ID
-    AutoSwap_PRUint16    nameID;                 // Name ID.
-    AutoSwap_PRUint16    length;                 // String length (in bytes).
-    AutoSwap_PRUint16    offset;                 // String offset from start of storage area (in bytes).
-
-    enum {
-        ENCODING_ID_MICROSOFT_UNICODEBMP = 1,    // with Microsoft platformID, BMP-only Unicode encoding
-        LANG_ID_MICROSOFT_EN_US = 0x0409,        // with Microsoft platformID, EN US lang code
-        LANG_ID_MACINTOSH_EN = 0
-    };
-};
-
 // name table stores set of name record structures, followed by
 // large block containing all the strings.  name record offset and length
 // indicates the offset and length within that block.
 // http://www.microsoft.com/typography/otspec/name.htm
 struct NameRecordData {
     PRUint32  offset;
     PRUint32  length;
 };
@@ -699,17 +633,19 @@ struct KernTableSubtableHeaderVersion1 {
     AutoSwap_PRUint16    tupleIndex;
 };
 
 static PRBool
 IsValidSFNTVersion(PRUint32 version)
 {
     // normally 0x00010000, CFF-style OT fonts == 'OTTO' and Apple TT fonts = 'true'
     // 'typ1' is also possible for old Type 1 fonts in a SFNT container but not supported
-    return version == 0x10000 || version == TRUETYPE_TAG('O','T','T','O') || version == TRUETYPE_TAG('t','r','u','e');
+    return version == 0x10000 ||
+           version == TRUETYPE_TAG('O','T','T','O') ||
+           version == TRUETYPE_TAG('t','r','u','e');
 }
 
 // copy and swap UTF-16 values, assume no surrogate pairs, can be in place
 static void
 CopySwapUTF16(const PRUint16 *aInBuf, PRUint16 *aOutBuf, PRUint32 aLen)
 {
     const PRUint16 *end = aInBuf + aLen;
     while (aInBuf < end) {
@@ -914,17 +850,18 @@ gfxFontUtils::ValidateSFNTHeaders(const 
 
     // -- sanity check the number of name records
     if (PRUint64(nameCount) * sizeof(NameRecord) + PRUint64(nameOffset) > dataLength) {
         NS_WARNING("invalid font (name records)");
         return PR_FALSE;
     }
     
     // -- iterate through name records
-    const NameRecord *nameRecord = reinterpret_cast<const NameRecord*>(aFontData + nameOffset + sizeof(NameHeader));
+    const NameRecord *nameRecord = reinterpret_cast<const NameRecord*>
+                                       (aFontData + nameOffset + sizeof(NameHeader));
     PRUint64 nameStringsBase = PRUint64(nameOffset) + PRUint64(nameHeader->stringOffset);
 
     for (i = 0; i < nameCount; i++, nameRecord++) {
         PRUint32 namelen = nameRecord->length;
         PRUint32 nameoff = nameRecord->offset;  // offset from base of string storage
 
         if (nameStringsBase + PRUint64(nameoff) + PRUint64(namelen) > dataLength) {
             NS_WARNING("invalid font (name table strings)");
@@ -948,21 +885,21 @@ nsresult
 gfxFontUtils::RenameFont(const nsAString& aName, const PRUint8 *aFontData, 
                          PRUint32 aFontDataLength, nsTArray<PRUint8> *aNewFont)
 {
     NS_ASSERTION(aNewFont, "null font data array");
     
     PRUint64 dataLength(aFontDataLength);
 
     // new name table
-    static const PRUint32 neededNameIDs[] = {gfxFontUtils::NAME_ID_FAMILY, 
-                                             gfxFontUtils::NAME_ID_STYLE,
-                                             gfxFontUtils::NAME_ID_UNIQUE,
-                                             gfxFontUtils::NAME_ID_FULL,
-                                             gfxFontUtils::NAME_ID_POSTSCRIPT};
+    static const PRUint32 neededNameIDs[] = {NAME_ID_FAMILY, 
+                                             NAME_ID_STYLE,
+                                             NAME_ID_UNIQUE,
+                                             NAME_ID_FULL,
+                                             NAME_ID_POSTSCRIPT};
 
     // calculate new name table size
     PRUint16 nameCount = NS_ARRAY_LENGTH(neededNameIDs);
 
     // leave room for null-terminator
     PRUint16 nameStrLength = (aName.Length() + 1) * sizeof(PRUnichar); 
 
     // round name table size up to 4-byte multiple
@@ -996,19 +933,19 @@ gfxFontUtils::RenameFont(const nsAString
     nameHeader->count = nameCount;
     nameHeader->stringOffset = sizeof(NameHeader) + nameCount * sizeof(NameRecord);
     
     // -- name records
     PRUint32 i;
     NameRecord *nameRecord = reinterpret_cast<NameRecord*>(nameHeader + 1);
     
     for (i = 0; i < nameCount; i++, nameRecord++) {
-        nameRecord->platformID = gfxFontUtils::PLATFORM_MICROSOFT;
-        nameRecord->encodingID = NameRecord::ENCODING_ID_MICROSOFT_UNICODEBMP;
-        nameRecord->languageID = NameRecord::LANG_ID_MICROSOFT_EN_US;
+        nameRecord->platformID = PLATFORM_ID_MICROSOFT;
+        nameRecord->encodingID = ENCODING_ID_MICROSOFT_UNICODEBMP;
+        nameRecord->languageID = LANG_ID_MICROSOFT_EN_US;
         nameRecord->nameID = neededNameIDs[i];
         nameRecord->offset = 0;
         nameRecord->length = nameStrLength;
     }
     
     // -- string data, located after the name records, stored in big-endian form
     PRUnichar *strData = reinterpret_cast<PRUnichar*>(nameRecord);
 
@@ -1084,133 +1021,267 @@ gfxFontUtils::RenameFont(const nsAString
 
     headData->checkSumAdjustment = HeadTable::HEAD_CHECKSUM_CALC_CONST - checksum;
 
     return NS_OK;
 }
 
 enum {
 #if defined(XP_MACOSX)
-    CANONICAL_LANG_ID = NameRecord::LANG_ID_MACINTOSH_EN,
-    PLATFORM_ID = gfxFontUtils::PLATFORM_MACINTOSH
+    CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MAC_ENGLISH,
+    PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MAC
 #else
-    CANONICAL_LANG_ID = NameRecord::LANG_ID_MICROSOFT_EN_US,
-    PLATFORM_ID = gfxFontUtils::PLATFORM_MICROSOFT
+    CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MICROSOFT_EN_US,
+    PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MICROSOFT
 #endif
 };    
 
 nsresult
 gfxFontUtils::ReadNames(nsTArray<PRUint8>& aNameTable, PRUint32 aNameID, 
                         PRInt32 aPlatformID, nsTArray<nsString>& aNames)
 {
-    return ReadNames(aNameTable, aNameID, NAME_LANG_ALL, aPlatformID, aNames);
+    return ReadNames(aNameTable, aNameID, LANG_ALL, aPlatformID, aNames);
 }
 
 nsresult
 gfxFontUtils::ReadCanonicalName(nsTArray<PRUint8>& aNameTable, PRUint32 aNameID, 
                                 nsString& aName)
 {
     nsresult rv;
     
     nsTArray<nsString> names;
     
     // first, look for the English name (this will succeed 99% of the time)
     rv = ReadNames(aNameTable, aNameID, CANONICAL_LANG_ID, PLATFORM_ID, names);
     NS_ENSURE_SUCCESS(rv, rv);
         
     // otherwise, grab names for all languages
     if (names.Length() == 0) {
-        rv = ReadNames(aNameTable, aNameID, NAME_LANG_ALL, PLATFORM_ID, names);
+        rv = ReadNames(aNameTable, aNameID, LANG_ALL, PLATFORM_ID, names);
         NS_ENSURE_SUCCESS(rv, rv);
     }
     
 #if defined(XP_MACOSX)
     // may be dealing with font that only has Microsoft name entries
     if (names.Length() == 0) {
-        rv = ReadNames(aNameTable, aNameID, NameRecord::LANG_ID_MICROSOFT_EN_US, 
-                       gfxFontUtils::PLATFORM_MICROSOFT, names);
+        rv = ReadNames(aNameTable, aNameID, LANG_ID_MICROSOFT_EN_US, 
+                       PLATFORM_ID_MICROSOFT, names);
         NS_ENSURE_SUCCESS(rv, rv);
         
         // getting really desperate now, take anything!
         if (names.Length() == 0) {
-            rv = ReadNames(aNameTable, aNameID, NAME_LANG_ALL, 
-                           gfxFontUtils::PLATFORM_MICROSOFT, names);
+            rv = ReadNames(aNameTable, aNameID, LANG_ALL, 
+                           PLATFORM_ID_MICROSOFT, names);
             NS_ENSURE_SUCCESS(rv, rv);
         }
     }
 #endif
 
     // return the first name (99.9% of the time names will
     // contain a single English name)
     if (names.Length()) {
         aName.Assign(names[0]);
         return NS_OK;
     }
         
     return NS_ERROR_FAILURE;
 }
 
-nsresult
-DecodeName(PRUint8 *aNameData, PRUint32 aByteLen, PRInt32 aPlatform, 
-           PRUint32 aEncoding, nsAString& aName)
+// Charsets to use for decoding Mac platform font names.
+// This table is sorted by {encoding, language}, with the wildcard "ANY" being
+// greater than any defined values for each field; we use a binary search on both
+// fields, and fall back to matching only encoding if necessary
+
+// Some "redundant" entries for specific combinations are included such as
+// encoding=roman, lang=english, in order that common entries will be found
+// on the first search.
+
+#define ANY 0xffff
+const gfxFontUtils::MacFontNameCharsetMapping gfxFontUtils::gMacFontNameCharsets[] =
 {
-    NS_ASSERTION(aPlatform != gfxFontUtils::PLATFORM_ALL, "need a defined platform to decode string");
-    
-#if defined(XP_MACOSX)
+    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ENGLISH,      "x-mac-roman"     },
+    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ICELANDIC,    "x-mac-icelandic" },
+    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_TURKISH,      "x-mac-turkish"   },
+    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_POLISH,       "x-mac-ce"        },
+    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ROMANIAN,     "x-mac-romanian"  },
+    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_CZECH,        "x-mac-ce"        },
+    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_SLOVAK,       "x-mac-ce"        },
+    { ENCODING_ID_MAC_ROMAN,        ANY,                      "x-mac-roman"     },
+    { ENCODING_ID_MAC_JAPANESE,     LANG_ID_MAC_JAPANESE,     "Shift_JIS"       },
+    { ENCODING_ID_MAC_JAPANESE,     ANY,                      "Shift_JIS"       },
+    { ENCODING_ID_MAC_TRAD_CHINESE, LANG_ID_MAC_TRAD_CHINESE, "Big5"            },
+    { ENCODING_ID_MAC_TRAD_CHINESE, ANY,                      "Big5"            },
+    { ENCODING_ID_MAC_KOREAN,       LANG_ID_MAC_KOREAN,       "EUC-KR"          },
+    { ENCODING_ID_MAC_KOREAN,       ANY,                      "EUC-KR"          },
+    { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_ARABIC,       "x-mac-arabic"    },
+    { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_URDU,         "x-mac-farsi"     },
+    { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_FARSI,        "x-mac-farsi"     },
+    { ENCODING_ID_MAC_ARABIC,       ANY,                      "x-mac-arabic"    },
+    { ENCODING_ID_MAC_HEBREW,       LANG_ID_MAC_HEBREW,       "x-mac-hebrew"    },
+    { ENCODING_ID_MAC_HEBREW,       ANY,                      "x-mac-hebrew"    },
+    { ENCODING_ID_MAC_GREEK,        ANY,                      "x-mac-greek"     },
+    { ENCODING_ID_MAC_CYRILLIC,     ANY,                      "x-mac-cyrillic"  },
+    { ENCODING_ID_MAC_DEVANAGARI,   ANY,                      "x-mac-devanagari"},
+    { ENCODING_ID_MAC_GURMUKHI,     ANY,                      "x-mac-gurmukhi"  },
+    { ENCODING_ID_MAC_GUJARATI,     ANY,                      "x-mac-gujarati"  },
+    { ENCODING_ID_MAC_SIMP_CHINESE, LANG_ID_MAC_SIMP_CHINESE, "GB2312"          },
+    { ENCODING_ID_MAC_SIMP_CHINESE, ANY,                      "GB2312"          }
+};
+
+const char* gfxFontUtils::gISOFontNameCharsets[] = 
+{
+    /* 0 */ "us-ascii"   ,
+    /* 1 */ nsnull       , /* spec says "ISO 10646" but does not specify encoding form! */
+    /* 2 */ "ISO-8859-1"
+};
 
-    CFStringRef name = NULL;
+const char* gfxFontUtils::gMSFontNameCharsets[] =
+{
+    /* [0] ENCODING_ID_MICROSOFT_SYMBOL */      ""          ,
+    /* [1] ENCODING_ID_MICROSOFT_UNICODEBMP */  ""          ,
+    /* [2] ENCODING_ID_MICROSOFT_SHIFTJIS */    "Shift_JIS" ,
+    /* [3] ENCODING_ID_MICROSOFT_PRC */         nsnull      ,
+    /* [4] ENCODING_ID_MICROSOFT_BIG5 */        "Big5"      ,
+    /* [5] ENCODING_ID_MICROSOFT_WANSUNG */     nsnull      ,
+    /* [6] ENCODING_ID_MICROSOFT_JOHAB */       "x-johab"   ,
+    /* [7] reserved */                          nsnull      ,
+    /* [8] reserved */                          nsnull      ,
+    /* [9] reserved */                          nsnull      ,
+    /*[10] ENCODING_ID_MICROSOFT_UNICODEFULL */ ""
+};
+
+#define ARRAY_SIZE(A) (sizeof(A) / sizeof(A[0]))
+
+// Return the name of the charset we should use to decode a font name
+// given the name table attributes.
+// Special return values:
+//    ""       charset is UTF16BE, no need for a converter
+//    nsnull   unknown charset, do not attempt conversion
+const char*
+gfxFontUtils::GetCharsetForFontName(PRUint16 aPlatform, PRUint16 aScript, PRUint16 aLanguage)
+{
+    switch (aPlatform)
+    {
+    case PLATFORM_ID_UNICODE:
+        return "";
 
-    if (aPlatform == gfxFontUtils::PLATFORM_MACINTOSH) {
-        name = CFStringCreateWithBytes(kCFAllocatorDefault, aNameData, aByteLen,
-                                       (CFStringEncoding) aEncoding, false);
-    } else if (aPlatform == gfxFontUtils::PLATFORM_UNICODE 
-               || aPlatform == gfxFontUtils::PLATFORM_MICROSOFT) 
-    {
-        name = CFStringCreateWithBytes(kCFAllocatorDefault, aNameData, aByteLen, 
-                                       kCFStringEncodingUTF16BE, false);
+    case PLATFORM_ID_MAC:
+        {
+            PRUint32 lo = 0, hi = ARRAY_SIZE(gMacFontNameCharsets);
+            MacFontNameCharsetMapping searchValue = { aScript, aLanguage, nsnull };
+            for (PRUint32 i = 0; i < 2; ++i) {
+                // binary search; if not found, set language to ANY and try again
+                while (lo < hi) {
+                    PRUint32 mid = (lo + hi) / 2;
+                    const MacFontNameCharsetMapping& entry = gMacFontNameCharsets[mid];
+                    if (entry < searchValue) {
+                        lo = mid + 1;
+                        continue;
+                    }
+                    if (searchValue < entry) {
+                        hi = mid;
+                        continue;
+                    }
+                    // found a match
+                    return entry.mCharsetName;
+                }
+
+                // no match, so reset high bound for search and re-try
+                hi = ARRAY_SIZE(gMacFontNameCharsets);
+                searchValue.mLanguage = ANY;
+            }
+        }
+        break;
+
+    case PLATFORM_ID_ISO:
+        if (aScript < ARRAY_SIZE(gISOFontNameCharsets)) {
+            return gISOFontNameCharsets[aScript];
+        }
+        break;
+
+    case PLATFORM_ID_MICROSOFT:
+        if (aScript < ARRAY_SIZE(gMSFontNameCharsets)) {
+            return gMSFontNameCharsets[aScript];
+        }
+        break;
     }
 
-    if (!name)
-        return NS_ERROR_FAILURE;
-        
-     CFIndex len = CFStringGetLength(name);
-     aName.SetLength(len);
-     CFStringGetCharacters(name, CFRangeMake(0, len), aName.BeginWriting());
-     CFRelease(name);
-     
-#else
+    return nsnull;
+}
+
+// convert a raw name from the name table to an nsString, if possible;
+// return value indicates whether conversion succeeded
+PRBool
+gfxFontUtils::DecodeFontName(const PRUint8 *aNameData, PRInt32 aByteLen, 
+                             PRUint32 aPlatformCode, PRUint32 aScriptCode,
+                             PRUint32 aLangCode, nsAString& aName)
+{
+    NS_ASSERTION(aByteLen > 0, "bad length for font name data");
+
+    const char *csName = GetCharsetForFontName(aPlatformCode, aScriptCode, aLangCode);
 
-    // skip non-MS platforms and non-Unicode encodings
-    if (aPlatform != gfxFontUtils::PLATFORM_MICROSOFT 
-        || aEncoding != NameRecord::ENCODING_ID_MICROSOFT_UNICODEBMP)
-        return NS_ERROR_FAILURE;
+    if (!csName) {
+        // nsnull -> unknown charset
+#ifdef DEBUG
+        char warnBuf[128];
+        if (aByteLen > 64)
+            aByteLen = 64;
+        sprintf(warnBuf, "skipping font name, unknown charset %d:%d:%d for <%.*s>",
+                aPlatformCode, aScriptCode, aLangCode, aByteLen, aNameData);
+        NS_WARNING(warnBuf);
+#endif
+        return PR_FALSE;
+    }
 
-    PRUint32 strLen = aByteLen/2;
-    PRUnichar *str;
-    
+    if (csName[0] == 0) {
+        // empty charset name: data is utf16be, no need to instantiate a converter
+        PRUint32 strLen = aByteLen / 2;
 #ifdef IS_LITTLE_ENDIAN
-    nsAutoTArray<PRUnichar,256> swapBuf;
-    if (!swapBuf.AppendElements(strLen))
-        NS_ERROR_FAILURE;
-    
-    str = (PRUnichar*) (swapBuf.Elements());
-    PRUnichar *ch, *end = (PRUnichar*)(aNameData + aByteLen);
-    for (ch = (PRUnichar*) aNameData; ch < end; ch++) {
-        *str++ = NS_SWAP16(*ch);
+        aName.SetLength(strLen);
+        CopySwapUTF16(reinterpret_cast<const PRUnichar*>(aNameData),
+                      aName.BeginWriting(), strLen);
+#else
+        aName.Assign(reinterpret_cast<const PRUnichar*>(aNameData), strLen);
+#endif    
+        return PR_TRUE;
+    }
+
+    nsresult rv;
+    nsCOMPtr<nsICharsetConverterManager> ccm =
+        do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
+    NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get charset converter manager");
+    if (NS_FAILED(rv)) {
+        return PR_FALSE;
     }
-    str = (PRUnichar*) (swapBuf.Elements());
-#else
-    str = (PRUnichar*) aNameData;
-#endif    
-    
-    aName.Assign(str, strLen);
+
+    nsCOMPtr<nsIUnicodeDecoder> decoder;
+    rv = ccm->GetUnicodeDecoderRaw(csName, getter_AddRefs(decoder));
+    if (NS_FAILED(rv)) {
+        NS_WARNING("failed to get the decoder for a font name string");
+        return PR_FALSE;
+    }
 
-#endif
+    PRInt32 destLength;
+    rv = decoder->GetMaxLength(reinterpret_cast<const char*>(aNameData), aByteLen, &destLength);
+    if (NS_FAILED(rv)) {
+        NS_WARNING("decoder->GetMaxLength failed, invalid font name?");
+        return PR_FALSE;
+    }
 
-    return NS_OK;
+    // make space for the converted string
+    aName.SetLength(destLength);
+    rv = decoder->Convert(reinterpret_cast<const char*>(aNameData), &aByteLen,
+                          aName.BeginWriting(), &destLength);
+    if (NS_FAILED(rv)) {
+        NS_WARNING("decoder->Convert failed, invalid font name?");
+        return PR_FALSE;
+    }
+    aName.Truncate(destLength); // set the actual length
+
+    return PR_TRUE;
 }
 
 nsresult
 gfxFontUtils::ReadNames(nsTArray<PRUint8>& aNameTable, PRUint32 aNameID, 
                         PRInt32 aLangID, PRInt32 aPlatformID,
                         nsTArray<nsString>& aNames)
 {
     PRUint32 nameTableLen = aNameTable.Length();
@@ -1247,17 +1318,17 @@ gfxFontUtils::ReadNames(nsTArray<PRUint8
 
         // skip over unwanted platform data
         platformID = nameRecord->platformID;
         if (aPlatformID != PLATFORM_ALL 
             && PRUint32(nameRecord->platformID) != PLATFORM_ID)
             continue;
             
         // skip over unwanted languages
-        if (aLangID != NAME_LANG_ALL 
+        if (aLangID != LANG_ALL 
               && PRUint32(nameRecord->languageID) != PRUint32(aLangID))
             continue;
         
         // add name to names array
         
         // -- calculate string location
         PRUint32 namelen = nameRecord->length;
         PRUint32 nameoff = nameRecord->offset;  // offset from base of string storage
@@ -1267,18 +1338,19 @@ gfxFontUtils::ReadNames(nsTArray<PRUint8
             NS_WARNING("invalid font (name table strings)");
             return NS_ERROR_FAILURE;
         }
         
         // -- decode if necessary and make nsString
         nsAutoString name;
         nsresult rv;
         
-        rv = DecodeName(nameTable + nameStringsBase + nameoff, namelen, 
-                        platformID, PRUint32(nameRecord->encodingID), name);
+        rv = DecodeFontName(nameTable + nameStringsBase + nameoff, namelen, 
+                            platformID, PRUint32(nameRecord->encodingID),
+                            PRUint32(nameRecord->languageID), name);
         
         if (NS_FAILED(rv))
             continue;
             
         PRUint32 k, numNames;
         PRBool foundName = PR_FALSE;
         
         numNames = aNames.Length();
@@ -1517,42 +1589,42 @@ gfxFontUtils::MakeEOTHeader(const PRUint
     PRUint32 needNames = (1 << EOTFixedHeader::EOT_FAMILY_NAME_INDEX) | 
                          (1 << EOTFixedHeader::EOT_STYLE_NAME_INDEX) | 
                          (1 << EOTFixedHeader::EOT_FULL_NAME_INDEX) | 
                          (1 << EOTFixedHeader::EOT_VERSION_NAME_INDEX);
 
     for (i = 0; i < nameCount; i++, nameRecord++) {
 
         // looking for Microsoft English US name strings, skip others
-        if (PRUint32(nameRecord->platformID) != gfxFontUtils::PLATFORM_MICROSOFT || 
-                PRUint32(nameRecord->encodingID) != NameRecord::ENCODING_ID_MICROSOFT_UNICODEBMP || 
-                PRUint32(nameRecord->languageID) != NameRecord::LANG_ID_MICROSOFT_EN_US)
+        if (PRUint32(nameRecord->platformID) != PLATFORM_ID_MICROSOFT || 
+                PRUint32(nameRecord->encodingID) != ENCODING_ID_MICROSOFT_UNICODEBMP || 
+                PRUint32(nameRecord->languageID) != LANG_ID_MICROSOFT_EN_US)
             continue;
 
         switch ((PRUint32)nameRecord->nameID) {
 
-        case gfxFontUtils::NAME_ID_FAMILY:
+        case NAME_ID_FAMILY:
             names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].offset = nameRecord->offset;
             names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].length = nameRecord->length;
             needNames &= ~(1 << EOTFixedHeader::EOT_FAMILY_NAME_INDEX);
             break;
 
-        case gfxFontUtils::NAME_ID_STYLE:
+        case NAME_ID_STYLE:
             names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].offset = nameRecord->offset;
             names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].length = nameRecord->length;
             needNames &= ~(1 << EOTFixedHeader::EOT_STYLE_NAME_INDEX);
             break;
 
-        case gfxFontUtils::NAME_ID_FULL:
+        case NAME_ID_FULL:
             names[EOTFixedHeader::EOT_FULL_NAME_INDEX].offset = nameRecord->offset;
             names[EOTFixedHeader::EOT_FULL_NAME_INDEX].length = nameRecord->length;
             needNames &= ~(1 << EOTFixedHeader::EOT_FULL_NAME_INDEX);
             break;
 
-        case gfxFontUtils::NAME_ID_VERSION:
+        case NAME_ID_VERSION:
             names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].offset = nameRecord->offset;
             names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].length = nameRecord->length;
             needNames &= ~(1 << EOTFixedHeader::EOT_VERSION_NAME_INDEX);
             break;
 
         default:
             break;
         }
rename from gfx/thebes/src/gfxQuartzFontCache.h
rename to gfx/thebes/src/gfxMacPlatformFontList.h
--- a/gfx/thebes/src/gfxQuartzFontCache.h
+++ b/gfx/thebes/src/gfxMacPlatformFontList.h
@@ -10,313 +10,123 @@
  * 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) 2006
+ * Portions created by the Initial Developer are Copyright (C) 2006-2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Vladimir Vukicevic <vladimir@pobox.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 GFXQUARTZFONTCACHE_H_
-#define GFXQUARTZFONTCACHE_H_
+#ifndef gfxMacPlatformFontList_H_
+#define gfxMacPlatformFontList_H_
 
 #include "nsDataHashtable.h"
 #include "nsRefPtrHashtable.h"
 
-#include "gfxFontUtils.h"
+#include "gfxPlatformFontList.h"
 #ifdef MOZ_CORETEXT
 #include "gfxCoreTextFonts.h"
 #endif
 #include "gfxAtsuiFonts.h"
 #include "gfxPlatform.h"
 
 #include <Carbon/Carbon.h>
 
 #include "nsUnicharUtils.h"
 #include "nsTArray.h"
 
-// used when picking fallback font
-struct FontSearch {
-    FontSearch(const PRUint32 aCharacter, gfxFont *aFont) :
-        ch(aCharacter), fontToMatch(aFont), matchRank(0) {
-    }
-    const PRUint32 ch;
-    gfxFont *fontToMatch;
-    PRInt32 matchRank;
-    nsRefPtr<MacOSFontEntry> bestMatch;
-};
-
-class MacOSFamilyEntry;
-class gfxQuartzFontCache;
-class FontEntryStandardFaceComparator;
+class gfxMacPlatformFontList;
 
 // a single member of a font family (i.e. a single face, such as Times Italic)
 class MacOSFontEntry : public gfxFontEntry
 {
 public:
-    friend class gfxQuartzFontCache;
-    friend class FontEntryStandardFaceComparator;
+    friend class gfxMacPlatformFontList;
 
-    // initialize with Apple-type weight [1..14]
-    MacOSFontEntry(const nsAString& aPostscriptName, PRInt32 aAppleWeight, PRUint32 aTraits, 
-                   PRBool aIsStandardFace = PR_FALSE);
-
-    PRUint32 Traits() { return mTraits; }
+    MacOSFontEntry(const nsAString& aPostscriptName, PRInt32 aWeight,
+                   gfxFontFamily *aFamily, PRBool aIsStandardFace = PR_FALSE);
 
     ATSFontRef GetFontRef();
     nsresult ReadCMAP();
 
 protected:
     // for use with data fonts
     MacOSFontEntry(const nsAString& aPostscriptName, ATSFontRef aFontRef,
                    PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle,
                    gfxUserFontData *aUserFontData);
 
-    PRUint32 mTraits;
+    virtual nsresult GetFontTable(PRUint32 aTableTag, nsTArray<PRUint8>& aBuffer);
 
     ATSFontRef mATSFontRef;
     PRPackedBool mATSFontRefInitialized;
-    PRPackedBool mStandardFace;
 };
 
-// helper class for adding other family names back into font cache
-class AddOtherFamilyNameFunctor;
-
-// a single font family, referencing one or more faces 
-class MacOSFamilyEntry : public gfxFontFamily
-{
+class gfxMacPlatformFontList : public gfxPlatformFontList {
 public:
-
-    friend class gfxQuartzFontCache;
-
-    // name is canonical font family name returned from NSFontManager
-    MacOSFamilyEntry(nsAString &aName) :
-        gfxFontFamily(aName), mOtherFamilyNamesInitialized(PR_FALSE), mHasOtherFamilyNames(PR_FALSE)
-    {}
-  
-    virtual ~MacOSFamilyEntry() {}
-        
-    virtual void LocalizedName(nsAString& aLocalizedName);
-    virtual PRBool HasOtherFamilyNames();
-    
-    nsTArray<nsRefPtr<MacOSFontEntry> >& GetFontList() { return mAvailableFonts; }
-    
-    void AddFontEntry(nsRefPtr<MacOSFontEntry> aFontEntry) {
-        mAvailableFonts.AppendElement(aFontEntry);
-    }
-    
-    // decides the right face for a given style, never fails
-    // may return a face that doesn't precisely match (e.g. normal face when no italic face exists)
-    // aNeedsBold is set to true when bolder face couldn't be found, false otherwise
-    MacOSFontEntry* FindFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold);
-    
-    // iterates over faces looking for a match with a given characters
-    // used as part of the font fallback process
-    void FindFontForChar(FontSearch *aMatchData);
-    
-    // read in other family names, if any, and use functor to add each into cache
-    virtual void ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor);
-    
-    // search for a specific face using the Postscript name
-    MacOSFontEntry* FindFont(const nsAString& aPostscriptName);
-
-    // read in cmaps for all the faces
-    void ReadCMAP() {
-        PRUint32 i, numFonts = mAvailableFonts.Length();
-        for (i = 0; i < numFonts; i++)
-            mAvailableFonts[i]->ReadCMAP();
-    }
-
-    // set whether this font family is in "bad" underline offset blacklist.
-    void SetBadUnderlineFont(PRBool aIsBadUnderlineFont) {
-        PRUint32 i, numFonts = mAvailableFonts.Length();
-        for (i = 0; i < numFonts; i++)
-            mAvailableFonts[i]->mIsBadUnderlineFont = aIsBadUnderlineFont;
+    static gfxMacPlatformFontList* PlatformFontList() {
+        return (gfxMacPlatformFontList*)sPlatformFontList;
     }
 
-    // sort available fonts to put less-desirable faces towards the end
-    void SortAvailableFonts();
+    static PRInt32 AppleWeightToCSSWeight(PRInt32 aAppleWeight);
 
-protected:
-    
-    // add font entries into array that match specified traits, returned in array listed by weight
-    // i.e. aFontsForWeights[4] ==> pointer to the font entry for a 400-weight face on return
-    // returns true if one or more faces found
-    PRBool FindFontsWithTraits(gfxFontEntry* aFontsForWeights[], PRUint32 aPosTraitsMask, 
-                                PRUint32 aNegTraitsMask);
-
-    PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], const gfxFontStyle& aFontStyle);
+    virtual gfxFontEntry* GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold);
 
-    nsTArray<nsRefPtr<MacOSFontEntry> >  mAvailableFonts;
-    PRPackedBool mOtherFamilyNamesInitialized;
-    PRPackedBool mHasOtherFamilyNames;
-};
+    virtual PRBool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
-// special-case situation where specific faces need to be treated as separate font family
-class SingleFaceFamily : public MacOSFamilyEntry
-{
-public:
-    SingleFaceFamily(nsAString &aName) :
-        MacOSFamilyEntry(aName)
-    {}
-    
-    virtual ~SingleFaceFamily() {}
-    
-    virtual void LocalizedName(nsAString& aLocalizedName);
+    virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
+                                          const nsAString& aFontName);
     
-    // read in other family names, if any, and use functor to add each into cache
-    virtual void ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor);
-};
-
-class gfxQuartzFontCache : private gfxFontInfoLoader {
-public:
-    static gfxQuartzFontCache* SharedFontCache() {
-        return sSharedFontCache;
-    }
-
-    static nsresult Init() {
-        NS_ASSERTION(!sSharedFontCache, "What's this doing here?");
-        sSharedFontCache = new gfxQuartzFontCache();
-        return sSharedFontCache ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
-    }
-    // It's OK to call Shutdown if we never actually started or if 
-    // we already shut down.
-    static void Shutdown() {
-        delete sSharedFontCache;
-        sSharedFontCache = nsnull;
-    }
-
-    // methods used by gfxPlatformMac
-    
-    void GetFontList (const nsACString& aLangGroup,
-                      const nsACString& aGenericFamily,
-                      nsTArray<nsString>& aListOfFonts);
-    PRBool ResolveFontName(const nsAString& aFontName,
-                           nsAString& aResolvedFontName);
-    PRBool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
-    void UpdateFontList() { InitFontList(); }
+    virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry,
+                                           const PRUint8 *aFontData, PRUint32 aLength);
 
     void ClearPrefFonts() { mPrefFonts.Clear(); }
 
-    void GetFontFamilyList(nsTArray<nsRefPtr<MacOSFamilyEntry> >& aFamilyArray);
-
-    MacOSFontEntry* FindFontForChar(const PRUint32 aCh, gfxFont *aPrevFont);
-
-    MacOSFamilyEntry* FindFamily(const nsAString& aFamily);
-    
-    MacOSFontEntry* FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, PRBool& aNeedsBold);
-    
-    MacOSFontEntry* GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold);
+private:
+    friend class gfxPlatformMac;
 
-    static PRInt32 AppleWeightToCSSWeight(PRInt32 aAppleWeight);
-    
-    PRBool GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> > *array);
-    void SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> >& array);
-    
-    void AddOtherFamilyName(MacOSFamilyEntry *aFamilyEntry, nsAString& aOtherFamilyName);
-
-    gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
-                                  const nsAString& aFontName);
-    
-    gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const PRUint8 *aFontData, PRUint32 aLength);
-
-private:
-    static PLDHashOperator FindFontForCharProc(nsStringHashKey::KeyType aKey,
-                                               nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
-                                               void* userArg);
-
-    static gfxQuartzFontCache *sSharedFontCache;
-
-    gfxQuartzFontCache();
+    gfxMacPlatformFontList();
 
     // initialize font lists
-    void InitFontList();
-    void ReadOtherFamilyNamesForFamily(const nsAString& aFamilyName);
-    
-    // separate initialization for reading in name tables, since this is expensive
-    void InitOtherFamilyNames();
-    
+    virtual void InitFontList();
+
     // special case font faces treated as font families (set via prefs)
     void InitSingleFaceList();
-    
-    // commonly used fonts for which the name table should be loaded at startup
-    void PreloadNamesList();
 
-    // initialize the bad underline blacklist from pref.
-    void InitBadUnderlineList();
-
-    // eliminate faces which have the same ATSUI id
+    // eliminate faces which have the same ATS font reference
     void EliminateDuplicateFaces(const nsAString& aFamilyName);
-                                                             
-    // explicitly set font traits for all faces to fixed-pitch
-    void SetFixedPitch(const nsAString& aFamilyName);
-                                                             
-    static PLDHashOperator InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
-                                                    nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
-                                                    void* userArg);
 
-    void GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult);
+    // get localized name (if any) for a given family
+    void GetLocalizedFamilyName(gfxFontFamily *aFamily, nsAString& aLocalizedName);
+
     static void ATSNotification(ATSFontNotificationInfoRef aInfo, void* aUserArg);
 
-    static PLDHashOperator
-        HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
-                                nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
-                                void* aUserArg);
-
-    // gfxFontInfoLoader overrides, used to load in font cmaps
-    virtual void InitLoader();
-    virtual PRBool RunLoader();
-    virtual void FinishLoader();
-
-    // canonical family name ==> family entry (unique, one name per family entry)
-    nsRefPtrHashtable<nsStringHashKey, MacOSFamilyEntry> mFontFamilies;    
-
-    // other family name ==> family entry (not unique, can have multiple names per 
-    // family entry, only names *other* than the canonical names are stored here)
-    nsRefPtrHashtable<nsStringHashKey, MacOSFamilyEntry> mOtherFamilyNames;    
-
-    // cached pref font lists
-    // maps list of family names ==> array of family entries, one per lang group
-    nsDataHashtable<nsUint32HashKey, nsTArray<nsRefPtr<MacOSFamilyEntry> > > mPrefFonts;
-
-    // when system-wide font lookup fails for a character, cache it to skip future searches
-    gfxSparseBitSet mCodepointsWithNoFonts;
-
-    // flag set after InitOtherFamilyNames is called upon first name lookup miss
-    PRPackedBool mOtherFamilyNamesInitialized;
-
-    // data used as part of the font cmap loading process
-    nsTArray<nsRefPtr<MacOSFamilyEntry> > mFontFamiliesToLoad;
-    PRUint32 mStartIndex;
-    PRUint32 mIncrement;
-    PRUint32 mNumFamilies;
-    
     // keep track of ATS generation to prevent unneeded updates when loading downloaded fonts
     PRUint32 mATSGeneration;
-    
+
     enum {
         kATSGenerationInitial = -1
     };
 };
 
-#endif /* GFXQUARTZFONTCACHE_H_ */
+#endif /* gfxMacPlatformFontList_H_ */
rename from gfx/thebes/src/gfxQuartzFontCache.mm
rename to gfx/thebes/src/gfxMacPlatformFontList.mm
--- a/gfx/thebes/src/gfxQuartzFontCache.mm
+++ b/gfx/thebes/src/gfxMacPlatformFontList.mm
@@ -1,13 +1,13 @@
 /* -*- Mode: ObjC; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * ***** BEGIN LICENSE BLOCK *****
  * Version: BSD
  *
- * Copyright (C) 2006-2008 Mozilla Corporation.  All rights reserved.
+ * Copyright (C) 2006-2009 Mozilla Corporation.  All rights reserved.
  *
  * Contributor(s):
  *   Vladimir Vukicevic <vladimir@pobox.com>
  *   Masayuki Nakano <masayuki@d-toybox.com>
  *   John Daggett <jdaggett@mozilla.com>
  *   Jonathan Kew <jfkthame@gmail.com>
  * 
  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
@@ -38,38 +38,37 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include <Carbon/Carbon.h>
 
 #import <AppKit/AppKit.h>
 
 #include "gfxPlatformMac.h"
-#include "gfxQuartzFontCache.h"
+#include "gfxMacPlatformFontList.h"
 #include "gfxAtsuiFonts.h"
 #include "gfxUserFontSet.h"
 
-#include "nsIPrefService.h"
-#include "nsIPrefBranch2.h"  // for pref changes callback notification
 #include "nsServiceManagerUtils.h"
 #include "nsTArray.h"
 
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsISimpleEnumerator.h"
 
 #include <unistd.h>
 #include <time.h>
 
-
 // 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
 
+// indexes into the NSArray objects that the Cocoa font manager returns
+// as the available members of a family
 #define INDEX_FONT_POSTSCRIPT_NAME 0
 #define INDEX_FONT_FACE_NAME 1
 #define INDEX_FONT_WEIGHT 2
 #define INDEX_FONT_TRAITS 3
 
 static const int kAppleMaxWeight = 14;
 static const int kAppleExtraLightWeight = 3;
 static const int kAppleUltraLightWeight = 2;
@@ -102,93 +101,63 @@ static void GetStringForNSString(const N
 static NSString* GetNSStringForString(const nsAString& aSrc)
 {
     return [NSString stringWithCharacters:aSrc.BeginReading()
                      length:aSrc.Length()];
 }
 
 static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
 
-class gfxQuartzFontCachePrefObserver : public nsIObserver {
-public:
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIOBSERVER
-};
-
-NS_IMPL_ISUPPORTS1(gfxQuartzFontCachePrefObserver, nsIObserver)
-
-NS_IMETHODIMP
-gfxQuartzFontCachePrefObserver::Observe(nsISupports     *aSubject,
-                                        const char      *aTopic,
-                                        const PRUnichar *aData)
-{
-    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.
-    gfxQuartzFontCache::SharedFontCache()->ClearPrefFonts();
-    return NS_OK;
-}
-
-void
-gfxQuartzFontCache::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
-{
-    aResult = aKeyName;
-    ToLowerCase(aResult);
-}
-
 /* MacOSFontEntry */
 #pragma mark-
 
 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, 
-                               PRInt32 aWeight, PRUint32 aTraits,
+                               PRInt32 aWeight,
+                               gfxFontFamily *aFamily,
                                PRBool aIsStandardFace)
-    : gfxFontEntry(aPostscriptName), mTraits(aTraits), mATSFontRef(0),
-      mATSFontRefInitialized(PR_FALSE), mStandardFace(aIsStandardFace)
+    : gfxFontEntry(aPostscriptName, aFamily, aIsStandardFace),
+      mATSFontRef(0),
+      mATSFontRefInitialized(PR_FALSE)
 {
     mWeight = aWeight;
-
-    mItalic = (mTraits & NSItalicFontMask ? 1 : 0);
-    mFixedPitch = (mTraits & NSFixedPitchFontMask ? 1 : 0);
 }
 
 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, ATSFontRef aFontRef,
                                PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle,
                                gfxUserFontData *aUserFontData)
-    : gfxFontEntry(aPostscriptName), mATSFontRef(aFontRef),
-      mATSFontRefInitialized(PR_TRUE), mStandardFace(PR_FALSE)
+    : gfxFontEntry(aPostscriptName),
+      mATSFontRef(aFontRef),
+      mATSFontRefInitialized(PR_TRUE)
 {
     // xxx - stretch is basically ignored for now
 
     mUserFontData = aUserFontData;
     mWeight = aWeight;
     mStretch = aStretch;
     mFixedPitch = PR_FALSE; // xxx - do we need this for downloaded fonts?
     mItalic = (aItalicStyle & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
     mIsUserFont = aUserFontData != nsnull;
-
-    mTraits = (mItalic ? NSItalicFontMask : NSUnitalicFontMask) |
-              (mFixedPitch ? NSFixedPitchFontMask : 0) |
-              (mWeight >= 600 ? NSBoldFontMask : NSUnboldFontMask);
 }
 
 ATSFontRef
 MacOSFontEntry::GetFontRef() 
 {
     if (!mATSFontRefInitialized) {
         mATSFontRefInitialized = PR_TRUE;
         NSString *psname = GetNSStringForString(mName);
-        mATSFontRef = ATSFontFindFromPostScriptName(CFStringRef(psname),
-                                                    kATSOptionFlagsDefault);
+        mATSFontRef = ::ATSFontFindFromPostScriptName(CFStringRef(psname),
+                                                      kATSOptionFlagsDefault);
     }
     return mATSFontRef;
 }
 
 // ATSUI requires AAT-enabled fonts to render complex scripts correctly.
 // For now, simple clear out the cmap codepoints for fonts that have
 // codepoints for complex scripts. (Bug 361986)
+// Core Text is similar, but can render Arabic using OpenType fonts as well.
 
 enum eComplexScript {
     eComplexScriptArabic,
     eComplexScriptIndic,
     eComplexScriptTibetan
 };
 
 struct ScriptRange {
@@ -204,543 +173,143 @@ const ScriptRange gScriptsThatRequireSha
     // Thai seems to be "renderable" without AAT morphing tables
     // xxx - Lao, Khmer?
 };
 
 nsresult
 MacOSFontEntry::ReadCMAP()
 {
     OSStatus status;
-    ByteCount size, cmapSize;
-
-    if (mCmapInitialized) return NS_OK;
-    ATSFontRef fontRef = GetFontRef();
+    ByteCount size;
 
     // attempt this once, if errors occur leave a blank cmap
+    if (mCmapInitialized)
+        return NS_OK;
     mCmapInitialized = PR_TRUE;
 
     PRUint32 kCMAP = TRUETYPE_TAG('c','m','a','p');
     
-    status = ATSFontGetTable(fontRef, kCMAP, 0, 0, 0, &size);
-    cmapSize = size;
-    //printf( "cmap size: %s %d", NS_ConvertUTF16toUTF8(mName).get(), size );
-#if DEBUG
-    if (status != noErr) {
-        char warnBuf[1024];
-        sprintf(warnBuf, "ATSFontGetTable returned %d for (%s)", (PRInt32)status, NS_ConvertUTF16toUTF8(mName).get());
-        NS_WARNING(warnBuf);
-    }   
-#endif    
-    NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
-
     nsAutoTArray<PRUint8,16384> buffer;
-    if (!buffer.AppendElements(size))
-        return NS_ERROR_OUT_OF_MEMORY;
+    if (GetFontTable(kCMAP, buffer) != NS_OK)
+        return NS_ERROR_FAILURE;
     PRUint8 *cmap = buffer.Elements();
 
-    status = ATSFontGetTable(fontRef, kCMAP, 0, size, cmap, &size);
-    NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
-
-    nsresult rv = NS_ERROR_FAILURE;
     PRPackedBool  unicodeFont, symbolFont; // currently ignored
-    rv = gfxFontUtils::ReadCMAP(cmap, size, mCharacterMap, unicodeFont, symbolFont);
+    nsresult rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(),
+                                         mCharacterMap, unicodeFont, symbolFont);
 
     // for complex scripts, check for the presence of mort/morx
     PRBool checkedForMorphTable = PR_FALSE, hasMorphTable = PR_FALSE;
 
+    ATSFontRef fontRef = GetFontRef();
     PRUint32 s, numScripts = sizeof(gScriptsThatRequireShaping) / sizeof(ScriptRange);
 
     for (s = 0; s < numScripts; s++) {
         eComplexScript  whichScript = gScriptsThatRequireShaping[s].script;
         
         // check to see if the cmap includes complex script codepoints
-        if (mCharacterMap.TestRange(gScriptsThatRequireShaping[s].rangeStart, gScriptsThatRequireShaping[s].rangeEnd)) {
-            
+        if (mCharacterMap.TestRange(gScriptsThatRequireShaping[s].rangeStart,
+                                    gScriptsThatRequireShaping[s].rangeEnd)) {
+            PRBool omitRange = PR_TRUE;
+
             // check for mort/morx table, if haven't already
             if (!checkedForMorphTable) {
-                status = ATSFontGetTable(fontRef, TRUETYPE_TAG('m','o','r','x'), 0, 0, 0, &size);
+                status = ::ATSFontGetTable(fontRef, TRUETYPE_TAG('m','o','r','x'), 0, 0, 0, &size);
                 if (status == noErr) {
                     checkedForMorphTable = PR_TRUE;
                     hasMorphTable = PR_TRUE;
                 } else {
                     // check for a mort table
-                    status = ATSFontGetTable(fontRef, TRUETYPE_TAG('m','o','r','t'), 0, 0, 0, &size);
+                    status = ::ATSFontGetTable(fontRef, TRUETYPE_TAG('m','o','r','t'), 0, 0, 0, &size);
                     checkedForMorphTable = PR_TRUE;
                     if (status == noErr) {
                         hasMorphTable = PR_TRUE;
                     }
                 }
             }
-            
-            // rude hack - the Chinese STxxx fonts on 10.4 contain morx tables and Arabic glyphs but 
-            // lack the proper info for shaping Arabic, so exclude explicitly, ick
-            if (whichScript == eComplexScriptArabic && hasMorphTable) {
+
+            if (hasMorphTable) {
+                omitRange = PR_FALSE;
+            }
+
+            // special-cases for Arabic:
+            if (whichScript == eComplexScriptArabic) {
+                // even if there's no morph table, CoreText can shape if there's GSUB support
+                if (gfxPlatformMac::GetPlatform()->UsingCoreText()) {
+                    // with CoreText, don't exclude Arabic if the font has GSUB
+                    status = ::ATSFontGetTable(fontRef, TRUETYPE_TAG('G','S','U','B'), 0, 0, 0, &size);
+                    if (status == noErr) {
+                        // TODO: to be really thorough, we could check that the GSUB table
+                        // actually supports the 'arab' script tag.
+                        omitRange = PR_FALSE;
+                    }
+                }
+
+                // rude hack - the Chinese STxxx fonts on 10.4 contain morx tables and Arabic glyphs but 
+                // lack the proper info for shaping Arabic, so exclude explicitly, ick
                 if (mName.CharAt(0) == 'S' && mName.CharAt(1) == 'T') {
-                    mCharacterMap.ClearRange(gScriptsThatRequireShaping[s].rangeStart, gScriptsThatRequireShaping[s].rangeEnd);
+                    omitRange = PR_TRUE;
                 }
             }
 
-            // general exclusion - if no morph table, exclude codepoints
-            if (!hasMorphTable) {
-                mCharacterMap.ClearRange(gScriptsThatRequireShaping[s].rangeStart, gScriptsThatRequireShaping[s].rangeEnd);
+            if (omitRange) {
+                mCharacterMap.ClearRange(gScriptsThatRequireShaping[s].rangeStart,
+                                         gScriptsThatRequireShaping[s].rangeEnd);
             }
         }
     }
 
     PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-cmap) psname: %s, size: %d\n", 
                                         NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
                                         
     return rv;
 }
 
+nsresult
+MacOSFontEntry::GetFontTable(PRUint32 aTableTag, nsTArray<PRUint8>& aBuffer)
+{
+    ATSFontRef fontRef = GetFontRef();
+    if (fontRef == (ATSFontRef)kATSUInvalidFontID)
+        return NS_ERROR_FAILURE;
 
-/* MacOSFamilyEntry */
+    ByteCount dataLength;
+    OSStatus status = ::ATSFontGetTable(fontRef, aTableTag, 0, 0, 0, &dataLength);
+    NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
+
+    if (!aBuffer.AppendElements(dataLength))
+        return NS_ERROR_OUT_OF_MEMORY;
+    PRUint8 *dataPtr = aBuffer.Elements();
+
+    status = ::ATSFontGetTable(fontRef, aTableTag, 0, dataLength, dataPtr, &dataLength);
+    NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
+
+    return NS_OK;
+}
+ 
+
+/* gfxMacPlatformFontList */
 #pragma mark-
 
-// helper class for adding other family names back into font cache
-class AddOtherFamilyNameFunctor 
-{
-public:
-    AddOtherFamilyNameFunctor(gfxQuartzFontCache *aFontCache) :
-        mFontCache(aFontCache)
-    {}
-
-    void operator() (MacOSFamilyEntry *aFamilyEntry, nsAString& aOtherName) {
-        mFontCache->AddOtherFamilyName(aFamilyEntry, aOtherName);
-    }
-
-    gfxQuartzFontCache *mFontCache;
-};
-
-void MacOSFamilyEntry::LocalizedName(nsAString& aLocalizedName)
-{
-    // no other names ==> only one name, just return it
-    if (!HasOtherFamilyNames()) {
-        aLocalizedName = mName;
-        return;
-    }
-
-    NSFontManager *fontManager = [NSFontManager sharedFontManager];
-
-    // dig out the localized family name
-    NSString *family = GetNSStringForString(mName);
-    NSString *localizedFamily = [fontManager localizedNameForFamily:family face:nil];
-
-    if (localizedFamily) {
-        GetStringForNSString(localizedFamily, aLocalizedName);
-    } else {
-        // failed to get a localized name, just use the canonical name
-        aLocalizedName = mName;
-    }
-}
-
-PRBool MacOSFamilyEntry::HasOtherFamilyNames()
-{
-    // need to read in other family names to determine this
-    if (!mOtherFamilyNamesInitialized) {
-        AddOtherFamilyNameFunctor addOtherNames(gfxQuartzFontCache::SharedFontCache());
-        ReadOtherFamilyNames(addOtherNames);  // sets mHasOtherFamilyNames
-    }
-    return mHasOtherFamilyNames;
-}
-
-static const PRUint32 kTraits_NonNormalWidthMask = NSNarrowFontMask | NSExpandedFontMask | 
-                            NSCondensedFontMask | NSCompressedFontMask | NSFixedPitchFontMask;
-
-MacOSFontEntry*
-MacOSFamilyEntry::FindFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold)
-{
-    return static_cast<MacOSFontEntry*> (FindFontForStyle(*aStyle, aNeedsBold));
-}
-
-MacOSFontEntry*
-MacOSFamilyEntry::FindFont(const nsAString& aPostscriptName)
-{
-    // find the font using a simple linear search
-    PRUint32 numFonts = mAvailableFonts.Length();
-    for (PRUint32 i = 0; i < numFonts; i++) {
-        MacOSFontEntry *fe = mAvailableFonts[i];
-        if (fe->Name() == aPostscriptName)
-            return fe;
-    }
-    return nsnull;
-}
-
-void
-MacOSFamilyEntry::FindFontForChar(FontSearch *aMatchData)
-{
-    // xxx - optimization point - keep a bit vector with the union of supported unicode ranges
-    // by all fonts for this family and bail immediately if the character is not in any of
-    // this family's cmaps
-
-    // iterate over fonts
-    PRUint32 numFonts = mAvailableFonts.Length();
-    for (PRUint32 i = 0; i < numFonts; i++) {
-        MacOSFontEntry *fe = mAvailableFonts[i];
-        PRInt32 rank = 0;
-
-        if (fe->TestCharacterMap(aMatchData->ch)) {
-            rank += 20;
-        }
-
-        // if we didn't match any characters don't bother wasting more time with this face.
-        if (rank == 0)
-            continue;
-            
-        // omitting from original windows code -- family name, lang group, pitch
-        // not available in current FontEntry implementation
-
-        if (aMatchData->fontToMatch) { 
-            const gfxFontStyle *style = aMatchData->fontToMatch->GetStyle();
-            
-            // italics
-            if (fe->IsItalic() && 
-                    (style->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0) {
-                rank += 5;
-            }
-            
-            // weight
-            PRInt8 baseWeight, weightDistance;
-            style->ComputeWeightAndOffset(&baseWeight, &weightDistance);
-
-            // xxx - not entirely correct, the one unit of weight distance reflects 
-            // the "next bolder/lighter face"
-            PRUint32 targetWeight = (baseWeight * 100) + (weightDistance * 100);
-
-            PRUint32 entryWeight = fe->Weight();
-            if (entryWeight == targetWeight) {
-                rank += 5;
-            } else {
-                PRUint32 diffWeight = abs(entryWeight - targetWeight);
-                if (diffWeight <= 100)  // favor faces close in weight
-                    rank += 2;
-            }
-        } else {
-            // if no font to match, prefer non-bold, non-italic fonts
-            if (!fe->IsItalic() && !fe->IsBold())
-                rank += 5;
-        }
-        
-        // xxx - add whether AAT font with morphing info for specific lang groups
-        
-        if (rank > aMatchData->matchRank
-            || (rank == aMatchData->matchRank && Compare(fe->Name(), aMatchData->bestMatch->Name()) > 0)) 
-        {
-            aMatchData->bestMatch = fe;
-            aMatchData->matchRank = rank;
-        }
-
-    }
-}
-
-PRBool
-MacOSFamilyEntry::FindFontsWithTraits(gfxFontEntry* aFontsForWeights[], PRUint32 aPosTraitsMask, 
-                                        PRUint32 aNegTraitsMask)
-{
-    PRBool found = PR_FALSE;
-
-    // iterate over fonts
-    PRUint32 numFonts = mAvailableFonts.Length();
-    for (PRUint32 i = 0; i < numFonts; i++) {
-        MacOSFontEntry *fe = mAvailableFonts[i];
-        
-        // if traits match, add to list of fonts
-        PRUint32 traits = fe->Traits();
-        
-        // aPosTraitsMask == 0 ==> match all
-        if ((!aPosTraitsMask || (traits & aPosTraitsMask)) && !(traits & aNegTraitsMask)) {
-            PRInt32 weight = fe->Weight() / 100;
-            NS_ASSERTION(weight >= 1 && weight <= 9, "bogus font weight value!");
-            
-            // always prefer the first font for a given weight, helps deal a bit with 
-            // families with lots of faces (e.g. Minion Pro)
-            if (!aFontsForWeights[weight]) {
-                aFontsForWeights[weight] = fe;
-                found = PR_TRUE;
-            }
-        }
-    }
-    return found;
-}
-
-PRBool 
-MacOSFamilyEntry::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], const gfxFontStyle& aFontStyle)
-{
-    // short-circuit the single face per family case
-    if (mAvailableFonts.Length() == 1) {
-        MacOSFontEntry *fe = mAvailableFonts[0];
-        PRUint32 weight = fe->Weight() / 100;
-        NS_ASSERTION(weight >= 1 && weight <= 9, "bogus font weight value!");
-        aFontsForWeights[weight] = fe;
-        return PR_TRUE;
-    }
-
-    PRBool found = PR_FALSE;
-    PRBool isItalic = (aFontStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
-
-    // match italic faces
-    if (isItalic) {    
-        // first search for italic normal width fonts
-        found = FindFontsWithTraits(aFontsForWeights, NSItalicFontMask, kTraits_NonNormalWidthMask);
-        
-        // if not found, italic any width ones
-        if (!found) {
-            found = FindFontsWithTraits(aFontsForWeights, NSItalicFontMask, 0);        
-        }
-    }
-
-    // match non-italic faces, if no italic faces fall through here
-    if (!found) {
-        // look for normal width fonts
-        found = FindFontsWithTraits(aFontsForWeights, NSUnitalicFontMask, kTraits_NonNormalWidthMask);
-        
-        // if not found, any face will do
-        if (!found) {
-            found = FindFontsWithTraits(aFontsForWeights, NSUnitalicFontMask, 0);        
-        } 
-    }
-
-    // still not found?!? family must only contain italic fonts when looking for a normal 
-    // face, just use the whole list
-    if (!found) {
-        found = FindFontsWithTraits(aFontsForWeights, 0, 0);
-    }
-    NS_ASSERTION(found, "Font family containing no faces");
-
-    return found;
-}
-
-class FontEntryStandardFaceComparator {
-  public:
-    PRBool Equals(const nsRefPtr<MacOSFontEntry>& a, const nsRefPtr<MacOSFontEntry>& b) const {
-        return a->mStandardFace == b->mStandardFace;
-    }
-    PRBool LessThan(const nsRefPtr<MacOSFontEntry>& a, const nsRefPtr<MacOSFontEntry>& b) const {
-        return (a->mStandardFace == PR_TRUE && b->mStandardFace == PR_FALSE);
-    }
-};
-
-void
-MacOSFamilyEntry::SortAvailableFonts()
-{
-    mAvailableFonts.Sort(FontEntryStandardFaceComparator());
-}
-
-
-static NSString* CreateNameFromBuffer(const UInt8 *aBuf, ByteCount aLength, 
-        FontPlatformCode aPlatformCode, FontScriptCode aScriptCode, FontLanguageCode aLangCode)
-{
-    CFStringRef outName = NULL;
-
-    if (aPlatformCode == kFontMacintoshPlatform) {
-        TextEncoding encoding;
-        OSStatus err = GetTextEncodingFromScriptInfo(aScriptCode, aLangCode, 
-                                                        kTextRegionDontCare, &encoding);
-        if (err) {
-            // some fonts are sloppy about the language code (e.g Arial Hebrew, Corsiva Hebrew)
-            // try again without the lang code to avoid bad combinations
-            OSStatus err = GetTextEncodingFromScriptInfo(aScriptCode, kTextLanguageDontCare, 
-                                                        kTextRegionDontCare, &encoding);
-            if (err) return nil;
-        }
-        outName = CFStringCreateWithBytes(kCFAllocatorDefault, aBuf, 
-                                            aLength, (CFStringEncoding) encoding, false);
-    } else if (aPlatformCode == kFontUnicodePlatform) {
-        outName = CFStringCreateWithCharacters(kCFAllocatorDefault, (UniChar*)aBuf, aLength/2);    
-    } else if (aPlatformCode == kFontMicrosoftPlatform) {
-        if (aScriptCode == 0) {
-            outName = CFStringCreateWithBytes(kCFAllocatorDefault, aBuf, 
-                                                aLength, kCFStringEncodingUTF16BE, false);
-        } else {
-            outName = CFStringCreateWithCharacters(kCFAllocatorDefault, (UniChar*)aBuf, aLength/2);    
-        }
-    }
-
-    return (NSString*) outName;
-}
-
-// 10.4 headers only define TT/OT name table id's up to the license id (14) but 10.5 does, so use our own enum
-enum {
-  kMozillaFontPreferredFamilyName            = 16,
-};
-
-// xxx - rather than use ATSUI calls, probably faster to load name table directly, 
-// this avoids copying around strings that are of no interest
-
-// returns true if other names were found, false otherwise
-static PRBool ReadOtherFamilyNamesForFace(AddOtherFamilyNameFunctor& aOtherFamilyFunctor, MacOSFamilyEntry *aFamilyEntry,
-                                        NSString *familyName, ATSFontRef aFontRef, bool useFullName = false)
-{
-    OSStatus err;
-    ItemCount i, nameCount;
-    PRBool foundNames = PR_FALSE;
-
-    ATSUFontID fontID = FMGetFontFromATSFontRef(aFontRef);
-
-    if (fontID == kATSUInvalidFontID)
-        return foundNames;
-
-    err = ATSUCountFontNames(fontID, &nameCount);
-    if (err != noErr) 
-        return foundNames;
-
-    for (i = 0; i < nameCount; i++) {
-
-        FontNameCode nameCode;
-        FontPlatformCode platformCode;
-        FontScriptCode scriptCode;
-        FontLanguageCode langCode;
-        const ByteCount kBufLength = 2048;
-        char buf[kBufLength];
-        ByteCount len;
-
-        err = ATSUGetIndFontName(fontID, i, kBufLength, buf, &len, &nameCode, &platformCode, &scriptCode, &langCode);
-        // couldn't find a font name? just continue to the next name table entry
-        if (err == kATSUNoFontNameErr) 
-            continue;
-        // any other error, bail
-        if (err != noErr) 
-            return foundNames;
-
-        if (useFullName) {
-            if (nameCode != kFontFullName)
-                continue;
-        } else {
-            if (!(nameCode == kFontFamilyName || nameCode == kMozillaFontPreferredFamilyName)) 
-                continue; 
-        }
-        if (len >= kBufLength) continue; 
-        buf[len] = 0;
-
-        NSString *name = CreateNameFromBuffer((UInt8*)buf, len, platformCode, scriptCode, langCode);
-
-        // add if not same as canonical family name or already in list of names
-        if (name) {
-
-            if (![name isEqualToString:familyName]) {
-                nsAutoString otherFamilyName;
-                GetStringForNSString(name, otherFamilyName);
-                aOtherFamilyFunctor(aFamilyEntry, otherFamilyName);
-                foundNames = PR_TRUE;
-            }
-
-            [name release];
-        }
-    }
-
-    return foundNames;
-}
-
-void
-MacOSFamilyEntry::ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor)
-{
-    if (mOtherFamilyNamesInitialized) 
-        return;
-    mOtherFamilyNamesInitialized = PR_TRUE;
-
-    NSString *familyName = GetNSStringForString(mName);
-
-    // read in other family names for the first face in the list
-    MacOSFontEntry *fe = mAvailableFonts[0];
-
-    mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aOtherFamilyFunctor, this, familyName, fe->GetFontRef());
-
-    // read in other names for the first face in the list with the assumption
-    // that if extra names don't exist in that face then they don't exist in
-    // other faces for the same font
-    if (mHasOtherFamilyNames) {
-        PRUint32 numFonts, i;
-        
-        // read in names for all faces, needed to catch cases where
-        // fonts all family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
-        numFonts = mAvailableFonts.Length();
-        for (i = 1; i < numFonts; i++) {
-            fe = mAvailableFonts[i];
-            ReadOtherFamilyNamesForFace(aOtherFamilyFunctor, this, familyName, fe->GetFontRef());
-        }
-    }
-}
-
-/* SingleFaceFamily */
-#pragma mark-
-
-void SingleFaceFamily::LocalizedName(nsAString& aLocalizedName)
-{
-    MacOSFontEntry *fontEntry;
-
-    // use the display name of the single face
-    fontEntry = mAvailableFonts[0];
-    if (!fontEntry) 
-        return;
-        
-    NSFont *font = [NSFont fontWithName:GetNSStringForString(fontEntry->Name()) size:0.0];
-    if (!font)
-        return;
-
-    NSString *fullname = [font displayName];
-    if (fullname) {
-        GetStringForNSString(fullname, aLocalizedName);
-    }
-}
-
-void SingleFaceFamily::ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor)
-{
-    if (mOtherFamilyNamesInitialized) 
-        return;
-    mOtherFamilyNamesInitialized = PR_TRUE;
-
-    NSString *familyName = GetNSStringForString(mName);
-
-    // read in other family names for the first face in the list
-    MacOSFontEntry *fe = mAvailableFonts[0];
-
-    // read in other names, using the full font names as the family names
-    mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aOtherFamilyFunctor, this, familyName, fe->GetFontRef(), true);    
-}
-
-/* gfxQuartzFontCache */
-#pragma mark-
-
-gfxQuartzFontCache *gfxQuartzFontCache::sSharedFontCache = nsnull;
-
-gfxQuartzFontCache::gfxQuartzFontCache()
-    : mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0)
+gfxMacPlatformFontList::gfxMacPlatformFontList()
 {
     mATSGeneration = PRUint32(kATSGenerationInitial);
 
-    mFontFamilies.Init(100);
-    mOtherFamilyNames.Init(30);
-    mOtherFamilyNamesInitialized = PR_FALSE;
-    mPrefFonts.Init(10);
-
-    InitFontList();
     ::ATSFontNotificationSubscribe(ATSNotification,
                                    kATSFontNotifyOptionDefault,
                                    (void*)this, nsnull);
 
-    // pref changes notification setup
-    gfxQuartzFontCachePrefObserver *observer = new gfxQuartzFontCachePrefObserver();
-    if (observer) {
-        nsCOMPtr<nsIPrefBranch2> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
-        if (pref) {
-            pref->AddObserver("font.", observer, PR_FALSE);
-            pref->AddObserver("font.name-list.", observer, PR_FALSE);
-            pref->AddObserver("intl.accept_languages", observer, PR_FALSE);  // hmmmm...
-        } else {
-            delete observer;
-        }
-    }
+    // this should always be available (though we won't actually fail if it's missing,
+    // we'll just end up doing a search and then caching the new result instead)
+    mReplacementCharFallbackFamily = NS_LITERAL_STRING("Lucida Grande");
 }
 
-const PRUint32 kNonNormalTraits = NSItalicFontMask | NSBoldFontMask | NSNarrowFontMask | NSExpandedFontMask | NSCondensedFontMask | NSCompressedFontMask;
-
 void
-gfxQuartzFontCache::InitFontList()
+gfxMacPlatformFontList::InitFontList()
 {
-    ATSGeneration currentGeneration = ATSGetGeneration();
+    ATSGeneration currentGeneration = ::ATSGetGeneration();
     
     // need to ignore notifications after adding each font
     if (mATSGeneration == currentGeneration)
         return;
 
     mATSGeneration = currentGeneration;
     PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit) updating to generation: %d", mATSGeneration));                                         
     
@@ -765,73 +334,82 @@ gfxQuartzFontCache::InitFontList()
    
     NSString *availableFamily = nil;
     while ((availableFamily = [families nextObject])) {
 
         // make a nsString
         GetStringForNSString(availableFamily, availableFamilyName);
         
         // create a family entry
-        MacOSFamilyEntry *familyEntry = new MacOSFamilyEntry(availableFamilyName);
+        gfxFontFamily *familyEntry = new gfxFontFamily(availableFamilyName);
         if (!familyEntry) break;
         
         // create a font entry for each face
         NSArray *fontfaces = [fontManager availableMembersOfFontFamily:availableFamily];  // returns an array of [psname, style name, weight, traits] elements, goofy api
         int faceCount = [fontfaces count];
         int faceIndex;
 
         for (faceIndex = 0; faceIndex < faceCount; faceIndex++) {
             NSArray *face = [fontfaces objectAtIndex:faceIndex];
             NSString *psname = [face objectAtIndex:INDEX_FONT_POSTSCRIPT_NAME];
             PRInt32 appKitWeight = [[face objectAtIndex:INDEX_FONT_WEIGHT] unsignedIntValue];
-            PRUint32 traits = [[face objectAtIndex:INDEX_FONT_TRAITS] unsignedIntValue];
+            PRUint32 macTraits = [[face objectAtIndex:INDEX_FONT_TRAITS] unsignedIntValue];
             NSString *facename = [face objectAtIndex:INDEX_FONT_FACE_NAME];
             PRBool isStandardFace = PR_FALSE;
 
             if (needToCheckLightFaces && appKitWeight == kAppleExtraLightWeight) {
                 // if the facename contains UltraLight, set the weight to the ultralight weight value
                 NSRange range = [facename rangeOfString:@"ultralight" options:NSCaseInsensitiveSearch];
                 if (range.location != NSNotFound) {
                     appKitWeight = kAppleUltraLightWeight;
                 }
             }
             
-            // 10.5 doesn't set NSUnitalicFontMask and NSUnboldFontMask - manually set these for consistency 
-            if (!(traits & NSBoldFontMask))
-                traits |= NSUnboldFontMask;
-            if (!(traits & NSItalicFontMask))
-                traits |= NSUnitalicFontMask;
+            PRInt32 cssWeight = gfxMacPlatformFontList::AppleWeightToCSSWeight(appKitWeight) * 100;
             
-            PRInt32 cssWeight = gfxQuartzFontCache::AppleWeightToCSSWeight(appKitWeight) * 100;
-            
-            PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit) family: %s, psname: %s, face: %s, apple-weight: %d, css-weight: %d, traits: %8.8x\n", 
-                [availableFamily UTF8String], [psname UTF8String], [facename UTF8String], appKitWeight, cssWeight, traits));
+            PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit) family: %s, psname: %s, face: %s, apple-weight: %d, css-weight: %d, macTraits: %8.8x\n", 
+                [availableFamily UTF8String], [psname UTF8String], [facename UTF8String], appKitWeight, cssWeight, macTraits));
 
             // make a nsString
             GetStringForNSString(psname, postscriptFontName);
 
             if ([facename isEqualToString:@"Regular"] ||
                 [facename isEqualToString:@"Bold"] ||
                 [facename isEqualToString:@"Italic"] ||
                 [facename isEqualToString:@"Oblique"] ||
                 [facename isEqualToString:@"Bold Italic"] ||
                 [facename isEqualToString:@"Bold Oblique"])
             {
                 isStandardFace = PR_TRUE;
             }
 
             // create a font entry
-            MacOSFontEntry *fontEntry = new MacOSFontEntry(postscriptFontName, cssWeight, traits, isStandardFace);
-            if (!fontEntry) break;            
-            
+            MacOSFontEntry *fontEntry = new MacOSFontEntry(postscriptFontName,
+                                                           cssWeight, familyEntry, isStandardFace);
+            if (!fontEntry) break;
+
+            // set additional properties based on the traits reported by Cocoa
+            if (macTraits & (NSCondensedFontMask | NSNarrowFontMask | NSCompressedFontMask)) {
+                fontEntry->mStretch = NS_FONT_STRETCH_CONDENSED;
+            } else if (macTraits & NSExpandedFontMask) {
+                fontEntry->mStretch = NS_FONT_STRETCH_EXPANDED;
+            }
+            if (macTraits & NSItalicFontMask) {
+                fontEntry->mItalic = PR_TRUE;
+            }
+            if (macTraits & NSFixedPitchFontMask) {
+                fontEntry->mFixedPitch = PR_TRUE;
+            }
+
             // insert into font entry array of family
             familyEntry->AddFontEntry(fontEntry);
         }
 
         familyEntry->SortAvailableFonts();
+        familyEntry->SetHasStyles(PR_TRUE);
 
         // add the family entry to the hash table
         ToLowerCase(availableFamilyName);
         mFontFamilies.Put(availableFamilyName, familyEntry);
     }
 
     InitSingleFaceList();
 
@@ -859,500 +437,234 @@ gfxQuartzFontCache::InitFontList()
 
     InitBadUnderlineList();
 
     // start the delayed cmap loader
     StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps); 
 
 }
 
-void 
-gfxQuartzFontCache::InitOtherFamilyNames()
-{
-    mOtherFamilyNamesInitialized = PR_TRUE;
-
-    // iterate over all font families and read in other family names
-    mFontFamilies.Enumerate(gfxQuartzFontCache::InitOtherFamilyNamesProc, this);
-}
-                                                         
-PLDHashOperator PR_CALLBACK gfxQuartzFontCache::InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
-                                                         nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
-                                                         void* userArg)
-{
-    gfxQuartzFontCache *fc = (gfxQuartzFontCache*) userArg;
-    AddOtherFamilyNameFunctor addOtherNames(fc);
-    aFamilyEntry->ReadOtherFamilyNames(addOtherNames);
-    return PL_DHASH_NEXT;
-}
-
 void
-gfxQuartzFontCache::ReadOtherFamilyNamesForFamily(const nsAString& aFamilyName)
-{
-    MacOSFamilyEntry *familyEntry = FindFamily(aFamilyName);
-
-    if (familyEntry) {
-        AddOtherFamilyNameFunctor addOtherNames(this);
-        familyEntry->ReadOtherFamilyNames(addOtherNames);
-    }
-}
-
-void
-gfxQuartzFontCache::InitSingleFaceList()
+gfxMacPlatformFontList::InitSingleFaceList()
 {
     nsAutoTArray<nsString, 10> singleFaceFonts;
     gfxFontUtils::GetPrefsFontList("font.single-face-list", singleFaceFonts);
 
     PRUint32 numFonts = singleFaceFonts.Length();
     for (PRUint32 i = 0; i < numFonts; i++) {
-        nsAutoString availableFamilyName;
+        PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontlist-singleface) face name: %s\n",
+                                            NS_ConvertUTF16toUTF8(singleFaceFonts[i]).get()));
+        gfxFontEntry *fontEntry = LookupLocalFont(nsnull, singleFaceFonts[i]);
+        if (fontEntry) {
+            nsAutoString familyName, key;
+            if (!GetStandardFamilyName(singleFaceFonts[i], familyName)) {
+                familyName = singleFaceFonts[i];
+            }
+            GenerateFontListKey(familyName, key);
+            PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontlist-singleface) family name: %s, key: %s\n",
+                   NS_ConvertUTF16toUTF8(familyName).get(), NS_ConvertUTF16toUTF8(key).get()));
 
-        // lookup the font using NSFont    
-        NSString *faceName = GetNSStringForString(singleFaceFonts[i]);
-        NSFont *font = [NSFont fontWithName:faceName size:0.0];
-        if (font) {
-            NSString *availableFamily = [font familyName];
-            GetStringForNSString(availableFamily, availableFamilyName);
- 
-            MacOSFamilyEntry *familyEntry = FindFamily(availableFamilyName);
-            if (familyEntry) {
-                MacOSFontEntry *fontEntry = familyEntry->FindFont(singleFaceFonts[i]);
-                if (fontEntry) {
-                    PRBool found;
-                    nsAutoString displayName, key;
-                    
-                    // use the display name the canonical name
-                    NSString *display = [font displayName];
-                    GetStringForNSString(display, displayName);
-                    GenerateFontListKey(displayName, key);
-
-                    // add only if doesn't exist already
-                    if (!(familyEntry = mFontFamilies.GetWeak(key, &found))) {
-                        familyEntry = new SingleFaceFamily(displayName);
-                        familyEntry->AddFontEntry(fontEntry);
-                        mFontFamilies.Put(key, familyEntry);
-                        PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-singleface) family: %s, psname: %s\n", [display UTF8String], [faceName UTF8String]));
-                    }
-                }
+            // add only if doesn't exist already
+            PRBool found;
+            gfxFontFamily *familyEntry;
+            if (!(familyEntry = mFontFamilies.GetWeak(key, &found))) {
+                familyEntry = new gfxFontFamily(familyName);
+                familyEntry->AddFontEntry(fontEntry);
+                familyEntry->SetHasStyles(PR_TRUE);
+                mFontFamilies.Put(key, familyEntry);
+                fontEntry->mFamily = familyEntry;
+                PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontlist-singleface) added new family\n",
+                       NS_ConvertUTF16toUTF8(familyName).get(), NS_ConvertUTF16toUTF8(key).get()));
             }
         }
-        
     }
-       
-}
-
-void
-gfxQuartzFontCache::PreloadNamesList()
-{
-    nsAutoTArray<nsString, 10> preloadFonts;
-    gfxFontUtils::GetPrefsFontList("font.preload-names-list", preloadFonts);
-
-    PRUint32 numFonts = preloadFonts.Length();
-    for (PRUint32 i = 0; i < numFonts; i++) {
-        PRBool found;
-        nsAutoString key;
-        GenerateFontListKey(preloadFonts[i], key);
-        
-        // only search canonical names!
-        MacOSFamilyEntry *familyEntry = mFontFamilies.GetWeak(key, &found);
-        if (familyEntry) {
-            AddOtherFamilyNameFunctor addOtherNames(this);
-            familyEntry->ReadOtherFamilyNames(addOtherNames);
-        }
-    }
-
 }
 
 void 
-gfxQuartzFontCache::EliminateDuplicateFaces(const nsAString& aFamilyName)
+gfxMacPlatformFontList::EliminateDuplicateFaces(const nsAString& aFamilyName)
 {
-    MacOSFamilyEntry *family = FindFamily(aFamilyName);
+    gfxFontFamily *family = FindFamily(aFamilyName);
     if (!family) return;
 
-    nsTArray<nsRefPtr<MacOSFontEntry> >& fontlist = family->GetFontList();
+    nsTArray<nsRefPtr<gfxFontEntry> >& fontlist = family->GetFontList();
 
     PRUint32 i, bold, numFonts, italicIndex;
     MacOSFontEntry *italic, *nonitalic;
-    PRUint32 boldtraits[2] = { 0, NSBoldFontMask };
 
     // if normal and italic have the same ATS font ref, delete italic
     // if bold and bold-italic have the same ATS font ref, delete bold-italic
 
     // two iterations, one for normal, one for bold
     for (bold = 0; bold < 2; bold++) {
         numFonts = fontlist.Length();
 
         // find the non-italic face
         nonitalic = nsnull;
         for (i = 0; i < numFonts; i++) {
-            PRUint32 traits = fontlist[i]->Traits();
-            if (((traits & NSBoldFontMask) == boldtraits[bold]) && !(traits & NSItalicFontMask)) {
-                nonitalic = fontlist[i];
+            if ((fontlist[i]->IsBold() == (bold == 1)) && !fontlist[i]->IsItalic()) {
+                nonitalic = static_cast<MacOSFontEntry*>(fontlist[i].get());
                 break;
             }
         }
 
         // find the italic face
         if (nonitalic) {
             italic = nsnull;
             for (i = 0; i < numFonts; i++) {
-                PRUint32 traits = fontlist[i]->Traits();
-                if (((traits & NSBoldFontMask) == boldtraits[bold]) && (traits & NSItalicFontMask)) {
-                    italic = fontlist[i];
+                if ((fontlist[i]->IsBold() == (bold == 1)) && fontlist[i]->IsItalic()) {
+                    italic = static_cast<MacOSFontEntry*>(fontlist[i].get());
                     italicIndex = i;
                     break;
                 }
             }
 
             // if italic face and non-italic face have matching ATS refs,
             // or if the italic returns 0 rather than an actual ATSFontRef,
             // then the italic face is bogus so remove it
             if (italic && (italic->GetFontRef() == 0 ||
                            italic->GetFontRef() == nonitalic->GetFontRef())) {
                 fontlist.RemoveElementAt(italicIndex);
             }
         }
     }
 }
 
-void 
-gfxQuartzFontCache::SetFixedPitch(const nsAString& aFamilyName)
-{
-    MacOSFamilyEntry *family = FindFamily(aFamilyName);
-    if (!family) return;
-
-    nsTArray<nsRefPtr<MacOSFontEntry> >& fontlist = family->GetFontList();
-
-    PRUint32 i, numFonts = fontlist.Length();
-
-    for (i = 0; i < numFonts; i++) {
-        fontlist[i]->mTraits |= NSFixedPitchFontMask;
-        fontlist[i]->mFixedPitch = 1;
-    }
-}
-
-void
-gfxQuartzFontCache::InitBadUnderlineList()
+PRBool
+gfxMacPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
-    nsAutoTArray<nsString, 10> blacklist;
-    gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist);
-    PRUint32 numFonts = blacklist.Length();
-    for (PRUint32 i = 0; i < numFonts; i++) {
-        PRBool found;
-        nsAutoString key;
-        GenerateFontListKey(blacklist[i], key);
-
-        MacOSFamilyEntry *familyEntry = mFontFamilies.GetWeak(key, &found);
-        if (familyEntry)
-            familyEntry->SetBadUnderlineFont(PR_TRUE);
-    }
-}
-
-PRBool 
-gfxQuartzFontCache::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
-{
-    MacOSFamilyEntry *family = FindFamily(aFontName);
+    gfxFontFamily *family = FindFamily(aFontName);
     if (family) {
-        aResolvedFontName = family->Name();
-        return PR_TRUE;
-    }
-    return PR_FALSE;
-}
-
-PRBool
-gfxQuartzFontCache::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
-{
-    MacOSFamilyEntry *family = FindFamily(aFontName);
-    if (family) {
-        family->LocalizedName(aFamilyName);
+        GetLocalizedFamilyName(family, aFamilyName);
         return PR_TRUE;
     }
 
     // Gecko 1.8 used Quickdraw font api's which produce a slightly different set of "family"
     // names.  Try to resolve based on these names, in case this is stored in an old profile
-    // 1.8: "Futura", "Futura Condensed" ==> 1.9: "Futura
-    FMFont fmFont;
-
-    // convert of a NSString
-    NSString *fontName = GetNSStringForString(aFontName);
+    // 1.8: "Futura", "Futura Condensed" ==> 1.9: "Futura"
 
-    // name ==> family id ==> old-style FMFont
-    ATSFontFamilyRef fmFontFamily = ATSFontFamilyFindFromName((CFStringRef)fontName, kATSOptionFlagsDefault);
-    OSStatus err = FMGetFontFromFontFamilyInstance(fmFontFamily, 0, &fmFont, nsnull);
-    if (err != noErr || fmFont == kInvalidFont)
-        return PR_FALSE;
-
-    ATSFontRef atsFont = FMGetATSFontRefFromFont(fmFont);
-    if (!atsFont)
-        return PR_FALSE;
+    // convert the name to a Pascal-style Str255 to try as Quickdraw name
+    Str255 qdname;
+    NS_ConvertUTF16toUTF8 utf8name(aFontName);
+    qdname[0] = PR_MAX(255, strlen(utf8name.get()));
+    memcpy(&qdname[1], utf8name.get(), qdname[0]);
 
-    NSString *psname;
-
-    // now lookup the Postscript name
-    err = ATSFontGetPostScriptName(atsFont, kATSOptionFlagsDefault, (CFStringRef*) (&psname));
-    if (err != noErr)
+    // look up the Quickdraw name
+    ATSFontFamilyRef atsFamily = ::ATSFontFamilyFindFromQuickDrawName(qdname);
+    if (atsFamily == (ATSFontFamilyRef)kInvalidFontFamily) {
         return PR_FALSE;
+    }
 
-    // given an NSFont instance, Cocoa api's return the canonical family name
-    NSString *canonicalfamily = [[NSFont fontWithName:psname size:0.0] familyName];
-    [psname release];
+    // if we found a family, get its ATS name
+    CFStringRef cfName;
+    OSStatus status = ::ATSFontFamilyGetName(atsFamily, kATSOptionFlagsDefault, &cfName);
+    if (status != noErr) {
+        return PR_FALSE;
+    }
 
+    // then use this to locate the family entry and retrieve its localized name
     nsAutoString familyName;
+    GetStringForNSString((const NSString*)cfName, familyName);
+    ::CFRelease(cfName);
 
-    // lookup again using the canonical family name
-    GetStringForNSString(canonicalfamily, familyName);
     family = FindFamily(familyName);
     if (family) {
-        family->LocalizedName(aFamilyName);
+        GetLocalizedFamilyName(family, aFamilyName);
         return PR_TRUE;
     }
 
     return PR_FALSE;
 }
 
 void
-gfxQuartzFontCache::ATSNotification(ATSFontNotificationInfoRef aInfo,
+gfxMacPlatformFontList::GetLocalizedFamilyName(gfxFontFamily *aFamily,
+                                           nsAString& aLocalizedName)
+{
+    if (!aFamily->HasOtherFamilyNames()) {
+        aLocalizedName = aFamily->Name();
+        return;
+    }
+
+    NSFontManager *fontManager = [NSFontManager sharedFontManager];
+
+    // dig out the localized family name
+    NSString *familyName = GetNSStringForString(aFamily->Name());
+    NSString *localizedFamily = [fontManager localizedNameForFamily:familyName face:nil];
+
+    if (localizedFamily) {
+        GetStringForNSString(localizedFamily, aLocalizedName);
+    } else {
+        // failed to get a localized name, just use the canonical name
+        aLocalizedName = aFamily->Name();
+    }
+}
+
+void
+gfxMacPlatformFontList::ATSNotification(ATSFontNotificationInfoRef aInfo,
                                     void* aUserArg)
 {
     // xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
-    gfxQuartzFontCache *qfc = (gfxQuartzFontCache*)aUserArg;
+    gfxMacPlatformFontList *qfc = (gfxMacPlatformFontList*)aUserArg;
     qfc->UpdateFontList();
 }
 
-MacOSFontEntry*
-gfxQuartzFontCache::GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold)
+gfxFontEntry*
+gfxMacPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold)
 {
     NSString *defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
     nsAutoString familyName;
 
     GetStringForNSString(defaultFamily, familyName);
     return FindFontForFamily(familyName, aStyle, aNeedsBold);
 }
 
-struct FontListData {
-    FontListData(const nsACString& aLangGroup,
-                 const nsACString& aGenericFamily,
-                 nsTArray<nsString>& aListOfFonts) :
-        mLangGroup(aLangGroup), mGenericFamily(aGenericFamily),
-        mListOfFonts(aListOfFonts) {}
-    const nsACString& mLangGroup;
-    const nsACString& mGenericFamily;
-    nsTArray<nsString>& mListOfFonts;
-};
-
-PLDHashOperator PR_CALLBACK
-gfxQuartzFontCache::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
-                                            nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
-                                            void *aUserArg)
-{
-    FontListData *data = (FontListData*)aUserArg;
-
-    nsAutoString localizedFamilyName;
-    aFamilyEntry->LocalizedName(localizedFamilyName);
-    data->mListOfFonts.AppendElement(localizedFamilyName);
-    return PL_DHASH_NEXT;
-}
-
-void
-gfxQuartzFontCache::GetFontList (const nsACString& aLangGroup,
-                                 const nsACString& aGenericFamily,
-                                 nsTArray<nsString>& aListOfFonts)
-{
-    FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
-
-    mFontFamilies.Enumerate(gfxQuartzFontCache::HashEnumFuncForFamilies, &data);
-
-    aListOfFonts.Sort();
-    aListOfFonts.Compact();
-}
-
-struct FontFamilyListData {
-    FontFamilyListData(nsTArray<nsRefPtr<MacOSFamilyEntry> >& aFamilyArray) 
-        : mFamilyArray(aFamilyArray)
-    {}
-
-    static PLDHashOperator PR_CALLBACK AppendFamily(nsStringHashKey::KeyType aKey,
-                                                    nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
-                                                    void *aUserArg)
-    {
-        FontFamilyListData *data = (FontFamilyListData*)aUserArg;
-        data->mFamilyArray.AppendElement(aFamilyEntry);
-        return PL_DHASH_NEXT;
-    }
-
-    nsTArray<nsRefPtr<MacOSFamilyEntry> >& mFamilyArray;
-};
-
-void
-gfxQuartzFontCache::GetFontFamilyList(nsTArray<nsRefPtr<MacOSFamilyEntry> >& aFamilyArray)
-{
-    FontFamilyListData data(aFamilyArray);
-    mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
-}
-
-MacOSFontEntry*  
-gfxQuartzFontCache::FindFontForChar(const PRUint32 aCh, gfxFont *aPrevFont)
-{
-    // is codepoint with no matching font? return null immediately
-    if (mCodepointsWithNoFonts.test(aCh)) {
-        return nsnull;
-    }
-
-    // short-circuit system font fallback for U+FFFD, used to represent encoding errors
-    // just use Lucida Grande (system font, guaranteed to be around)
-    // this helps speed up pages with lots of encoding errors, binary-as-text, etc.
-    if (aCh == 0xFFFD) {
-        MacOSFontEntry* fontEntry;
-        PRBool needsBold;  // ignored in the system fallback case
-        
-        if (aPrevFont) {
-            fontEntry = FindFontForFamily(NS_LITERAL_STRING("Lucida Grande"), aPrevFont->GetStyle(), needsBold);
-        } else {
-            gfxFontStyle normalStyle;
-            fontEntry = FindFontForFamily(NS_LITERAL_STRING("Lucida Grande"), &normalStyle, needsBold);
-        }
-
-        if (fontEntry && fontEntry->TestCharacterMap(aCh))
-            return fontEntry;
-    }
-
-    FontSearch data(aCh, aPrevFont);
-
-    // iterate over all font families to find a font that support the character
-    mFontFamilies.Enumerate(gfxQuartzFontCache::FindFontForCharProc, &data);
-
-    // no match? add to set of non-matching codepoints
-    if (!data.bestMatch) {
-        mCodepointsWithNoFonts.set(aCh);
-    }
-
-    return data.bestMatch;
-}
-
-PLDHashOperator PR_CALLBACK 
-gfxQuartzFontCache::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
-     void *userArg)
-{
-    FontSearch *data = (FontSearch*)userArg;
-
-    // evaluate all fonts in this family for a match
-    aFamilyEntry->FindFontForChar(data);
-    return PL_DHASH_NEXT;
-}
-
-MacOSFamilyEntry* 
-gfxQuartzFontCache::FindFamily(const nsAString& aFamily)
-{
-    nsAutoString key;
-    MacOSFamilyEntry *familyEntry;
-    PRBool found;
-    GenerateFontListKey(aFamily, key);
-
-    // lookup in canonical (i.e. English) family name list
-    if ((familyEntry = mFontFamilies.GetWeak(key, &found))) {
-        return familyEntry;
-    }
-
-    // lookup in other family names list (mostly localized names)
-    if ((familyEntry = mOtherFamilyNames.GetWeak(key, &found))) {
-        return familyEntry;
-    }
-
-    // name not found and other family names not yet fully initialized so
-    // initialize the rest of the list and try again.  this is done lazily
-    // since reading name table entries is expensive
-    if (!mOtherFamilyNamesInitialized) {
-        InitOtherFamilyNames();
-        if ((familyEntry = mOtherFamilyNames.GetWeak(key, &found))) {
-            return familyEntry;
-        }
-    }
-
-    return nsnull;
-}
-
-MacOSFontEntry*
-gfxQuartzFontCache::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, PRBool& aNeedsBold)
-{
-    MacOSFamilyEntry *familyEntry = FindFamily(aFamily);
-
-    aNeedsBold = PR_FALSE;
-
-    if (familyEntry)
-        return familyEntry->FindFont(aStyle, aNeedsBold);
-
-    return nsnull;
-}
-
 PRInt32 
-gfxQuartzFontCache::AppleWeightToCSSWeight(PRInt32 aAppleWeight)
+gfxMacPlatformFontList::AppleWeightToCSSWeight(PRInt32 aAppleWeight)
 {
     if (aAppleWeight < 1)
         aAppleWeight = 1;
     else if (aAppleWeight > kAppleMaxWeight)
         aAppleWeight = kAppleMaxWeight;
     return gAppleWeightToCSSWeight[aAppleWeight];
 }
 
-PRBool
-gfxQuartzFontCache::GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> > *array)
-{
-    return mPrefFonts.Get(PRUint32(aLangGroup), array);
-}
-
-void
-gfxQuartzFontCache::SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> >& array)
-{
-    mPrefFonts.Put(PRUint32(aLangGroup), array);
-}
-
-void 
-gfxQuartzFontCache::AddOtherFamilyName(MacOSFamilyEntry *aFamilyEntry, nsAString& aOtherFamilyName)
-{
-    nsAutoString key;
-    PRBool found;
-    GenerateFontListKey(aOtherFamilyName, key);
-
-    if (!mOtherFamilyNames.GetWeak(key, &found)) {
-        mOtherFamilyNames.Put(key, aFamilyEntry);
-        PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-otherfamily) canonical family: %s, other family: %s\n", 
-                                            NS_ConvertUTF16toUTF8(aFamilyEntry->Name()).get(), 
-                                            NS_ConvertUTF16toUTF8(aOtherFamilyName).get()));
-    }
-}
-
 gfxFontEntry* 
-gfxQuartzFontCache::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
+gfxMacPlatformFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                     const nsAString& aFontName)
 {
     NSString *faceName = GetNSStringForString(aFontName);
     
     // first lookup a single face based on postscript name
-    ATSFontRef fontRef = ATSFontFindFromPostScriptName(CFStringRef(faceName), 
-                                                       kATSOptionFlagsDefault);
+    ATSFontRef fontRef = ::ATSFontFindFromPostScriptName(CFStringRef(faceName), 
+                                                         kATSOptionFlagsDefault);
 
     // if not found, lookup using full font name
     if (fontRef == kInvalidFont)
-        fontRef = ATSFontFindFromName(CFStringRef(faceName), 
-                                      kATSOptionFlagsDefault);
+        fontRef = ::ATSFontFindFromName(CFStringRef(faceName), 
+                                        kATSOptionFlagsDefault);
                                       
     // not found                                  
     if (fontRef == kInvalidFont)
         return nsnull;
 
-    PRUint16 w = aProxyEntry->mWeight;
-    NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
+    MacOSFontEntry *newFontEntry;
+    if (aProxyEntry) {
+        PRUint16 w = aProxyEntry->mWeight;
+        NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
 
-    MacOSFontEntry *newFontEntry =
-        new MacOSFontEntry(aFontName, 
-                           FMGetFontFromATSFontRef(fontRef),
-                           w, aProxyEntry->mStretch, 
-                           (PRUint32(aProxyEntry->mItalic) ? 
-                           FONT_STYLE_ITALIC : 
-                           FONT_STYLE_NORMAL), 
-                           nsnull);
+        newFontEntry =
+            new MacOSFontEntry(aFontName, fontRef,
+                               w, aProxyEntry->mStretch, 
+                               aProxyEntry->mItalic ?
+                                   FONT_STYLE_ITALIC : FONT_STYLE_NORMAL,
+                               nsnull);
+    } else {
+        newFontEntry =
+            new MacOSFontEntry(aFontName, fontRef,
+                               400, 0, FONT_STYLE_NORMAL, nsnull);
+    }
 
     return newFontEntry;
 }
 
 // grumble, another non-publised Apple API dependency (found in Webkit code)
 // activated with this value, font will not be found via system lookup routines
 // it can only be used via the created ATSFontRef
 // needed to prevent one doc from finding a font used in a separate doc
@@ -1366,24 +678,24 @@ public:
     MacOSUserFontData(ATSFontContainerRef aContainerRef)
         : mContainerRef(aContainerRef)
     { }
 
     virtual ~MacOSUserFontData()
     {
         // deactivate font
         if (mContainerRef)
-            ATSFontDeactivate(mContainerRef, NULL, kATSOptionFlagsDefault);
+            ::ATSFontDeactivate(mContainerRef, NULL, kATSOptionFlagsDefault);
     }
 
     ATSFontContainerRef     mContainerRef;
 };
 
 gfxFontEntry* 
-gfxQuartzFontCache::MakePlatformFont(const gfxFontEntry *aProxyEntry, 
+gfxMacPlatformFontList::MakePlatformFont(const gfxFontEntry *aProxyEntry, 
                                      const PRUint8 *aFontData, PRUint32 aLength)
 {
     OSStatus err;
     
     NS_ASSERTION(aFontData && aLength != 0, 
                  "MakePlatformFont called with null data ptr");
                  
     // do simple validation check on font data before 
@@ -1403,80 +715,80 @@ gfxQuartzFontCache::MakePlatformFont(con
     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) {
-        err = ATSFontActivateFromMemory(const_cast<PRUint8*>(aFontData), aLength, 
-                                        kPrivateATSFontContextPrivate,
-                                        kATSFontFormatUnspecified,
-                                        NULL, 
-                                        kATSOptionFlagsDoNotNotify, 
-                                        &containerRef);
-        mATSGeneration = ATSGetGeneration();
+        err = ::ATSFontActivateFromMemory(const_cast<PRUint8*>(aFontData), aLength, 
+                                          kPrivateATSFontContextPrivate,
+                                          kATSFontFormatUnspecified,
+                                          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_WARNING(warnBuf);
 #endif    
             return nsnull;
         }
 
         // ignoring containers with multiple fonts, use the first face only for now
-        err = ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1, 
-                                       &fontRef, NULL);
+        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_WARNING(warnBuf);
 #endif  
-            ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
+            ::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));
+        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_WARNING(warnBuf);
 #endif
-            ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
+            ::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;
         }
 
         // font entry will own this
         MacOSUserFontData *userFontData = new MacOSUserFontData(containerRef);
 
         if (!userFontData) {
-            ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
+            ::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
             return nsnull;
         }
 
         PRUint16 w = aProxyEntry->mWeight;
         NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
 
         // create the font entry
         nsAutoString uniqueName;
@@ -1484,21 +796,20 @@ gfxQuartzFontCache::MakePlatformFont(con
         nsresult rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
         if (NS_FAILED(rv)) {
             delete userFontData;
             return nsnull;
         }
         
         MacOSFontEntry *newFontEntry = 
             new MacOSFontEntry(uniqueName,
-                               FMGetFontFromATSFontRef(fontRef),
+                               fontRef,
                                w, aProxyEntry->mStretch, 
-                               (PRUint32(aProxyEntry->mItalic) ? 
-                                           FONT_STYLE_ITALIC : 
-                                           FONT_STYLE_NORMAL), 
+                               aProxyEntry->mItalic ?
+                                   FONT_STYLE_ITALIC : FONT_STYLE_NORMAL, 
                                userFontData);
 
         if (!newFontEntry) {
             delete userFontData;
             return nsnull;
         }
 
         // if we succeeded (which should always be the case), return the new font
@@ -1523,46 +834,8 @@ gfxQuartzFontCache::MakePlatformFont(con
         NS_WARNING("invalid font entry for a newly activated font");
         break;
     }
 
     // if we get here, the activation failed (even with possible retries); can't use this font
     return nsnull;
 }
 
-
-void 
-gfxQuartzFontCache::InitLoader()
-{
-    GetFontFamilyList(mFontFamiliesToLoad);
-    mStartIndex = 0;
-    mNumFamilies = mFontFamiliesToLoad.Length();
-}
-
-PRBool 
-gfxQuartzFontCache::RunLoader()
-{
-    PRUint32 i, endIndex = (mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies);
-
-    // for each font family, load in various font info
-    for (i = mStartIndex; i < endIndex; i++) {
-        AddOtherFamilyNameFunctor addOtherNames(this);
-
-        // load the cmap
-        mFontFamiliesToLoad[i]->ReadCMAP();
-
-        // read in other family names
-        mFontFamiliesToLoad[i]->ReadOtherFamilyNames(addOtherNames);
-    }
-
-    mStartIndex += mIncrement;
-    if (mStartIndex < mNumFamilies)
-        return PR_FALSE;
-    return PR_TRUE;
-}
-
-void 
-gfxQuartzFontCache::FinishLoader()
-{
-    mFontFamiliesToLoad.Clear();
-    mNumFamilies = 0;
-}
-
--- a/gfx/thebes/src/gfxPlatform.cpp
+++ b/gfx/thebes/src/gfxPlatform.cpp
@@ -36,27 +36,27 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxPlatform.h"
 
 #if defined(XP_WIN)
 #include "gfxWindowsPlatform.h"
 #elif defined(XP_MACOSX)
 #include "gfxPlatformMac.h"
-#include "gfxQuartzFontCache.h"
 #elif defined(MOZ_WIDGET_GTK2)
 #include "gfxPlatformGtk.h"
 #elif defined(MOZ_WIDGET_QT)
 #include "gfxQtPlatform.h"
 #elif defined(XP_BEOS)
 #include "gfxBeOSPlatform.h"
 #elif defined(XP_OS2)
 #include "gfxOS2Platform.h"
 #endif
 
+#include "gfxPlatformFontList.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 #include "gfxTextRunCache.h"
 #include "gfxTextRunWordCache.h"
 #include "gfxUserFontSet.h"
 
 #include "nsServiceManagerUtils.h"
 #include "nsTArray.h"
@@ -179,20 +179,20 @@ gfxPlatform::Init()
 #elif defined(XP_OS2)
     gPlatform = new gfxOS2Platform;
 #endif
     if (!gPlatform)
         return NS_ERROR_OUT_OF_MEMORY;
 
     nsresult rv;
 
-#if defined(XP_MACOSX)
-    rv = gfxQuartzFontCache::Init();
+#if defined(XP_MACOSX) // temporary, until this is implemented on others
+    rv = gfxPlatformFontList::Init();
     if (NS_FAILED(rv)) {
-        NS_ERROR("Could not initialize gfxQuartzFontCache");
+        NS_ERROR("Could not initialize gfxPlatformFontList");
         Shutdown();
         return rv;
     }
 #endif
 
     rv = gfxFontCache::Init();
     if (NS_FAILED(rv)) {
         NS_ERROR("Could not initialize gfxFontCache");
@@ -229,18 +229,18 @@ 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)
-    gfxQuartzFontCache::Shutdown();
+#if defined(XP_MACOSX) // 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);
     if (prefs)
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/gfxPlatformFontList.cpp
@@ -0,0 +1,458 @@
+/* -*- 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) 2006-2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   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.
+ *
+ * Based in part on sample code provided by Apple Computer, Inc.,
+ * under the following license:
+ *
+ * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "gfxPlatformFontList.h"
+
+#include "nsIPrefService.h"
+#include "nsIPrefBranch2.h"  // for pref changes callback notification
+#include "nsServiceManagerUtils.h"
+#include "nsUnicharUtils.h"
+
+// 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 PRLogModuleInfo *gFontListLog = PR_NewLogModule("fontListLog");
+
+
+gfxPlatformFontList *gfxPlatformFontList::sPlatformFontList = nsnull;
+
+
+class gfxFontListPrefObserver : public nsIObserver {
+public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIOBSERVER
+};
+
+NS_IMPL_ISUPPORTS1(gfxFontListPrefObserver, nsIObserver)
+
+NS_IMETHODIMP
+gfxFontListPrefObserver::Observe(nsISupports     *aSubject,
+                                 const char      *aTopic,
+                                 const PRUnichar *aData)
+{
+    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.
+    gfxPlatformFontList::PlatformFontList()->ClearPrefFonts();
+    return NS_OK;
+}
+
+
+gfxPlatformFontList::gfxPlatformFontList()
+    : mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0)
+{
+    mFontFamilies.Init(100);
+    mOtherFamilyNames.Init(30);
+    mOtherFamilyNamesInitialized = PR_FALSE;
+    mPrefFonts.Init(10);
+
+    // pref changes notification setup
+    gfxFontListPrefObserver *observer = new gfxFontListPrefObserver();
+    if (observer) {
+        nsCOMPtr<nsIPrefBranch2> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
+        if (pref) {
+            pref->AddObserver("font.", observer, PR_FALSE);
+            pref->AddObserver("font.name-list.", observer, PR_FALSE);
+            pref->AddObserver("intl.accept_languages", observer, PR_FALSE);  // hmmmm...
+        } else {
+            delete observer;
+        }
+    }
+}
+
+void
+gfxPlatformFontList::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
+{
+    aResult = aKeyName;
+    ToLowerCase(aResult);
+}
+
+void 
+gfxPlatformFontList::InitOtherFamilyNames()
+{
+    mOtherFamilyNamesInitialized = PR_TRUE;
+
+    // iterate over all font families and read in other family names
+    mFontFamilies.Enumerate(gfxPlatformFontList::InitOtherFamilyNamesProc, this);
+}
+                                                         
+PLDHashOperator PR_CALLBACK
+gfxPlatformFontList::InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
+                                              nsRefPtr<gfxFontFamily>& aFamilyEntry,
+                                              void* userArg)
+{
+    gfxPlatformFontList *fc = static_cast<gfxPlatformFontList*>(userArg);
+    AddOtherFamilyNameFunctor addOtherNames(fc);
+    aFamilyEntry->ReadOtherFamilyNames(addOtherNames);
+    return PL_DHASH_NEXT;
+}
+
+void
+gfxPlatformFontList::ReadOtherFamilyNamesForFamily(const nsAString& aFamilyName)
+{
+    gfxFontFamily *familyEntry = FindFamily(aFamilyName);
+
+    if (familyEntry) {
+        AddOtherFamilyNameFunctor addOtherNames(this);
+        familyEntry->ReadOtherFamilyNames(addOtherNames);
+    }
+}
+
+void
+gfxPlatformFontList::PreloadNamesList()
+{
+    nsAutoTArray<nsString, 10> preloadFonts;
+    gfxFontUtils::GetPrefsFontList("font.preload-names-list", preloadFonts);
+
+    PRUint32 numFonts = preloadFonts.Length();
+    for (PRUint32 i = 0; i < numFonts; i++) {
+        PRBool found;
+        nsAutoString key;
+        GenerateFontListKey(preloadFonts[i], key);
+        
+        // only search canonical names!
+        gfxFontFamily *familyEntry = mFontFamilies.GetWeak(key, &found);
+        if (familyEntry) {
+            AddOtherFamilyNameFunctor addOtherNames(this);
+            familyEntry->ReadOtherFamilyNames(addOtherNames);
+        }
+    }
+
+}
+
+void 
+gfxPlatformFontList::SetFixedPitch(const nsAString& aFamilyName)
+{
+    gfxFontFamily *family = FindFamily(aFamilyName);
+    if (!family) return;
+
+    nsTArray<nsRefPtr<gfxFontEntry> >& fontlist = family->GetFontList();
+
+    PRUint32 i, numFonts = fontlist.Length();
+
+    for (i = 0; i < numFonts; i++) {
+        fontlist[i]->mFixedPitch = 1;
+    }
+}
+
+void
+gfxPlatformFontList::InitBadUnderlineList()
+{
+    nsAutoTArray<nsString, 10> blacklist;
+    gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist);
+    PRUint32 numFonts = blacklist.Length();
+    for (PRUint32 i = 0; i < numFonts; i++) {
+        PRBool found;
+        nsAutoString key;
+        GenerateFontListKey(blacklist[i], key);
+
+        gfxFontFamily *familyEntry = mFontFamilies.GetWeak(key, &found);
+        if (familyEntry)
+            familyEntry->SetBadUnderlineFont(PR_TRUE);
+    }
+}
+
+PRBool 
+gfxPlatformFontList::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
+{
+    gfxFontFamily *family = FindFamily(aFontName);
+    if (family) {
+        aResolvedFontName = family->Name();
+        return PR_TRUE;
+    }
+    return PR_FALSE;
+}
+
+struct FontListData {
+    FontListData(const nsACString& aLangGroup,
+                 const nsACString& aGenericFamily,
+                 nsTArray<nsString>& aListOfFonts) :
+        mLangGroup(aLangGroup), mGenericFamily(aGenericFamily),
+        mListOfFonts(aListOfFonts) {}
+    const nsACString& mLangGroup;
+    const nsACString& mGenericFamily;
+    nsTArray<nsString>& mListOfFonts;
+};
+
+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);
+    return PL_DHASH_NEXT;
+}
+
+void
+gfxPlatformFontList::GetFontList (const nsACString& aLangGroup,
+                                 const nsACString& aGenericFamily,
+                                 nsTArray<nsString>& aListOfFonts)
+{
+    FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
+
+    mFontFamilies.Enumerate(gfxPlatformFontList::HashEnumFuncForFamilies, &data);
+
+    aListOfFonts.Sort();
+    aListOfFonts.Compact();
+}
+
+struct FontFamilyListData {
+    FontFamilyListData(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray) 
+        : mFamilyArray(aFamilyArray)
+    {}
+
+    static PLDHashOperator PR_CALLBACK AppendFamily(nsStringHashKey::KeyType aKey,
+                                                    nsRefPtr<gfxFontFamily>& aFamilyEntry,
+                                                    void *aUserArg)
+    {
+        FontFamilyListData *data = static_cast<FontFamilyListData*>(aUserArg);
+        data->mFamilyArray.AppendElement(aFamilyEntry);
+        return PL_DHASH_NEXT;
+    }
+
+    nsTArray<nsRefPtr<gfxFontFamily> >& mFamilyArray;
+};
+
+void
+gfxPlatformFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
+{
+    FontFamilyListData data(aFamilyArray);
+    mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
+}
+
+gfxFontEntry*  
+gfxPlatformFontList::FindFontForChar(const PRUint32 aCh, gfxFont *aPrevFont)
+{
+    // is codepoint with no matching font? return null immediately
+    if (mCodepointsWithNoFonts.test(aCh)) {
+        return nsnull;
+    }
+
+    // TODO: optimize fallback e.g. by caching lists of fonts to try for a given
+    // unicode range or script
+
+    // try to short-circuit font fallback for U+FFFD, used to represent encoding errors:
+    // just use a platform-specific fallback system font that is guaranteed (or at least
+    // highly likely) to be around, or a cached family from last time U+FFFD was seen.
+    // this helps speed up pages with lots of encoding errors, binary-as-text, etc.
+    if (aCh == 0xFFFD && mReplacementCharFallbackFamily.Length() > 0) {
+        gfxFontEntry* fontEntry = nsnull;
+        PRBool needsBold;  // ignored in the system fallback case
+
+        if (aPrevFont) {
+            fontEntry = FindFontForFamily(mReplacementCharFallbackFamily, aPrevFont->GetStyle(), needsBold);
+        } else {
+            gfxFontStyle normalStyle;
+            fontEntry = FindFontForFamily(mReplacementCharFallbackFamily, &normalStyle, needsBold);
+        }
+
+        if (fontEntry && fontEntry->TestCharacterMap(aCh))
+            return fontEntry;
+    }
+
+    FontSearch data(aCh, aPrevFont);
+
+    // iterate over all font families to find a font that support the character
+    mFontFamilies.Enumerate(gfxPlatformFontList::FindFontForCharProc, &data);
+
+    // no match? add to set of non-matching codepoints
+    if (!data.mBestMatch) {
+        mCodepointsWithNoFonts.set(aCh);
+    } else if (aCh == 0xFFFD) {
+        mReplacementCharFallbackFamily = data.mBestMatch->FamilyName();
+    }
+
+    return data.mBestMatch;
+}
+
+PLDHashOperator PR_CALLBACK 
+gfxPlatformFontList::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<gfxFontFamily>& aFamilyEntry,
+     void *userArg)
+{
+    FontSearch *data = static_cast<FontSearch*>(userArg);
+
+    // evaluate all fonts in this family for a match
+    aFamilyEntry->FindFontForChar(data);
+    return PL_DHASH_NEXT;
+}
+
+gfxFontFamily* 
+gfxPlatformFontList::FindFamily(const nsAString& aFamily)
+{
+    nsAutoString key;
+    gfxFontFamily *familyEntry;
+    PRBool found;
+    GenerateFontListKey(aFamily, key);
+
+    // lookup in canonical (i.e. English) family name list
+    if ((familyEntry = mFontFamilies.GetWeak(key, &found))) {
+        return familyEntry;
+    }
+
+    // lookup in other family names list (mostly localized names)
+    if ((familyEntry = mOtherFamilyNames.GetWeak(key, &found))) {
+        return familyEntry;
+    }
+
+    // name not found and other family names not yet fully initialized so
+    // initialize the rest of the list and try again.  this is done lazily
+    // since reading name table entries is expensive
+    if (!mOtherFamilyNamesInitialized) {
+        InitOtherFamilyNames();
+        if ((familyEntry = mOtherFamilyNames.GetWeak(key, &found))) {
+            return familyEntry;
+        }
+    }
+
+    return nsnull;
+}
+
+gfxFontEntry*
+gfxPlatformFontList::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, PRBool& aNeedsBold)
+{
+    gfxFontFamily *familyEntry = FindFamily(aFamily);
+
+    aNeedsBold = PR_FALSE;
+
+    if (familyEntry)
+        return familyEntry->FindFontForStyle(*aStyle, aNeedsBold);
+
+    return nsnull;
+}
+
+PRBool
+gfxPlatformFontList::GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> > *array)
+{
+    return mPrefFonts.Get(PRUint32(aLangGroup), array);
+}
+
+void
+gfxPlatformFontList::SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> >& array)
+{
+    mPrefFonts.Put(PRUint32(aLangGroup), array);
+}
+
+void 
+gfxPlatformFontList::AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString& aOtherFamilyName)
+{
+    nsAutoString key;
+    PRBool found;
+    GenerateFontListKey(aOtherFamilyName, key);
+
+    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()));
+    }
+}
+
+void 
+gfxPlatformFontList::InitLoader()
+{
+    GetFontFamilyList(mFontFamiliesToLoad);
+    mStartIndex = 0;
+    mNumFamilies = mFontFamiliesToLoad.Length();
+}
+
+PRBool 
+gfxPlatformFontList::RunLoader()
+{
+    PRUint32 i, endIndex = (mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies);
+
+    // for each font family, load in various font info
+    for (i = mStartIndex; i < endIndex; i++) {
+        AddOtherFamilyNameFunctor addOtherNames(this);
+
+        // load the cmap
+        mFontFamiliesToLoad[i]->ReadCMAP();
+
+        // read in other family names
+        mFontFamiliesToLoad[i]->ReadOtherFamilyNames(addOtherNames);
+
+        // check whether the family can be considered "simple" for style matching
+        mFontFamiliesToLoad[i]->CheckForSimpleFamily();
+    }
+
+    mStartIndex += mIncrement;
+    if (mStartIndex < mNumFamilies)
+        return PR_FALSE;
+    return PR_TRUE;
+}
+
+void 
+gfxPlatformFontList::FinishLoader()
+{
+    mFontFamiliesToLoad.Clear();
+    mNumFamilies = 0;
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/gfxPlatformFontList.h
@@ -0,0 +1,206 @@
+/* -*- 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) 2008-2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   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 GFXPLATFORMFONTLIST_H_
+#define GFXPLATFORMFONTLIST_H_
+
+#include "nsDataHashtable.h"
+#include "nsRefPtrHashtable.h"
+
+#include "gfxFontUtils.h"
+#include "gfxFont.h"
+#include "gfxPlatform.h"
+
+// gfxPlatformFontList is an abstract class for the global font list on the system;
+// concrete subclasses for each platform implement the actual interface to the system fonts.
+// This class exists because we cannot rely on the platform font-finding APIs to behave
+// in sensible/similar ways, particularly with rich, complex OpenType families,
+// so we do our own font family/style management here instead.
+
+// Much of this is based on the old gfxQuartzFontCache, but adapted for use on all platforms.
+
+class gfxPlatformFontList : protected gfxFontInfoLoader
+{
+public:
+    static gfxPlatformFontList* PlatformFontList() {
+        return sPlatformFontList;
+    }
+
+    static nsresult Init() {
+        NS_ASSERTION(!sPlatformFontList, "What's this doing here?");
+        sPlatformFontList = gfxPlatform::GetPlatform()->CreatePlatformFontList();
+        if (!sPlatformFontList) return NS_ERROR_OUT_OF_MEMORY;
+        sPlatformFontList->InitFontList();
+        return NS_OK;
+    }
+
+    static void Shutdown() {
+        delete sPlatformFontList;
+        sPlatformFontList = nsnull;
+    }
+
+    void GetFontList (const nsACString& aLangGroup,
+                      const nsACString& aGenericFamily,
+                      nsTArray<nsString>& aListOfFonts);
+
+    virtual PRBool ResolveFontName(const nsAString& aFontName,
+                                   nsAString& aResolvedFontName);
+
+    void UpdateFontList() { InitFontList(); }
+
+    void ClearPrefFonts() { mPrefFonts.Clear(); }
+
+    void GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray);
+
+    gfxFontEntry* FindFontForChar(const PRUint32 aCh, gfxFont *aPrevFont);
+
+    gfxFontFamily* FindFamily(const nsAString& aFamily);
+
+    gfxFontEntry* FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, PRBool& aNeedsBold);
+
+    PRBool GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> > *array);
+    void SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> >& array);
+
+    void AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString& aOtherFamilyName);
+
+    // pure virtual functions, to be provided by concrete subclasses
+
+    // get the system default font
+    virtual gfxFontEntry* GetDefaultFont(const gfxFontStyle* aStyle,
+                                         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)
+    virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *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;
+
+protected:
+    gfxPlatformFontList();
+
+    static gfxPlatformFontList *sPlatformFontList;
+
+    static PLDHashOperator FindFontForCharProc(nsStringHashKey::KeyType aKey,
+                                               nsRefPtr<gfxFontFamily>& aFamilyEntry,
+                                               void* userArg);
+
+    // initialize font lists [pure virtual]
+    virtual void InitFontList() = 0;
+
+    // read secondary family names
+    void ReadOtherFamilyNamesForFamily(const nsAString& aFamilyName);
+
+    // separate initialization for reading in name tables, since this is expensive
+    void InitOtherFamilyNames();
+
+    // commonly used fonts for which the name table should be loaded at startup
+    virtual void PreloadNamesList();
+
+    // initialize the bad underline blacklist from pref.
+    virtual void InitBadUnderlineList();
+
+    // explicitly set fixed-pitch flag for all faces
+    void SetFixedPitch(const nsAString& aFamilyName);
+
+    static PLDHashOperator InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
+                                                    nsRefPtr<gfxFontFamily>& aFamilyEntry,
+                                                    void* userArg);
+
+    void GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult);
+
+    static PLDHashOperator
+        HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
+                                nsRefPtr<gfxFontFamily>& aFamilyEntry,
+                                void* aUserArg);
+
+    // gfxFontInfoLoader overrides, used to load in font cmaps
+    virtual void InitLoader();
+    virtual PRBool RunLoader();
+    virtual void FinishLoader();
+
+    // canonical family name ==> family entry (unique, one name per family entry)
+    nsRefPtrHashtable<nsStringHashKey, gfxFontFamily> mFontFamilies;    
+
+    // other family name ==> family entry (not unique, can have multiple names per 
+    // family entry, only names *other* than the canonical names are stored here)
+    nsRefPtrHashtable<nsStringHashKey, gfxFontFamily> mOtherFamilyNames;    
+
+    // cached pref font lists
+    // maps list of family names ==> array of family entries, one per lang group
+    nsDataHashtable<nsUint32HashKey, nsTArray<nsRefPtr<gfxFontFamily> > > mPrefFonts;
+
+    // when system-wide font lookup fails for a character, cache it to skip future searches
+    gfxSparseBitSet mCodepointsWithNoFonts;
+
+    // the family to use for U+FFFD fallback, to avoid expensive search every time
+    // on pages with lots of problems
+    nsString mReplacementCharFallbackFamily;
+
+    // flag set after InitOtherFamilyNames is called upon first name lookup miss
+    PRPackedBool mOtherFamilyNamesInitialized;
+
+    // data used as part of the font cmap loading process
+    nsTArray<nsRefPtr<gfxFontFamily> > mFontFamiliesToLoad;
+    PRUint32 mStartIndex;
+    PRUint32 mIncrement;
+    PRUint32 mNumFamilies;
+};
+
+
+// helper class for adding other family names back into font cache
+class AddOtherFamilyNameFunctor 
+{
+public:
+    AddOtherFamilyNameFunctor(gfxPlatformFontList *aFontList) :
+        mFontList(aFontList)
+    {}
+
+    void operator() (gfxFontFamily *aFamilyEntry, nsAString& aOtherName) {
+        mFontList->AddOtherFamilyName(aFamilyEntry, aOtherName);
+    }
+
+    gfxPlatformFontList *mFontList;
+};
+
+
+#endif /* GFXPLATFORMFONTLIST_H_ */
--- a/gfx/thebes/src/gfxPlatformMac.cpp
+++ b/gfx/thebes/src/gfxPlatformMac.cpp
@@ -37,17 +37,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxPlatformMac.h"
 
 #include "gfxImageSurface.h"
 #include "gfxQuartzSurface.h"
 #include "gfxQuartzImageSurface.h"
 
-#include "gfxQuartzFontCache.h"
+#include "gfxMacPlatformFontList.h"
 #include "gfxAtsuiFonts.h"
 #include "gfxUserFontSet.h"
 
 #ifdef MOZ_CORETEXT
 #include "gfxCoreTextFonts.h"
 #endif
 
 #include "nsIPrefBranch.h"
@@ -95,16 +95,22 @@ gfxPlatformMac::~gfxPlatformMac()
 #ifdef MOZ_CORETEXT
 #ifndef __LP64__
     if (mUseCoreText)
 #endif
         gfxCoreTextFont::Shutdown();
 #endif
 }
 
+gfxPlatformFontList*
+gfxPlatformMac::CreatePlatformFontList()
+{
+    return new gfxMacPlatformFontList();
+}
+
 already_AddRefed<gfxASurface>
 gfxPlatformMac::CreateOffscreenSurface(const gfxIntSize& size,
                                        gfxASurface::gfxImageFormat imageFormat)
 {
     gfxASurface *newSurface = nsnull;
 
     newSurface = new gfxQuartzSurface(size, imageFormat);
 
@@ -133,29 +139,29 @@ gfxPlatformMac::OptimizeImage(gfxImageSu
 }
 
 nsresult
 gfxPlatformMac::ResolveFontName(const nsAString& aFontName,
                                 FontResolverCallback aCallback,
                                 void *aClosure, PRBool& aAborted)
 {
     nsAutoString resolvedName;
-    if (!gfxQuartzFontCache::SharedFontCache()->
+    if (!gfxPlatformFontList::PlatformFontList()->
              ResolveFontName(aFontName, resolvedName)) {
         aAborted = PR_FALSE;
         return NS_OK;
     }
     aAborted = !(*aCallback)(resolvedName, aClosure);
     return NS_OK;
 }
 
 nsresult
 gfxPlatformMac::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
-    gfxQuartzFontCache::SharedFontCache()->GetStandardFamilyName(aFontName, aFamilyName);
+    gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
     return NS_OK;
 }
 
 gfxFontGroup *
 gfxPlatformMac::CreateFontGroup(const nsAString &aFamilies,
                                 const gfxFontStyle *aStyle,
                                 gfxUserFontSet *aUserFontSet)
 {
@@ -165,30 +171,31 @@ gfxPlatformMac::CreateFontGroup(const ns
 #ifdef MOZ_CORETEXT
     if (mUseCoreText)
         return new gfxCoreTextFontGroup(aFamilies, aStyle, aUserFontSet);
 #endif
     return new gfxAtsuiFontGroup(aFamilies, aStyle, aUserFontSet);
 #endif
 }
 
+// these will move to gfxPlatform once all platforms support the fontlist
 gfxFontEntry* 
 gfxPlatformMac::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                 const nsAString& aFontName)
 {
-    return gfxQuartzFontCache::SharedFontCache()->LookupLocalFont(aProxyEntry, 
-                                                                  aFontName);
+    return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry, 
+                                                                    aFontName);
 }
 
 gfxFontEntry* 
 gfxPlatformMac::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                  nsISupports *aLoader,
                                  const PRUint8 *aFontData, PRUint32 aLength)
 {
-    return gfxQuartzFontCache::SharedFontCache()->MakePlatformFont(aProxyEntry, aFontData, aLength);
+    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");
@@ -204,39 +211,39 @@ gfxPlatformMac::IsFontFormatSupported(ns
     if (aFormatFlags != 0) {
         return PR_FALSE;
     }
 
     // no format hint set, need to look at data
     return PR_TRUE;
 }
 
+// these will also move to gfxPlatform once all platforms support the fontlist
 nsresult
 gfxPlatformMac::GetFontList(const nsACString& aLangGroup,
                             const nsACString& aGenericFamily,
                             nsTArray<nsString>& aListOfFonts)
 {
-    gfxQuartzFontCache::SharedFontCache()->GetFontList(aLangGroup, aGenericFamily, aListOfFonts);
-
+    gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, aGenericFamily, aListOfFonts);
     return NS_OK;
 }
 
 nsresult
 gfxPlatformMac::UpdateFontList()
 {
-    gfxQuartzFontCache::SharedFontCache()->UpdateFontList();
+    gfxPlatformFontList::PlatformFontList()->UpdateFontList();
     return NS_OK;
 }
 
 PRInt32 
 gfxPlatformMac::OSXVersion()
 {
     if (!mOSXVersion) {
         // minor version is not accurate, use gestaltSystemVersionMajor, gestaltSystemVersionMinor, gestaltSystemVersionBugFix for these
-        OSErr err = ::Gestalt(gestaltSystemVersion, (SInt32*) &mOSXVersion);
+        OSErr err = ::Gestalt(gestaltSystemVersion, reinterpret_cast<SInt32*>(&mOSXVersion));
         if (err != noErr) {
             //This should probably be changed when our minimum version changes
             NS_ERROR("Couldn't determine OS X version, assuming 10.4");
             mOSXVersion = MAC_OS_X_VERSION_10_4_HEX;
         }
     }
     return mOSXVersion;
 }
@@ -397,17 +404,17 @@ gfxPlatformMac::GetPlatformCMSOutputProf
 
     qcms_profile *profile = nsnull;
     switch (device.locType) {
 #ifndef __LP64__
     case cmFileBasedProfile: {
         FSRef fsRef;
         if (!FSpMakeFSRef(&device.u.fileLoc.spec, &fsRef)) {
             char path[512];
-            if (!FSRefMakePath(&fsRef, (UInt8*)(path), sizeof(path))) {
+            if (!FSRefMakePath(&fsRef, reinterpret_cast<UInt8*>(path), sizeof(path))) {
                 profile = qcms_profile_from_path(path);
 #ifdef DEBUG_tor
                 if (profile)
                     fprintf(stderr,
                             "ICM profile read from %s fileLoc successfully\n", path);
 #endif
             }
         }
--- a/gfx/thebes/src/gfxTextRunCache.cpp
+++ b/gfx/thebes/src/gfxTextRunCache.cpp
@@ -35,23 +35,27 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxTextRunCache.h"
 #include "gfxTextRunWordCache.h"
 
 #include "nsExpirationTracker.h"
 
+enum {
+    TEXTRUN_TIMEOUT_MS = 10 * 1000 // textruns expire after 3 * this period
+};
+
 /*
- * Cache textruns and expire them after 3*10 seconds of no use
+ * Cache textruns and expire them after a period of no use
  */
 class TextRunExpiringCache : public nsExpirationTracker<gfxTextRun,3> {
 public:
     TextRunExpiringCache()
-        : nsExpirationTracker<gfxTextRun,3>(10*1000) {}
+        : nsExpirationTracker<gfxTextRun,3>(TEXTRUN_TIMEOUT_MS) {}
     ~TextRunExpiringCache() {
         AgeAllGenerations();
     }
 
     // This gets called when the timeout has expired on a gfxTextRun
     virtual void NotifyExpired(gfxTextRun *aTextRun) {
         RemoveObject(aTextRun);
         gfxTextRunWordCache::RemoveTextRun(aTextRun);
--- a/gfx/thebes/src/gfxUserFontSet.cpp
+++ b/gfx/thebes/src/gfxUserFontSet.cpp
@@ -58,62 +58,32 @@ static PRUint64 sFontSetGeneration = LL_
 // TODO: support for unicode ranges not yet implemented
 
 gfxProxyFontEntry::gfxProxyFontEntry(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, 
              gfxMixedFontFamily *aFamily,
              PRUint32 aWeight, 
              PRUint32 aStretch, 
              PRUint32 aItalicStyle, 
              gfxSparseBitSet *aUnicodeRanges)
-    : gfxFontEntry(NS_LITERAL_STRING("Proxy")), mIsLoading(PR_FALSE),
-      mFamily(aFamily)
+    : gfxFontEntry(NS_LITERAL_STRING("Proxy"), aFamily), mIsLoading(PR_FALSE)
 {
     mIsProxy = PR_TRUE;
     mSrcList = aFontFaceSrcList;
     mSrcIndex = 0;
     mWeight = aWeight;
     mStretch = aStretch;
     mItalic = (aItalicStyle & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
     mIsUserFont = PR_TRUE;
 }
 
 gfxProxyFontEntry::~gfxProxyFontEntry()
 {
 
 }
 
-
-PRBool
-gfxMixedFontFamily::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], 
-                                        const gfxFontStyle& aFontStyle)
-{
-    PRBool italic = (aFontStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
-    PRBool matchesSomething;
-
-    for (PRUint32 j = 0; j < 2; j++) {
-        matchesSomething = PR_FALSE;
-        PRUint32 numFonts = mAvailableFonts.Length();
-        // build up an array of weights that match the italicness we're looking for
-        for (PRUint32 i = 0; i < numFonts; i++) {
-            gfxFontEntry *fe = mAvailableFonts[i];
-            PRUint32 weight = fe->mWeight/100;
-            if (fe->mItalic == italic) {
-                aFontsForWeights[weight] = fe;
-                matchesSomething = PR_TRUE;
-            }
-        }
-        if (matchesSomething)
-            break;
-        italic = !italic;
-    }
-
-    return matchesSomething;
-}
-
-
 gfxUserFontSet::gfxUserFontSet()
 {
     mFontFamilies.Init(5);
     IncrementGeneration();
 }
 
 gfxUserFontSet::~gfxUserFontSet()
 {
@@ -214,17 +184,17 @@ gfxUserFontSet::OnLoadComplete(gfxFontEn
     gfxProxyFontEntry *pe = static_cast<gfxProxyFontEntry*> (aFontToLoad);
 
     // download successful, make platform font using font data
     if (NS_SUCCEEDED(aDownloadStatus)) {
         gfxFontEntry *fe = 
             gfxPlatform::GetPlatform()->MakePlatformFont(pe, aLoader,
                                                          aFontData, aLength);
         if (fe) {
-            pe->mFamily->ReplaceFontEntry(pe, fe);
+            static_cast<gfxMixedFontFamily*>(pe->mFamily)->ReplaceFontEntry(pe, fe);
             IncrementGeneration();
 #ifdef PR_LOGGING
             if (LOG_ENABLED()) {
                 nsCAutoString fontURI;
                 pe->mSrcList[pe->mSrcIndex].mURI->GetSpec(fontURI);
 
                 LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n", 
                      this, pe->mSrcIndex, fontURI.get(), 
@@ -297,17 +267,17 @@ gfxUserFontSet::LoadNext(gfxProxyFontEnt
                 gfxPlatform::GetPlatform()->LookupLocalFont(aProxyEntry,
                                                             currSrc.mLocalName);
             if (fe) {
                 LOG(("userfonts (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n", 
                      this, aProxyEntry->mSrcIndex, 
                      NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(), 
                      NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get(), 
                      PRUint32(mGeneration)));
-                aProxyEntry->mFamily->ReplaceFontEntry(aProxyEntry, fe);
+                static_cast<gfxMixedFontFamily*>(aProxyEntry->mFamily)->ReplaceFontEntry(aProxyEntry, fe);
                 return STATUS_LOADED;
             } else {
                 LOG(("userfonts (%p) [src %d] failed local: (%s) for (%s)\n", 
                      this, aProxyEntry->mSrcIndex, 
                      NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(), 
                      NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get()));            
             }
         } 
@@ -356,19 +326,19 @@ gfxUserFontSet::LoadNext(gfxProxyFontEnt
 
         aProxyEntry->mSrcIndex++;
     }
 
     // all src's failed, remove this face
     LOG(("userfonts (%p) failed all src for (%s)\n", 
                this, NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get()));            
 
-    gfxMixedFontFamily *family = aProxyEntry->mFamily;
+    gfxMixedFontFamily *family = static_cast<gfxMixedFontFamily*>(aProxyEntry->mFamily);
 
-    aProxyEntry->mFamily->RemoveFontEntry(aProxyEntry);
+    family->RemoveFontEntry(aProxyEntry);
 
     // no more faces?  remove the entire family
     if (family->mAvailableFonts.Length() == 0) {
         LOG(("userfonts (%p) failed all faces, remove family (%s)\n", 
              this, NS_ConvertUTF16toUTF8(family->Name()).get()));            
         RemoveFamily(family->Name());
     }
 
--- a/gfx/thebes/src/gfxWindowsFonts.cpp
+++ b/gfx/thebes/src/gfxWindowsFonts.cpp
@@ -192,47 +192,47 @@ FontFamily::FamilyAddStylesProc(const EN
 
     // 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->mVariations.Length(); ++i) {
-        fe = ff->mVariations[i];
+    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->mVariations.RemoveElementAt(i);
+            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->mVariations.Length(); ++i) {
-        fe = ff->mVariations[i];
+    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->mVariations.AppendElement(fe);
+    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 &&
@@ -277,85 +277,81 @@ FontFamily::FindStyleVariations()
     logFont.lfFaceName[l] = 0;
 
     FamilyAddStyleProcData faspd;
     faspd.dc = hdc;
     faspd.ff = this;
 
     EnumFontFamiliesExW(hdc, &logFont, (FONTENUMPROCW)FontFamily::FamilyAddStylesProc, (LPARAM)&faspd, 0);
 #ifdef DEBUG
-    if (mVariations.Length() == 0) {
+    if (mAvailableFonts.Length() == 0) {
         char msgBuf[256];
         (void)sprintf(msgBuf, "no styles available in family \"%s\"",
                       NS_ConvertUTF16toUTF8(mName).get());
-        NS_ASSERTION(mVariations.Length() != 0, msgBuf);
+        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 < mVariations.Length(); i++) {
-        FontEntry *fe = mVariations[i];
+    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;
-        mVariations.AppendElement(newEntry);
+        mAvailableFonts.AppendElement(newEntry);
     }
     if (darkestNonItalic && darkestNonItalic->mWeight < 600) {
         FontEntry *newEntry = new FontEntry(*darkestNonItalic);
         newEntry->mWeight = 600;
-        mVariations.AppendElement(newEntry);
+        mAvailableFonts.AppendElement(newEntry);
     }
 }
 
 
 FontEntry *
 FontFamily::FindFontEntry(const gfxFontStyle& aFontStyle)
 {
     PRBool needsBold;
     return static_cast<FontEntry*> (FindFontForStyle(aFontStyle, needsBold));
 }
 
 PRBool
-FontFamily::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], const gfxFontStyle& aFontStyle)
+FontFamily::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
+                                PRBool anItalic, PRInt16 aStretch)
 {
-    if (!mHasStyles)
-        FindStyleVariations();
-
-    PRBool italic = (aFontStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
-    PRBool matchesSomething;
+    PRBool matchesSomething = PR_FALSE;
 
     for (PRUint32 j = 0; j < 2; j++) {
-        matchesSomething = PR_FALSE;
         // build up an array of weights that match the italicness we're looking for
-        for (PRUint32 i = 0; i < mVariations.Length(); i++) {
-            FontEntry *fe = mVariations[i];
+        for (PRUint32 i = 0; i < mAvailableFonts.Length(); i++) {
+            gfxFontEntry *fe = mAvailableFonts[i];
             const PRUint8 weight = (fe->mWeight / 100);
-            if (fe->mItalic == italic) {
+            if (fe->mItalic == anItalic) {
                 aFontsForWeights[weight] = fe;
                 matchesSomething = PR_TRUE;
             }
         }
         if (matchesSomething)
             break;
-        italic = !italic;
+        anItalic = !anItalic;
     }
 
     return matchesSomething;
 }
 
 // from t2embapi.h, included in Platform SDK 6.1 but not 6.0
 
 #ifndef __t2embapi__
--- a/gfx/thebes/src/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/src/gfxWindowsPlatform.cpp
@@ -304,17 +304,18 @@ void gfxWindowsPlatform::AppendFacesFrom
             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->mFaces.AppendElement(fe);
+                ff->mAvailableFonts.AppendElement(fe);
+                ff->SetHasStyles(PR_TRUE);
             }
         }
         FT_Done_Face(dummy);
     }
 }
 
 void
 gfxWindowsPlatform::FindFonts()
@@ -597,36 +598,26 @@ gfxWindowsPlatform::FontResolveProc(cons
     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.
 }
 
-struct FontSearch {
-    FontSearch(PRUint32 aCh, gfxFont *aFont) :
-        ch(aCh), fontToMatch(aFont), matchRank(-1) {
-    }
-    PRUint32 ch;
-    nsRefPtr<gfxFont> fontToMatch;
-    PRInt32 matchRank;
-    nsRefPtr<FontEntry> bestMatch;
-};
-
 PLDHashOperator
 gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
                                         nsRefPtr<FontFamily>& aFontFamily,
                                         void* userArg)
 {
     FontSearch *data = (FontSearch*)userArg;
 
-    const PRUint32 ch = data->ch;
+    const PRUint32 ch = data->mCh;
 
-    nsRefPtr<FontEntry> fe = aFontFamily->FindFontEntry(*data->fontToMatch->GetStyle());
+    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;
 
     PRInt32 rank = 0;
 
 #ifndef MOZ_FT2_FONTS
     // skip over non-unicode and bitmap fonts and fonts that don't have
@@ -634,43 +625,43 @@ gfxWindowsPlatform::FindFontForCharProc(
     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->fontToMatch->GetStyle()->langGroup))
+    if (fe->SupportsLangGroup(data->mFontToMatch->GetStyle()->langGroup))
         rank += 2;
 
-    FontEntry* mfe = static_cast<FontEntry*>(data->fontToMatch->GetFontEntry());
+    FontEntry* mfe = static_cast<FontEntry*>(data->mFontToMatch->GetFontEntry());
 
     if (fe->mWindowsFamily == mfe->mWindowsFamily)
         rank += 3;
     if (fe->mWindowsPitch == mfe->mWindowsPitch)
         rank += 3;
 #endif
     /* italic */
-    const PRBool italic = (data->fontToMatch->GetStyle()->style != FONT_STYLE_NORMAL);
+    const PRBool italic = (data->mFontToMatch->GetStyle()->style != FONT_STYLE_NORMAL);
     if (fe->mItalic != italic)
         rank += 3;
 
     /* weight */
     PRInt8 baseWeight, weightDistance;
-    data->fontToMatch->GetStyle()->ComputeWeightAndOffset(&baseWeight, &weightDistance);
+    data->mFontToMatch->GetStyle()->ComputeWeightAndOffset(&baseWeight, &weightDistance);
     if (fe->mWeight == (baseWeight * 100) + (weightDistance * 100))
         rank += 2;
-    else if (fe->mWeight == data->fontToMatch->GetFontEntry()->mWeight)
+    else if (fe->mWeight == data->mFontToMatch->GetFontEntry()->mWeight)
         rank += 1;
 
-    if (rank > data->matchRank ||
-        (rank == data->matchRank && Compare(fe->Name(), data->bestMatch->Name()) > 0)) {
-        data->bestMatch = fe;
-        data->matchRank = rank;
+    if (rank > data->mMatchRank ||
+        (rank == data->mMatchRank && Compare(fe->Name(), data->mBestMatch->Name()) > 0)) {
+        data->mBestMatch = fe;
+        data->mMatchRank = rank;
     }
 
     return PL_DHASH_NEXT;
 }
 
 already_AddRefed<gfxFont>
 gfxWindowsPlatform::FindFontForChar(PRUint32 aCh, gfxFont *aFont)
 {
@@ -679,26 +670,27 @@ gfxWindowsPlatform::FindFontForChar(PRUi
         return nsnull;
     }
 
     FontSearch data(aCh, aFont);
 
     // find fonts that support the character
     mFonts.Enumerate(gfxWindowsPlatform::FindFontForCharProc, &data);
 
-    if (data.bestMatch) {
+    if (data.mBestMatch) {
 #ifdef MOZ_FT2_FONTS
         nsRefPtr<gfxFT2Font> font =
-            gfxFT2Font::GetOrMakeFont(data.bestMatch->mName, 
+            gfxFT2Font::GetOrMakeFont(data.mBestMatch->mName, 
                                       aFont->GetStyle()); 
             gfxFont* ret = font.forget().get();
             return already_AddRefed<gfxFont>(ret);
 #else
         nsRefPtr<gfxWindowsFont> font =
-            gfxWindowsFont::GetOrMakeFont(data.bestMatch, aFont->GetStyle());
+            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
@@ -777,23 +769,23 @@ FindFullName(nsStringHashKey::KeyType aK
     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->mFaces.Length();
+        int len = aFontFamily->mAvailableFonts.Length();
         int index = 0;
         for (; index < len && 
-                 !aFontFamily->mFaces[index]->Name().Equals(data->mFullName); index++);
+                 !aFontFamily->mAvailableFonts[index]->Name().Equals(data->mFullName); index++);
         if (index < len) {
             data->mFound = PR_TRUE;
-            data->mFontEntry = aFontFamily->mFaces[index];
+            data->mFontEntry = aFontFamily->mAvailableFonts[index];
         }
 #else
         HDC hdc;
         
         if (!data->mDC) {
             data->mDC= GetDC(nsnull);
             SetGraphicsMode(data->mDC, GM_ADVANCED);
         }