Bug 280443 p3 - use fontlist struct in gfx. r=roc,fredw
authorJohn Daggett <jdaggett@mozilla.com>
Fri, 06 Jun 2014 15:09:23 +0900
changeset 206259 e39cfafa8517ce7810685f6a99fce6fad919d5f4
parent 206258 014f475ca0ec0334c7f29e9240a958d626acb521
child 206260 a73b48626bb5c404a6519c43b5c4e5d7829aa5f0
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, fredw
bugs280443
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 280443 p3 - use fontlist struct in gfx. r=roc,fredw
content/canvas/src/CanvasRenderingContext2D.cpp
gfx/src/nsFont.cpp
gfx/src/nsFont.h
gfx/src/nsFontMetrics.cpp
gfx/thebes/gfxAndroidPlatform.cpp
gfx/thebes/gfxAndroidPlatform.h
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
gfx/thebes/gfxFT2FontList.cpp
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
gfx/thebes/gfxFontUtils.cpp
gfx/thebes/gfxFontUtils.h
gfx/thebes/gfxFontconfigUtils.cpp
gfx/thebes/gfxFontconfigUtils.h
gfx/thebes/gfxGDIFontList.cpp
gfx/thebes/gfxGDIFontList.h
gfx/thebes/gfxPangoFonts.cpp
gfx/thebes/gfxPangoFonts.h
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxPlatformFontList.h
gfx/thebes/gfxPlatformGtk.cpp
gfx/thebes/gfxPlatformGtk.h
gfx/thebes/gfxPlatformMac.cpp
gfx/thebes/gfxPlatformMac.h
gfx/thebes/gfxQtPlatform.cpp
gfx/thebes/gfxQtPlatform.h
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/base/nsPresShell.cpp
layout/mathml/nsMathMLChar.cpp
layout/mathml/nsMathMLChar.h
layout/style/nsCSSValue.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -2316,17 +2316,17 @@ CanvasRenderingContext2D::SetFont(const 
                      printerFont,
                      fontStyle->mFont.variant == NS_STYLE_FONT_VARIANT_SMALL_CAPS,
                      fontStyle->mFont.languageOverride);
 
   fontStyle->mFont.AddFontFeaturesToStyle(&style);
 
   nsPresContext *c = presShell->GetPresContext();
   CurrentState().fontGroup =
-      gfxPlatform::GetPlatform()->CreateFontGroup(fontStyle->mFont.name,
+      gfxPlatform::GetPlatform()->CreateFontGroup(fontStyle->mFont.fontlist,
                                                   &style,
                                                   c->GetUserFontSet());
   NS_ASSERTION(CurrentState().fontGroup, "Could not get font group");
   CurrentState().fontGroup->SetTextPerfMetrics(c->GetTextPerfMetrics());
 
   // The font getter is required to be reserialized based on what we
   // parsed (including having line-height removed).  (Older drafts of
   // the spec required font sizes be converted to pixels, but that no
@@ -2993,17 +2993,17 @@ gfxFontGroup *CanvasRenderingContext2D::
     ErrorResult err;
     NS_NAMED_LITERAL_STRING(kDefaultFontStyle, "10px sans-serif");
     static float kDefaultFontSize = 10.0;
     SetFont(kDefaultFontStyle, err);
     if (err.Failed()) {
       gfxFontStyle style;
       style.size = kDefaultFontSize;
       CurrentState().fontGroup =
-        gfxPlatform::GetPlatform()->CreateFontGroup(NS_LITERAL_STRING("sans-serif"),
+        gfxPlatform::GetPlatform()->CreateFontGroup(FontFamilyList(eFamily_sans_serif),
                                                     &style,
                                                     nullptr);
       if (CurrentState().fontGroup) {
         CurrentState().font = kDefaultFontStyle;
 
         nsIPresShell* presShell = GetPresShell();
         if (presShell) {
           CurrentState().fontGroup->SetTextPerfMetrics(
--- a/gfx/src/nsFont.cpp
+++ b/gfx/src/nsFont.cpp
@@ -11,70 +11,65 @@
 #include "nsCRT.h"                      // for nsCRT
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupports.h"
 #include "nsUnicharUtils.h"
 #include "nscore.h"                     // for char16_t
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/gfx/2D.h"
 
-nsFont::nsFont(const char* aName, uint8_t aStyle, uint8_t aVariant,
-               uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
-               nscoord aSize)
+using namespace mozilla;
+
+nsFont::nsFont(const FontFamilyList& aFontlist, uint8_t aStyle,
+               uint8_t aVariant, uint16_t aWeight, int16_t aStretch,
+               uint8_t aDecoration, nscoord aSize)
+  : fontlist(aFontlist)
 {
-  NS_ASSERTION(aName && IsASCII(nsDependentCString(aName)),
-               "Must only pass ASCII names here");
-  name.AssignASCII(aName);
+  Init();
   style = aStyle;
-  systemFont = false;
   variant = aVariant;
   weight = aWeight;
   stretch = aStretch;
   decorations = aDecoration;
-  smoothing = NS_FONT_SMOOTHING_AUTO;
   size = aSize;
-  sizeAdjust = 0.0;
-  kerning = NS_FONT_KERNING_AUTO;
-  synthesis = NS_FONT_SYNTHESIS_WEIGHT | NS_FONT_SYNTHESIS_STYLE;
-
-  variantAlternates = 0;
-  variantCaps = NS_FONT_VARIANT_CAPS_NORMAL;
-  variantEastAsian = 0;
-  variantLigatures = 0;
-  variantNumeric = 0;
-  variantPosition = NS_FONT_VARIANT_POSITION_NORMAL;
 }
 
-nsFont::nsFont(const nsSubstring& aName, uint8_t aStyle, uint8_t aVariant,
+nsFont::nsFont(FontFamilyType aGenericType, uint8_t aStyle, uint8_t aVariant,
                uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
                nscoord aSize)
-  : name(aName)
+  : fontlist(aGenericType)
 {
+  Init();
   style = aStyle;
-  systemFont = false;
   variant = aVariant;
   weight = aWeight;
   stretch = aStretch;
   decorations = aDecoration;
+  size = aSize;
+}
+
+void
+nsFont::Init()
+{
+  systemFont = false;
   smoothing = NS_FONT_SMOOTHING_AUTO;
-  size = aSize;
   sizeAdjust = 0.0;
   kerning = NS_FONT_KERNING_AUTO;
   synthesis = NS_FONT_SYNTHESIS_WEIGHT | NS_FONT_SYNTHESIS_STYLE;
 
   variantAlternates = 0;
   variantCaps = NS_FONT_VARIANT_CAPS_NORMAL;
   variantEastAsian = 0;
   variantLigatures = 0;
   variantNumeric = 0;
   variantPosition = NS_FONT_VARIANT_POSITION_NORMAL;
 }
 
 nsFont::nsFont(const nsFont& aOther)
-  : name(aOther.name)
+  : fontlist(aOther.fontlist)
 {
   style = aOther.style;
   systemFont = aOther.systemFont;
   variant = aOther.variant;
   weight = aOther.weight;
   stretch = aOther.stretch;
   decorations = aOther.decorations;
   smoothing = aOther.smoothing;
@@ -105,17 +100,17 @@ nsFont::~nsFont()
 bool nsFont::BaseEquals(const nsFont& aOther) const
 {
   if ((style == aOther.style) &&
       (systemFont == aOther.systemFont) &&
       (weight == aOther.weight) &&
       (stretch == aOther.stretch) &&
       (size == aOther.size) &&
       (sizeAdjust == aOther.sizeAdjust) &&
-      name.Equals(aOther.name, nsCaseInsensitiveStringComparator()) &&
+      (fontlist == aOther.fontlist) &&
       (kerning == aOther.kerning) &&
       (synthesis == aOther.synthesis) &&
       (fontFeatureSettings == aOther.fontFeatureSettings) &&
       (languageOverride == aOther.languageOverride) &&
       (variant == aOther.variant) &&
       (variantAlternates == aOther.variantAlternates) &&
       (variantCaps == aOther.variantCaps) &&
       (variantEastAsian == aOther.variantEastAsian) &&
@@ -136,17 +131,17 @@ bool nsFont::Equals(const nsFont& aOther
       (decorations == aOther.decorations)) {
     return true;
   }
   return false;
 }
 
 nsFont& nsFont::operator=(const nsFont& aOther)
 {
-  name = aOther.name;
+  fontlist = aOther.fontlist;
   style = aOther.style;
   systemFont = aOther.systemFont;
   variant = aOther.variant;
   weight = aOther.weight;
   stretch = aOther.stretch;
   decorations = aOther.decorations;
   smoothing = aOther.smoothing;
   size = aOther.size;
@@ -169,78 +164,16 @@ nsFont& nsFont::operator=(const nsFont& 
 void
 nsFont::CopyAlternates(const nsFont& aOther)
 {
   variantAlternates = aOther.variantAlternates;
   alternateValues = aOther.alternateValues;
   featureValueLookup = aOther.featureValueLookup;
 }
 
-static bool IsGenericFontFamily(const nsString& aFamily)
-{
-  uint8_t generic;
-  nsFont::GetGenericID(aFamily, &generic);
-  return generic != kGenericFont_NONE;
-}
-
-const char16_t kSingleQuote  = char16_t('\'');
-const char16_t kDoubleQuote  = char16_t('\"');
-const char16_t kComma        = char16_t(',');
-
-bool nsFont::EnumerateFamilies(nsFontFamilyEnumFunc aFunc, void* aData) const
-{
-  const char16_t *p, *p_end;
-  name.BeginReading(p);
-  name.EndReading(p_end);
-  nsAutoString family;
-
-  while (p < p_end) {
-    while (nsCRT::IsAsciiSpace(*p))
-      if (++p == p_end)
-        return true;
-
-    bool generic;
-    if (*p == kSingleQuote || *p == kDoubleQuote) {
-      // quoted font family
-      char16_t quoteMark = *p;
-      if (++p == p_end)
-        return true;
-      const char16_t *nameStart = p;
-
-      // XXX What about CSS character escapes?
-      while (*p != quoteMark)
-        if (++p == p_end)
-          return true;
-
-      family = Substring(nameStart, p);
-      generic = false;
-
-      while (++p != p_end && *p != kComma)
-        /* nothing */ ;
-
-    } else {
-      // unquoted font family
-      const char16_t *nameStart = p;
-      while (++p != p_end && *p != kComma)
-        /* nothing */ ;
-
-      family = Substring(nameStart, p);
-      family.CompressWhitespace(false, true);
-      generic = IsGenericFontFamily(family);
-    }
-
-    if (!family.IsEmpty() && !(*aFunc)(family, generic, aData))
-      return false;
-
-    ++p; // may advance past p_end
-  }
-
-  return true;
-}
-
 // mapping from bitflag to font feature tag/value pair
 //
 // these need to be kept in sync with the constants listed
 // in gfxFontConstants.h (e.g. NS_FONT_VARIANT_EAST_ASIAN_JIS78)
 
 // NS_FONT_VARIANT_EAST_ASIAN_xxx values
 const gfxFontFeature eastAsianDefaults[] = {
   { TRUETYPE_TAG('j','p','7','8'), 1 },
@@ -444,31 +377,8 @@ void nsFont::AddFontFeaturesToStyle(gfxF
   // add in features from font-feature-settings
   aStyle->featureSettings.AppendElements(fontFeatureSettings);
 
   // enable grayscale antialiasing for text
   if (smoothing == NS_FONT_SMOOTHING_GRAYSCALE) {
     aStyle->useGrayscaleAntialiasing = true;
   }
 }
-
-static bool FontEnumCallback(const nsString& aFamily, bool aGeneric, void *aData)
-{
-  *((nsString*)aData) = aFamily;
-  return false;
-}
-
-void nsFont::GetFirstFamily(nsString& aFamily) const
-{
-  EnumerateFamilies(FontEnumCallback, &aFamily);
-}
-
-/*static*/
-void nsFont::GetGenericID(const nsString& aGeneric, uint8_t* aID)
-{
-  *aID = kGenericFont_NONE;
-  if (aGeneric.LowerCaseEqualsLiteral("-moz-fixed"))      *aID = kGenericFont_moz_fixed;
-  else if (aGeneric.LowerCaseEqualsLiteral("serif"))      *aID = kGenericFont_serif;
-  else if (aGeneric.LowerCaseEqualsLiteral("sans-serif")) *aID = kGenericFont_sans_serif;
-  else if (aGeneric.LowerCaseEqualsLiteral("cursive"))    *aID = kGenericFont_cursive;
-  else if (aGeneric.LowerCaseEqualsLiteral("fantasy"))    *aID = kGenericFont_fantasy;
-  else if (aGeneric.LowerCaseEqualsLiteral("monospace"))  *aID = kGenericFont_monospace;
-}
--- a/gfx/src/nsFont.h
+++ b/gfx/src/nsFont.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsFont_h___
 #define nsFont_h___
 
 #include <stdint.h>                     // for uint8_t, uint16_t
 #include <sys/types.h>                  // for int16_t
 #include "gfxCore.h"                    // for NS_GFX
+#include "gfxFontFamilyList.h"
 #include "gfxFontFeatures.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCoord.h"                    // for nscoord
 #include "nsStringFwd.h"                // for nsSubstring
 #include "nsString.h"               // for nsString
 #include "nsTArray.h"                   // for nsTArray
 
 struct gfxFontStyle;
@@ -35,18 +36,19 @@ const uint8_t kGenericFont_moz_fixed    
 const uint8_t kGenericFont_serif        = 0x02;
 const uint8_t kGenericFont_sans_serif   = 0x04;
 const uint8_t kGenericFont_monospace    = 0x08;
 const uint8_t kGenericFont_cursive      = 0x10;
 const uint8_t kGenericFont_fantasy      = 0x20;
 
 // Font structure.
 struct NS_GFX nsFont {
-  // The family name of the font
-  nsString name;
+
+  // list of font families, either named or generic
+  mozilla::FontFamilyList fontlist;
 
   // The style of font (normal, italic, oblique; see gfxFontConstants.h)
   uint8_t style;
 
   // Force this font to not be considered a 'generic' font, even if
   // the name is the same as a CSS generic font family.
   bool systemFont;
 
@@ -107,23 +109,23 @@ struct NS_GFX nsFont {
   // Font features from CSS font-feature-settings
   nsTArray<gfxFontFeature> fontFeatureSettings;
 
   // Language system tag, to override document language;
   // this is an OpenType "language system" tag represented as a 32-bit integer
   // (see http://www.microsoft.com/typography/otspec/languagetags.htm).
   nsString languageOverride;
 
-  // Initialize the font struct with an ASCII name
-  nsFont(const char* aName, uint8_t aStyle, uint8_t aVariant,
-         uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
-         nscoord aSize);
+  // initialize the font with a fontlist
+  nsFont(const mozilla::FontFamilyList& aFontlist, uint8_t aStyle,
+         uint8_t aVariant, uint16_t aWeight, int16_t aStretch,
+         uint8_t aDecoration, nscoord aSize);
 
-  // Initialize the font struct with a (potentially) unicode name
-  nsFont(const nsSubstring& aName, uint8_t aStyle, uint8_t aVariant,
+  // initialize the font with a single generic
+  nsFont(mozilla::FontFamilyType aGenericType, uint8_t aStyle, uint8_t aVariant,
          uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
          nscoord aSize);
 
   // Make a copy of the given font
   nsFont(const nsFont& aFont);
 
   nsFont();
   ~nsFont();
@@ -138,25 +140,18 @@ struct NS_GFX nsFont {
 
   nsFont& operator=(const nsFont& aOther);
 
   void CopyAlternates(const nsFont& aOther);
 
   // Add featureSettings into style
   void AddFontFeaturesToStyle(gfxFontStyle *aStyle) const;
 
-  // Utility method to interpret name string
-  // enumerates all families specified by this font only
-  // returns true if completed, false if stopped
-  // enclosing quotes will be removed, and whitespace compressed (as needed)
-  bool EnumerateFamilies(nsFontFamilyEnumFunc aFunc, void* aData) const;
-  void GetFirstFamily(nsString& aFamily) const;
-
-  // Utility method to return the ID of a generic font
-  static void GetGenericID(const nsString& aGeneric, uint8_t* aID);
+protected:
+  void Init(); // helper method for initialization
 };
 
 #define NS_FONT_VARIANT_NORMAL            0
 #define NS_FONT_VARIANT_SMALL_CAPS        1
 
 #define NS_FONT_DECORATION_NONE           0x0
 #define NS_FONT_DECORATION_UNDERLINE      0x1
 #define NS_FONT_DECORATION_OVERLINE       0x2
--- a/gfx/src/nsFontMetrics.cpp
+++ b/gfx/src/nsFontMetrics.cpp
@@ -123,17 +123,17 @@ nsFontMetrics::Init(const nsFont& aFont,
                        aFont.systemFont,
                        mDeviceContext->IsPrinterSurface(),
                        aFont.variant == NS_STYLE_FONT_VARIANT_SMALL_CAPS,
                        aFont.languageOverride);
 
     aFont.AddFontFeaturesToStyle(&style);
 
     mFontGroup = gfxPlatform::GetPlatform()->
-        CreateFontGroup(aFont.name, &style, aUserFontSet);
+        CreateFontGroup(aFont.fontlist, &style, aUserFontSet);
     mFontGroup->SetTextPerfMetrics(aTextPerf);
     if (mFontGroup->FontListLength() < 1)
         return NS_ERROR_UNEXPECTED;
 
     return NS_OK;
 }
 
 void
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -243,32 +243,16 @@ gfxAndroidPlatform::GetFontList(Infallib
 nsresult
 gfxAndroidPlatform::UpdateFontList()
 {
     gfxPlatformFontList::PlatformFontList()->UpdateFontList();
     return NS_OK;
 }
 
 nsresult
-gfxAndroidPlatform::ResolveFontName(const nsAString& aFontName,
-                                    FontResolverCallback aCallback,
-                                    void *aClosure,
-                                    bool& aAborted)
-{
-    nsAutoString resolvedName;
-    if (!gfxPlatformFontList::PlatformFontList()->
-             ResolveFontName(aFontName, resolvedName)) {
-        aAborted = false;
-        return NS_OK;
-    }
-    aAborted = !(*aCallback)(resolvedName, aClosure);
-    return NS_OK;
-}
-
-nsresult
 gfxAndroidPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
     gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
     return NS_OK;
 }
 
 gfxPlatformFontList*
 gfxAndroidPlatform::CreatePlatformFontList()
@@ -300,21 +284,21 @@ gfxAndroidPlatform::IsFontFormatSupporte
         return false;
     }
 
     // no format hint set, need to look at data
     return true;
 }
 
 gfxFontGroup *
-gfxAndroidPlatform::CreateFontGroup(const nsAString &aFamilies,
-                               const gfxFontStyle *aStyle,
-                               gfxUserFontSet* aUserFontSet)
+gfxAndroidPlatform::CreateFontGroup(const FontFamilyList& aFontFamilyList,
+                                    const gfxFontStyle *aStyle,
+                                    gfxUserFontSet* aUserFontSet)
 {
-    return new gfxFontGroup(aFamilies, aStyle, aUserFontSet);
+    return new gfxFontGroup(aFontFamilyList, aStyle, aUserFontSet);
 }
 
 FT_Library
 gfxAndroidPlatform::GetFTLibrary()
 {
     return gPlatformFTLibrary;
 }
 
--- a/gfx/thebes/gfxAndroidPlatform.h
+++ b/gfx/thebes/gfxAndroidPlatform.h
@@ -57,26 +57,23 @@ public:
                                         nsTArray<const char*>& aFontList);
 
     virtual nsresult GetFontList(nsIAtom *aLangGroup,
                                  const nsACString& aGenericFamily,
                                  nsTArray<nsString>& aListOfFonts);
 
     virtual nsresult UpdateFontList();
 
-    virtual nsresult ResolveFontName(const nsAString& aFontName,
-                                     FontResolverCallback aCallback,
-                                     void *aClosure, bool& aAborted);
-
     virtual nsresult GetStandardFamilyName(const nsAString& aFontName,
                                            nsAString& aFamilyName);
 
-    virtual gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
-                                          const gfxFontStyle *aStyle,
-                                          gfxUserFontSet* aUserFontSet);
+    virtual gfxFontGroup*
+    CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
+                    const gfxFontStyle *aStyle,
+                    gfxUserFontSet* aUserFontSet);
 
     virtual bool FontHintingEnabled() MOZ_OVERRIDE;
     virtual bool RequiresLinearZoom() MOZ_OVERRIDE;
 
     FT_Library GetFTLibrary();
 
     virtual int GetScreenDepth() const;
 
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -723,29 +723,31 @@ gfxDWriteFontList::gfxDWriteFontList()
 //   Arial to avoid this.
 
 gfxFontFamily *
 gfxDWriteFontList::GetDefaultFont(const gfxFontStyle *aStyle)
 {
     nsAutoString resolvedName;
 
     // try Arial first
-    if (ResolveFontName(NS_LITERAL_STRING("Arial"), resolvedName)) {
-        return FindFamily(resolvedName);
+    gfxFontFamily *ff;
+    if (ff = FindFamily(NS_LITERAL_STRING("Arial"))) {
+        return ff;
     }
 
     // otherwise, use local default
     NONCLIENTMETRICSW ncm;
     ncm.cbSize = sizeof(ncm);
     BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 
                                           sizeof(ncm), &ncm, 0);
+
     if (status) {
-        if (ResolveFontName(nsDependentString(ncm.lfMessageFont.lfFaceName),
-                            resolvedName)) {
-            return FindFamily(resolvedName);
+        ff = FindFamily(nsDependentString(ncm.lfMessageFont.lfFaceName));
+        if (ff) {
+            return ff;
         }
     }
 
     return nullptr;
 }
 
 gfxFontEntry *
 gfxDWriteFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
@@ -1318,55 +1320,42 @@ gfxDWriteFontList::GetStandardFamilyName
 
 gfxFontFamily* gfxDWriteFontList::FindFamily(const nsAString& aFamily)
 {
     if (!mInitialized) {
         mInitialized = true;
         DelayedInitFontList();
     }
 
+    nsAutoString keyName(aFamily);
+    BuildKeyNameFromFontName(keyName);
+
+    gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
+    if (ff) {
+        return ff;
+    }
+
+    if (mNonExistingFonts.Contains(keyName)) {
+        return nullptr;
+    }
+
     return gfxPlatformFontList::FindFamily(aFamily);
 }
 
 void
 gfxDWriteFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
 {
     if (!mInitialized) {
         mInitialized = true;
         DelayedInitFontList();
     }
 
     return gfxPlatformFontList::GetFontFamilyList(aFamilyArray);
 }
 
-bool 
-gfxDWriteFontList::ResolveFontName(const nsAString& aFontName,
-                                   nsAString& aResolvedFontName)
-{
-    if (!mInitialized) {
-        mInitialized = true;
-        DelayedInitFontList();
-    }
-
-    nsAutoString keyName(aFontName);
-    BuildKeyNameFromFontName(keyName);
-
-    gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
-    if (ff) {
-        aResolvedFontName = ff->Name();
-        return true;
-    }
-
-    if (mNonExistingFonts.Contains(keyName)) {
-        return false;
-    }
-
-    return gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName);
-}
-
 void
 gfxDWriteFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                                           FontListSizes* aSizes) const
 {
     gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 
     aSizes->mFontListSize +=
         mFontSubstitutes.SizeOfExcludingThis(SizeOfFamilyNameEntryExcludingThis,
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -349,19 +349,16 @@ public:
 
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
 
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const uint8_t *aFontData,
                                            uint32_t aLength);
     
-    virtual bool ResolveFontName(const nsAString& aFontName,
-                                   nsAString& aResolvedFontName);
-
     bool GetStandardFamilyName(const nsAString& aFontName,
                                  nsAString& aFamilyName);
 
     IDWriteGdiInterop *GetGDIInterop() { return mGDIInterop; }
     bool UseGDIFontTableAccess() { return mGDIFontTableAccess; }
 
     virtual gfxFontFamily* FindFamily(const nsAString& aFamily);
 
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -1427,30 +1427,27 @@ gfxFT2FontList::LookupLocalFont(const gf
     }
 
     return fe;
 }
 
 gfxFontFamily*
 gfxFT2FontList::GetDefaultFont(const gfxFontStyle* aStyle)
 {
+    gfxFontFamily *ff = nullptr;
 #ifdef MOZ_WIDGET_GONK
-    nsAutoString resolvedName;
-    if (ResolveFontName(NS_LITERAL_STRING("Fira Sans OT"), resolvedName)) {
-        return FindFamily(resolvedName);
-    }
+    ff = FindFamily(NS_LITERAL_STRING("Fira Sans OT"));
 #elif defined(MOZ_WIDGET_ANDROID)
-    nsAutoString resolvedName;
-    if (ResolveFontName(NS_LITERAL_STRING("Roboto"), resolvedName) ||
-        ResolveFontName(NS_LITERAL_STRING("Droid Sans"), resolvedName)) {
-        return FindFamily(resolvedName);
+    ff = FindFamily(NS_LITERAL_STRING("Roboto"));
+    if (!ff) {
+        ff = FindFamily(NS_LITERAL_STRING("Droid Sans"));
     }
 #endif
     /* TODO: what about Qt or other platforms that may use this? */
-    return nullptr;
+    return ff;
 }
 
 gfxFontEntry*
 gfxFT2FontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                  const uint8_t *aFontData,
                                  uint32_t aLength)
 {
     // The FT2 font needs the font data to persist, so we do NOT free it here
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -4820,42 +4820,171 @@ gfxGlyphExtents::SizeOfExcludingThis(Mal
 }
 
 size_t
 gfxGlyphExtents::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
 }
 
-gfxFontGroup::gfxFontGroup(const nsAString& aFamilies,
+gfxFontGroup::gfxFontGroup(const FontFamilyList& aFontFamilyList,
                            const gfxFontStyle *aStyle,
                            gfxUserFontSet *aUserFontSet)
-    : mFamilies(aFamilies)
+    : mFamilyList(aFontFamilyList)
     , mStyle(*aStyle)
     , mUnderlineOffset(UNDERLINE_OFFSET_NOT_SET)
     , mHyphenWidth(-1)
     , mUserFontSet(aUserFontSet)
     , mTextPerf(nullptr)
     , mPageLang(gfxPlatform::GetFontPrefLangFor(aStyle->language))
     , mSkipDrawing(false)
 {
     // We don't use SetUserFontSet() here, as we want to unconditionally call
     // BuildFontList() rather than only do UpdateFontList() if it changed.
     mCurrGeneration = GetGeneration();
     BuildFontList();
 }
 
 void
+gfxFontGroup::FindGenericFonts(FontFamilyType aGenericType,
+                               nsIAtom *aLanguage,
+                               void *aClosure)
+{
+    nsAutoTArray<nsString, 5> resolvedGenerics;
+    ResolveGenericFontNames(aGenericType, aLanguage, resolvedGenerics);
+    uint32_t g = 0, numGenerics = resolvedGenerics.Length();
+    for (g = 0; g < numGenerics; g++) {
+        FindPlatformFont(resolvedGenerics[g], false, aClosure);
+    }
+}
+
+/* static */ void
+gfxFontGroup::ResolveGenericFontNames(FontFamilyType aGenericType,
+                                      nsIAtom *aLanguage,
+                                      nsTArray<nsString>& aGenericFamilies)
+{
+    static const char kGeneric_serif[] = "serif";
+    static const char kGeneric_sans_serif[] = "sans-serif";
+    static const char kGeneric_monospace[] = "monospace";
+    static const char kGeneric_cursive[] = "cursive";
+    static const char kGeneric_fantasy[] = "fantasy";
+
+    // type should be standard generic type at this point
+    NS_ASSERTION(aGenericType >= eFamily_serif &&
+                 aGenericType <= eFamily_fantasy,
+                 "standard generic font family type required");
+
+    // create the lang string
+    nsIAtom *langGroupAtom = nullptr;
+    nsAutoCString langGroupString;
+    if (aLanguage) {
+        if (!gLangService) {
+            CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService);
+        }
+        if (gLangService) {
+            nsresult rv;
+            langGroupAtom = gLangService->GetLanguageGroup(aLanguage, &rv);
+        }
+    }
+    if (!langGroupAtom) {
+        langGroupAtom = nsGkAtoms::Unicode;
+    }
+    langGroupAtom->ToUTF8String(langGroupString);
+
+    // map generic type to string
+    const char *generic = nullptr;
+    switch (aGenericType) {
+        case eFamily_serif:
+            generic = kGeneric_serif;
+            break;
+        case eFamily_sans_serif:
+            generic = kGeneric_sans_serif;
+            break;
+        case eFamily_monospace:
+            generic = kGeneric_monospace;
+            break;
+        case eFamily_cursive:
+            generic = kGeneric_cursive;
+            break;
+        case eFamily_fantasy:
+            generic = kGeneric_fantasy;
+            break;
+        default:
+            break;
+    }
+
+    if (!generic) {
+        return;
+    }
+
+    aGenericFamilies.Clear();
+
+    // load family for "font.name.generic.lang"
+    nsAutoCString prefFontName("font.name.");
+    prefFontName.Append(generic);
+    prefFontName.Append('.');
+    prefFontName.Append(langGroupString);
+    gfxFontUtils::AppendPrefsFontList(prefFontName.get(),
+                                      aGenericFamilies);
+
+    // if lang has pref fonts, also load fonts for "font.name-list.generic.lang"
+    if (!aGenericFamilies.IsEmpty()) {
+        nsAutoCString prefFontListName("font.name-list.");
+        prefFontListName.Append(generic);
+        prefFontListName.Append('.');
+        prefFontListName.Append(langGroupString);
+        gfxFontUtils::AppendPrefsFontList(prefFontListName.get(),
+                                          aGenericFamilies);
+    }
+
+#if 0  // dump out generic mappings
+    printf("%s ===> ", prefFontName.get());
+    for (uint32_t k = 0; k < aGenericFamilies.Length(); k++) {
+        if (k > 0) printf(", ");
+        printf("%s", NS_ConvertUTF16toUTF8(aGenericFamilies[k]).get());
+    }
+    printf("\n");
+#endif
+}
+
+void gfxFontGroup::EnumerateFontList(nsIAtom *aLanguage, void *aClosure)
+{
+    // initialize fonts in the font family list
+    const nsTArray<FontFamilyName>& fontlist = mFamilyList.GetFontlist();
+
+    // lookup fonts in the fontlist
+    uint32_t i, numFonts = fontlist.Length();
+    for (i = 0; i < numFonts; i++) {
+        const FontFamilyName& name = fontlist[i];
+        if (name.IsNamed()) {
+            FindPlatformFont(name.mName, true, aClosure);
+        } else {
+            FindGenericFonts(name.mType, aLanguage, aClosure);
+        }
+    }
+
+    // if necessary, append default generic onto the end
+    if (mFamilyList.GetDefaultFontType() != eFamily_none &&
+        !mFamilyList.HasDefaultGeneric()) {
+        FindGenericFonts(mFamilyList.GetDefaultFontType(),
+                         aLanguage,
+                         aClosure);
+    }
+}
+
+void
 gfxFontGroup::BuildFontList()
 {
-// "#if" to be removed once all platforms are moved to gfxPlatformFontList interface
-// and subclasses of gfxFontGroup eliminated
+// gfxPangoFontGroup behaves differently, so this method is a no-op on that platform
 #if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID)
-    ForEachFont(FindPlatformFont, this);
-
+
+    EnumerateFontList(mStyle.language);
+
+    // at this point, fontlist should have been filled in
+    // get a default font if none exists
     if (mFonts.Length() == 0) {
         bool needsBold;
         gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
         gfxFontFamily *defaultFamily = pfl->GetDefaultFont(&mStyle);
         NS_ASSERTION(defaultFamily,
                      "invalid default font returned by GetDefaultFont");
 
         if (defaultFamily) {
@@ -4892,18 +5021,20 @@ gfxFontGroup::BuildFontList()
                 }
             }
         }
 
         if (mFonts.Length() == 0) {
             // an empty font list at this point is fatal; we're not going to
             // be able to do even the most basic layout operations
             char msg[256]; // CHECK buffer length if revising message below
+            nsAutoString families;
+            mFamilyList.ToString(families);
             sprintf(msg, "unable to find a usable font (%.220s)",
-                    NS_ConvertUTF16toUTF8(mFamilies).get());
+                    NS_ConvertUTF16toUTF8(families).get());
             NS_RUNTIMEABORT(msg);
         }
     }
 
     if (!mStyle.systemFont) {
         uint32_t count = mFonts.Length();
         for (uint32_t i = 0; i < count; ++i) {
             gfxFont* font = mFonts[i].Font();
@@ -4913,69 +5044,62 @@ gfxFontGroup::BuildFontList()
                 mUnderlineOffset = std::min(first, bad);
                 break;
             }
         }
     }
 #endif
 }
 
-bool
+void
 gfxFontGroup::FindPlatformFont(const nsAString& aName,
-                               const nsACString& aGenericName,
                                bool aUseFontSet,
                                void *aClosure)
 {
-    gfxFontGroup *fontGroup = static_cast<gfxFontGroup*>(aClosure);
-    const gfxFontStyle *fontStyle = fontGroup->GetStyle();
-
     bool needsBold;
     gfxFontFamily *family = nullptr;
     gfxFontEntry *fe = nullptr;
 
     if (aUseFontSet) {
         // First, look up in the user font set...
         // If the fontSet matches the family, we must not look for a platform
         // font of the same name, even if we fail to actually get a fontEntry
         // here; we'll fall back to the next name in the CSS font-family list.
-        gfxUserFontSet *fs = fontGroup->GetUserFontSet();
-        if (fs) {
+        if (mUserFontSet) {
             // If the fontSet matches the family, but the font has not yet finished
             // loading (nor has its load timeout fired), the fontGroup should wait
             // for the download, and not actually draw its text yet.
-            family = fs->GetFamily(aName);
+            family = mUserFontSet->GetFamily(aName);
             if (family) {
                 bool waitForUserFont = false;
-                fe = fs->FindFontEntry(family, *fontStyle,
-                                       needsBold, waitForUserFont);
+                fe = mUserFontSet->FindFontEntry(family, mStyle,
+                                                 needsBold, waitForUserFont);
                 if (!fe && waitForUserFont) {
-                    fontGroup->mSkipDrawing = true;
+                    mSkipDrawing = true;
                 }
             }
         }
     }
 
     // Not known in the user font set ==> check system fonts
     if (!family) {
         gfxPlatformFontList *fontList = gfxPlatformFontList::PlatformFontList();
         family = fontList->FindFamily(aName);
         if (family) {
-            fe = family->FindFontForStyle(*fontStyle, needsBold);
+            fe = family->FindFontForStyle(mStyle, needsBold);
         }
     }
 
     // add to the font group, unless it's already there
-    if (fe && !fontGroup->HasFont(fe)) {
-        nsRefPtr<gfxFont> font = fe->FindOrMakeFont(fontStyle, needsBold);
+    if (fe && !HasFont(fe)) {
+        nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, needsBold);
         if (font) {
-            fontGroup->mFonts.AppendElement(FamilyFace(family, font));
-        }
-    }
-
-    return true;
+            mFonts.AppendElement(FamilyFace(family, font));
+        }
+    }
 }
 
 bool
 gfxFontGroup::HasFont(const gfxFontEntry *aFontEntry)
 {
     uint32_t count = mFonts.Length();
     for (uint32_t i = 0; i < count; ++i) {
         if (mFonts[i].Font()->GetFontEntry() == aFontEntry)
@@ -4987,17 +5111,17 @@ gfxFontGroup::HasFont(const gfxFontEntry
 gfxFontGroup::~gfxFontGroup()
 {
     mFonts.Clear();
 }
 
 gfxFontGroup *
 gfxFontGroup::Copy(const gfxFontStyle *aStyle)
 {
-    gfxFontGroup *fg = new gfxFontGroup(mFamilies, aStyle, mUserFontSet);
+    gfxFontGroup *fg = new gfxFontGroup(mFamilyList, aStyle, mUserFontSet);
     fg->SetTextPerfMetrics(mTextPerf);
     return fg;
 }
 
 bool 
 gfxFontGroup::IsInvalidChar(uint8_t ch)
 {
     return ((ch & 0x7f) < 0x20 || ch == 0x7f);
@@ -5014,218 +5138,16 @@ gfxFontGroup::IsInvalidChar(char16_t ch)
     if (ch <= 0x9f) {
         return true;
     }
     return (((ch & 0xFF00) == 0x2000 /* Unicode control character */ &&
              (ch == 0x200B/*ZWSP*/ || ch == 0x2028/*LSEP*/ || ch == 0x2029/*PSEP*/)) ||
             IsBidiControl(ch));
 }
 
-bool
-gfxFontGroup::ForEachFont(FontCreationCallback fc,
-                          void *closure)
-{
-    return ForEachFontInternal(mFamilies, mStyle.language,
-                               true, true, true, fc, closure);
-}
-
-bool
-gfxFontGroup::ForEachFont(const nsAString& aFamilies,
-                          nsIAtom *aLanguage,
-                          FontCreationCallback fc,
-                          void *closure)
-{
-    return ForEachFontInternal(aFamilies, aLanguage,
-                               false, true, true, fc, closure);
-}
-
-struct ResolveData {
-    ResolveData(gfxFontGroup::FontCreationCallback aCallback,
-                nsACString& aGenericFamily,
-                bool aUseFontSet,
-                void *aClosure) :
-        mCallback(aCallback),
-        mGenericFamily(aGenericFamily),
-        mUseFontSet(aUseFontSet),
-        mClosure(aClosure) {
-    }
-    gfxFontGroup::FontCreationCallback mCallback;
-    nsCString mGenericFamily;
-    bool mUseFontSet;
-    void *mClosure;
-};
-
-bool
-gfxFontGroup::ForEachFontInternal(const nsAString& aFamilies,
-                                  nsIAtom *aLanguage,
-                                  bool aResolveGeneric,
-                                  bool aResolveFontName,
-                                  bool aUseFontSet,
-                                  FontCreationCallback fc,
-                                  void *closure)
-{
-    const char16_t kSingleQuote  = char16_t('\'');
-    const char16_t kDoubleQuote  = char16_t('\"');
-    const char16_t kComma        = char16_t(',');
-
-    nsIAtom *groupAtom = nullptr;
-    nsAutoCString groupString;
-    if (aLanguage) {
-        if (!gLangService) {
-            CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService);
-        }
-        if (gLangService) {
-            nsresult rv;
-            groupAtom = gLangService->GetLanguageGroup(aLanguage, &rv);
-        }
-    }
-    if (!groupAtom) {
-        groupAtom = nsGkAtoms::Unicode;
-    }
-    groupAtom->ToUTF8String(groupString);
-
-    nsPromiseFlatString families(aFamilies);
-    const char16_t *p, *p_end;
-    families.BeginReading(p);
-    families.EndReading(p_end);
-    nsAutoString family;
-    nsAutoCString lcFamily;
-    nsAutoString genericFamily;
-
-    while (p < p_end) {
-        while (nsCRT::IsAsciiSpace(*p) || *p == kComma)
-            if (++p == p_end)
-                return true;
-
-        bool generic;
-        if (*p == kSingleQuote || *p == kDoubleQuote) {
-            // quoted font family
-            char16_t quoteMark = *p;
-            if (++p == p_end)
-                return true;
-            const char16_t *nameStart = p;
-
-            // XXX What about CSS character escapes?
-            while (*p != quoteMark)
-                if (++p == p_end)
-                    return true;
-
-            family = Substring(nameStart, p);
-            generic = false;
-            genericFamily.SetIsVoid(true);
-
-            while (++p != p_end && *p != kComma)
-                /* nothing */ ;
-
-        } else {
-            // unquoted font family
-            const char16_t *nameStart = p;
-            while (++p != p_end && *p != kComma)
-                /* nothing */ ;
-
-            family = Substring(nameStart, p);
-            family.CompressWhitespace(false, true);
-
-            if (aResolveGeneric &&
-                (family.LowerCaseEqualsLiteral("serif") ||
-                 family.LowerCaseEqualsLiteral("sans-serif") ||
-                 family.LowerCaseEqualsLiteral("monospace") ||
-                 family.LowerCaseEqualsLiteral("cursive") ||
-                 family.LowerCaseEqualsLiteral("fantasy")))
-            {
-                generic = true;
-
-                ToLowerCase(NS_LossyConvertUTF16toASCII(family), lcFamily);
-
-                nsAutoCString prefName("font.name.");
-                prefName.Append(lcFamily);
-                prefName.Append('.');
-                prefName.Append(groupString);
-
-                nsAdoptingString value = Preferences::GetString(prefName.get());
-                if (value) {
-                    CopyASCIItoUTF16(lcFamily, genericFamily);
-                    family = value;
-                }
-            } else {
-                generic = false;
-                genericFamily.SetIsVoid(true);
-            }
-        }
-
-        NS_LossyConvertUTF16toASCII gf(genericFamily);
-        if (generic) {
-            ForEachFontInternal(family, groupAtom, false,
-                                aResolveFontName, false,
-                                fc, closure);
-        } else if (!family.IsEmpty()) {
-            if (aResolveFontName) {
-                ResolveData data(fc, gf, aUseFontSet, closure);
-                bool aborted = false, needsBold;
-                nsresult rv = NS_OK;
-                bool foundFamily = false;
-                bool waitForUserFont = false;
-                gfxFontEntry *fe = nullptr;
-                if (aUseFontSet && mUserFontSet) {
-                    gfxFontFamily *fam = mUserFontSet->GetFamily(family);
-                    if (fam) {
-                        fe = mUserFontSet->FindFontEntry(fam, mStyle,
-                                                         needsBold,
-                                                         waitForUserFont);
-                    }
-                }
-                if (fe) {
-                    gfxFontGroup::FontResolverProc(family, &data);
-                } else {
-                    if (waitForUserFont) {
-                        mSkipDrawing = true;
-                    }
-                    if (!foundFamily) {
-                        gfxPlatform *pf = gfxPlatform::GetPlatform();
-                        rv = pf->ResolveFontName(family,
-                                                 gfxFontGroup::FontResolverProc,
-                                                 &data, aborted);
-                    }
-                }
-                if (NS_FAILED(rv) || aborted)
-                    return false;
-            }
-            else {
-                if (!fc(family, gf, aUseFontSet, closure))
-                    return false;
-            }
-        }
-
-        if (generic && aResolveGeneric) {
-            nsAutoCString prefName("font.name-list.");
-            prefName.Append(lcFamily);
-            prefName.Append('.');
-            prefName.Append(groupString);
-            nsAdoptingString value = Preferences::GetString(prefName.get());
-            if (value) {
-                ForEachFontInternal(value, groupAtom, false,
-                                    aResolveFontName, false,
-                                    fc, closure);
-            }
-        }
-
-        ++p; // may advance past p_end
-    }
-
-    return true;
-}
-
-bool
-gfxFontGroup::FontResolverProc(const nsAString& aName, void *aClosure)
-{
-    ResolveData *data = reinterpret_cast<ResolveData*>(aClosure);
-    return (data->mCallback)(aName, data->mGenericFamily, data->mUseFontSet,
-                             data->mClosure);
-}
-
 gfxTextRun *
 gfxFontGroup::MakeEmptyTextRun(const Parameters *aParams, uint32_t aFlags)
 {
     aFlags |= TEXT_IS_8BIT | TEXT_IS_ASCII | TEXT_IS_PERSISTENT;
     return gfxTextRun::Create(aParams, 0, this, aFlags);
 }
 
 gfxTextRun *
@@ -5424,23 +5346,29 @@ gfxFontGroup::InitTextRun(gfxContext *aC
 #endif
 
     if (sizeof(T) == sizeof(uint8_t) && !transformedString) {
 
 #ifdef PR_LOGGING
         if (MOZ_UNLIKELY(PR_LOG_TEST(log, PR_LOG_WARNING))) {
             nsAutoCString lang;
             mStyle.language->ToUTF8String(lang);
+            nsAutoString families;
+            mFamilyList.ToString(families);
             nsAutoCString str((const char*)aString, aLength);
             PR_LOG(log, PR_LOG_WARNING,\
-                   ("(%s) fontgroup: [%s] lang: %s script: %d len %d "
-                    "weight: %d width: %d style: %s size: %6.2f %d-byte "
+                   ("(%s) fontgroup: [%s] default: %s lang: %s script: %d "
+                    "len %d weight: %d width: %d style: %s size: %6.2f %d-byte "
                     "TEXTRUN [%s] ENDTEXTRUN\n",
                     (mStyle.systemFont ? "textrunui" : "textrun"),
-                    NS_ConvertUTF16toUTF8(mFamilies).get(),
+                    NS_ConvertUTF16toUTF8(families).get(),
+                    (mFamilyList.GetDefaultFontType() == eFamily_serif ?
+                     "serif" :
+                     (mFamilyList.GetDefaultFontType() == eFamily_sans_serif ?
+                      "sans-serif" : "none")),
                     lang.get(), MOZ_SCRIPT_LATIN, aLength,
                     uint32_t(mStyle.weight), uint32_t(mStyle.stretch),
                     (mStyle.style & NS_FONT_STYLE_ITALIC ? "italic" :
                     (mStyle.style & NS_FONT_STYLE_OBLIQUE ? "oblique" :
                                                             "normal")),
                     mStyle.size,
                     sizeof(T),
                     str.get()));
@@ -5468,23 +5396,29 @@ gfxFontGroup::InitTextRun(gfxContext *aC
         uint32_t runStart = 0, runLimit = aLength;
         int32_t runScript = MOZ_SCRIPT_LATIN;
         while (scriptRuns.Next(runStart, runLimit, runScript)) {
 
 #ifdef PR_LOGGING
             if (MOZ_UNLIKELY(PR_LOG_TEST(log, PR_LOG_WARNING))) {
                 nsAutoCString lang;
                 mStyle.language->ToUTF8String(lang);
+                nsAutoString families;
+                mFamilyList.ToString(families);
                 uint32_t runLen = runLimit - runStart;
                 PR_LOG(log, PR_LOG_WARNING,\
-                       ("(%s) fontgroup: [%s] lang: %s script: %d len %d "
-                        "weight: %d width: %d style: %s size: %6.2f %d-byte "
-                        "TEXTRUN [%s] ENDTEXTRUN\n",
+                       ("(%s) fontgroup: [%s] default: %s lang: %s script: %d "
+                        "len %d weight: %d width: %d style: %s size: %6.2f "
+                        "%d-byte TEXTRUN [%s] ENDTEXTRUN\n",
                         (mStyle.systemFont ? "textrunui" : "textrun"),
-                        NS_ConvertUTF16toUTF8(mFamilies).get(),
+                        NS_ConvertUTF16toUTF8(families).get(),
+                        (mFamilyList.GetDefaultFontType() == eFamily_serif ?
+                         "serif" :
+                         (mFamilyList.GetDefaultFontType() == eFamily_sans_serif ?
+                          "sans-serif" : "none")),
                         lang.get(), runScript, runLen,
                         uint32_t(mStyle.weight), uint32_t(mStyle.stretch),
                         (mStyle.style & NS_FONT_STYLE_ITALIC ? "italic" :
                         (mStyle.style & NS_FONT_STYLE_OBLIQUE ? "oblique" :
                                                                 "normal")),
                         mStyle.size,
                         sizeof(T),
                         NS_ConvertUTF16toUTF8(textPtr + runStart, runLen).get()));
@@ -6100,31 +6034,27 @@ gfxFontGroup::SetUserFontSet(gfxUserFont
 uint64_t
 gfxFontGroup::GetGeneration()
 {
     if (!mUserFontSet)
         return 0;
     return mUserFontSet->GetGeneration();
 }
 
+// note: gfxPangoFontGroup overrides UpdateFontList, such that
+//       BuildFontList is never used
 void
 gfxFontGroup::UpdateFontList()
 {
     if (mCurrGeneration != GetGeneration()) {
         // xxx - can probably improve this to detect when all fonts were found, so no need to update list
         mFonts.Clear();
         mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET;
         mSkipDrawing = false;
-
-        // bug 548184 - need to clean up FT2, OS/2 platform code to use BuildFontList
-#if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID)
         BuildFontList();
-#else
-        ForEachFont(FindPlatformFont, this);
-#endif
         mCurrGeneration = GetGeneration();
         mCachedEllipsisTextRun = nullptr;
     }
 }
 
 struct PrefFontCallbackData {
     PrefFontCallbackData(nsTArray<nsRefPtr<gfxFontFamily> >& aFamiliesArray)
         : mPrefFamilies(aFamiliesArray)
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_FONT_H
 #define GFX_FONT_H
 
 #include "gfxTypes.h"
 #include "nsString.h"
 #include "gfxPoint.h"
+#include "gfxFontFamilyList.h"
 #include "gfxFontUtils.h"
 #include "nsTArray.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "gfxSkipChars.h"
 #include "gfxRect.h"
 #include "nsExpirationTracker.h"
 #include "gfxPlatform.h"
@@ -3512,17 +3513,19 @@ public:
 
     private:
         nsRefPtr<gfxFontFamily> mFamily;
         nsRefPtr<gfxFont>       mFont;
     };
 
     static void Shutdown(); // platform must call this to release the languageAtomService
 
-    gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet = nullptr);
+    gfxFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
+                 const gfxFontStyle *aStyle,
+                 gfxUserFontSet *aUserFontSet = nullptr);
 
     virtual ~gfxFontGroup();
 
     virtual gfxFont *GetFontAt(int32_t i) {
         // If it turns out to be hard for all clients that cache font
         // groups to call UpdateFontList at appropriate times, we could
         // instead consider just calling UpdateFontList from someplace
         // more central (such as here).
@@ -3596,37 +3599,22 @@ public:
      * This will use U+2010 HYPHEN if available in the first font,
      * otherwise fall back to U+002D HYPHEN-MINUS.
      * The caller is responsible for deleting the returned text run
      * when no longer required.
      */
     gfxTextRun *MakeHyphenTextRun(gfxContext *aCtx,
                                   uint32_t aAppUnitsPerDevUnit);
 
-    /* helper function for splitting font families on commas and
-     * calling a function for each family to fill the mFonts array
-     */
-    typedef bool (*FontCreationCallback) (const nsAString& aName,
-                                            const nsACString& aGenericName,
-                                            bool aUseFontSet,
-                                            void *closure);
-    bool ForEachFont(const nsAString& aFamilies,
-                       nsIAtom *aLanguage,
-                       FontCreationCallback fc,
-                       void *closure);
-    bool ForEachFont(FontCreationCallback fc, void *closure);
-
     /**
      * Check whether a given font (specified by its gfxFontEntry)
      * is already in the fontgroup's list of actual fonts
      */
     bool HasFont(const gfxFontEntry *aFontEntry);
 
-    const nsString& GetFamilies() { return mFamilies; }
-
     // This returns the preferred underline for this font group.
     // Some CJK fonts have wrong underline offset in its metrics.
     // If this group has such "bad" font, each platform's gfxFontGroup initialized mUnderlineOffset.
     // The value should be lower value of first font's metrics and the bad font's metrics.
     // Otherwise, this returns from first font's metrics.
     enum { UNDERLINE_OFFSET_NOT_SET = INT16_MAX };
     virtual gfxFloat GetUnderlineOffset() {
         if (mUnderlineOffset == UNDERLINE_OFFSET_NOT_SET)
@@ -3680,18 +3668,24 @@ public:
     // The gfxFontGroup keeps ownership of this textrun.
     // It is only guaranteed to exist until the next call to GetEllipsisTextRun
     // (which might use a different appUnitsPerDev value) for the font group,
     // or until UpdateFontList is called, or the fontgroup is destroyed.
     // Get it/use it/forget it :) - don't keep a reference that might go stale.
     gfxTextRun* GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel,
                                    LazyReferenceContextGetter& aRefContextGetter);
 
+    // helper method for resolving generic font families
+    static void
+    ResolveGenericFontNames(mozilla::FontFamilyType aGenericType,
+                            nsIAtom *aLanguage,
+                            nsTArray<nsString>& aGenericFamilies);
+
 protected:
-    nsString mFamilies;
+    mozilla::FontFamilyList mFamilyList;
     gfxFontStyle mStyle;
     nsTArray<FamilyFace> mFonts;
     gfxFloat mUnderlineOffset;
     gfxFloat mHyphenWidth;
 
     nsRefPtr<gfxUserFontSet> mUserFontSet;
     uint64_t mCurrGeneration;  // track the current user font set generation, rebuild font list if needed
 
@@ -3742,42 +3736,32 @@ protected:
     template<typename T>
     void InitScriptRun(gfxContext *aContext,
                        gfxTextRun *aTextRun,
                        const T *aString,
                        uint32_t aScriptRunStart,
                        uint32_t aScriptRunEnd,
                        int32_t aRunScript);
 
-    /* If aResolveGeneric is true, then CSS/Gecko generic family names are
-     * replaced with preferred fonts.
-     *
-     * If aResolveFontName is true then fc() is called only for existing fonts
-     * and with actual font names.  If false then fc() is called with each
-     * family name in aFamilies (after resolving CSS/Gecko generic family names
-     * if aResolveGeneric).
-     * If aUseFontSet is true, the fontgroup's user font set is checked;
-     * if false then it is skipped.
-     */
-    bool ForEachFontInternal(const nsAString& aFamilies,
-                               nsIAtom *aLanguage,
-                               bool aResolveGeneric,
-                               bool aResolveFontName,
-                               bool aUseFontSet,
-                               FontCreationCallback fc,
-                               void *closure);
-
     // Helper for font-matching:
     // see if aCh is supported in any of the faces from aFamily;
     // if so return the best style match, else return null.
     already_AddRefed<gfxFont> TryAllFamilyMembers(gfxFontFamily* aFamily,
                                                   uint32_t aCh);
 
-    static bool FontResolverProc(const nsAString& aName, void *aClosure);
-
-    static bool FindPlatformFont(const nsAString& aName,
-                                   const nsACString& aGenericName,
-                                   bool aUseFontSet,
-                                   void *closure);
+    // helper methods for looking up fonts
+
+    // iterate over the fontlist, lookup names and expand generics
+    void EnumerateFontList(nsIAtom *aLanguage, void *aClosure = nullptr);
+
+    // expand a generic to a list of specific names based on prefs
+    void FindGenericFonts(mozilla::FontFamilyType aGenericType,
+                          nsIAtom *aLanguage,
+                          void *aClosure);
+
+    // lookup and add a font with a given name (i.e. *not* a generic!)
+    virtual void FindPlatformFont(const nsAString& aName,
+                                  bool aUseFontSet,
+                                  void *aClosure);
 
     static nsILanguageAtomService* gLangService;
 };
 #endif
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -716,48 +716,59 @@ gfxFontUtils::MapCharToGlyph(const uint8
 
         // else the variation sequence was not supported, use default mapping
         // of the character code alone
     }
 
     return gid;
 }
 
-void gfxFontUtils::GetPrefsFontList(const char *aPrefName, nsTArray<nsString>& aFontList)
+void gfxFontUtils::ParseFontList(const nsAString& aFamilyList,
+                                 nsTArray<nsString>& aFontList)
 {
     const char16_t kComma = char16_t(',');
     
-    aFontList.Clear();
-    
-    // get the list of single-face font families
-    nsAdoptingString fontlistValue = Preferences::GetString(aPrefName);
-    if (!fontlistValue) {
-        return;
-    }
-
     // append each font name to the list
     nsAutoString fontname;
     const char16_t *p, *p_end;
-    fontlistValue.BeginReading(p);
-    fontlistValue.EndReading(p_end);
+    aFamilyList.BeginReading(p);
+    aFamilyList.EndReading(p_end);
 
      while (p < p_end) {
         const char16_t *nameStart = p;
         while (++p != p_end && *p != kComma)
         /* nothing */ ;
 
         // pull out a single name and clean out leading/trailing whitespace        
         fontname = Substring(nameStart, p);
         fontname.CompressWhitespace(true, true);
         
         // append it to the list
         aFontList.AppendElement(fontname);
         ++p;
     }
+}
 
+void gfxFontUtils::AppendPrefsFontList(const char *aPrefName,
+                                       nsTArray<nsString>& aFontList)
+{
+    // get the list of single-face font families
+    nsAdoptingString fontlistValue = Preferences::GetString(aPrefName);
+    if (!fontlistValue) {
+        return;
+    }
+
+    ParseFontList(fontlistValue, aFontList);
+}
+
+void gfxFontUtils::GetPrefsFontList(const char *aPrefName,
+                                    nsTArray<nsString>& aFontList)
+{
+    aFontList.Clear();
+    AppendPrefsFontList(aPrefName, aFontList);
 }
 
 // produce a unique font name that is (1) a valid Postscript name and (2) less
 // than 31 characters in length.  Using AddFontMemResourceEx on Windows fails 
 // for names longer than 30 characters in length.
 
 #define MAX_B64_LEN 32
 
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -929,18 +929,27 @@ public:
         if ((aCh & 0xFF00) == kUnicodeFirstHighSurrogateBlock)
             // surrogate that could be part of a bidi supplementary char
             // (Cypriot, Aramaic, Phoenecian, etc)
             return true;
 
         // otherwise we know this char cannot trigger bidi reordering
         return false;
     }
-    
-    // for a given font list pref name, set up a list of font names
+
+    // parse a simple list of font family names into
+    // an array of strings
+    static void ParseFontList(const nsAString& aFamilyList,
+                              nsTArray<nsString>& aFontList);
+
+    // for a given font list pref name, append list of font names
+    static void AppendPrefsFontList(const char *aPrefName,
+                                    nsTArray<nsString>& aFontList);
+
+    // for a given font list pref name, initialize a list of font names
     static void GetPrefsFontList(const char *aPrefName, 
                                  nsTArray<nsString>& aFontList);
 
     // generate a unique font name
     static nsresult MakeUniqueUserFontName(nsAString& aName);
 
     // for color layer from glyph using COLR and CPAL tables
     static bool ValidateColorGlyphs(hb_blob_t* aCOLR, hb_blob_t* aCPAL);
--- a/gfx/thebes/gfxFontconfigUtils.cpp
+++ b/gfx/thebes/gfxFontconfigUtils.cpp
@@ -772,48 +772,16 @@ gfxFontconfigUtils::GetStandardFamilyNam
     if (givenFS)
         FcFontSetDestroy(givenFS);
     if (candidateFS)
         FcFontSetDestroy(candidateFS);
 
     return rv;
 }
 
-nsresult
-gfxFontconfigUtils::ResolveFontName(const nsAString& aFontName,
-                                    gfxPlatform::FontResolverCallback aCallback,
-                                    void *aClosure,
-                                    bool& aAborted)
-{
-    aAborted = false;
-
-    nsresult rv = UpdateFontListInternal();
-    if (NS_FAILED(rv))
-        return rv;
-
-    NS_ConvertUTF16toUTF8 fontname(aFontName);
-    // Sometimes, the font has two or more names (e.g., "Sazanami Gothic" has
-    // Japanese localized name).  We should not resolve to a single name
-    // because different names sometimes have different behavior. e.g., with
-    // the default settings of "Sazanami" on Fedora Core 5, the non-localized
-    // name uses anti-alias, but the localized name uses it.  So, we should
-    // check just whether the font is existing, without resolving to regular
-    // name.
-    //
-    // The family names in mAliasForMultiFonts are names understood by
-    // fontconfig.  The actual font to which they resolve depends on the
-    // entire match pattern.  That info is not available here, but there
-    // will be a font so leave the resolving to the gfxFontGroup.
-    if (IsExistingFamily(fontname) ||
-        mAliasForMultiFonts.Contains(fontname, gfxIgnoreCaseCStringComparator()))
-        aAborted = !(*aCallback)(aFontName, aClosure);
-
-    return NS_OK;
-}
-
 bool
 gfxFontconfigUtils::IsExistingFamily(const nsCString& aFamilyName)
 {
     return mFontsByFamily.GetEntry(ToFcChar8(aFamilyName)) != nullptr;
 }
 
 const nsTArray< nsCountedRef<FcPattern> >&
 gfxFontconfigUtils::GetFontsForFamily(const FcChar8 *aFamilyName)
--- a/gfx/thebes/gfxFontconfigUtils.h
+++ b/gfx/thebes/gfxFontconfigUtils.h
@@ -66,20 +66,16 @@ public:
     static void Shutdown();
 
     nsresult GetFontList(nsIAtom *aLangGroup,
                          const nsACString& aGenericFamily,
                          nsTArray<nsString>& aListOfFonts);
 
     nsresult UpdateFontList();
 
-    nsresult ResolveFontName(const nsAString& aFontName,
-                             gfxPlatform::FontResolverCallback aCallback,
-                             void *aClosure, bool& aAborted);
-
     nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
     const nsTArray< nsCountedRef<FcPattern> >&
     GetFontsForFamily(const FcChar8 *aFamilyName);
 
     const nsTArray< nsCountedRef<FcPattern> >&
     GetFontsForFullname(const FcChar8 *aFullname);
 
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -834,63 +834,58 @@ gfxGDIFontList::MakePlatformFont(const g
     if (isCFF && !IsWin7OrLater()) {
         fe->mForceGDI = true;
     }
 
     return fe;
 }
 
 gfxFontFamily*
+gfxGDIFontList::FindFamily(const nsAString& aFamily)
+{
+    nsAutoString keyName(aFamily);
+    BuildKeyNameFromFontName(keyName);
+
+    gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
+    if (ff) {
+        return ff;
+    }
+
+    if (mNonExistingFonts.Contains(keyName)) {
+        return nullptr;
+    }
+
+    return gfxPlatformFontList::FindFamily(aFamily);
+}
+
+gfxFontFamily*
 gfxGDIFontList::GetDefaultFont(const gfxFontStyle* aStyle)
 {
+    gfxFontFamily *ff = nullptr;
+
     // this really shouldn't fail to find a font....
     HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
     LOGFONTW logFont;
     if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) {
-        nsAutoString resolvedName;
-        if (ResolveFontName(nsDependentString(logFont.lfFaceName), resolvedName)) {
-            return FindFamily(resolvedName);
+        ff = FindFamily(nsDependentString(logFont.lfFaceName));
+        if (ff) {
+            return ff;
         }
     }
 
     // ...but just in case, try another approach as well
     NONCLIENTMETRICSW ncm;
     ncm.cbSize = sizeof(ncm);
     BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 
                                           sizeof(ncm), &ncm, 0);
     if (status) {
-        nsAutoString resolvedName;
-        if (ResolveFontName(nsDependentString(ncm.lfMessageFont.lfFaceName), resolvedName)) {
-            return FindFamily(resolvedName);
-        }
+        ff = FindFamily(nsDependentString(ncm.lfMessageFont.lfFaceName));
     }
 
-    return nullptr;
-}
-
-
-bool 
-gfxGDIFontList::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
-{
-    nsAutoString keyName(aFontName);
-    BuildKeyNameFromFontName(keyName);
-
-    gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
-    if (ff) {
-        aResolvedFontName = ff->Name();
-        return true;
-    }
-
-    if (mNonExistingFonts.Contains(keyName))
-        return false;
-
-    if (gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName))
-        return true;
-
-    return false;
+    return ff;
 }
 
 void
 gfxGDIFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                                        FontListSizes* aSizes) const
 {
     gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
     aSizes->mFontListSize +=
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -308,25 +308,24 @@ public:
         return static_cast<gfxGDIFontList*>(sPlatformFontList);
     }
 
     // initialize font lists
     virtual nsresult InitFontList();
 
     virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle);
 
+    virtual gfxFontFamily* FindFamily(const nsAString& aFamily);
+
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
 
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const uint8_t *aFontData, uint32_t aLength);
 
-    virtual bool ResolveFontName(const nsAString& aFontName,
-                                   nsAString& aResolvedFontName);
-
     virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const;
     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const;
 
 private:
     friend class gfxWindowsPlatform;
 
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -1220,95 +1220,20 @@ PrepareSortPattern(FcPattern *aPattern, 
 
     FcDefaultSubstitute(aPattern);
 }
 
 /**
  ** gfxPangoFontGroup
  **/
 
-struct FamilyCallbackData {
-    FamilyCallbackData(nsTArray<nsString> *aFcFamilyList,
-                       gfxUserFontSet *aUserFontSet)
-        : mFcFamilyList(aFcFamilyList), mUserFontSet(aUserFontSet)
-    {
-    }
-    nsTArray<nsString> *mFcFamilyList;
-    const gfxUserFontSet *mUserFontSet;
-};
-
-static int
-FFRECountHyphens (const nsAString &aFFREName)
-{
-    int h = 0;
-    int32_t hyphen = 0;
-    while ((hyphen = aFFREName.FindChar('-', hyphen)) >= 0) {
-        ++h;
-        ++hyphen;
-    }
-    return h;
-}
-
-static bool
-FamilyCallback (const nsAString& fontName, const nsACString& genericName,
-                bool aUseFontSet, void *closure)
-{
-    FamilyCallbackData *data = static_cast<FamilyCallbackData*>(closure);
-    nsTArray<nsString> *list = data->mFcFamilyList;
-
-    // We ignore prefs that have three hypens since they are X style prefs.
-    if (genericName.Length() && FFRECountHyphens(fontName) >= 3)
-        return true;
-
-    if (!list->Contains(fontName)) {
-        // The family properties of FcPatterns for @font-face fonts have a
-        // namespace to identify them among system fonts.  (see
-        // FONT_FACE_FAMILY_PREFIX.)
-        //
-        // Earlier versions of this code allowed the CSS family name to match
-        // either the @font-face family or the system font family, so both
-        // were added here. This was in accordance with earlier versions of
-        // the W3C specifications regarding @font-face.
-        //
-        // The current (2011-02-27) draft of CSS3 Fonts says
-        //
-        // (Section 4.2: Font family: the font-family descriptor):
-        // "If the font family name is the same as a font family available in
-        // a given user's environment, it effectively hides the underlying
-        // font for documents that use the stylesheet."
-        //
-        // (Section 5: Font matching algorithm)
-        // "... the user agent attempts to find the family name among fonts
-        // defined via @font-face rules and then among available system fonts,
-        // .... If a font family defined via @font-face rules contains only
-        // invalid font data, it should be considered as if a font was present
-        // but contained an empty character map; matching a platform font with
-        // the same name must not occur in this case."
-        //
-        // Therefore, for names present in the user font set, this code no
-        // longer includes the family name for matching against system fonts.
-        //
-        const gfxUserFontSet *userFontSet = data->mUserFontSet;
-        if (aUseFontSet && genericName.Length() == 0 &&
-            userFontSet && userFontSet->HasFamily(fontName)) {
-            nsAutoString userFontName =
-                NS_LITERAL_STRING(FONT_FACE_FAMILY_PREFIX) + fontName;
-            list->AppendElement(userFontName);
-        } else {
-            list->AppendElement(fontName);
-        }
-    }
-
-    return true;
-}
-
-gfxPangoFontGroup::gfxPangoFontGroup (const nsAString& families,
-                                      const gfxFontStyle *aStyle,
-                                      gfxUserFontSet *aUserFontSet)
-    : gfxFontGroup(families, aStyle, aUserFontSet),
+gfxPangoFontGroup::gfxPangoFontGroup(const FontFamilyList& aFontFamilyList,
+                                     const gfxFontStyle *aStyle,
+                                     gfxUserFontSet *aUserFontSet)
+    : gfxFontGroup(aFontFamilyList, aStyle, aUserFontSet),
       mPangoLanguage(GuessPangoLanguage(aStyle->language))
 {
     // This language is passed to the font for shaping.
     // Shaping doesn't know about lang groups so make it a real language.
     if (mPangoLanguage) {
         mStyle.language = do_GetAtom(pango_language_to_string(mPangoLanguage));
     }
 
@@ -1318,29 +1243,36 @@ gfxPangoFontGroup::gfxPangoFontGroup (co
 
 gfxPangoFontGroup::~gfxPangoFontGroup()
 {
 }
 
 gfxFontGroup *
 gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle)
 {
-    return new gfxPangoFontGroup(mFamilies, aStyle, mUserFontSet);
+    return new gfxPangoFontGroup(mFamilyList, aStyle, mUserFontSet);
 }
 
-// An array of family names suitable for fontconfig
 void
-gfxPangoFontGroup::GetFcFamilies(nsTArray<nsString> *aFcFamilyList,
-                                 nsIAtom *aLanguage)
+gfxPangoFontGroup::FindPlatformFont(const nsAString& fontName,
+                                    bool aUseFontSet,
+                                    void *aClosure)
 {
-    FamilyCallbackData data(aFcFamilyList, mUserFontSet);
-    // Leave non-existing fonts in the list so that fontconfig can get the
-    // best match.
-    ForEachFontInternal(mFamilies, aLanguage, true, false, true,
-                        FamilyCallback, &data);
+    nsTArray<nsString> *list = static_cast<nsTArray<nsString>*>(aClosure);
+
+    if (!list->Contains(fontName)) {
+        // names present in the user fontset are not matched against system fonts
+        if (aUseFontSet && mUserFontSet && mUserFontSet->HasFamily(fontName)) {
+            nsAutoString userFontName =
+                NS_LITERAL_STRING(FONT_FACE_FAMILY_PREFIX) + fontName;
+            list->AppendElement(userFontName);
+        } else {
+            list->AppendElement(fontName);
+        }
+    }
 }
 
 gfxFcFont *
 gfxPangoFontGroup::GetBaseFont()
 {
     if (mFonts[0].Font() == nullptr) {
         gfxFont* font = GetBaseFontSet()->GetFontAt(0, GetStyle());
         mFonts[0] = FamilyFace(nullptr, font);
@@ -1388,18 +1320,18 @@ gfxPangoFontGroup::MakeFontSet(PangoLang
 
     nsRefPtr <nsIAtom> langGroup;
     if (aLang != mPangoLanguage) {
         // Set up langGroup for Mozilla's font prefs.
         langGroup = do_GetAtom(lang);
     }
 
     nsAutoTArray<nsString, 20> fcFamilyList;
-    GetFcFamilies(&fcFamilyList,
-                  langGroup ? langGroup.get() : mStyle.language.get());
+    EnumerateFontList(langGroup ? langGroup.get() : mStyle.language.get(),
+                      &fcFamilyList);
 
     // To consider: A fontset cache here could be helpful.
 
     // Get a pattern suitable for matching.
     nsAutoRef<FcPattern> pattern
         (gfxFontconfigUtils::NewPattern(fcFamilyList, mStyle, lang));
 
     PrepareSortPattern(pattern, mStyle.size, aSizeAdjustFactor, mStyle.printerFont);
@@ -1687,17 +1619,17 @@ gfxPangoFontGroup::GetFTLibrary()
         // has been called on each FT_Face, at least until this bug is fixed:
         // https://bugs.freedesktop.org/show_bug.cgi?id=18857
         //
         // Cairo's FT_Library can be obtained from any cairo_scaled_font.  The
         // font properties requested here are chosen to get an FT_Face that is
         // likely to be also used elsewhere.
         gfxFontStyle style;
         nsRefPtr<gfxPangoFontGroup> fontGroup =
-            new gfxPangoFontGroup(NS_LITERAL_STRING("sans-serif"),
+            new gfxPangoFontGroup(FontFamilyList(eFamily_sans_serif),
                                   &style, nullptr);
 
         gfxFcFont *font = fontGroup->GetBaseFont();
         if (!font)
             return nullptr;
 
         gfxFT2LockedFace face(font);
         if (!face.get())
--- a/gfx/thebes/gfxPangoFonts.h
+++ b/gfx/thebes/gfxPangoFonts.h
@@ -19,20 +19,20 @@ class gfxFcFontSet;
 class gfxFcFont;
 class gfxProxyFontEntry;
 typedef struct _FcPattern FcPattern;
 typedef struct FT_FaceRec_* FT_Face;
 typedef struct FT_LibraryRec_  *FT_Library;
 
 class gfxPangoFontGroup : public gfxFontGroup {
 public:
-    gfxPangoFontGroup (const nsAString& families,
-                       const gfxFontStyle *aStyle,
-                       gfxUserFontSet *aUserFontSet);
-    virtual ~gfxPangoFontGroup ();
+    gfxPangoFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
+                      const gfxFontStyle *aStyle,
+                      gfxUserFontSet *aUserFontSet);
+    virtual ~gfxPangoFontGroup();
 
     virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
 
     virtual gfxFont *GetFontAt(int32_t i);
 
     virtual void UpdateFontList();
 
     virtual already_AddRefed<gfxFont>
@@ -65,19 +65,16 @@ private:
     };
     // There is only one of entry in this array unless characters from scripts
     // of other languages are measured.
     nsAutoTArray<FontSetByLangEntry,1> mFontSets;
 
     gfxFloat mSizeAdjustFactor;
     PangoLanguage *mPangoLanguage;
 
-    void GetFcFamilies(nsTArray<nsString> *aFcFamilyList,
-                       nsIAtom *aLanguage);
-
     // @param aLang [in] language to use for pref fonts and system font
     //        resolution, or nullptr to guess a language from the gfxFontStyle.
     // @param aMatchPattern [out] if non-nullptr, will return the pattern used.
     already_AddRefed<gfxFcFontSet>
     MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor,
                 nsAutoRef<FcPattern> *aMatchPattern = nullptr);
 
     gfxFcFontSet *GetBaseFontSet();
@@ -85,13 +82,17 @@ private:
 
     gfxFloat GetSizeAdjustFactor()
     {
         if (mFontSets.Length() == 0)
             GetBaseFontSet();
         return mSizeAdjustFactor;
     }
 
+    virtual void FindPlatformFont(const nsAString& aName,
+                                  bool aUseFontSet,
+                                  void *aClosure);
+
     friend class gfxSystemFcFontEntry;
     static FT_Library GetFTLibrary();
 };
 
 #endif /* GFX_PANGOFONTS_H */
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -8,16 +8,17 @@
 
 #include "prlog.h"
 #include "nsTArray.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 
 #include "gfxTypes.h"
+#include "gfxFontFamilyList.h"
 #include "nsRect.h"
 
 #include "qcms.h"
 
 #include "mozilla/RefPtr.h"
 #include "GfxInfoCollector.h"
 
 #include "mozilla/layers/CompositorTypes.h"
@@ -283,40 +284,28 @@ public:
      * gfxPlatformFontList *and* to call its InitFontList() method.
      */
     virtual gfxPlatformFontList *CreatePlatformFontList() {
         NS_NOTREACHED("oops, this platform doesn't have a gfxPlatformFontList implementation");
         return nullptr;
     }
 
     /**
-     * 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 false, the aAborted value is set to
-     * true, otherwise, false.
-     */
-    typedef bool (*FontResolverCallback) (const nsAString& aName,
-                                            void *aClosure);
-    virtual nsresult ResolveFontName(const nsAString& aFontName,
-                                     FontResolverCallback aCallback,
-                                     void *aClosure,
-                                     bool& aAborted) = 0;
-
-    /**
      * Resolving a font name to family name. The result MUST be in the result of GetFontList().
      * If the name doesn't in the system, aFamilyName will be empty string, but not failed.
      */
     virtual nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) = 0;
 
     /**
      * Create the appropriate platform font group
      */
-    virtual gfxFontGroup *CreateFontGroup(const nsAString& aFamilies,
-                                          const gfxFontStyle *aStyle,
-                                          gfxUserFontSet *aUserFontSet) = 0;
+    virtual gfxFontGroup
+    *CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
+                     const gfxFontStyle *aStyle,
+                     gfxUserFontSet *aUserFontSet) = 0;
                                           
                                           
     /**
      * Look up a local platform font using the full font face name.
      * (Needed to support @font-face src local().)
      * Ownership of the returned gfxFontEntry is passed to the caller,
      * who must either AddRef() or delete.
      */
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -431,27 +431,16 @@ gfxPlatformFontList::LoadBadUnderlineLis
     uint32_t numFonts = blacklist.Length();
     for (uint32_t i = 0; i < numFonts; i++) {
         nsAutoString key;
         GenerateFontListKey(blacklist[i], key);
         mBadUnderlineFamilyNames.PutEntry(key);
     }
 }
 
-bool 
-gfxPlatformFontList::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
-{
-    gfxFontFamily *family = FindFamily(aFontName);
-    if (family) {
-        aResolvedFontName = family->Name();
-        return true;
-    }
-    return false;
-}
-
 static PLDHashOperator
 RebuildLocalFonts(nsPtrHashKey<gfxUserFontSet>* aKey,
                   void* aClosure)
 {
     aKey->GetKey()->RebuildLocalRules();
     return PL_DHASH_NEXT;
 }
 
@@ -846,18 +835,22 @@ gfxPlatformFontList::AddPostscriptName(g
 #endif
     }
 }
 
 bool
 gfxPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
     aFamilyName.Truncate();
-    ResolveFontName(aFontName, aFamilyName);
-    return !aFamilyName.IsEmpty();
+    gfxFontFamily *ff = FindFamily(aFontName);
+    if (!ff) {
+        return false;
+    }
+    aFamilyName.Assign(ff->Name());
+    return true;
 }
 
 gfxCharacterMap*
 gfxPlatformFontList::FindCharMap(gfxCharacterMap *aCmap)
 {
     aCmap->CalcHash();
     gfxCharacterMap *cmap = AddCmap(aCmap);
     cmap->mShared = true;
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -109,19 +109,16 @@ public:
 
     // initialize font lists
     virtual nsresult InitFontList();
 
     void GetFontList (nsIAtom *aLangGroup,
                       const nsACString& aGenericFamily,
                       nsTArray<nsString>& aListOfFonts);
 
-    virtual bool ResolveFontName(const nsAString& aFontName,
-                                   nsAString& aResolvedFontName);
-
     void UpdateFontList();
 
     void ClearPrefFonts() { mPrefFonts.Clear(); }
 
     virtual void GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray);
 
     virtual gfxFontEntry*
     SystemFindFontForChar(const uint32_t aCh,
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -144,37 +144,27 @@ gfxPlatformGtk::GetFontList(nsIAtom *aLa
 
 nsresult
 gfxPlatformGtk::UpdateFontList()
 {
     return sFontconfigUtils->UpdateFontList();
 }
 
 nsresult
-gfxPlatformGtk::ResolveFontName(const nsAString& aFontName,
-                                FontResolverCallback aCallback,
-                                void *aClosure,
-                                bool& aAborted)
-{
-    return sFontconfigUtils->ResolveFontName(aFontName, aCallback,
-                                             aClosure, aAborted);
-}
-
-nsresult
 gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
     return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName);
 }
 
 gfxFontGroup *
-gfxPlatformGtk::CreateFontGroup(const nsAString &aFamilies,
+gfxPlatformGtk::CreateFontGroup(const FontFamilyList& aFontFamilyList,
                                 const gfxFontStyle *aStyle,
                                 gfxUserFontSet *aUserFontSet)
 {
-    return new gfxPangoFontGroup(aFamilies, aStyle, aUserFontSet);
+    return new gfxPangoFontGroup(aFontFamilyList, aStyle, aUserFontSet);
 }
 
 gfxFontEntry*
 gfxPlatformGtk::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                 const nsAString& aFontName)
 {
     return gfxPangoFontGroup::NewFontEntry(*aProxyEntry, aFontName);
 }
--- a/gfx/thebes/gfxPlatformGtk.h
+++ b/gfx/thebes/gfxPlatformGtk.h
@@ -35,23 +35,19 @@ public:
       GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont);
 
     nsresult GetFontList(nsIAtom *aLangGroup,
                          const nsACString& aGenericFamily,
                          nsTArray<nsString>& aListOfFonts);
 
     nsresult UpdateFontList();
 
-    nsresult ResolveFontName(const nsAString& aFontName,
-                             FontResolverCallback aCallback,
-                             void *aClosure, bool& aAborted);
-
     nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
-    gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
+    gfxFontGroup *CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                                   const gfxFontStyle *aStyle,
                                   gfxUserFontSet *aUserFontSet);
 
     /**
      * Look up a local platform font using the full font face name (needed to
      * support @font-face src local() )
      */
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -127,43 +127,28 @@ gfxPlatformMac::OptimizeImage(gfxImageSu
 TemporaryRef<ScaledFont>
 gfxPlatformMac::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
 {
     gfxMacFont *font = static_cast<gfxMacFont*>(aFont);
     return font->GetScaledFont(aTarget);
 }
 
 nsresult
-gfxPlatformMac::ResolveFontName(const nsAString& aFontName,
-                                FontResolverCallback aCallback,
-                                void *aClosure, bool& aAborted)
-{
-    nsAutoString resolvedName;
-    if (!gfxPlatformFontList::PlatformFontList()->
-             ResolveFontName(aFontName, resolvedName)) {
-        aAborted = false;
-        return NS_OK;
-    }
-    aAborted = !(*aCallback)(resolvedName, aClosure);
-    return NS_OK;
-}
-
-nsresult
 gfxPlatformMac::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
     gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
     return NS_OK;
 }
 
 gfxFontGroup *
-gfxPlatformMac::CreateFontGroup(const nsAString &aFamilies,
+gfxPlatformMac::CreateFontGroup(const FontFamilyList& aFontFamilyList,
                                 const gfxFontStyle *aStyle,
                                 gfxUserFontSet *aUserFontSet)
 {
-    return new gfxFontGroup(aFamilies, aStyle, aUserFontSet);
+    return new gfxFontGroup(aFontFamilyList, aStyle, aUserFontSet);
 }
 
 // these will move to gfxPlatform once all platforms support the fontlist
 gfxFontEntry* 
 gfxPlatformMac::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                 const nsAString& aFontName)
 {
     return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry, 
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -30,25 +30,22 @@ public:
                              gfxContentType contentType) MOZ_OVERRIDE;
 
     already_AddRefed<gfxASurface> OptimizeImage(gfxImageSurface *aSurface,
                                                 gfxImageFormat format);
 
     mozilla::TemporaryRef<mozilla::gfx::ScaledFont>
       GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont);
 
-    nsresult ResolveFontName(const nsAString& aFontName,
-                             FontResolverCallback aCallback,
-                             void *aClosure, bool& aAborted);
-
     nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
-    gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
-                                  const gfxFontStyle *aStyle,
-                                  gfxUserFontSet *aUserFontSet);
+    gfxFontGroup*
+    CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
+                    const gfxFontStyle *aStyle,
+                    gfxUserFontSet *aUserFontSet);
 
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
 
     virtual gfxPlatformFontList* CreatePlatformFontList();
 
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const uint8_t *aFontData,
--- a/gfx/thebes/gfxQtPlatform.cpp
+++ b/gfx/thebes/gfxQtPlatform.cpp
@@ -126,37 +126,27 @@ gfxQtPlatform::GetFontList(nsIAtom *aLan
 
 nsresult
 gfxQtPlatform::UpdateFontList()
 {
     return sFontconfigUtils->UpdateFontList();
 }
 
 nsresult
-gfxQtPlatform::ResolveFontName(const nsAString& aFontName,
-                                FontResolverCallback aCallback,
-                                void *aClosure,
-                                bool& aAborted)
-{
-    return sFontconfigUtils->ResolveFontName(aFontName, aCallback,
-                                             aClosure, aAborted);
-}
-
-nsresult
 gfxQtPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
     return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName);
 }
 
 gfxFontGroup *
-gfxQtPlatform::CreateFontGroup(const nsAString &aFamilies,
+gfxQtPlatform::CreateFontGroup(const FontFamilyList& aFontFamilyList,
                                const gfxFontStyle *aStyle,
                                gfxUserFontSet* aUserFontSet)
 {
-    return new gfxPangoFontGroup(aFamilies, aStyle, aUserFontSet);
+    return new gfxPangoFontGroup(aFontFamilyList, aStyle, aUserFontSet);
 }
 
 gfxFontEntry*
 gfxQtPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                 const nsAString& aFontName)
 {
     return gfxPangoFontGroup::NewFontEntry(*aProxyEntry, aFontName);
 }
--- a/gfx/thebes/gfxQtPlatform.h
+++ b/gfx/thebes/gfxQtPlatform.h
@@ -38,23 +38,19 @@ public:
       GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont) MOZ_OVERRIDE;
 
     virtual nsresult GetFontList(nsIAtom *aLangGroup,
                                  const nsACString& aGenericFamily,
                                  nsTArray<nsString>& aListOfFonts) MOZ_OVERRIDE;
 
     virtual nsresult UpdateFontList() MOZ_OVERRIDE;
 
-    virtual nsresult ResolveFontName(const nsAString& aFontName,
-                                     FontResolverCallback aCallback,
-                                     void *aClosure, bool& aAborted) MOZ_OVERRIDE;
-
     virtual nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) MOZ_OVERRIDE;
 
-    virtual gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
+    virtual gfxFontGroup *CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                                           const gfxFontStyle *aStyle,
                                           gfxUserFontSet* aUserFontSet) MOZ_OVERRIDE;
 
     /**
      * Look up a local platform font using the full font face name (needed to
      * support @font-face src local() )
      */
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -929,58 +929,29 @@ gfxWindowsPlatform::GetCommonFallbackFon
         }
     }
 
     // Arial Unicode MS has lots of glyphs for obscure characters,
     // use it as a last resort
     aFontList.AppendElement(kFontArialUnicodeMS);
 }
 
-struct ResolveData {
-    ResolveData(gfxPlatform::FontResolverCallback aCallback,
-                gfxWindowsPlatform *aCaller, const nsAString *aFontName,
-                void *aClosure) :
-        mFoundCount(0), mCallback(aCallback), mCaller(aCaller),
-        mFontName(aFontName), mClosure(aClosure) {}
-    uint32_t mFoundCount;
-    gfxPlatform::FontResolverCallback mCallback;
-    gfxWindowsPlatform *mCaller;
-    const nsAString *mFontName;
-    void *mClosure;
-};
-
-nsresult
-gfxWindowsPlatform::ResolveFontName(const nsAString& aFontName,
-                                    FontResolverCallback aCallback,
-                                    void *aClosure,
-                                    bool& aAborted)
-{
-    nsAutoString resolvedName;
-    if (!gfxPlatformFontList::PlatformFontList()->
-             ResolveFontName(aFontName, resolvedName)) {
-        aAborted = false;
-        return NS_OK;
-    }
-    aAborted = !(*aCallback)(resolvedName, aClosure);
-    return NS_OK;
-}
-
 nsresult
 gfxWindowsPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
     gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
     return NS_OK;
 }
 
 gfxFontGroup *
-gfxWindowsPlatform::CreateFontGroup(const nsAString &aFamilies,
+gfxWindowsPlatform::CreateFontGroup(const FontFamilyList& aFontFamilyList,
                                     const gfxFontStyle *aStyle,
                                     gfxUserFontSet *aUserFontSet)
 {
-    return new gfxFontGroup(aFamilies, aStyle, aUserFontSet);
+    return new gfxFontGroup(aFontFamilyList, aStyle, aUserFontSet);
 }
 
 gfxFontEntry* 
 gfxWindowsPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                     const nsAString& aFontName)
 {
     return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry, 
                                                                     aFontName);
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -187,23 +187,19 @@ public:
                          nsTArray<nsString>& aListOfFonts);
 
     nsresult UpdateFontList();
 
     virtual void GetCommonFallbackFonts(const uint32_t aCh,
                                         int32_t aRunScript,
                                         nsTArray<const char*>& aFontList);
 
-    nsresult ResolveFontName(const nsAString& aFontName,
-                             FontResolverCallback aCallback,
-                             void *aClosure, bool& aAborted);
-
     nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
-    gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
+    gfxFontGroup *CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                                   const gfxFontStyle *aStyle,
                                   gfxUserFontSet *aUserFontSet);
 
     /**
      * Look up a local platform font using the full font face name (needed to support @font-face src local() )
      */
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -552,23 +552,33 @@ nsPresContext::GetFontPrefsForLang(nsIAt
 
     // set the default variable font (the other fonts are seen as 'generic' fonts
     // in GFX and will be queried there when hunting for alternative fonts)
     if (eType == eDefaultFont_Variable) {
       MAKE_FONT_PREF_KEY(pref, "font.name.variable.", langGroup);
 
       nsAdoptingString value = Preferences::GetString(pref.get());
       if (!value.IsEmpty()) {
-        prefs->mDefaultVariableFont.name.Assign(value);
+        FontFamilyName defaultVariableName = FontFamilyName::Convert(value);
+        FontFamilyType defaultType = defaultVariableName.mType;
+        NS_ASSERTION(defaultType == eFamily_serif ||
+                     defaultType == eFamily_sans_serif,
+                     "default type must be serif or sans-serif");
+        prefs->mDefaultVariableFont.fontlist = FontFamilyList(defaultType);
       }
       else {
         MAKE_FONT_PREF_KEY(pref, "font.default.", langGroup);
         value = Preferences::GetString(pref.get());
         if (!value.IsEmpty()) {
-          prefs->mDefaultVariableFont.name.Assign(value);
+          FontFamilyName defaultVariableName = FontFamilyName::Convert(value);
+          FontFamilyType defaultType = defaultVariableName.mType;
+          NS_ASSERTION(defaultType == eFamily_serif ||
+                       defaultType == eFamily_sans_serif,
+                       "default type must be serif or sans-serif");
+          prefs->mDefaultVariableFont.fontlist = FontFamilyList(defaultType);
         }
       }
     }
     else {
       if (eType == eDefaultFont_Monospace) {
         // This takes care of the confusion whereby people often expect "monospace"
         // to have the same default font-size as "-moz-fixed" (this tentative
         // size may be overwritten with the specific value for "monospace" when
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -1059,33 +1059,38 @@ protected:
   // dtor:
   struct LangGroupFontPrefs;
   friend class nsAutoPtr<LangGroupFontPrefs>;
   struct LangGroupFontPrefs {
     // Font sizes default to zero; they will be set in GetFontPreferences
     LangGroupFontPrefs()
       : mLangGroup(nullptr)
       , mMinimumFontSize(0)
-      , mDefaultVariableFont("serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
-                             NS_FONT_WEIGHT_NORMAL, NS_FONT_STRETCH_NORMAL, 0, 0)
-      , mDefaultFixedFont("monospace", NS_FONT_STYLE_NORMAL,
+      , mDefaultVariableFont(mozilla::eFamily_serif, NS_FONT_STYLE_NORMAL,
+                             NS_FONT_VARIANT_NORMAL,
+                             NS_FONT_WEIGHT_NORMAL,
+                             NS_FONT_STRETCH_NORMAL, 0, 0)
+      , mDefaultFixedFont(mozilla::eFamily_monospace, NS_FONT_STYLE_NORMAL,
+                          NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
+                          NS_FONT_STRETCH_NORMAL, 0, 0)
+      , mDefaultSerifFont(mozilla::eFamily_serif, NS_FONT_STYLE_NORMAL,
                           NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
                           NS_FONT_STRETCH_NORMAL, 0, 0)
-      , mDefaultSerifFont("serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
-                        NS_FONT_WEIGHT_NORMAL, NS_FONT_STRETCH_NORMAL, 0, 0)
-      , mDefaultSansSerifFont("sans-serif", NS_FONT_STYLE_NORMAL,
+      , mDefaultSansSerifFont(mozilla::eFamily_sans_serif,
+                              NS_FONT_STYLE_NORMAL,
+                              NS_FONT_VARIANT_NORMAL,
+                              NS_FONT_WEIGHT_NORMAL,
+                              NS_FONT_STRETCH_NORMAL, 0, 0)
+      , mDefaultMonospaceFont(mozilla::eFamily_monospace, NS_FONT_STYLE_NORMAL,
                               NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
                               NS_FONT_STRETCH_NORMAL, 0, 0)
-      , mDefaultMonospaceFont("monospace", NS_FONT_STYLE_NORMAL,
-                              NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
-                              NS_FONT_STRETCH_NORMAL, 0, 0)
-      , mDefaultCursiveFont("cursive", NS_FONT_STYLE_NORMAL,
+      , mDefaultCursiveFont(mozilla::eFamily_cursive, NS_FONT_STYLE_NORMAL,
                             NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
                             NS_FONT_STRETCH_NORMAL, 0, 0)
-      , mDefaultFantasyFont("fantasy", NS_FONT_STYLE_NORMAL,
+      , mDefaultFantasyFont(mozilla::eFamily_fantasy, NS_FONT_STYLE_NORMAL,
                             NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
                             NS_FONT_STRETCH_NORMAL, 0, 0)
     {}
 
     size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
       size_t n = 0;
       LangGroupFontPrefs *curr = mNext;
       while (curr) {
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -9818,17 +9818,17 @@ void ReflowCountMgr::PaintCount(const ch
       aFrame != nullptr) {
     char key[KEY_BUF_SIZE_FOR_PTR];
     sprintf(key, "%p", (void*)aFrame);
     IndiReflowCounter * counter =
       (IndiReflowCounter *)PL_HashTableLookup(mIndiFrameCounts, key);
     if (counter != nullptr && counter->mName.EqualsASCII(aName)) {
       aRenderingContext->PushState();
       aRenderingContext->Translate(aOffset);
-      nsFont font("Times", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
+      nsFont font(eFamily_serif, NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
                   NS_FONT_WEIGHT_NORMAL, NS_FONT_STRETCH_NORMAL, 0,
                   nsPresContext::CSSPixelsToAppUnits(11));
 
       nsRefPtr<nsFontMetrics> fm;
       aPresContext->DeviceContext()->GetMetricsFor(font,
         // We have one frame, therefore we must have a root...
         aPresContext->GetPresShell()->GetRootFrame()->
           StyleFont()->mLanguage,
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -36,16 +36,25 @@ using namespace mozilla;
 
 // BUG 848725 Drawing failure with stretchy horizontal parenthesis when no fonts
 // are installed. "kMaxScaleFactor" is required to limit the scale for the
 // vertical and horizontal stretchy operators.
 static const float kMaxScaleFactor = 20.0;
 static const float kLargeOpFactor = float(M_SQRT2);
 static const float kIntegralFactor = 2.0;
 
+static void
+NormalizeDefaultFont(nsFont& aFont)
+{
+  if (aFont.fontlist.GetDefaultFontType() != eFamily_none) {
+    aFont.fontlist.Append(aFont.fontlist.GetDefaultFontType());
+    aFont.fontlist.SetDefaultFontType(eFamily_none);
+  }
+}
+
 // -----------------------------------------------------------------------------
 static const nsGlyphCode kNullGlyph = {{{0, 0}}, 0};
 
 // -----------------------------------------------------------------------------
 // nsGlyphTable is a class that provides an interface for accessing glyphs
 // of stretchy chars. It acts like a table that stores the variants of bigger
 // sizes (if any) and the partial glyphs needed to build extensible symbols.
 //
@@ -56,17 +65,17 @@ static const nsGlyphCode kNullGlyph = {{
 // points (for nsPropertiesTable) or as direct glyph indices (for
 // nsOpenTypeTable)
 // -----------------------------------------------------------------------------
 
 class nsGlyphTable {
 public:
   virtual ~nsGlyphTable() {}
 
-  virtual const nsAString&
+  virtual const FontFamilyName&
   FontNameFor(const nsGlyphCode& aGlyphCode) const = 0;
 
   // Getters for the parts
   virtual nsGlyphCode ElementAt(gfxContext*   aThebesContext,
                                 int32_t       aAppUnitsPerDevPixel,
                                 gfxFontGroup* aFontGroup,
                                 char16_t      aChar,
                                 bool          aVertical,
@@ -143,39 +152,38 @@ LoadProperties(const nsString& aName,
   uriStr.AppendLiteral(".properties");
   return NS_LoadPersistentPropertiesFromURISpec(getter_AddRefs(aProperties), 
                                                 NS_ConvertUTF16toUTF8(uriStr));
 }
 
 class nsPropertiesTable MOZ_FINAL : public nsGlyphTable {
 public:
   explicit nsPropertiesTable(const nsString& aPrimaryFontName)
-    : mFontName(1) // ensure space for primary font name.
-    , mState(NS_TABLE_STATE_EMPTY)
+    : mState(NS_TABLE_STATE_EMPTY)
   {
     MOZ_COUNT_CTOR(nsPropertiesTable);
-    mFontName.AppendElement(aPrimaryFontName);
+    mGlyphCodeFonts.AppendElement(FontFamilyName(aPrimaryFontName, eUnquotedName));
   }
 
   ~nsPropertiesTable()
   {
     MOZ_COUNT_DTOR(nsPropertiesTable);
   }
 
-  const nsAString& PrimaryFontName() const
+  const FontFamilyName& PrimaryFontName() const
   {
-    return mFontName[0];
+    return mGlyphCodeFonts[0];
   }
 
-  const nsAString&
+  const FontFamilyName&
   FontNameFor(const nsGlyphCode& aGlyphCode) const MOZ_OVERRIDE
   {
     NS_ASSERTION(!aGlyphCode.IsGlyphID(),
                  "nsPropertiesTable can only access glyphs by code point");
-    return mFontName[aGlyphCode.font];
+    return mGlyphCodeFonts[aGlyphCode.font];
   }
 
   virtual nsGlyphCode ElementAt(gfxContext*   aThebesContext,
                                 int32_t       aAppUnitsPerDevPixel,
                                 gfxFontGroup* aFontGroup,
                                 char16_t      aChar,
                                 bool          aVertical,
                                 uint32_t      aPosition) MOZ_OVERRIDE;
@@ -208,20 +216,20 @@ public:
   }
 
   virtual gfxTextRun* MakeTextRun(gfxContext*        aThebesContext,
                                   int32_t            aAppUnitsPerDevPixel,
                                   gfxFontGroup*      aFontGroup,
                                   const nsGlyphCode& aGlyph) MOZ_OVERRIDE;
 private:
 
-  // mFontName[0] is the primary font associated to this table. The others 
-  // are possible "external" fonts for glyphs not in the primary font
+  // mGlyphCodeFonts[0] is the primary font associated to this table. The
+  // others are possible "external" fonts for glyphs not in the primary font
   // but which are needed to stretch certain characters in the table
-  nsTArray<nsString> mFontName;
+  nsTArray<FontFamilyName> mGlyphCodeFonts;
 
   // Tri-state variable for error/empty/ready
   int32_t mState;
 
   // The set of glyph data in this table, as provided by the MathFont Property
   // File
   nsCOMPtr<nsIPersistentProperties> mGlyphProperties;
 
@@ -252,22 +260,24 @@ nsPropertiesTable::ElementAt(gfxContext*
                              gfxFontGroup* /* aFontGroup */,
                              char16_t      aChar,
                              bool          /* aVertical */,
                              uint32_t      aPosition)
 {
   if (mState == NS_TABLE_STATE_ERROR) return kNullGlyph;
   // Load glyph properties if this is the first time we have been here
   if (mState == NS_TABLE_STATE_EMPTY) {
-    nsresult rv = LoadProperties(mFontName[0], mGlyphProperties);
+    nsAutoString primaryFontName;
+    mGlyphCodeFonts[0].AppendToString(primaryFontName);
+    nsresult rv = LoadProperties(primaryFontName, mGlyphProperties);
 #ifdef DEBUG
     nsAutoCString uriStr;
     uriStr.AssignLiteral("resource://gre/res/fonts/mathfont");
-    LossyAppendUTF16toASCII(mFontName[0], uriStr);
-    uriStr.StripWhitespace(); // that may come from mFontName
+    LossyAppendUTF16toASCII(primaryFontName, uriStr);
+    uriStr.StripWhitespace(); // that may come from mGlyphCodeFonts
     uriStr.AppendLiteral(".properties");
     printf("Loading %s ... %s\n",
             uriStr.get(),
             (NS_FAILED(rv)) ? "Failed" : "Done");
 #endif
     if (NS_FAILED(rv)) {
       mState = NS_TABLE_STATE_ERROR; // never waste time with this table again
       return kNullGlyph;
@@ -278,17 +288,17 @@ nsPropertiesTable::ElementAt(gfxContext*
     nsAutoCString key;
     nsAutoString value;
     for (int32_t i = 1; ; i++) {
       key.AssignLiteral("external.");
       key.AppendInt(i, 10);
       rv = mGlyphProperties->GetStringProperty(key, value);
       if (NS_FAILED(rv)) break;
       Clean(value);
-      mFontName.AppendElement(value); // i.e., mFontName[i] holds this font name
+      mGlyphCodeFonts.AppendElement(FontFamilyName(value, eUnquotedName)); // i.e., mGlyphCodeFonts[i] holds this font name
     }
   }
 
   // Update our cache if it is not associated to this character
   if (mCharCache != aChar) {
     // The key in the property file is interpreted as ASCII and kept
     // as such ...
     char key[10]; PR_snprintf(key, sizeof(key), "\\u%04X", aChar);
@@ -298,17 +308,17 @@ nsPropertiesTable::ElementAt(gfxContext*
     if (NS_FAILED(rv)) return kNullGlyph;
     Clean(value);
     // See if this char uses external fonts; e.g., if the 2nd glyph is taken
     // from the external font '1', the property line looks like
     // \uNNNN = \uNNNN\uNNNN@1\uNNNN.
     // This is where mGlyphCache is pre-processed to explicitly store all glyph
     // codes as combined pairs of 'code@font', excluding the '@' separator. This
     // means that mGlyphCache[3*k],mGlyphCache[3*k+1] will later be rendered
-    // with mFontName[mGlyphCache[3*k+2]]
+    // with mGlyphCodeFonts[mGlyphCache[3*k+2]]
     // Note: font identifier is internally an ASCII digit to avoid the null
     // char issue
     nsAutoString buffer;
     int32_t length = value.Length();
     int32_t i = 0; // index in value
     while (i < length) {
       char16_t code = value[i];
       ++i;
@@ -325,22 +335,22 @@ nsPropertiesTable::ElementAt(gfxContext*
       // See if an external font is needed for the code point.
       // Limit of 9 external fonts
       char16_t font = 0;
       if (i+1 < length && value[i] == char16_t('@') &&
           value[i+1] >= char16_t('0') && value[i+1] <= char16_t('9')) {
         ++i;
         font = value[i] - '0';
         ++i;
-        if (font >= mFontName.Length()) {
+        if (font >= mGlyphCodeFonts.Length()) {
           NS_ERROR("Nonexistent font referenced in glyph table");
           return kNullGlyph;
         }
         // The char cannot be handled if this font is not installed
-        if (!mFontName[font].Length()) {
+        if (!mGlyphCodeFonts[font].mName.Length()) {
           return kNullGlyph;
         }
       }
       buffer.Append(font);
     }
     // update our cache with the new settings
     mGlyphCache.Assign(buffer);
     mCharCache = aChar;
@@ -394,21 +404,21 @@ public:
                             bool          aVertical,
                             uint32_t      aSize) MOZ_OVERRIDE;
   virtual bool HasPartsOf(gfxContext*   aThebesContext,
                           int32_t       aAppUnitsPerDevPixel,
                           gfxFontGroup* aFontGroup,
                           char16_t      aChar,
                           bool          aVertical) MOZ_OVERRIDE;
 
-  const nsAString&
+  const FontFamilyName&
   FontNameFor(const nsGlyphCode& aGlyphCode) const MOZ_OVERRIDE {
     NS_ASSERTION(aGlyphCode.IsGlyphID(),
                  "nsOpenTypeTable can only access glyphs by id");
-    return mFontEntry->FamilyName();
+    return mFontFamilyName;
   }
 
   virtual gfxTextRun* MakeTextRun(gfxContext*        aThebesContext,
                                   int32_t            aAppUnitsPerDevPixel,
                                   gfxFontGroup*      aFontGroup,
                                   const nsGlyphCode& aGlyph) MOZ_OVERRIDE;
 
   // This returns a new OpenTypeTable instance to give access to OpenType MATH
@@ -419,20 +429,22 @@ public:
     if (!aFont->GetFontEntry()->TryGetMathTable(aFont)) {
       return nullptr;
     }
     return new nsOpenTypeTable(aFont->GetFontEntry());
   }
 
 private:
   nsRefPtr<gfxFontEntry> mFontEntry;
+  FontFamilyName mFontFamilyName;
   uint32_t mGlyphID;
 
   explicit nsOpenTypeTable(gfxFontEntry* aFontEntry)
-    : mFontEntry(aFontEntry) {
+    : mFontEntry(aFontEntry),
+      mFontFamilyName(aFontEntry->FamilyName(), eUnquotedName) {
     MOZ_COUNT_CTOR(nsOpenTypeTable);
   }
 
   void UpdateCache(gfxContext*   aThebesContext,
                    int32_t       aAppUnitsPerDevPixel,
                    gfxFontGroup* aFontGroup,
                    char16_t      aChar);
 };
@@ -666,19 +678,21 @@ nsGlyphTableList::AddGlyphTable(const ns
   return glyphTable;
 }
 
 nsGlyphTable*
 nsGlyphTableList::GetGlyphTableFor(const nsAString& aFamily)
 {
   for (int32_t i = 0; i < PropertiesTableCount(); i++) {
     nsPropertiesTable* glyphTable = PropertiesTableAt(i);
-    const nsAString& fontName = glyphTable->PrimaryFontName();
+    const FontFamilyName& primaryFontName = glyphTable->PrimaryFontName();
+    nsAutoString primaryFontNameStr;
+    primaryFontName.AppendToString(primaryFontNameStr);
     // TODO: would be nice to consider StripWhitespace and other aliasing
-    if (fontName.Equals(aFamily, nsCaseInsensitiveStringComparator())) {
+    if (primaryFontNameStr.Equals(aFamily, nsCaseInsensitiveStringComparator())) {
       return glyphTable;
     }
   }
   // Fall back to default Unicode table
   return &mUnicodeTable;
 }
 
 // -----------------------------------------------------------------------------
@@ -939,118 +953,55 @@ ComputeSizeFromParts(nsPresContext* aPre
 
   if (minSize > aTargetSize)
     return minSize; // settle with the minimum size
 
   // Fill-up the target area
   return aTargetSize;
 }
 
-// Insert aFallbackFamilies before the first generic family in or at the end
-// of a CSS aFontName.
-static void
-AddFallbackFonts(nsAString& aFontName, const nsAString& aFallbackFamilies)
-{
-  if (aFallbackFamilies.IsEmpty())
-    return;
-
-  if (aFontName.IsEmpty()) {
-    return;
-  }
-
-  static const char16_t kSingleQuote  = char16_t('\'');
-  static const char16_t kDoubleQuote  = char16_t('\"');
-  static const char16_t kComma        = char16_t(',');
-
-  const char16_t *p_begin, *p_end;
-  aFontName.BeginReading(p_begin);
-  aFontName.EndReading(p_end);
-
-  const char16_t *p = p_begin;
-  const char16_t *p_name = nullptr;
-  while (p < p_end) {
-    while (nsCRT::IsAsciiSpace(*p))
-      if (++p == p_end)
-        goto insert;
-
-    p_name = p;
-    if (*p == kSingleQuote || *p == kDoubleQuote) {
-      // quoted font family
-      char16_t quoteMark = *p;
-      if (++p == p_end)
-        goto insert;
-
-      // XXX What about CSS character escapes?
-      while (*p != quoteMark)
-        if (++p == p_end)
-          goto insert;
-
-      while (++p != p_end && *p != kComma)
-        /* nothing */ ;
-
-    } else {
-      // unquoted font family
-      const char16_t *nameStart = p;
-      while (++p != p_end && *p != kComma)
-        /* nothing */ ;
-
-      nsAutoString family;
-      family = Substring(nameStart, p);
-      family.CompressWhitespace(false, true);
-
-      uint8_t generic;
-      nsFont::GetGenericID(family, &generic);
-      if (generic != kGenericFont_NONE)
-        goto insert;
-    }
-
-    ++p; // may advance past p_end
-  }
-
-  aFontName.Append(',');
-  aFontName.Append(aFallbackFamilies);
-  return;
-
-insert:
-  if (p_name) {
-    aFontName.Insert(aFallbackFamilies + NS_LITERAL_STRING(","),
-                     p_name - p_begin);
-  }
-  else { // whitespace or empty
-    aFontName = aFallbackFamilies;
-  }
-}
-
 // Update the font if there is a family change and returns the font group.
 bool
 nsMathMLChar::SetFontFamily(nsPresContext*          aPresContext,
                             const nsGlyphTable*     aGlyphTable,
                             const nsGlyphCode&      aGlyphCode,
-                            const nsAString&        aDefaultFamily,
+                            const FontFamilyList&   aDefaultFamilyList,
                             nsFont&                 aFont,
                             nsRefPtr<gfxFontGroup>* aFontGroup)
 {
-  const nsAString& family =
-    aGlyphCode.font ? aGlyphTable->FontNameFor(aGlyphCode) : aDefaultFamily;
-  if (!*aFontGroup || !family.Equals(aFont.name)) {
+  FontFamilyList glyphCodeFont;
+
+  if (aGlyphCode.font) {
+    glyphCodeFont.Append(aGlyphTable->FontNameFor(aGlyphCode));
+  }
+
+  const FontFamilyList& familyList =
+    aGlyphCode.font ? glyphCodeFont : aDefaultFamilyList;
+
+  if (!*aFontGroup || !(aFont.fontlist == familyList)) {
     nsFont font = aFont;
-    font.name = family;
+    font.fontlist = familyList;
     nsRefPtr<nsFontMetrics> fm;
     aPresContext->DeviceContext()->
       GetMetricsFor(font,
                     mStyleContext->StyleFont()->mLanguage,
                     aPresContext->GetUserFontSet(),
                     aPresContext->GetTextPerfMetrics(),
                     *getter_AddRefs(fm));
     // Set the font if it is an unicode table
     // or if the same family name has been found
+    gfxFont *firstFont = fm->GetThebesFontGroup()->GetFontAt(0);
+    FontFamilyList firstFontList;
+    if (firstFont) {
+      firstFontList.Append(
+        FontFamilyName(firstFont->GetFontEntry()->FamilyName(), eUnquotedName));
+    }
     if (aGlyphTable == &gGlyphTableList->mUnicodeTable ||
-        fm->GetThebesFontGroup()->GetFontAt(0)->GetFontEntry()->
-        FamilyName() == family) {
-      aFont.name = family;
+        firstFontList == familyList) {
+      aFont.fontlist = familyList;
       *aFontGroup = fm->GetThebesFontGroup();
     } else {
       return false; // We did not set the font
     }
   }
   return true;
 }
 
@@ -1076,50 +1027,50 @@ class nsMathMLChar::StretchEnumContext {
 public:
   StretchEnumContext(nsMathMLChar*        aChar,
                      nsPresContext*       aPresContext,
                      gfxContext*          aThebesContext,
                      nsStretchDirection   aStretchDirection,
                      nscoord              aTargetSize,
                      uint32_t             aStretchHint,
                      nsBoundingMetrics&   aStretchedMetrics,
-                     const nsAString&     aFamilies,
+                     const FontFamilyList&  aFamilyList,
                      bool&              aGlyphFound)
     : mChar(aChar),
       mPresContext(aPresContext),
       mThebesContext(aThebesContext),
       mDirection(aStretchDirection),
       mTargetSize(aTargetSize),
       mStretchHint(aStretchHint),
       mBoundingMetrics(aStretchedMetrics),
-      mFamilies(aFamilies),
+      mFamilyList(aFamilyList),
       mTryVariants(true),
       mTryParts(true),
       mGlyphFound(aGlyphFound) {}
 
   static bool
-  EnumCallback(const nsString& aFamily, bool aGeneric, void *aData);
+  EnumCallback(const FontFamilyName& aFamily, bool aGeneric, void *aData);
 
 private:
   bool TryVariants(nsGlyphTable* aGlyphTable,
                    nsRefPtr<gfxFontGroup>* aFontGroup,
-                   const nsAString& aFamily);
+                   const FontFamilyList& aFamilyList);
   bool TryParts(nsGlyphTable* aGlyphTable,
                 nsRefPtr<gfxFontGroup>* aFontGroup,
-                const nsAString& aFamily);
+                const FontFamilyList& aFamilyList);
 
   nsMathMLChar* mChar;
   nsPresContext* mPresContext;
   gfxContext* mThebesContext;
   const nsStretchDirection mDirection;
   const nscoord mTargetSize;
   const uint32_t mStretchHint;
   nsBoundingMetrics& mBoundingMetrics;
   // Font families to search
-  const nsAString& mFamilies;
+  const FontFamilyList& mFamilyList;
 
 public:
   bool mTryVariants;
   bool mTryParts;
 
 private:
   nsAutoTArray<nsGlyphTable*,16> mTablesTried;
   bool&       mGlyphFound;
@@ -1128,21 +1079,22 @@ private:
 
 // 2. See if there are any glyphs of the appropriate size.
 // Returns true if the size is OK, false to keep searching.
 // Always updates the char if a better match is found.
 bool
 nsMathMLChar::
 StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable,
                                 nsRefPtr<gfxFontGroup>* aFontGroup,
-                                const nsAString& aFamily)
+                                const FontFamilyList& aFamilyList)
 {
   // Use our stretchy style context now that stretching is in progress
   nsStyleContext *sc = mChar->mStyleContext;
   nsFont font = sc->StyleFont()->mFont;
+  NormalizeDefaultFont(font);
 
   bool isVertical = (mDirection == NS_STRETCH_DIRECTION_VERTICAL);
   nscoord oneDevPixel = mPresContext->AppUnitsPerDevPixel();
   char16_t uchar = mChar->mData[0];
   bool largeop = (NS_STRETCH_LARGEOP & mStretchHint) != 0;
   bool largeopOnly =
     largeop && (NS_STRETCH_VARIABLE_MASK & mStretchHint) == 0;
   bool maxWidth = (NS_STRETCH_MAXWIDTH & mStretchHint) != 0;
@@ -1186,17 +1138,17 @@ StretchEnumContext::TryVariants(nsGlyphT
   }
 #ifdef NOISY_SEARCH
   printf("  searching in %s ...\n",
            NS_LossyConvertUTF16toASCII(aFamily).get());
 #endif
   while ((ch = aGlyphTable->BigOf(mThebesContext, oneDevPixel, *aFontGroup,
                                   uchar, isVertical, size)).Exists()) {
 
-    if (!mChar->SetFontFamily(mPresContext, aGlyphTable, ch, aFamily, font,
+    if (!mChar->SetFontFamily(mPresContext, aGlyphTable, ch, aFamilyList, font,
                               aFontGroup)) {
       // if largeopOnly is set, break now
       if (largeopOnly) break;
       ++size;
       continue;
     }
 
     nsAutoPtr<gfxTextRun> textRun;
@@ -1277,20 +1229,21 @@ StretchEnumContext::TryVariants(nsGlyphT
 }
 
 // 3. Build by parts.
 // Returns true if the size is OK, false to keep searching.
 // Always updates the char if a better match is found.
 bool
 nsMathMLChar::StretchEnumContext::TryParts(nsGlyphTable* aGlyphTable,
                                            nsRefPtr<gfxFontGroup>* aFontGroup,
-                                           const nsAString& aFamily)
+                                           const FontFamilyList& aFamilyList)
 {
   // Use our stretchy style context now that stretching is in progress
   nsFont font = mChar->mStyleContext->StyleFont()->mFont;
+  NormalizeDefaultFont(font);
 
   // Compute the bounding metrics of all partial glyphs
   nsAutoPtr<gfxTextRun> textRun[4];
   nsGlyphCode chdata[4];
   nsBoundingMetrics bmdata[4];
   nscoord sizedata[4];
 
   bool isVertical = (mDirection == NS_STRETCH_DIRECTION_VERTICAL);
@@ -1301,17 +1254,17 @@ nsMathMLChar::StretchEnumContext::TryPar
                                uchar, isVertical))
     return false; // to next table
 
   for (int32_t i = 0; i < 4; i++) {
     nsGlyphCode ch = aGlyphTable->ElementAt(mThebesContext, oneDevPixel,
                                             *aFontGroup, uchar, isVertical, i);
     chdata[i] = ch;
     if (ch.Exists()) {
-      if (!mChar->SetFontFamily(mPresContext, aGlyphTable, ch, aFamily, font,
+      if (!mChar->SetFontFamily(mPresContext, aGlyphTable, ch, aFamilyList, font,
                                 aFontGroup))
         return false;
 
       textRun[i] = aGlyphTable->MakeTextRun(mThebesContext, oneDevPixel,
                                             *aFontGroup, ch);
       nsBoundingMetrics bm = MeasureTextRun(mThebesContext, textRun[i]);
       bmdata[i] = bm;
       sizedata[i] = isVertical ? bm.ascent + bm.descent
@@ -1443,28 +1396,31 @@ nsMathMLChar::StretchEnumContext::TryPar
     mChar->mBmData[i] = bmdata[i];
   }
 
   return IsSizeOK(mPresContext, computedSize, mTargetSize, mStretchHint);
 }
 
 // This is called for each family, whether it exists or not
 bool
-nsMathMLChar::StretchEnumContext::EnumCallback(const nsString& aFamily,
+nsMathMLChar::StretchEnumContext::EnumCallback(const FontFamilyName& aFamily,
                                                bool aGeneric, void *aData)
 {
   StretchEnumContext* context = static_cast<StretchEnumContext*>(aData);
 
   // Check font family if it is not a generic one
   // We test with the kNullGlyph
   nsStyleContext *sc = context->mChar->mStyleContext;
   nsFont font = sc->StyleFont()->mFont;
+  NormalizeDefaultFont(font);
   nsRefPtr<gfxFontGroup> fontGroup;
+  FontFamilyList family;
+  family.Append(aFamily);
   if (!aGeneric && !context->mChar->SetFontFamily(context->mPresContext,
-                                                  nullptr, kNullGlyph, aFamily,
+                                                  nullptr, kNullGlyph, family,
                                                   font, &fontGroup))
      return true; // Could not set the family
 
   // Determine the glyph table to use for this font.
   nsAutoPtr<nsOpenTypeTable> openTypeTable;
   nsGlyphTable* glyphTable;
   if (aGeneric) {
     // This is a generic font, use the Unicode table.
@@ -1472,42 +1428,72 @@ nsMathMLChar::StretchEnumContext::EnumCa
   } else {
     // If the font contains an Open Type MATH table, use it.
     openTypeTable = nsOpenTypeTable::Create(fontGroup->GetFontAt(0));
     if (openTypeTable) {
       glyphTable = openTypeTable;
     } else {
       // Otherwise try to find a .properties file corresponding to that font
       // family or fallback to the Unicode table.
-      glyphTable = gGlyphTableList->GetGlyphTableFor(aFamily);
+      nsAutoString familyName;
+      aFamily.AppendToString(familyName);
+      glyphTable = gGlyphTableList->GetGlyphTableFor(familyName);
     }
   }
 
   if (!openTypeTable) {
     if (context->mTablesTried.Contains(glyphTable))
       return true; // already tried this one
     
     // Only try this table once.
     context->mTablesTried.AppendElement(glyphTable);
   }
 
   // If the unicode table is being used, then search all font families.  If a
   // special table is being used then the font in this family should have the
   // specified glyphs.
-  const nsAString& family = glyphTable == &gGlyphTableList->mUnicodeTable ?
-    context->mFamilies : aFamily;
+  const FontFamilyList& familyList = glyphTable == &gGlyphTableList->mUnicodeTable ?
+    context->mFamilyList : family;
 
   if((context->mTryVariants &&
-      context->TryVariants(glyphTable, &fontGroup, family)) ||
-     (context->mTryParts && context->TryParts(glyphTable, &fontGroup, family)))
+      context->TryVariants(glyphTable, &fontGroup, familyList)) ||
+     (context->mTryParts && context->TryParts(glyphTable,
+                                              &fontGroup,
+                                              familyList)))
     return false; // no need to continue
 
   return true; // true means continue
 }
 
+// insert math fallback families just before the first generic or at the end
+// when no generic present
+static void
+InsertMathFallbacks(FontFamilyList& aFamilyList,
+                    nsTArray<nsString>& aFallbacks)
+{
+  FontFamilyList aMergedList;
+
+  bool inserted = false;
+  const nsTArray<FontFamilyName>& fontlist = aFamilyList.GetFontlist();
+  uint32_t i, num = fontlist.Length();
+  for (i = 0; i < num; i++) {
+    const FontFamilyName& name = fontlist[i];
+    if (!inserted && name.IsGeneric()) {
+      inserted = true;
+      aMergedList.Append(aFallbacks);
+    }
+    aMergedList.Append(name);
+  }
+
+  if (!inserted) {
+    aMergedList.Append(aFallbacks);
+  }
+  aFamilyList = aMergedList;
+}
+
 nsresult
 nsMathMLChar::StretchInternal(nsPresContext*           aPresContext,
                               gfxContext*              aThebesContext,
                               nsStretchDirection&      aStretchDirection,
                               const nsBoundingMetrics& aContainerSize,
                               nsBoundingMetrics&       aDesiredStretchSize,
                               uint32_t                 aStretchHint,
                               // These are currently only used when
@@ -1519,16 +1505,17 @@ nsMathMLChar::StretchInternal(nsPresCont
   // direction may have been set to NS_STRETCH_DIRECTION_UNSUPPORTED.
   // So first set our direction back to its instrinsic value
   nsStretchDirection direction = nsMathMLOperators::GetStretchyDirection(mData);
 
   // Set default font and get the default bounding metrics
   // mStyleContext is a leaf context used only when stretching happens.
   // For the base size, the default font should come from the parent context
   nsFont font = mStyleContext->GetParent()->StyleFont()->mFont;
+  NormalizeDefaultFont(font);
 
   nsRefPtr<nsFontMetrics> fm;
   aPresContext->DeviceContext()->
     GetMetricsFor(font,
                   mStyleContext->StyleFont()->mLanguage,
                   aPresContext->GetUserFontSet(),
                   aPresContext->GetTextPerfMetrics(),
                   *getter_AddRefs(fm));
@@ -1631,32 +1618,43 @@ nsMathMLChar::StretchInternal(nsPresCont
   // 2/3. Search for a glyph or set of part glyphs of appropriate size
   //////////////////////////////////////////////////////////////////////////////
 
   bool glyphFound = false;
 
   if (!done) { // normal case
     // Use the css font-family but add preferred fallback fonts.
     font = mStyleContext->StyleFont()->mFont;
-    NS_NAMED_LITERAL_CSTRING(defaultKey, "font.mathfont-family");
-    nsAdoptingString fallbackFonts = Preferences::GetString(defaultKey.get());
-    if (!fallbackFonts.IsEmpty()) {
-      AddFallbackFonts(font.name, fallbackFonts);
-    }
+    NormalizeDefaultFont(font);
+
+    // really shouldn't be doing things this way but for now
+    // insert fallbacks into the list
+    nsAutoTArray<nsString, 10> mathFallbacks;
+    gfxFontUtils::GetPrefsFontList("font.mathfont-family", mathFallbacks);
+    InsertMathFallbacks(font.fontlist, mathFallbacks);
+
 
 #ifdef NOISY_SEARCH
+    nsAutoString fontlistStr;
+    font.fontlist.ToString(fontlistStr, false, true);
     printf("Searching in "%s" for a glyph of appropriate size for: 0x%04X:%c\n",
-           font.name, mData[0], mData[0]&0x00FF);
+           NS_ConvertUTF16toUTF8(fontlistStr).get(), mData[0], mData[0]&0x00FF);
 #endif
     StretchEnumContext enumData(this, aPresContext, aThebesContext,
                                 aStretchDirection, targetSize, aStretchHint,
-                                aDesiredStretchSize, font.name, glyphFound);
+                                aDesiredStretchSize, font.fontlist, glyphFound);
     enumData.mTryParts = !largeopOnly;
 
-    font.EnumerateFamilies(StretchEnumContext::EnumCallback, &enumData);
+    const nsTArray<FontFamilyName>& fontlist = font.fontlist.GetFontlist();
+    uint32_t i, num = fontlist.Length();
+    bool next = true;
+    for (i = 0; i < num && next; i++) {
+      const FontFamilyName& name = fontlist[i];
+      next = StretchEnumContext::EnumCallback(name, name.IsGeneric(), &enumData);
+    }
   }
 
   if (!maxWidth) {
     // Now, we know how we are going to draw the char. Update the member
     // variables accordingly.
     mUnscaledAscent = aDesiredStretchSize.ascent;
   }
     
--- a/layout/mathml/nsMathMLChar.h
+++ b/layout/mathml/nsMathMLChar.h
@@ -233,17 +233,17 @@ private:
   class StretchEnumContext;
   friend class StretchEnumContext;
 
   // helper methods
   bool
   SetFontFamily(nsPresContext*          aPresContext,
                 const nsGlyphTable*     aGlyphTable,
                 const nsGlyphCode&      aGlyphCode,
-                const nsAString&        aDefaultFamily,
+                const mozilla::FontFamilyList& aDefaultFamily,
                 nsFont&                 aFont,
                 nsRefPtr<gfxFontGroup>* aFontGroup);
 
   nsresult
   StretchInternal(nsPresContext*           aPresContext,
                   gfxContext*              aThebesContext,
                   nsStretchDirection&      aStretchDirection,
                   const nsBoundingMetrics& aContainerSize,
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -542,16 +542,18 @@ public:
     NS_ABORT_IF_FALSE(mUnit == eCSSUnit_SharedList, "not a shared list value");
     return mValue.mSharedList;
   }
 
   mozilla::FontFamilyList* GetFontFamilyListValue() const
   {
     NS_ABORT_IF_FALSE(mUnit == eCSSUnit_FontFamilyList,
                       "not a font family list value");
+    NS_ASSERTION(mValue.mFontFamilyList != nullptr,
+                 "font family list value should never be null");
     return mValue.mFontFamilyList;
   }
 
   // bodies of these are below
   inline nsCSSValuePair& GetPairValue();
   inline const nsCSSValuePair& GetPairValue() const;
 
   inline nsCSSRect& GetRectValue();
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1426,40 +1426,20 @@ nsComputedDOMStyle::DoGetQuotes()
 }
 
 CSSValue*
 nsComputedDOMStyle::DoGetFontFamily()
 {
   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
 
   const nsStyleFont* font = StyleFont();
-
-  nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocumentWeak);
-  NS_ASSERTION(doc, "document is required");
-  nsIPresShell* presShell = doc->GetShell();
-  NS_ASSERTION(presShell, "pres shell is required");
-  nsPresContext *presContext = presShell->GetPresContext();
-  NS_ASSERTION(presContext, "pres context is required");
-
-  const nsString& fontName = font->mFont.name;
-  if (font->mGenericID == kGenericFont_NONE && !font->mFont.systemFont) {
-    const nsFont* defaultFont =
-      presContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
-                                  font->mLanguage);
-
-    int32_t lendiff = fontName.Length() - defaultFont->name.Length();
-    if (lendiff > 0) {
-      val->SetString(Substring(fontName, 0, lendiff-1)); // -1 removes comma
-    } else {
-      val->SetString(fontName);
-    }
-  } else {
-    val->SetString(fontName);
-  }
-
+  nsAutoString fontlistStr;
+  nsStyleUtil::AppendEscapedCSSFontFamilyList(font->mFont.fontlist,
+                                              fontlistStr);
+  val->SetString(fontlistStr);
   return val;
 }
 
 CSSValue*
 nsComputedDOMStyle::DoGetFontSize()
 {
   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
 
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -3290,17 +3290,21 @@ nsRuleNode::SetFont(nsPresContext* aPres
   const nsCSSValue* systemFontValue = aRuleData->ValueForSystemFont();
   if (eCSSUnit_Enumerated == systemFontValue->GetUnit()) {
     gfxFontStyle fontStyle;
     LookAndFeel::FontID fontID =
       (LookAndFeel::FontID)systemFontValue->GetIntValue();
     float devPerCSS =
       (float)nsPresContext::AppUnitsPerCSSPixel() /
       aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
-    if (LookAndFeel::GetFont(fontID, systemFont.name, fontStyle, devPerCSS)) {
+    nsAutoString systemFontName;
+    if (LookAndFeel::GetFont(fontID, systemFontName, fontStyle, devPerCSS)) {
+      systemFontName.Trim("\"'");
+      systemFont.fontlist = FontFamilyList(systemFontName, eUnquotedName);
+      systemFont.fontlist.SetDefaultFontType(eFamily_none);
       systemFont.style = fontStyle.style;
       systemFont.systemFont = fontStyle.systemFont;
       systemFont.variant = NS_FONT_VARIANT_NORMAL;
       systemFont.weight = fontStyle.weight;
       systemFont.stretch = fontStyle.stretch;
       systemFont.decorations = NS_FONT_DECORATION_NONE;
       systemFont.size = NSFloatPixelsToAppUnits(fontStyle.size,
                                                 aPresContext->DeviceContext()->
@@ -3339,42 +3343,47 @@ nsRuleNode::SetFont(nsPresContext* aPres
   // font-family: font family list, enum, inherit
   const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
   NS_ASSERTION(eCSSUnit_Enumerated != familyValue->GetUnit(),
                "system fonts should not be in mFamily anymore");
   if (eCSSUnit_FontFamilyList == familyValue->GetUnit()) {
     // set the correct font if we are using DocumentFonts OR we are overriding for XUL
     // MJA: bug 31816
     if (aGenericFontID == kGenericFont_NONE) {
-      // only bother appending fallback fonts if this isn't a fallback generic font itself
-      if (!aFont->mFont.name.IsEmpty())
-        aFont->mFont.name.Append((char16_t)',');
-      // defaultVariableFont.name should always be "serif" or "sans-serif".
-      aFont->mFont.name.Append(defaultVariableFont->name);
+      uint32_t len = defaultVariableFont->fontlist.Length();
+      FontFamilyType generic = defaultVariableFont->fontlist.FirstGeneric();
+      NS_ASSERTION(len == 1 &&
+                   (generic == eFamily_serif || generic == eFamily_sans_serif),
+                   "default variable font must be a single serif or sans-serif");
+      if (len == 1 && generic != eFamily_none) {
+        aFont->mFont.fontlist.SetDefaultFontType(generic);
+      }
+    } else {
+      aFont->mFont.fontlist.SetDefaultFontType(eFamily_none);
     }
     aFont->mFont.systemFont = false;
     // Technically this is redundant with the code below, but it's good
     // to have since we'll still want it once we get rid of
     // SetGenericFont (bug 380915).
     aFont->mGenericID = aGenericFontID;
   }
   else if (eCSSUnit_System_Font == familyValue->GetUnit()) {
-    aFont->mFont.name = systemFont.name;
+    aFont->mFont.fontlist = systemFont.fontlist;
     aFont->mFont.systemFont = true;
     aFont->mGenericID = kGenericFont_NONE;
   }
   else if (eCSSUnit_Inherit == familyValue->GetUnit() ||
            eCSSUnit_Unset == familyValue->GetUnit()) {
     aCanStoreInRuleTree = false;
-    aFont->mFont.name = aParentFont->mFont.name;
+    aFont->mFont.fontlist = aParentFont->mFont.fontlist;
     aFont->mFont.systemFont = aParentFont->mFont.systemFont;
     aFont->mGenericID = aParentFont->mGenericID;
   }
   else if (eCSSUnit_Initial == familyValue->GetUnit()) {
-    aFont->mFont.name = defaultVariableFont->name;
+    aFont->mFont.fontlist = defaultVariableFont->fontlist;
     aFont->mFont.systemFont = defaultVariableFont->systemFont;
     aFont->mGenericID = kGenericFont_NONE;
   }
 
   // When we're in the loop in SetGenericFont, we must ensure that we
   // always keep aFont->mFlags set to the correct generic.  But we have
   // to be careful not to touch it when we're called directly from
   // ComputeFontData, because we could have a start struct.
@@ -3899,24 +3908,24 @@ nsRuleNode::ComputeFontData(void* aStart
   }
 
   // Figure out if we are a generic font
   uint8_t generic = kGenericFont_NONE;
   // XXXldb What if we would have had a string if we hadn't been doing
   // the optimization with a non-null aStartStruct?
   const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
   if (eCSSUnit_FontFamilyList == familyValue->GetUnit()) {
-    font->mFont.name.Truncate();
     const FontFamilyList* fontlist = familyValue->GetFontFamilyListValue();
-    nsStyleUtil::AppendEscapedCSSFontFamilyList(*fontlist, font->mFont.name);
+    FontFamilyList& fl = font->mFont.fontlist;
+    fl = *fontlist;
 
     // extract the first generic in the fontlist, if exists
     FontFamilyType fontType = fontlist->FirstGeneric();
 
-    // if only a generic, set the generic type
+    // if only a single generic, set the generic type
     if (fontlist->Length() == 1) {
       switch (fontType) {
         case eFamily_serif:
           generic = kGenericFont_serif;
           break;
         case eFamily_sans_serif:
           generic = kGenericFont_sans_serif;
           break;
@@ -3935,28 +3944,26 @@ nsRuleNode::ComputeFontData(void* aStart
         default:
           break;
       }
     }
 
     // If we aren't allowed to use document fonts, then we are only entitled
     // to use the user's default variable-width font and fixed-width font
     if (!useDocumentFonts) {
-
       switch (fontType) {
         case eFamily_monospace:
-          font->mFont.name.AssignLiteral("monospace");
+          fl = FontFamilyList(eFamily_monospace);
           generic = kGenericFont_monospace;
           break;
         case eFamily_moz_fixed:
-          font->mFont.name.AssignLiteral("-moz-fixed");
+          fl = FontFamilyList(eFamily_moz_fixed);
           generic = kGenericFont_moz_fixed;
-          break;
         default:
-          font->mFont.name.Truncate();
+          fl.Clear();
           generic = kGenericFont_NONE;
           break;
       }
     }
   }
 
   // Now compute our font struct
   if (generic == kGenericFont_NONE) {
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -219,17 +219,17 @@ nsChangeHint nsStyleFont::CalcFontDiffer
 {
   if ((aFont1.size == aFont2.size) && 
       (aFont1.sizeAdjust == aFont2.sizeAdjust) && 
       (aFont1.style == aFont2.style) &&
       (aFont1.variant == aFont2.variant) &&
       (aFont1.weight == aFont2.weight) &&
       (aFont1.stretch == aFont2.stretch) &&
       (aFont1.smoothing == aFont2.smoothing) &&
-      (aFont1.name == aFont2.name) &&
+      (aFont1.fontlist == aFont2.fontlist) &&
       (aFont1.kerning == aFont2.kerning) &&
       (aFont1.synthesis == aFont2.synthesis) &&
       (aFont1.variantAlternates == aFont2.variantAlternates) &&
       (aFont1.alternateValues == aFont2.alternateValues) &&
       (aFont1.featureValueLookup == aFont2.featureValueLookup) &&
       (aFont1.variantCaps == aFont2.variantCaps) &&
       (aFont1.variantEastAsian == aFont2.variantEastAsian) &&
       (aFont1.variantLigatures == aFont2.variantLigatures) &&