bug 821442 - eliminate the unreliable mFamily back-pointer in gfxFontEntry, and instead pass/track font family explicitly where needed. r=roc
authorJonathan Kew <jkew@mozilla.com>
Wed, 19 Dec 2012 09:42:25 +0000
changeset 125540 1b6ab3a080d81bb9519e09304abd0713489eebba
parent 125539 bfd85c9652fa63023a338c5d425d5ab319418d45
child 125622 27a1c1839d428dd1e89ad4dae30719744142382e
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs821442
milestone20.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 821442 - eliminate the unreliable mFamily back-pointer in gfxFontEntry, and instead pass/track font family explicitly where needed. r=roc
accessible/src/base/TextAttrs.cpp
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
gfx/thebes/gfxDWriteFonts.cpp
gfx/thebes/gfxFT2FontList.cpp
gfx/thebes/gfxFT2FontList.h
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
gfx/thebes/gfxFontUtils.cpp
gfx/thebes/gfxFontUtils.h
gfx/thebes/gfxGDIFontList.cpp
gfx/thebes/gfxGDIFontList.h
gfx/thebes/gfxMacPlatformFontList.h
gfx/thebes/gfxMacPlatformFontList.mm
gfx/thebes/gfxPangoFonts.cpp
gfx/thebes/gfxPangoFonts.h
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxPlatformFontList.h
gfx/thebes/gfxUserFontSet.cpp
gfx/thebes/gfxUserFontSet.h
layout/inspector/src/nsFontFace.cpp
layout/inspector/src/nsFontFace.h
layout/inspector/src/nsFontFaceList.cpp
layout/mathml/nsMathMLChar.cpp
layout/style/nsFontFaceLoader.cpp
layout/style/nsFontFaceLoader.h
--- a/accessible/src/base/TextAttrs.cpp
+++ b/accessible/src/base/TextAttrs.cpp
@@ -360,19 +360,17 @@ TextAttrsMgr::FontFamilyTextAttr::
 bool
 TextAttrsMgr::FontFamilyTextAttr::
   GetFontFamily(nsIFrame* aFrame, nsString& aFamily)
 {
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
 
   gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
-  gfxFont* font = fontGroup->GetFontAt(0);
-  gfxFontEntry* fontEntry = font->GetFontEntry();
-  aFamily = fontEntry->FamilyName();
+  aFamily = fontGroup->GetFamilyNameAt(0);
   return true;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // FontSizeTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -549,36 +549,35 @@ gfxDWriteFontList::gfxDWriteFontList()
 {
     mFontSubstitutes.Init();
 }
 
 // bug 602792 - CJK systems default to large CJK fonts which cause excessive
 //   I/O strain during cold startup due to dwrite caching bugs.  Default to
 //   Arial to avoid this.
 
-gfxFontEntry *
-gfxDWriteFontList::GetDefaultFont(const gfxFontStyle *aStyle,
-                                  bool &aNeedsBold)
+gfxFontFamily *
+gfxDWriteFontList::GetDefaultFont(const gfxFontStyle *aStyle)
 {
     nsAutoString resolvedName;
 
     // try Arial first
     if (ResolveFontName(NS_LITERAL_STRING("Arial"), resolvedName)) {
-        return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
+        return FindFamily(resolvedName);
     }
 
     // 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 FindFontForFamily(resolvedName, aStyle, aNeedsBold);
+            return FindFamily(resolvedName);
         }
     }
 
     return nullptr;
 }
 
 gfxFontEntry *
 gfxDWriteFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
@@ -1308,25 +1307,27 @@ IFACEMETHODIMP FontFallbackRenderer::Dra
     }
     return hr;
 }
 
 gfxFontEntry*
 gfxDWriteFontList::GlobalFontFallback(const uint32_t aCh,
                                       int32_t aRunScript,
                                       const gfxFontStyle* aMatchStyle,
-                                      uint32_t& aCmapCount)
+                                      uint32_t& aCmapCount,
+                                      gfxFontFamily** aMatchedFamily)
 {
     bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
 
     if (useCmaps) {
         return gfxPlatformFontList::GlobalFontFallback(aCh,
                                                        aRunScript,
                                                        aMatchStyle,
-                                                       aCmapCount);
+                                                       aCmapCount,
+                                                       aMatchedFamily);
     }
 
     HRESULT hr;
 
     nsRefPtr<IDWriteFactory> dwFactory =
         gfxWindowsPlatform::GetPlatform()->GetDWriteFactory();
     if (!dwFactory) {
         return nullptr;
@@ -1377,18 +1378,22 @@ gfxDWriteFontList::GlobalFontFallback(co
 
     // call the draw method to invoke the DirectWrite layout functions
     // which determine the fallback font
     hr = fallbackLayout->Draw(NULL, mFallbackRenderer, 50.0f, 50.0f);
     if (FAILED(hr)) {
         return nullptr;
     }
 
-    gfxFontEntry *fontEntry = nullptr;
-    bool needsBold;  // ignored in the system fallback case
-    fontEntry = FindFontForFamily(mFallbackRenderer->FallbackFamilyName(),
-                                  aMatchStyle, needsBold);
-    if (fontEntry && !fontEntry->TestCharacterMap(aCh)) {
-        fontEntry = nullptr;
+    gfxFontFamily *family = FindFamily(mFallbackRenderer->FallbackFamilyName());
+    if (family) {
+        gfxFontEntry *fontEntry;
+        bool needsBold;  // ignored in the system fallback case
+        fontEntry = family->FindFontForStyle(*aMatchStyle, needsBold);
+        if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
+            *aMatchedFamily = family;
+            return fontEntry;
+        }
         Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, true);
     }
-    return fontEntry;
+
+    return nullptr;
 }
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -328,18 +328,17 @@ public:
 
     static gfxDWriteFontList* PlatformFontList() {
         return static_cast<gfxDWriteFontList*>(sPlatformFontList);
     }
 
     // initialize font lists
     virtual nsresult InitFontList();
 
-    virtual gfxFontEntry* GetDefaultFont(const gfxFontStyle* aStyle,
-                                         bool& aNeedsBold);
+    virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle);
 
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
 
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const uint8_t *aFontData,
                                            uint32_t aLength);
     
@@ -369,17 +368,18 @@ private:
     nsresult GetFontSubstitutes();
 
     void GetDirectWriteSubstitutes();
 
     // search fonts system-wide for a given character, null otherwise
     virtual gfxFontEntry* GlobalFontFallback(const uint32_t aCh,
                                              int32_t aRunScript,
                                              const gfxFontStyle* aMatchStyle,
-                                             uint32_t& aCmapCount);
+                                             uint32_t& aCmapCount,
+                                             gfxFontFamily** aMatchedFamily);
 
     virtual bool UsesSystemFallback() { return true; }
 
     /**
      * Fonts listed in the registry as substitutes but for which no actual
      * font family is found.
      */
     nsTArray<nsString> mNonExistingFonts;
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -149,17 +149,20 @@ gfxDWriteFont::GetMetrics()
 }
 
 bool
 gfxDWriteFont::GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics)
 {
     gfxFontStyle style(mStyle);
     style.weight = 700;
     bool needsBold;
-    gfxFontEntry *fe = mFontEntry->Family()->FindFontForStyle(style, needsBold);
+
+    gfxFontEntry* fe =
+        gfxPlatformFontList::PlatformFontList()->
+            FindFontForFamily(NS_LITERAL_STRING("Arial"), &style, needsBold);
     if (!fe || fe == mFontEntry) {
         return false;
     }
 
     nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&style, needsBold);
     gfxDWriteFont *dwFont = static_cast<gfxDWriteFont*>(font.get());
     dwFont->mFontFace->GetMetrics(aFontMetrics);
 
@@ -167,17 +170,17 @@ gfxDWriteFont::GetFakeMetricsForArialBla
 }
 
 void
 gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption)
 {
     DWRITE_FONT_METRICS fontMetrics;
     if (!(mFontEntry->Weight() == 900 &&
           !mFontEntry->IsUserFont() &&
-          mFontEntry->FamilyName().EqualsLiteral("Arial") &&
+          mFontEntry->Name().EqualsLiteral("Arial Black") &&
           GetFakeMetricsForArialBlack(&fontMetrics)))
     {
         mFontFace->GetMetrics(&fontMetrics);
     }
 
     if (mStyle.sizeAdjust != 0.0) {
         gfxFloat aspect = (gfxFloat)fontMetrics.xHeight /
                    fontMetrics.designUnitsPerEm;
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -728,36 +728,34 @@ AppendToFaceList(nsCString& aFaceList,
     aFaceList.Append(',');
     aFaceList.AppendInt(aFontEntry->Weight());
     aFaceList.Append(',');
     aFaceList.AppendInt(aFontEntry->Stretch());
     aFaceList.Append(',');
 }
 
 void
-FT2FontEntry::CheckForBrokenFont()
+FT2FontEntry::CheckForBrokenFont(gfxFontFamily *aFamily)
 {
-    NS_ASSERTION(mFamily != nullptr, "font entry must belong to a family");
-
     // note if the family is in the "bad underline" blacklist
-    if (mFamily->IsBadUnderlineFamily()) {
+    if (aFamily->IsBadUnderlineFamily()) {
         mIsBadUnderlineFont = true;
     }
 
     // bug 721719 - set the IgnoreGSUB flag on entries for Roboto
     // because of unwanted on-by-default "ae" ligature.
     // (See also AppendFaceFromFontListEntry.)
-    if (mFamily->Name().EqualsLiteral("roboto")) {
+    if (aFamily->Name().EqualsLiteral("roboto")) {
         mIgnoreGSUB = true;
     }
 
     // bug 706888 - set the IgnoreGSUB flag on the broken version of
     // Droid Sans Arabic from certain phones, as identified by the
     // font checksum in the 'head' table
-    else if (mFamily->Name().EqualsLiteral("droid sans arabic")) {
+    else if (aFamily->Name().EqualsLiteral("droid sans arabic")) {
         const TT_Header *head = static_cast<const TT_Header*>
             (FT_Get_Sfnt_Table(mFTFace, ft_sfnt_head));
         if (head && head->CheckSum_Adjust == 0xe445242) {
             mIgnoreGSUB = true;
         }
     }
 }
 
@@ -813,18 +811,17 @@ gfxFT2FontList::AppendFacesFromFontFile(
                     mFontFamilies.Put(name, family);
                     if (mBadUnderlineFamilyNames.Contains(name)) {
                         family->SetBadUnderlineFamily();
                     }
                 }
                 fe->mStandardFace = aStdFile;
                 family->AddFontEntry(fe);
 
-                // this depends on the entry having been added to its family
-                fe->CheckForBrokenFont();
+                fe->CheckForBrokenFont(family);
 
                 AppendToFaceList(faceList, name, fe);
 #ifdef PR_LOGGING
                 if (LOG_ENABLED()) {
                     LOG(("(fontinit) added (%s) to family (%s)"
                          " with style: %s weight: %d stretch: %d",
                          NS_ConvertUTF16toUTF8(fe->Name()).get(), 
                          NS_ConvertUTF16toUTF8(family->Name()).get(), 
@@ -1184,18 +1181,17 @@ gfxFT2FontList::AppendFaceFromFontListEn
             family = new FT2FontFamily(name);
             mFontFamilies.Put(name, family);
             if (mBadUnderlineFamilyNames.Contains(name)) {
                 family->SetBadUnderlineFamily();
             }
         }
         family->AddFontEntry(fe);
 
-        // this depends on the entry having been added to its family
-        fe->CheckForBrokenFont();
+        fe->CheckForBrokenFont(family);
     }
 }
 
 static PLDHashOperator
 AddFamilyToFontList(nsStringHashKey::KeyType aKey,
                     nsRefPtr<gfxFontFamily>& aFamily,
                     void* aUserArg)
 {
@@ -1271,33 +1267,33 @@ gfxFT2FontList::LookupLocalFont(const gf
     // walk over list of names
     FullFontNameSearch data(aFontName);
 
     mFontFamilies.Enumerate(FindFullName, &data);
 
     return data.mFontEntry;
 }
 
-gfxFontEntry*
-gfxFT2FontList::GetDefaultFont(const gfxFontStyle* aStyle, bool& aNeedsBold)
+gfxFontFamily*
+gfxFT2FontList::GetDefaultFont(const gfxFontStyle* aStyle)
 {
 #ifdef XP_WIN
     HGDIOBJ hGDI = ::GetStockObject(SYSTEM_FONT);
     LOGFONTW logFont;
     if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) {
         nsAutoString resolvedName;
         if (ResolveFontName(nsDependentString(logFont.lfFaceName), resolvedName)) {
-            return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
+            return FindFamily(resolvedName);
         }
     }
 #elif defined(ANDROID)
     nsAutoString resolvedName;
     if (ResolveFontName(NS_LITERAL_STRING("Roboto"), resolvedName) ||
         ResolveFontName(NS_LITERAL_STRING("Droid Sans"), resolvedName)) {
-        return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
+        return FindFamily(resolvedName);
     }
 #endif
     /* TODO: what about Qt or other platforms that may use this? */
     return nullptr;
 }
 
 gfxFontEntry*
 gfxFT2FontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
--- a/gfx/thebes/gfxFT2FontList.h
+++ b/gfx/thebes/gfxFT2FontList.h
@@ -65,17 +65,17 @@ public:
     cairo_font_face_t *CairoFontFace();
     cairo_scaled_font_t *CreateScaledFont(const gfxFontStyle *aStyle);
 
     nsresult ReadCMAP();
     nsresult GetFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer);
 
     // Check for various kinds of brokenness, and set flags on the entry
     // accordingly so that we avoid using bad font tables
-    void CheckForBrokenFont();
+    void CheckForBrokenFont(gfxFontFamily *aFamily);
 
     virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontListSizes*    aSizes) const;
     virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontListSizes*    aSizes) const;
 
     FT_Face mFTFace;
     cairo_font_face_t *mFontFace;
@@ -94,18 +94,17 @@ public:
     void AddFacesToFontList(InfallibleTArray<FontListEntry>* aFontList);
 };
 
 class gfxFT2FontList : public gfxPlatformFontList
 {
 public:
     gfxFT2FontList();
 
-    virtual gfxFontEntry* GetDefaultFont(const gfxFontStyle* aStyle,
-                                         bool& aNeedsBold);
+    virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle);
 
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
 
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const uint8_t *aFontData,
                                            uint32_t aLength);
 
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -162,24 +162,29 @@ uint16_t gfxFontEntry::GetUVSGlyph(uint3
 
 nsresult gfxFontEntry::ReadCMAP()
 {
     NS_ASSERTION(false, "using default no-op implementation of ReadCMAP");
     mCharacterMap = new gfxCharacterMap();
     return NS_OK;
 }
 
-nsString gfxFontEntry::FamilyName() const
-{
-    NS_ASSERTION(mFamily, "orphaned font entry");
-    if (mFamily) {
-        return mFamily->Name();
-    } else {
-        return nsString();
-    }
+nsString
+gfxFontEntry::FamilyName()
+{
+    FallibleTArray<uint8_t> nameTable;
+    nsresult rv = GetFontTable(TRUETYPE_TAG('n','a','m','e'), nameTable);
+    if (NS_SUCCEEDED(rv)) {
+        nsAutoString name;
+        rv = gfxFontUtils::GetFamilyNameFromTable(nameTable, name);
+        if (NS_SUCCEEDED(rv)) {
+            return name;
+        }
+    }
+    return Name();
 }
 
 nsString
 gfxFontEntry::RealFaceName()
 {
     FallibleTArray<uint8_t> nameTable;
     nsresult rv = GetFontTable(TRUETYPE_TAG('n','a','m','e'), nameTable);
     if (NS_SUCCEEDED(rv)) {
@@ -879,16 +884,17 @@ gfxFontFamily::FindFontForChar(GlobalFon
 
         // xxx - add whether AAT font with morphing info for specific lang groups
 
         if (rank > aMatchData->mMatchRank
             || (rank == aMatchData->mMatchRank &&
                 Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
         {
             aMatchData->mBestMatch = fe;
+            aMatchData->mMatchedFamily = this;
             aMatchData->mMatchRank = rank;
         }
     }
 }
 
 void
 gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch *aMatchData)
 {
@@ -898,16 +904,17 @@ gfxFontFamily::SearchAllFontsForChar(Glo
         if (fe && fe->TestCharacterMap(aMatchData->mCh)) {
             int32_t rank = RANK_MATCHED_CMAP;
             rank += CalcStyleMatch(fe, aMatchData->mStyle);
             if (rank > aMatchData->mMatchRank
                 || (rank == aMatchData->mMatchRank &&
                     Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
             {
                 aMatchData->mBestMatch = fe;
+                aMatchData->mMatchedFamily = this;
                 aMatchData->mMatchRank = rank;
             }
         }
     }
 }
 
 // returns true if other names were found, false otherwise
 bool
@@ -3144,24 +3151,29 @@ gfxFontGroup::BuildFontList()
 // "#if" to be removed once all platforms are moved to gfxPlatformFontList interface
 // and subclasses of gfxFontGroup eliminated
 #if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID)
     ForEachFont(FindPlatformFont, this);
 
     if (mFonts.Length() == 0) {
         bool needsBold;
         gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
-        gfxFontEntry *defaultFont = pfl->GetDefaultFont(&mStyle, needsBold);
-        NS_ASSERTION(defaultFont, "invalid default font returned by GetDefaultFont");
-
-        if (defaultFont) {
-            nsRefPtr<gfxFont> font = defaultFont->FindOrMakeFont(&mStyle,
-                                                                 needsBold);
-            if (font) {
-                mFonts.AppendElement(font);
+        gfxFontFamily *defaultFamily = pfl->GetDefaultFont(&mStyle);
+        NS_ASSERTION(defaultFamily,
+                     "invalid default font returned by GetDefaultFont");
+
+        if (defaultFamily) {
+            gfxFontEntry *fe = defaultFamily->FindFontForStyle(mStyle,
+                                                               needsBold);
+            if (fe) {
+                nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle,
+                                                            needsBold);
+                if (font) {
+                    mFonts.AppendElement(FamilyFace(defaultFamily, font));
+                }
             }
         }
 
         if (mFonts.Length() == 0) {
             // Try for a "font of last resort...."
             // Because an empty font list would be Really Bad for later code
             // that assumes it will be able to get valid metrics for layout,
             // just look for the first usable font and put in the list.
@@ -3171,17 +3183,17 @@ gfxFontGroup::BuildFontList()
             uint32_t count = families.Length();
             for (uint32_t i = 0; i < count; ++i) {
                 gfxFontEntry *fe = families[i]->FindFontForStyle(mStyle,
                                                                  needsBold);
                 if (fe) {
                     nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle,
                                                                 needsBold);
                     if (font) {
-                        mFonts.AppendElement(font);
+                        mFonts.AppendElement(FamilyFace(families[i], font));
                         break;
                     }
                 }
             }
         }
 
         if (mFonts.Length() == 0) {
             // an empty font list at this point is fatal; we're not going to
@@ -3191,19 +3203,19 @@ gfxFontGroup::BuildFontList()
                     NS_ConvertUTF16toUTF8(mFamilies).get());
             NS_RUNTIMEABORT(msg);
         }
     }
 
     if (!mStyle.systemFont) {
         uint32_t count = mFonts.Length();
         for (uint32_t i = 0; i < count; ++i) {
-            gfxFont* font = mFonts[i];
+            gfxFont* font = mFonts[i].Font();
             if (font->GetFontEntry()->mIsBadUnderlineFont) {
-                gfxFloat first = mFonts[0]->GetMetrics().underlineOffset;
+                gfxFloat first = mFonts[0].Font()->GetMetrics().underlineOffset;
                 gfxFloat bad = font->GetMetrics().underlineOffset;
                 mUnderlineOffset = NS_MIN(first, bad);
                 break;
             }
         }
     }
 #endif
 }
@@ -3213,61 +3225,67 @@ gfxFontGroup::FindPlatformFont(const nsA
                                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;
 
-    bool foundFamily = false;
     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 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.
-            bool waitForUserFont = false;
-            fe = fs->FindFontEntry(aName, *fontStyle, foundFamily,
-                                   needsBold, waitForUserFont);
-            if (!fe && waitForUserFont) {
-                fontGroup->mSkipDrawing = true;
+            family = fs->GetFamily(aName);
+            if (family) {
+                bool waitForUserFont = false;
+                fe = fs->FindFontEntry(family, *fontStyle,
+                                       needsBold, waitForUserFont);
+                if (!fe && waitForUserFont) {
+                    fontGroup->mSkipDrawing = true;
+                }
             }
         }
     }
 
     // Not known in the user font set ==> check system fonts
-    if (!foundFamily) {
-        fe = gfxPlatformFontList::PlatformFontList()->
-            FindFontForFamily(aName, fontStyle, needsBold);
+    if (!family) {
+        gfxPlatformFontList *fontList = gfxPlatformFontList::PlatformFontList();
+        family = fontList->FindFamily(aName);
+        if (family) {
+            fe = family->FindFontForStyle(*fontStyle, needsBold);
+        }
     }
 
     // add to the font group, unless it's already there
     if (fe && !fontGroup->HasFont(fe)) {
         nsRefPtr<gfxFont> font = fe->FindOrMakeFont(fontStyle, needsBold);
         if (font) {
-            fontGroup->mFonts.AppendElement(font);
+            fontGroup->mFonts.AppendElement(FamilyFace(family, font));
         }
     }
 
     return true;
 }
 
 bool
 gfxFontGroup::HasFont(const gfxFontEntry *aFontEntry)
 {
     uint32_t count = mFonts.Length();
     for (uint32_t i = 0; i < count; ++i) {
-        if (mFonts.ElementAt(i)->GetFontEntry() == aFontEntry)
+        if (mFonts[i].Font()->GetFontEntry() == aFontEntry)
             return true;
     }
     return false;
 }
 
 gfxFontGroup::~gfxFontGroup() {
     mFonts.Clear();
     SetUserFontSet(nullptr);
@@ -3440,20 +3458,26 @@ gfxFontGroup::ForEachFontInternal(const 
                                 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;
-                if (aUseFontSet && mUserFontSet &&
-                    mUserFontSet->FindFontEntry(family, mStyle, foundFamily,
-                                                needsBold, waitForUserFont))
-                {
+                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,
@@ -3838,60 +3862,59 @@ gfxFontGroup::InitScriptRun(gfxContext *
             }
         }
 
         runStart += matchedLength;
     }
 }
 
 already_AddRefed<gfxFont>
-gfxFontGroup::TryOtherFamilyMembers(gfxFont* aFont, uint32_t aCh)
-{
-    gfxFontFamily *family = aFont->GetFontEntry()->Family();
-    if (family && !aFont->GetFontEntry()->mIsProxy &&
-        family->TestCharacterMap(aCh)) {
-        // Note that we don't need the actual runScript in matchData for
-        // gfxFontFamily::SearchAllFontsForChar, it's only used for the
-        // system-fallback case. So we can just set it to 0 here.
-        GlobalFontMatch matchData(aCh, 0, &mStyle);
-        family->SearchAllFontsForChar(&matchData);
-        gfxFontEntry *fe = matchData.mBestMatch;
-        if (fe) {
-            bool needsBold = aFont->GetStyle()->weight >= 600 && !fe->IsBold();
-            nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, needsBold);
-            if (font) {
-                return font.forget();
-            }
-        }
-    }
-    return nullptr;
+gfxFontGroup::TryAllFamilyMembers(gfxFontFamily* aFamily, uint32_t aCh)
+{
+    if (!aFamily->TestCharacterMap(aCh)) {
+        return nullptr;
+    }
+
+    // Note that we don't need the actual runScript in matchData for
+    // gfxFontFamily::SearchAllFontsForChar, it's only used for the
+    // system-fallback case. So we can just set it to 0 here.
+    GlobalFontMatch matchData(aCh, 0, &mStyle);
+    aFamily->SearchAllFontsForChar(&matchData);
+    gfxFontEntry *fe = matchData.mBestMatch;
+    if (!fe) {
+        return nullptr;
+    }
+
+    bool needsBold = mStyle.weight >= 600 && !fe->IsBold();
+    nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, needsBold);
+    return font.forget();
 }
 
 already_AddRefed<gfxFont>
 gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh,
                               int32_t aRunScript, gfxFont *aPrevMatchedFont,
                               uint8_t *aMatchType)
 {
     // To optimize common cases, try the first font in the font-group
     // before going into the more detailed checks below
     uint32_t nextIndex = 0;
     bool isJoinControl = gfxFontUtils::IsJoinControl(aCh);
     bool wasJoinCauser = gfxFontUtils::IsJoinCauser(aPrevCh);
     bool isVarSelector = gfxFontUtils::IsVarSelector(aCh);
 
     if (!isJoinControl && !wasJoinCauser && !isVarSelector) {
-        gfxFont *firstFont = mFonts[0];
+        gfxFont *firstFont = mFonts[0].Font();
         if (firstFont->HasCharacter(aCh)) {
             *aMatchType = gfxTextRange::kFontGroup;
             firstFont->AddRef();
             return firstFont;
         }
         // It's possible that another font in the family (e.g. regular face,
         // where the requested style was italic) will support the character
-        nsRefPtr<gfxFont> font = TryOtherFamilyMembers(firstFont, aCh);
+        nsRefPtr<gfxFont> font = TryAllFamilyMembers(mFonts[0].Family(), aCh);
         if (font) {
             *aMatchType = gfxTextRange::kFontGroup;
             return font.forget();
         }
         // we don't need to check the first font again below
         ++nextIndex;
     }
 
@@ -3925,23 +3948,23 @@ gfxFontGroup::FindFontForChar(uint32_t a
         }
         // VS alone. it's meaningless to search different fonts
         return nullptr;
     }
 
     // 1. check remaining fonts in the font group
     uint32_t fontListLength = FontListLength();
     for (uint32_t i = nextIndex; i < fontListLength; i++) {
-        nsRefPtr<gfxFont> font = mFonts[i];
+        nsRefPtr<gfxFont> font = mFonts[i].Font();
         if (font->HasCharacter(aCh)) {
             *aMatchType = gfxTextRange::kFontGroup;
             return font.forget();
         }
 
-        font = TryOtherFamilyMembers(font, aCh);
+        font = TryAllFamilyMembers(mFonts[i].Family(), aCh);
         if (font) {
             *aMatchType = gfxTextRange::kFontGroup;
             return font.forget();
         }
     }
 
     // if character is in Private Use Area, don't do matching against pref or system fonts
     if ((aCh >= 0xE000  && aCh <= 0xF8FF) || (aCh >= 0xF0000 && aCh <= 0x10FFFD))
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -216,31 +216,37 @@ public:
         mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
 #ifdef MOZ_GRAPHITE
         mCheckedForGraphiteTables(false),
 #endif
         mHasCmapTable(false),
         mUVSOffset(0), mUVSData(nullptr),
         mUserFontData(nullptr),
         mSVGGlyphs(nullptr),
-        mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
-        mFamily(aFamily)
+        mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE)
     { }
 
     virtual ~gfxFontEntry();
 
     // unique name for the face, *not* the family; not necessarily the
     // "real" or user-friendly name, may be an internal identifier
     const nsString& Name() const { return mName; }
 
-    // the "real" name of the face, if available from the font resource
-    // (may be expensive); returns Name() if nothing better is available
+    // The following two methods may be relatively expensive, as they
+    // will (usually, except on Linux) load and parse the 'name' table;
+    // they are intended only for the font-inspection API, not for
+    // perf-critical layout/drawing work.
+
+    // The "real" name of the face, if available from the font resource;
+    // returns Name() if nothing better is available.
     virtual nsString RealFaceName();
 
-    gfxFontFamily* Family() const { return mFamily; }
+    // The family name (if available) that would be used in css font-family
+    // properties; returns Name() if nothing better available.
+    virtual nsString FamilyName();
 
     uint16_t Weight() const { return mWeight; }
     int16_t Stretch() const { return mStretch; }
 
     bool IsUserFont() const { return mIsUserFont; }
     bool IsLocalUserFont() const { return mIsLocalUserFont; }
     bool IsFixedPitch() const { return mFixedPitch; }
     bool IsItalic() const { return mItalic; }
@@ -294,22 +300,16 @@ public:
     virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const {
         return true;
     }
 
     virtual nsresult GetFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer) {
         return NS_ERROR_FAILURE; // all platform subclasses should reimplement this!
     }
 
-    void SetFamily(gfxFontFamily* aFamily) {
-        mFamily = aFamily;
-    }
-
-    virtual nsString FamilyName() const;
-
     already_AddRefed<gfxFont> FindOrMakeFont(const gfxFontStyle *aStyle,
                                              bool aNeedsBold);
 
     // Get an existing font table cache entry in aBlob if it has been
     // registered, or return false if not.  Callers must call
     // hb_blob_destroy on aBlob if true is returned.
     //
     // Note that some gfxFont implementations may not call this at all,
@@ -385,31 +385,28 @@ protected:
         mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
 #ifdef MOZ_GRAPHITE
         mCheckedForGraphiteTables(false),
 #endif
         mHasCmapTable(false),
         mUVSOffset(0), mUVSData(nullptr),
         mUserFontData(nullptr),
         mSVGGlyphs(nullptr),
-        mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
-        mFamily(nullptr)
+        mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE)
     { }
 
     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold) {
         NS_NOTREACHED("oops, somebody didn't override CreateFontInstance");
         return nullptr;
     }
 
 #ifdef MOZ_GRAPHITE
     virtual void CheckForGraphiteTables();
 #endif
 
-    gfxFontFamily *mFamily;
-
 private:
 
     /**
      * Font table hashtable, to support GetFontTable for harfbuzz.
      *
      * The harfbuzz shaper (and potentially other clients) needs access to raw
      * font table data. This needs to be cached so that it can be used
      * repeatedly (each time we construct a text run; in some cases, for
@@ -520,16 +517,17 @@ struct GlobalFontMatch {
 
         }
 
     const uint32_t         mCh;          // codepoint to be matched
     int32_t                mRunScript;   // Unicode script for the codepoint
     const gfxFontStyle*    mStyle;       // style to match
     int32_t                mMatchRank;   // metric indicating closest match
     nsRefPtr<gfxFontEntry> mBestMatch;   // current best match
+    nsRefPtr<gfxFontFamily> mMatchedFamily; // the family it belongs to
     uint32_t               mCount;       // number of fonts matched
     uint32_t               mCmapsTested; // number of cmaps tested
 };
 
 class gfxFontFamily {
 public:
     NS_INLINE_DECL_REFCOUNTING(gfxFontFamily)
 
@@ -539,28 +537,17 @@ public:
         mHasOtherFamilyNames(false),
         mFaceNamesInitialized(false),
         mHasStyles(false),
         mIsSimpleFamily(false),
         mIsBadUnderlineFamily(false),
         mFamilyCharacterMapInitialized(false)
         { }
 
-    virtual ~gfxFontFamily() {
-        // clear Family pointers in our faces; the font entries might stay
-        // alive due to cached font objects, but they can no longer refer
-        // to their families.
-        uint32_t i = mAvailableFonts.Length();
-        while (i) {
-             gfxFontEntry *fe = mAvailableFonts[--i];
-             if (fe) {
-                 fe->SetFamily(nullptr);
-             }
-        }
-    }
+    virtual ~gfxFontFamily() { }
 
     const nsString& Name() { return mName; }
 
     virtual void LocalizedName(nsAString& aLocalizedName);
     virtual bool HasOtherFamilyNames();
     
     nsTArray<nsRefPtr<gfxFontEntry> >& GetFontList() { return mAvailableFonts; }
     
@@ -568,17 +555,16 @@ public:
         // bug 589682 - set the IgnoreGDEF flag on entries for Italic faces
         // of Times New Roman, because of buggy table in those fonts
         if (aFontEntry->IsItalic() && !aFontEntry->IsUserFont() &&
             Name().EqualsLiteral("Times New Roman"))
         {
             aFontEntry->mIgnoreGDEF = true;
         }
         mAvailableFonts.AppendElement(aFontEntry);
-        aFontEntry->SetFamily(this);
     }
 
     // note that the styles for this family have been added
     void SetHasStyles(bool aHasStyles) { mHasStyles = aHasStyles; }
 
     // choose a specific face to match a style using CSS font matching
     // rules (weight matching occurs here).  may return a face that doesn't
     // precisely match (e.g. normal face when no italic face exists).
@@ -661,16 +647,27 @@ public:
     void CheckForSimpleFamily();
 
     // For memory reporter
     virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontListSizes*    aSizes) const;
     virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontListSizes*    aSizes) const;
 
+    // Only used for debugging checks - does a linear search
+    bool ContainsFace(gfxFontEntry* aFontEntry) {
+        uint32_t i, numFonts = mAvailableFonts.Length();
+        for (i = 0; i < numFonts; i++) {
+            if (mAvailableFonts[i] == aFontEntry) {
+                return true;
+            }
+        }
+        return false;
+    }
+
 protected:
     // fills in an array with weights of faces that match style,
     // returns whether any matching entries found
     virtual bool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
                                        bool anItalic, int16_t aStretch);
 
     bool ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
                                        FallibleTArray<uint8_t>& aNameTable,
@@ -2995,34 +2992,68 @@ private:
 
     bool              mSkipDrawing; // true if the font group we used had a user font
                                     // download that's in progress, so we should hide text
                                     // until the download completes (or timeout fires)
 };
 
 class THEBES_API gfxFontGroup : public gfxTextRunFactory {
 public:
+    class FamilyFace {
+    public:
+        FamilyFace() { }
+
+        FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont)
+            : mFamily(aFamily), mFont(aFont)
+        {
+            NS_ASSERTION(aFont, "font pointer must not be null");
+            NS_ASSERTION(!aFamily ||
+                         aFamily->ContainsFace(aFont->GetFontEntry()),
+                         "font is not a member of the given family");
+        }
+
+        gfxFontFamily* Family() const { return mFamily.get(); }
+        gfxFont* Font() const { return mFont.get(); }
+
+    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);
 
     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).
         NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
                      "Whoever was caching this font group should have "
                      "called UpdateFontList on it");
-        NS_ASSERTION(mFonts.Length() > uint32_t(i), 
+        NS_ASSERTION(mFonts.Length() > uint32_t(i) && mFonts[i].Font(), 
                      "Requesting a font index that doesn't exist");
 
-        return static_cast<gfxFont*>(mFonts[i]);
+        return mFonts[i].Font();
+    }
+
+    // Return the family name of the primary font in the group.
+    // Note that gfxPangoFontGroup (for the Linux/Fontconfig backend),
+    // which does not have gfxFontFamily objects, must override this.
+    virtual nsString GetFamilyNameAt(int32_t i) {
+        NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
+                     "Whoever was caching this font group should have "
+                     "called UpdateFontList on it");
+        NS_ASSERTION(mFonts.Length() > uint32_t(i) && mFonts[i].Family(),
+                     "No fonts in the group!");
+
+        return mFonts[i].Family()->Name();
     }
 
     uint32_t FontListLength() const {
         return mFonts.Length();
     }
 
     bool Equals(const gfxFontGroup& other) const {
         return mFamilies.Equals(other.mFamilies) &&
@@ -3136,17 +3167,17 @@ public:
 
     bool ShouldSkipDrawing() const {
         return mSkipDrawing;
     }
 
 protected:
     nsString mFamilies;
     gfxFontStyle mStyle;
-    nsTArray< nsRefPtr<gfxFont> > mFonts;
+    nsTArray<FamilyFace> mFonts;
     gfxFloat mUnderlineOffset;
 
     gfxUserFontSet* mUserFontSet;
     uint64_t mCurrGeneration;  // track the current user font set generation, rebuild font list if needed
 
     // cache the most recent pref font to avoid general pref font lookup
     nsRefPtr<gfxFontFamily> mLastPrefFamily;
     nsRefPtr<gfxFont>       mLastPrefFont;
@@ -3211,20 +3242,20 @@ protected:
                                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 other faces from aFont's family;
+    // 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> TryOtherFamilyMembers(gfxFont* aFont,
-                                                    uint32_t aCh);
+    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);
 
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -1536,16 +1536,32 @@ gfxFontUtils::GetFullNameFromTable(Falli
             aFullName = name;
         }
         return NS_OK;
     }
 
     return NS_ERROR_NOT_AVAILABLE;
 }
 
+nsresult
+gfxFontUtils::GetFamilyNameFromTable(FallibleTArray<uint8_t>& aNameTable,
+                                     nsAString& aFullName)
+{
+    nsAutoString name;
+    nsresult rv =
+        gfxFontUtils::ReadCanonicalName(aNameTable,
+                                        gfxFontUtils::NAME_ID_FAMILY,
+                                        name);
+    if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
+        aFullName = name;
+        return NS_OK;
+    }
+    return NS_ERROR_NOT_AVAILABLE;
+}
+
 enum {
 #if defined(XP_MACOSX)
     CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MAC_ENGLISH,
     PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MAC
 #else
     CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MICROSOFT_EN_US,
     PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MICROSOFT
 #endif
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -761,21 +761,27 @@ public:
     // Read the fullname from the sfnt data (used to save the original name
     // prior to renaming the font for installation).
     // This is called with sfnt data that has already been validated,
     // so it should always succeed in finding the name table.
     static nsresult
     GetFullNameFromSFNT(const uint8_t* aFontData, uint32_t aLength,
                         nsAString& aFullName);
 
-    // helper to get fullname from name table
+    // helper to get fullname from name table, constructing from family+style
+    // if no explicit fullname is present
     static nsresult
     GetFullNameFromTable(FallibleTArray<uint8_t>& aNameTable,
                          nsAString& aFullName);
 
+    // helper to get family name from name table
+    static nsresult
+    GetFamilyNameFromTable(FallibleTArray<uint8_t>& aNameTable,
+                           nsAString& aFamilyName);
+
     // create a new name table and build a new font with that name table
     // appended on the end, returns true on success
     static nsresult
     RenameFont(const nsAString& aName, const uint8_t *aFontData, 
                uint32_t aFontDataLength, FallibleTArray<uint8_t> *aNewFont);
     
     // read all names matching aNameID, returning in aNames array
     static nsresult
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -951,17 +951,18 @@ gfxGDIFontList::MakePlatformFont(const g
             ret = TTLoadEmbeddedFontPtr(&fontRef, TTLOAD_PRIVATE, &privStatus,
                                         LICENSE_PREVIEWPRINT, &pulStatus,
                                         EOTFontStreamReader::ReadEOTStream,
                                         &eotReader,
                                         (PRUnichar*)(fontName.get()), 0, 0);
             if (ret != E_NONE) {
                 fontRef = nullptr;
                 char buf[256];
-                sprintf(buf, "font (%s) not loaded using TTLoadEmbeddedFont - error %8.8x", NS_ConvertUTF16toUTF8(aProxyEntry->FamilyName()).get(), ret);
+                sprintf(buf, "font (%s) not loaded using TTLoadEmbeddedFont - error %8.8x",
+                        NS_ConvertUTF16toUTF8(aProxyEntry->Name()).get(), ret);
                 NS_WARNING(buf);
             }
         }
     }
 
     // load CFF fonts or fonts that failed with t2embed loader
     if (fontRef == nullptr) {
         // Postscript-style glyphs, swizzle name table, load directly
@@ -1015,38 +1016,38 @@ gfxGDIFontList::MakePlatformFont(const g
     if (isCFF && gfxWindowsPlatform::WindowsOSVersion() 
                  < gfxWindowsPlatform::kWindows7) {
         fe->mForceGDI = true;
     }
  
     return fe;
 }
 
-gfxFontEntry*
-gfxGDIFontList::GetDefaultFont(const gfxFontStyle* aStyle, bool& aNeedsBold)
+gfxFontFamily*
+gfxGDIFontList::GetDefaultFont(const gfxFontStyle* aStyle)
 {
     // this really shouldn't fail to find a font....
     HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
     LOGFONTW logFont;
     if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) {
         nsAutoString resolvedName;
         if (ResolveFontName(nsDependentString(logFont.lfFaceName), resolvedName)) {
-            return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
+            return FindFamily(resolvedName);
         }
     }
 
     // ...but just in case, try another approach as well
     NONCLIENTMETRICSW ncm;
     ncm.cbSize = sizeof(ncm);
     BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 
                                           sizeof(ncm), &ncm, 0);
     if (status) {
         nsAutoString resolvedName;
         if (ResolveFontName(nsDependentString(ncm.lfMessageFont.lfFaceName), resolvedName)) {
-            return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
+            return FindFamily(resolvedName);
         }
     }
 
     return nullptr;
 }
 
 
 bool 
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -305,17 +305,17 @@ class gfxGDIFontList : public gfxPlatfor
 public:
     static gfxGDIFontList* PlatformFontList() {
         return static_cast<gfxGDIFontList*>(sPlatformFontList);
     }
 
     // initialize font lists
     virtual nsresult InitFontList();
 
-    virtual gfxFontEntry* GetDefaultFont(const gfxFontStyle* aStyle, bool& aNeedsBold);
+    virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle);
 
     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,
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -68,17 +68,17 @@ protected:
 class gfxMacPlatformFontList : public gfxPlatformFontList {
 public:
     static gfxMacPlatformFontList* PlatformFontList() {
         return static_cast<gfxMacPlatformFontList*>(sPlatformFontList);
     }
 
     static int32_t AppleWeightToCSSWeight(int32_t aAppleWeight);
 
-    virtual gfxFontEntry* GetDefaultFont(const gfxFontStyle* aStyle, bool& aNeedsBold);
+    virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle);
 
     virtual bool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
     
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const uint8_t *aFontData, uint32_t aLength);
@@ -98,17 +98,18 @@ private:
     void InitSingleFaceList();
 
     static void ATSNotification(ATSFontNotificationInfoRef aInfo, void* aUserArg);
 
     // search fonts system-wide for a given character, null otherwise
     virtual gfxFontEntry* GlobalFontFallback(const uint32_t aCh,
                                              int32_t aRunScript,
                                              const gfxFontStyle* aMatchStyle,
-                                             uint32_t& aCmapCount);
+                                             uint32_t& aCmapCount,
+                                             gfxFontFamily** aMatchedFamily);
 
     virtual bool UsesSystemFallback() { return true; }
 
     // keep track of ATS generation to prevent unneeded updates when loading downloaded fonts
     uint32_t mATSGeneration;
 
     enum {
         kATSGenerationInitial = -1
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -662,20 +662,16 @@ gfxSingleFaceMacFontFamily::ReadOtherFam
 gfxMacPlatformFontList::gfxMacPlatformFontList() :
     gfxPlatformFontList(false), mATSGeneration(uint32_t(kATSGenerationInitial)),
     mDefaultFont(nullptr)
 {
     ::ATSFontNotificationSubscribe(ATSNotification,
                                    kATSFontNotifyOptionDefault,
                                    (void*)this, nullptr);
 
-    // this should always be available (though we won't actually fail if it's missing,
-    // we'll just end up doing a search and then caching the new result instead)
-    mReplacementCharFallbackFamily = NS_LITERAL_STRING("Lucida Grande");
-
     // cache this in a static variable so that MacOSFontFamily objects
     // don't have to repeatedly look it up
     sFontManager = [NSFontManager sharedFontManager];
 }
 
 gfxMacPlatformFontList::~gfxMacPlatformFontList()
 {
     if (mDefaultFont) {
@@ -767,17 +763,16 @@ gfxMacPlatformFontList::InitSingleFaceLi
 
             // add only if doesn't exist already
             if (!mFontFamilies.GetWeak(key)) {
                 gfxFontFamily *familyEntry =
                     new gfxSingleFaceMacFontFamily(familyName);
                 familyEntry->AddFontEntry(fontEntry);
                 familyEntry->SetHasStyles(true);
                 mFontFamilies.Put(key, familyEntry);
-                fontEntry->mFamily = familyEntry;
 #ifdef PR_LOGGING
                 LOG_FONTLIST(("(fontlist-singleface) added new family\n",
                               NS_ConvertUTF16toUTF8(familyName).get(),
                               NS_ConvertUTF16toUTF8(key).get()));
 #endif
             }
         }
     }
@@ -837,25 +832,27 @@ gfxMacPlatformFontList::ATSNotification(
     gfxMacPlatformFontList *qfc = (gfxMacPlatformFontList*)aUserArg;
     qfc->UpdateFontList();
 }
 
 gfxFontEntry*
 gfxMacPlatformFontList::GlobalFontFallback(const uint32_t aCh,
                                            int32_t aRunScript,
                                            const gfxFontStyle* aMatchStyle,
-                                           uint32_t& aCmapCount)
+                                           uint32_t& aCmapCount,
+                                           gfxFontFamily** aMatchedFamily)
 {
     bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
 
     if (useCmaps) {
         return gfxPlatformFontList::GlobalFontFallback(aCh,
                                                        aRunScript,
                                                        aMatchStyle,
-                                                       aCmapCount);
+                                                       aCmapCount,
+                                                       aMatchedFamily);
     }
 
     CFStringRef str;
     UniChar ch[2];
     CFIndex len = 1;
 
     if (IS_IN_BMP(aCh)) {
         ch[0] = aCh;
@@ -895,24 +892,31 @@ gfxMacPlatformFontList::GlobalFontFallba
                               kCFCompareCaseInsensitive) != kCFCompareEqualTo)
         {
             nsAutoTArray<UniChar, 1024> buffer;
             CFIndex len = ::CFStringGetLength(familyName);
             buffer.SetLength(len+1);
             ::CFStringGetCharacters(familyName, ::CFRangeMake(0, len),
                                     buffer.Elements());
             buffer[len] = 0;
-            nsDependentString family(buffer.Elements(), len);
+            nsDependentString familyName(buffer.Elements(), len);
 
             bool needsBold;  // ignored in the system fallback case
 
-            fontEntry = FindFontForFamily(family, aMatchStyle, needsBold);
-            if (fontEntry && !fontEntry->TestCharacterMap(aCh)) {
-                fontEntry = nullptr;
-                cantUseFallbackFont = true;
+            gfxFontFamily *family = FindFamily(familyName);
+            if (family) {
+                fontEntry = family->FindFontForStyle(*aMatchStyle, needsBold);
+                if (fontEntry) {
+                    if (fontEntry->TestCharacterMap(aCh)) {
+                        *aMatchedFamily = family;
+                    } else {
+                        fontEntry = nullptr;
+                        cantUseFallbackFont = true;
+                    }
+                }
             }
         }
 
         if (familyName) {
             ::CFRelease(familyName);
         }
     }
 
@@ -920,26 +924,26 @@ gfxMacPlatformFontList::GlobalFontFallba
         Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, cantUseFallbackFont);
     }
 
     ::CFRelease(str);
 
     return fontEntry;
 }
 
-gfxFontEntry*
-gfxMacPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle, bool& aNeedsBold)
+gfxFontFamily*
+gfxMacPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle)
 {
     nsAutoreleasePool localPool;
 
     NSString *defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
     nsAutoString familyName;
 
     GetStringForNSString(defaultFamily, familyName);
-    return FindFontForFamily(familyName, aStyle, aNeedsBold);
+    return FindFamily(familyName);
 }
 
 int32_t
 gfxMacPlatformFontList::AppleWeightToCSSWeight(int32_t aAppleWeight)
 {
     if (aAppleWeight < 1)
         aAppleWeight = 1;
     else if (aAppleWeight > kAppleMaxWeight)
@@ -1026,17 +1030,15 @@ gfxMacPlatformFontList::MakePlatformFont
     ::CFRelease(fontRef);
 
     // if succeeded and font cmap is good, return the new font
     if (newFontEntry->mIsValid && NS_SUCCEEDED(newFontEntry->ReadCMAP())) {
         return newFontEntry.forget();
     }
 
     // if something is funky about this font, delete immediately
+
 #if DEBUG
-    char warnBuf[1024];
-    sprintf(warnBuf, "downloaded font not loaded properly, removed face for (%s)",
-            NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get());
-    NS_WARNING(warnBuf);
+    NS_WARNING("downloaded font not loaded properly");
 #endif
 
     return nullptr;
 }
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -165,25 +165,23 @@ public:
     void SkipHarfBuzz() { mSkipHarfBuzz = true; }
 
     static gfxFcFontEntry *LookupFontEntry(cairo_font_face_t *aFace)
     {
         return static_cast<gfxFcFontEntry*>
             (cairo_font_face_get_user_data(aFace, &sFontEntryKey));
     }
 
-    // override the default impl in gfxFontEntry because we don't organize
-    // gfxFcFontEntries in families; just read the name from fontconfig
-    virtual nsString FamilyName() const;
-
     // override the gfxFontEntry impl to read the name from fontconfig
     // instead of trying to get the 'name' table, as we don't implement
     // GetFontTable() here
     virtual nsString RealFaceName();
 
+    virtual nsString FamilyName();
+
     // This is needed to make gfxFontEntry::HasCharacter(aCh) work.
     virtual bool TestCharacterMap(uint32_t aCh)
     {
         for (uint32_t i = 0; i < mPatterns.Length(); ++i) {
             if (HasChar(mPatterns[i], aCh)) {
                 return true;
             }
         }
@@ -208,33 +206,16 @@ protected:
     bool mSkipGraphiteCheck;
 
     static cairo_user_data_key_t sFontEntryKey;
 };
 
 cairo_user_data_key_t gfxFcFontEntry::sFontEntryKey;
 
 nsString
-gfxFcFontEntry::FamilyName() const
-{
-    if (mIsUserFont) {
-        // for user fonts, we want the name of the family
-        // as specified in the user font set
-        return gfxFontEntry::FamilyName();
-    }
-    FcChar8 *familyname;
-    if (!mPatterns.IsEmpty() &&
-        FcPatternGetString(mPatterns[0],
-                           FC_FAMILY, 0, &familyname) == FcResultMatch) {
-        return NS_ConvertUTF8toUTF16((const char*)familyname);
-    }
-    return gfxFontEntry::FamilyName();
-}
-
-nsString
 gfxFcFontEntry::RealFaceName()
 {
     FcChar8 *name;
     if (!mPatterns.IsEmpty()) {
         if (FcPatternGetString(mPatterns[0],
                                FC_FULLNAME, 0, &name) == FcResultMatch) {
             return NS_ConvertUTF8toUTF16((const char*)name);
         }
@@ -244,19 +225,34 @@ gfxFcFontEntry::RealFaceName()
             if (FcPatternGetString(mPatterns[0],
                                    FC_STYLE, 0, &name) == FcResultMatch) {
                 result.AppendLiteral(" ");
                 AppendUTF8toUTF16((const char*)name, result);
             }
             return result;
         }
     }
+    // fall back to gfxFontEntry implementation (only works for sfnt fonts)
     return gfxFontEntry::RealFaceName();
 }
 
+nsString
+gfxFcFontEntry::FamilyName()
+{
+    FcChar8 *name;
+    if (!mPatterns.IsEmpty()) {
+        if (FcPatternGetString(mPatterns[0],
+                               FC_FAMILY, 0, &name) == FcResultMatch) {
+            return NS_ConvertUTF8toUTF16((const char*)name);
+        }
+    }
+    // fall back to gfxFontEntry implementation (only works for sfnt fonts)
+    return gfxFontEntry::FamilyName();
+}
+
 #ifdef MOZ_GRAPHITE
 void
 gfxFcFontEntry::CheckForGraphiteTables()
 {
     FcChar8 *capability;
     mHasGraphiteTables =
         !mPatterns.IsEmpty() &&
         FcPatternGetString(mPatterns[0],
@@ -395,18 +391,17 @@ private:
 // Multiple patterns in an entry also effectively deals with a set of
 // PostScript Type 1 font files that all have the same face name but are in
 // several files because of the limit on the number of glyphs in a Type 1 font
 // file.  (e.g. Computer Modern.)
 
 class gfxUserFcFontEntry : public gfxFcFontEntry {
 protected:
     gfxUserFcFontEntry(const gfxProxyFontEntry &aProxyEntry)
-        // store the family name
-        : gfxFcFontEntry(aProxyEntry.mFamily->Name())
+        : gfxFcFontEntry(aProxyEntry.Name())
     {
         mItalic = aProxyEntry.mItalic;
         mWeight = aProxyEntry.mWeight;
         mStretch = aProxyEntry.mStretch;
         mIsUserFont = true;
     }
 
     // Helper function to change a pattern so that it matches the CSS style
@@ -793,16 +788,26 @@ public:
     // The PangoFont returned is owned by the gfxFcFont
     PangoFont *GetPangoFont() {
         if (!mPangoFont) {
             MakePangoFont();
         }
         return mPangoFont;
     }
 
+    nsString GetFamilyName() {
+        PangoFontDescription *desc = pango_font_describe(GetPangoFont());
+        const char *name = pango_font_description_get_family(desc);
+        if (name) {
+            return NS_ConvertUTF8toUTF16(name);
+        } else {
+            return GetFontEntry()->FamilyName();
+        }
+    }
+
 protected:
     virtual bool ShapeWord(gfxContext *aContext,
                            gfxShapedWord *aShapedWord,
                            const PRUnichar *aString,
                            bool aPreferPlatformShaping);
 
     bool InitGlyphRunWithPango(gfxShapedWord *aTextRun,
                                const PRUnichar *aString);
@@ -1267,45 +1272,50 @@ private:
 };
 
 // Find the FcPattern for an @font-face font suitable for CSS family |aFamily|
 // and style |aStyle| properties.
 static const nsTArray< nsCountedRef<FcPattern> >*
 FindFontPatterns(gfxUserFontSet *mUserFontSet,
                  const nsACString &aFamily, uint8_t aStyle,
                  uint16_t aWeight, int16_t aStretch,
-                 bool& aFoundFamily, bool& aWaitForUserFont)
+                 bool& aWaitForUserFont)
 {
     // Convert to UTF16
     NS_ConvertUTF8toUTF16 utf16Family(aFamily);
 
     // needsBold is not used here.  Instead synthetic bold is enabled through
     // FcFontRenderPrepare when the weight in the requested pattern is
     // compared against the weight in the font pattern.
     bool needsBold;
 
     gfxFontStyle style;
     style.style = aStyle;
     style.weight = aWeight;
     style.stretch = aStretch;
 
-    gfxUserFcFontEntry *fontEntry = static_cast<gfxUserFcFontEntry*>
-        (mUserFontSet->FindFontEntry(utf16Family, style, aFoundFamily,
-                                     needsBold, aWaitForUserFont));
-
-    // Accept synthetic oblique for italic and oblique.
-    if (!fontEntry && aStyle != NS_FONT_STYLE_NORMAL) {
-        style.style = NS_FONT_STYLE_NORMAL;
+    gfxUserFcFontEntry *fontEntry = nullptr;
+    gfxFontFamily *family = mUserFontSet->GetFamily(utf16Family);
+    if (family) {
         fontEntry = static_cast<gfxUserFcFontEntry*>
-            (mUserFontSet->FindFontEntry(utf16Family, style, aFoundFamily,
-                                         needsBold, aWaitForUserFont));
+            (mUserFontSet->FindFontEntry(family, style, needsBold,
+                                         aWaitForUserFont));
+
+        // Accept synthetic oblique for italic and oblique.
+        if (!fontEntry && aStyle != NS_FONT_STYLE_NORMAL) {
+            style.style = NS_FONT_STYLE_NORMAL;
+            fontEntry = static_cast<gfxUserFcFontEntry*>
+                (mUserFontSet->FindFontEntry(family, style, needsBold,
+                                             aWaitForUserFont));
+        }
     }
 
-    if (!fontEntry)
-        return NULL;
+    if (!fontEntry) {
+        return nullptr;
+    }
 
     return &fontEntry->GetPatterns();
 }
 
 typedef FcBool (*FcPatternRemoveFunction)(FcPattern *p, const char *object,
                                           int id);
 
 // FcPatternRemove is available in fontconfig-2.3.0 (2005)
@@ -1451,26 +1461,24 @@ gfxFcFontSet::SortPreferredFonts(bool &a
 
                 uint8_t thebesStyle =
                     gfxFontconfigUtils::FcSlantToThebesStyle(requestedSlant);
                 uint16_t thebesWeight =
                     gfxFontconfigUtils::GetThebesWeight(mSortPattern);
                 int16_t thebesStretch =
                     gfxFontconfigUtils::GetThebesStretch(mSortPattern);
 
-                bool foundFamily, waitForUserFont;
+                bool waitForUserFont;
                 familyFonts = FindFontPatterns(mUserFontSet, cssFamily,
                                                thebesStyle,
                                                thebesWeight, thebesStretch,
-                                               foundFamily, waitForUserFont);
+                                               waitForUserFont);
                 if (waitForUserFont) {
                     aWaitForUserFont = true;
                 }
-                NS_ASSERTION(foundFamily,
-                             "expected to find a user font, but it's missing!");
             }
         }
 
         if (!isUserFont) {
             familyFonts = &utils->GetFontsForFamily(family);
         }
 
         if (!familyFonts || familyFonts->Length() == 0) {
@@ -1913,17 +1921,18 @@ gfxPangoFontGroup::gfxPangoFontGroup (co
       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));
     }
 
-    mFonts.AppendElements(1);
+    // dummy entry, will be replaced when actually needed
+    mFonts.AppendElement(FamilyFace());
 }
 
 gfxPangoFontGroup::~gfxPangoFontGroup()
 {
 }
 
 gfxFontGroup *
 gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle)
@@ -1941,49 +1950,58 @@ gfxPangoFontGroup::GetFcFamilies(nsTArra
     // best match.
     ForEachFontInternal(mFamilies, aLanguage, true, false, true,
                         FamilyCallback, &data);
 }
 
 gfxFcFont *
 gfxPangoFontGroup::GetBaseFont()
 {
-    if (!mFonts[0]) {
-        mFonts[0] = GetBaseFontSet()->GetFontAt(0, GetStyle());
+    if (mFonts[0].Font() == nullptr) {
+        gfxFont* font = GetBaseFontSet()->GetFontAt(0, GetStyle());
+        mFonts[0] = FamilyFace(nullptr, font);
     }
 
-    return static_cast<gfxFcFont*>(mFonts[0].get());
+    return static_cast<gfxFcFont*>(mFonts[0].Font());
 }
 
 gfxFont *
-gfxPangoFontGroup::GetFontAt(int32_t i) {
+gfxPangoFontGroup::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).
     NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
                  "Whoever was caching this font group should have "
                  "called UpdateFontList on it");
 
     NS_PRECONDITION(i == 0, "Only have one font");
 
     return GetBaseFont();
 }
 
+nsString
+gfxPangoFontGroup::GetFamilyNameAt(int32_t i)
+{
+    gfxFcFont* font = static_cast<gfxFcFont*>(GetFontAt(i));
+    return font->GetFamilyName();
+}
+
 void
 gfxPangoFontGroup::UpdateFontList()
 {
     if (!mUserFontSet)
         return;
 
     uint64_t newGeneration = mUserFontSet->GetGeneration();
     if (newGeneration == mCurrGeneration)
         return;
 
-    mFonts[0] = NULL;
+    mFonts[0] = FamilyFace();
     mFontSets.Clear();
     mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET;
     mCurrGeneration = newGeneration;
     mSkipDrawing = false;
 }
 
 already_AddRefed<gfxFcFontSet>
 gfxPangoFontGroup::MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor,
--- a/gfx/thebes/gfxPangoFonts.h
+++ b/gfx/thebes/gfxPangoFonts.h
@@ -28,16 +28,18 @@ public:
                        const gfxFontStyle *aStyle,
                        gfxUserFontSet *aUserFontSet);
     virtual ~gfxPangoFontGroup ();
 
     virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
 
     virtual gfxFont *GetFontAt(int32_t i);
 
+    virtual nsString GetFamilyNameAt(int32_t i);
+
     virtual void UpdateFontList();
 
     virtual already_AddRefed<gfxFont>
         FindFontForChar(uint32_t aCh, uint32_t aPrevCh, int32_t aRunScript,
                         gfxFont *aPrevMatchedFont,
                         uint8_t *aMatchType);
 
     static void Shutdown();
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -150,16 +150,18 @@ gfxPlatformFontList::gfxPlatformFontList
     // pref changes notification setup
     NS_ASSERTION(!gFontListPrefObserver,
                  "There has been font list pref observer already");
     gFontListPrefObserver = new gfxFontListPrefObserver();
     NS_ADDREF(gFontListPrefObserver);
     Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs);
 
     mSharedCmaps.Init(16);
+
+    NS_RegisterMemoryMultiReporter(new MemoryReporter);
 }
 
 gfxPlatformFontList::~gfxPlatformFontList()
 {
     mSharedCmaps.Clear();
     NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer");
     Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs);
     NS_RELEASE(gFontListPrefObserver);
@@ -172,25 +174,24 @@ gfxPlatformFontList::InitFontList()
     mOtherFamilyNames.Clear();
     mOtherFamilyNamesInitialized = false;
     if (mNeedFullnamePostscriptNames) {
         mFullnames.Clear();
         mPostscriptNames.Clear();
     }
     mFaceNamesInitialized = false;
     mPrefFonts.Clear();
+    mReplacementCharFallbackFamily = nullptr;
     CancelLoader();
 
     // initialize ranges of characters for which system-wide font search should be skipped
     mCodepointsWithNoFonts.reset();
     mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
     mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
 
-    NS_RegisterMemoryMultiReporter(new MemoryReporter);
-
     sPlatformFontList = this;
 
     return NS_OK;
 }
 
 void
 gfxPlatformFontList::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
 {
@@ -385,42 +386,47 @@ gfxPlatformFontList::SystemFindFontForCh
  {
     gfxFontEntry* fontEntry = nullptr;
 
     // is codepoint with no matching font? return null immediately
     if (mCodepointsWithNoFonts.test(aCh)) {
         return nullptr;
     }
 
-    // try to short-circuit font fallback for U+FFFD, used to represent
-    // encoding errors: just use a platform-specific fallback system
-    // font that is guaranteed (or at least highly likely) to be around,
-    // or a cached family from last time U+FFFD was seen. this helps
-    // speed up pages with lots of encoding errors, binary-as-text, etc.
-    if (aCh == 0xFFFD && mReplacementCharFallbackFamily.Length() > 0) {
+    // Try to short-circuit font fallback for U+FFFD, used to represent
+    // encoding errors: just use cached family from last time U+FFFD was seen.
+    // This helps speed up pages with lots of encoding errors, binary-as-text,
+    // etc.
+    if (aCh == 0xFFFD && mReplacementCharFallbackFamily) {
         bool needsBold;  // ignored in the system fallback case
 
-        fontEntry = FindFontForFamily(mReplacementCharFallbackFamily,
-                                      aStyle, needsBold);
+        fontEntry =
+            mReplacementCharFallbackFamily->FindFontForStyle(*aStyle,
+                                                             needsBold);
 
-        if (fontEntry && fontEntry->TestCharacterMap(aCh))
+        // this should never fail, as we must have found U+FFFD in order to set
+        // mReplacementCharFallbackFamily at all, but better play it safe
+        if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
             return fontEntry;
+        }
     }
 
     TimeStamp start = TimeStamp::Now();
 
     // search commonly available fonts
     bool common = true;
-    fontEntry = CommonFontFallback(aCh, aRunScript, aStyle);
+    gfxFontFamily *fallbackFamily = nullptr;
+    fontEntry = CommonFontFallback(aCh, aRunScript, aStyle, &fallbackFamily);
  
     // if didn't find a font, do system-wide fallback (except for specials)
     uint32_t cmapCount = 0;
     if (!fontEntry) {
         common = false;
-        fontEntry = GlobalFontFallback(aCh, aRunScript, aStyle, cmapCount);
+        fontEntry = GlobalFontFallback(aCh, aRunScript, aStyle, cmapCount,
+                                       &fallbackFamily);
     }
     TimeDuration elapsed = TimeStamp::Now() - start;
 
 #ifdef PR_LOGGING
     PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textrun);
 
     if (MOZ_UNLIKELY(log)) {
         uint32_t charRange = gfxFontUtils::CharRangeBit(aCh);
@@ -436,20 +442,20 @@ gfxPlatformFontList::SystemFindFontForCh
                     "<none>"),
                 int32_t(elapsed.ToMicroseconds()),
                 cmapCount));
     }
 #endif
 
     // no match? add to set of non-matching codepoints
     if (!fontEntry) {
-         mCodepointsWithNoFonts.set(aCh);
-    } else if (aCh == 0xFFFD && fontEntry) {
-        mReplacementCharFallbackFamily = fontEntry->FamilyName();
-     }
+        mCodepointsWithNoFonts.set(aCh);
+    } else if (aCh == 0xFFFD && fontEntry && fallbackFamily) {
+        mReplacementCharFallbackFamily = fallbackFamily;
+    }
  
     // track system fallback time
     static bool first = true;
     int32_t intElapsed = int32_t(first ? elapsed.ToMilliseconds() :
                                          elapsed.ToMicroseconds());
     Telemetry::Accumulate((first ? Telemetry::SYSTEM_FONT_FALLBACK_FIRST :
                                    Telemetry::SYSTEM_FONT_FALLBACK),
                           intElapsed);
@@ -462,29 +468,30 @@ gfxPlatformFontList::SystemFindFontForCh
     return fontEntry;
 }
 
 PLDHashOperator 
 gfxPlatformFontList::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<gfxFontFamily>& aFamilyEntry,
      void *userArg)
 {
     GlobalFontMatch *data = static_cast<GlobalFontMatch*>(userArg);
- 
-     // evaluate all fonts in this family for a match
-     aFamilyEntry->FindFontForChar(data);
 
-     return PL_DHASH_NEXT;
+    // evaluate all fonts in this family for a match
+    aFamilyEntry->FindFontForChar(data);
+
+    return PL_DHASH_NEXT;
 }
 
 #define NUM_FALLBACK_FONTS        8
 
 gfxFontEntry*
 gfxPlatformFontList::CommonFontFallback(const uint32_t aCh,
                                         int32_t aRunScript,
-                                        const gfxFontStyle* aMatchStyle)
+                                        const gfxFontStyle* aMatchStyle,
+                                        gfxFontFamily** aMatchedFamily)
 {
     nsAutoTArray<const char*,NUM_FALLBACK_FONTS> defaultFallbacks;
     uint32_t i, numFallbacks;
 
     gfxPlatform::GetPlatform()->GetCommonFallbackFonts(aCh, aRunScript,
                                                        defaultFallbacks);
     numFallbacks = defaultFallbacks.Length();
     for (i = 0; i < numFallbacks; i++) {
@@ -498,36 +505,39 @@ gfxPlatformFontList::CommonFontFallback(
             continue;
 
         gfxFontEntry *fontEntry;
         bool needsBold;  // ignored in the system fallback case
 
         // use first font in list that supports a given character
         fontEntry = fallback->FindFontForStyle(*aMatchStyle, needsBold);
         if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
+            *aMatchedFamily = fallback;
             return fontEntry;
         }
     }
 
     return nullptr;
 }
 
 gfxFontEntry*
 gfxPlatformFontList::GlobalFontFallback(const uint32_t aCh,
                                         int32_t aRunScript,
                                         const gfxFontStyle* aMatchStyle,
-                                        uint32_t& aCmapCount)
+                                        uint32_t& aCmapCount,
+                                        gfxFontFamily** aMatchedFamily)
 {
     // otherwise, try to find it among local fonts
     GlobalFontMatch data(aCh, aRunScript, aMatchStyle);
 
     // iterate over all font families to find a font that support the character
     mFontFamilies.Enumerate(gfxPlatformFontList::FindFontForCharProc, &data);
 
     aCmapCount = data.mCmapsTested;
+    *aMatchedFamily = data.mMatchedFamily;
 
     return data.mBestMatch;
 }
 
 #ifdef XP_WIN
 #include <windows.h>
 
 // crude hack for using when monitoring process
@@ -842,18 +852,16 @@ gfxPlatformFontList::SizeOfExcludingThis
         aSizes->mFontListSize +=
             mPostscriptNames.SizeOfExcludingThis(SizeOfFontNameEntryExcludingThis,
                                                  aMallocSizeOf);
     }
 
     aSizes->mFontListSize +=
         mCodepointsWithNoFonts.SizeOfExcludingThis(aMallocSizeOf);
     aSizes->mFontListSize +=
-        mReplacementCharFallbackFamily.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
-    aSizes->mFontListSize +=
         mFontFamiliesToLoad.SizeOfExcludingThis(aMallocSizeOf);
 
     aSizes->mFontListSize +=
         mPrefFonts.SizeOfExcludingThis(SizeOfPrefFontEntryExcludingThis,
                                        aMallocSizeOf);
 
     aSizes->mFontListSize +=
         mBadUnderlineFamilyNames.SizeOfExcludingThis(SizeOfStringEntryExcludingThis,
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -139,19 +139,18 @@ public:
     void AddFullname(gfxFontEntry *aFontEntry, nsAString& aFullname);
 
     void AddPostscriptName(gfxFontEntry *aFontEntry, nsAString& aPostscriptName);
 
     bool NeedFullnamePostscriptNames() { return mNeedFullnamePostscriptNames; }
 
     // pure virtual functions, to be provided by concrete subclasses
 
-    // get the system default font
-    virtual gfxFontEntry* GetDefaultFont(const gfxFontStyle* aStyle,
-                                         bool& aNeedsBold) = 0;
+    // get the system default font family
+    virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle) = 0;
 
     // look up a font by name on the host platform
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName) = 0;
 
     // create a new platform font from downloaded data (@font-face)
     // this method is responsible to ensure aFontData is NS_Free()'d
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
@@ -190,25 +189,27 @@ protected:
 
     static gfxPlatformFontList *sPlatformFontList;
 
     static PLDHashOperator FindFontForCharProc(nsStringHashKey::KeyType aKey,
                                                nsRefPtr<gfxFontFamily>& aFamilyEntry,
                                                void* userArg);
 
     // returns default font for a given character, null otherwise
-    virtual gfxFontEntry* CommonFontFallback(const uint32_t aCh,
-                                             int32_t aRunScript,
-                                             const gfxFontStyle* aMatchStyle);
+    gfxFontEntry* CommonFontFallback(const uint32_t aCh,
+                                     int32_t aRunScript,
+                                     const gfxFontStyle* aMatchStyle,
+                                     gfxFontFamily** aMatchedFamily);
 
     // search fonts system-wide for a given character, null otherwise
     virtual gfxFontEntry* GlobalFontFallback(const uint32_t aCh,
                                              int32_t aRunScript,
                                              const gfxFontStyle* aMatchStyle,
-                                             uint32_t& aCmapCount);
+                                             uint32_t& aCmapCount,
+                                             gfxFontFamily** aMatchedFamily);
 
     // whether system-based font fallback is used or not
     // if system fallback is used, no need to load all cmaps
     virtual bool UsesSystemFallback() { return false; }
 
     // separate initialization for reading in name tables, since this is expensive
     void InitOtherFamilyNames();
 
@@ -277,17 +278,17 @@ protected:
     // maps list of family names ==> array of family entries, one per lang group
     nsDataHashtable<nsUint32HashKey, nsTArray<nsRefPtr<gfxFontFamily> > > mPrefFonts;
 
     // when system-wide font lookup fails for a character, cache it to skip future searches
     gfxSparseBitSet mCodepointsWithNoFonts;
 
     // the family to use for U+FFFD fallback, to avoid expensive search every time
     // on pages with lots of problems
-    nsString mReplacementCharFallbackFamily;
+    nsRefPtr<gfxFontFamily> mReplacementCharFallbackFamily;
 
     nsTHashtable<nsStringHashKey> mBadUnderlineFamilyNames;
 
     // character map data shared across families
     // contains weak ptrs to cmaps shared by font entry objects
     nsTHashtable<CharMapHashKey> mSharedCmaps;
 
     // data used as part of the font cmap loading process
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -153,32 +153,24 @@ gfxUserFontSet::AddFontFace(const nsAStr
         family = new gfxMixedFontFamily(aFamilyName);
         mFontFamilies.Put(key, family);
     }
 
     family->AddFontEntry(aFontEntry);
 }
 
 gfxFontEntry*
-gfxUserFontSet::FindFontEntry(const nsAString& aName, 
-                              const gfxFontStyle& aFontStyle, 
-                              bool& aFoundFamily,
+gfxUserFontSet::FindFontEntry(gfxFontFamily *aFamily,
+                              const gfxFontStyle& aFontStyle,
                               bool& aNeedsBold,
                               bool& aWaitForUserFont)
 {
     aWaitForUserFont = false;
-    gfxMixedFontFamily *family = GetFamily(aName);
+    gfxMixedFontFamily *family = static_cast<gfxMixedFontFamily*>(aFamily);
 
-    // no user font defined for this name
-    if (!family) {
-        aFoundFamily = false;
-        return nullptr;
-    }
-
-    aFoundFamily = true;
     gfxFontEntry* fe = family->FindFontForStyle(aFontStyle, aNeedsBold);
 
     // if not a proxy, font has already been loaded
     if (!fe->mIsProxy) {
         return fe;
     }
 
     gfxProxyFontEntry *proxyEntry = static_cast<gfxProxyFontEntry*> (fe);
@@ -190,17 +182,17 @@ gfxUserFontSet::FindFontEntry(const nsAS
         return nullptr;
     }
 
     // hasn't been loaded yet, start the load process
     LoadStatus status;
 
     // NOTE that if all sources in the entry fail, this will delete proxyEntry,
     // so we cannot use it again if status==STATUS_END_OF_LIST
-    status = LoadNext(proxyEntry);
+    status = LoadNext(family, proxyEntry);
 
     // if the load succeeded immediately, the font entry was replaced so
     // search again
     if (status == STATUS_LOADED) {
         return family->FindFontForStyle(aFontStyle, aNeedsBold);
     }
 
     // check whether we should wait for load to complete before painting
@@ -328,59 +320,62 @@ private:
     void*        mPtr;
     size_t       mLength;
     const size_t mLimit;
     off_t        mOff;
 };
 
 #ifdef MOZ_OTS_REPORT_ERRORS
 struct OTSCallbackUserData {
-    gfxUserFontSet    *mFontSet;
-    gfxProxyFontEntry *mProxy;
+    gfxUserFontSet     *mFontSet;
+    gfxMixedFontFamily *mFamily;
+    gfxProxyFontEntry  *mProxy;
 };
 
 /* static */ bool
 gfxUserFontSet::OTSMessage(void *aUserData, const char *format, ...)
 {
     va_list va;
     va_start(va, format);
 
     // buf should be more than adequate for any message OTS generates,
     // so we don't worry about checking the result of vsnprintf()
     char buf[512];
     (void)vsnprintf(buf, sizeof(buf), format, va);
 
     va_end(va);
 
     OTSCallbackUserData *d = static_cast<OTSCallbackUserData*>(aUserData);
-    d->mFontSet->LogMessage(d->mProxy, buf);
+    d->mFontSet->LogMessage(d->mFamily, d->mProxy, buf);
 
     return false;
 }
 #endif
 
 // Call the OTS library to sanitize an sfnt before attempting to use it.
 // Returns a newly-allocated block, or NULL in case of fatal errors.
 const uint8_t*
-gfxUserFontSet::SanitizeOpenTypeData(gfxProxyFontEntry *aProxy,
+gfxUserFontSet::SanitizeOpenTypeData(gfxMixedFontFamily *aFamily,
+                                     gfxProxyFontEntry *aProxy,
                                      const uint8_t* aData, uint32_t aLength,
                                      uint32_t& aSaneLength, bool aIsCompressed)
 {
     // limit output/expansion to 256MB
     ExpandingMemoryStream output(aIsCompressed ? aLength * 2 : aLength,
                                  1024 * 1024 * 256);
 #ifdef MOZ_GRAPHITE
 #define PRESERVE_GRAPHITE true
 #else
 #define PRESERVE_GRAPHITE false
 #endif
 
 #ifdef MOZ_OTS_REPORT_ERRORS
     OTSCallbackUserData userData;
     userData.mFontSet = this;
+    userData.mFamily = aFamily;
     userData.mProxy = aProxy;
 #define ERROR_REPORTING_ARGS &gfxUserFontSet::OTSMessage, &userData,
 #else
 #define ERROR_REPORTING_ARGS
 #endif
 
     if (ots::Process(&output, aData, aLength,
                      ERROR_REPORTING_ARGS
@@ -464,58 +459,61 @@ gfxUserFontSet::CopyWOFFMetadata(const u
     memcpy(aMetadata->Elements(), aFontData + metaOffset, metaCompLen);
     *aMetaOrigLen = woff->metaOrigLen;
 }
 
 // This is called when a font download finishes.
 // Ownership of aFontData passes in here, and the font set must
 // ensure that it is eventually deleted via NS_Free().
 bool
-gfxUserFontSet::OnLoadComplete(gfxProxyFontEntry *aProxy,
+gfxUserFontSet::OnLoadComplete(gfxMixedFontFamily *aFamily,
+                               gfxProxyFontEntry *aProxy,
                                const uint8_t *aFontData, uint32_t aLength,
                                nsresult aDownloadStatus)
 {
     // forget about the loader, as we no longer potentially need to cancel it
     // if the entry is obsoleted
     aProxy->mLoader = nullptr;
 
     // download successful, make platform font using font data
     if (NS_SUCCEEDED(aDownloadStatus)) {
-        gfxFontEntry *fe = LoadFont(aProxy, aFontData, aLength);
+        gfxFontEntry *fe = LoadFont(aFamily, aProxy, aFontData, aLength);
         aFontData = nullptr;
 
         if (fe) {
             IncrementGeneration();
             return true;
         }
 
     } else {
         // download failed
-        LogMessage(aProxy, "download failed", nsIScriptError::errorFlag,
+        LogMessage(aFamily, aProxy,
+                   "download failed", nsIScriptError::errorFlag,
                    aDownloadStatus);
     }
 
     if (aFontData) {
         NS_Free((void*)aFontData);
     }
 
     // error occurred, load next src
-    (void)LoadNext(aProxy);
+    (void)LoadNext(aFamily, aProxy);
 
     // We ignore the status returned by LoadNext();
     // even if loading failed, we need to bump the font-set generation
     // and return true in order to trigger reflow, so that fallback
     // will be used where the text was "masked" by the pending download
     IncrementGeneration();
     return true;
 }
 
 
 gfxUserFontSet::LoadStatus
-gfxUserFontSet::LoadNext(gfxProxyFontEntry *aProxyEntry)
+gfxUserFontSet::LoadNext(gfxMixedFontFamily *aFamily,
+                         gfxProxyFontEntry *aProxyEntry)
 {
     uint32_t numSrc = aProxyEntry->mSrcList.Length();
 
     NS_ASSERTION(aProxyEntry->mSrcIndex < numSrc,
                  "already at the end of the src list for user font");
 
     if (aProxyEntry->mLoadingState == gfxProxyFontEntry::NOT_LOADING) {
         aProxyEntry->mLoadingState = gfxProxyFontEntry::LOADING_STARTED;
@@ -537,28 +535,28 @@ gfxUserFontSet::LoadNext(gfxProxyFontEnt
         if (currSrc.mIsLocal) {
             gfxFontEntry *fe =
                 gfxPlatform::GetPlatform()->LookupLocalFont(aProxyEntry,
                                                             currSrc.mLocalName);
             if (fe) {
                 LOG(("userfonts (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
                      this, aProxyEntry->mSrcIndex,
                      NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
-                     NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get(),
+                     NS_ConvertUTF16toUTF8(aFamily->Name()).get(),
                      uint32_t(mGeneration)));
                 fe->mFeatureSettings.AppendElements(aProxyEntry->mFeatureSettings);
                 fe->mLanguageOverride = aProxyEntry->mLanguageOverride;
                 StoreUserFontData(fe, aProxyEntry, nsString(), nullptr, 0);
-                ReplaceFontEntry(aProxyEntry, fe);
+                ReplaceFontEntry(aFamily, aProxyEntry, fe);
                 return STATUS_LOADED;
             } else {
                 LOG(("userfonts (%p) [src %d] failed local: (%s) for (%s)\n",
                      this, aProxyEntry->mSrcIndex,
                      NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
-                     NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get()));
+                     NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
             }
         }
 
         // src url ==> start the load process
         else {
             if (gfxPlatform::GetPlatform()->IsFontFormatSupported(currSrc.mURI,
                     currSrc.mFormatFlags)) {
 
@@ -566,17 +564,17 @@ gfxUserFontSet::LoadNext(gfxProxyFontEnt
                 nsresult rv = CheckFontLoad(&currSrc, &principal);
 
                 if (NS_SUCCEEDED(rv) && principal != nullptr) {
                     // see if we have an existing entry for this source
                     gfxFontEntry *fe =
                         UserFontCache::GetFont(currSrc.mURI, principal,
                                                aProxyEntry);
                     if (fe) {
-                        ReplaceFontEntry(aProxyEntry, fe);
+                        ReplaceFontEntry(aFamily, aProxyEntry, fe);
                         return STATUS_LOADED;
                     }
 
                     // record the principal returned by CheckFontLoad,
                     // for use when creating a channel
                     // and when caching the loaded entry
                     aProxyEntry->mPrincipal = principal;
 
@@ -587,64 +585,67 @@ gfxUserFontSet::LoadNext(gfxProxyFontEnt
                     if (NS_SUCCEEDED(rv) && loadDoesntSpin) {
                         uint8_t *buffer = nullptr;
                         uint32_t bufferLength = 0;
 
                         // sync load font immediately
                         rv = SyncLoadFontData(aProxyEntry, &currSrc,
                                               buffer, bufferLength);
                         if (NS_SUCCEEDED(rv) &&
-                            (fe = LoadFont(aProxyEntry, buffer, bufferLength))) {
+                            (fe = LoadFont(aFamily, aProxyEntry,
+                                           buffer, bufferLength))) {
                             UserFontCache::CacheFont(fe);
                             return STATUS_LOADED;
                         } else {
-                            LogMessage(aProxyEntry, "font load failed",
+                            LogMessage(aFamily, aProxyEntry,
+                                       "font load failed",
                                        nsIScriptError::errorFlag, rv);
                         }
                     } else {
                         // otherwise load font async
-                        rv = StartLoad(aProxyEntry, &currSrc);
+                        rv = StartLoad(aFamily, aProxyEntry, &currSrc);
                         if (NS_SUCCEEDED(rv)) {
 #ifdef PR_LOGGING
                             if (LOG_ENABLED()) {
                                 nsAutoCString fontURI;
                                 currSrc.mURI->GetSpec(fontURI);
                                 LOG(("userfonts (%p) [src %d] loading uri: (%s) for (%s)\n",
                                      this, aProxyEntry->mSrcIndex, fontURI.get(),
-                                     NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get()));
+                                     NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
                             }
 #endif
                             return STATUS_LOADING;
                         } else {
-                            LogMessage(aProxyEntry, "download failed",
+                            LogMessage(aFamily, aProxyEntry,
+                                       "download failed",
                                        nsIScriptError::errorFlag, rv);
                         }
                     }
                 } else {
-                    LogMessage(aProxyEntry, "download not allowed",
+                    LogMessage(aFamily, aProxyEntry, "download not allowed",
                                nsIScriptError::errorFlag, rv);
                 }
             } else {
                 // We don't log a warning to the web console yet,
                 // as another source may load successfully
                 aProxyEntry->mUnsupportedFormat = true;
             }
         }
 
         aProxyEntry->mSrcIndex++;
     }
 
     if (aProxyEntry->mUnsupportedFormat) {
-        LogMessage(aProxyEntry, "no supported format found",
+        LogMessage(aFamily, aProxyEntry, "no supported format found",
                    nsIScriptError::warningFlag);
     }
 
     // all src's failed; mark this entry as unusable (so fallback will occur)
     LOG(("userfonts (%p) failed all src for (%s)\n",
-        this, NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get()));
+        this, NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
     aProxyEntry->mLoadingState = gfxProxyFontEntry::LOADING_FAILED;
 
     return STATUS_END_OF_LIST;
 }
 
 void
 gfxUserFontSet::IncrementGeneration()
 {
@@ -652,27 +653,20 @@ gfxUserFontSet::IncrementGeneration()
     ++sFontSetGeneration;
     if (sFontSetGeneration == 0)
        ++sFontSetGeneration;
     mGeneration = sFontSetGeneration;
 }
 
 
 gfxFontEntry*
-gfxUserFontSet::LoadFont(gfxProxyFontEntry *aProxy,
+gfxUserFontSet::LoadFont(gfxMixedFontFamily *aFamily,
+                         gfxProxyFontEntry *aProxy,
                          const uint8_t *aFontData, uint32_t &aLength)
 {
-    // if the proxy doesn't belong to a family, we just bail as it won't be
-    // accessible/usable anyhow (maybe the font set got modified right as
-    // the load was completing?)
-    if (!aProxy->Family()) {
-        NS_Free(const_cast<uint8_t*>(aFontData));
-        return nullptr;
-    }
-
     gfxFontEntry *fe = nullptr;
 
     gfxUserFontType fontType =
         gfxFontUtils::DetermineFontDataType(aFontData, aLength);
 
     // Save a copy of the metadata block (if present) for nsIDOMFontFace
     // to use if required. Ownership of the metadata block will be passed
     // to the gfxUserFontData record below.
@@ -693,35 +687,35 @@ gfxUserFontSet::LoadFont(gfxProxyFontEnt
     // it can be reported via the nsIDOMFontFace API.
     nsAutoString originalFullName;
 
     if (gfxPlatform::GetPlatform()->SanitizeDownloadedFonts()) {
        // Call the OTS sanitizer; this will also decode WOFF to sfnt
         // if necessary. The original data in aFontData is left unchanged.
         uint32_t saneLen;
         const uint8_t* saneData =
-            SanitizeOpenTypeData(aProxy, aFontData, aLength, saneLen,
+            SanitizeOpenTypeData(aFamily, aProxy, aFontData, aLength, saneLen,
                                  fontType == GFX_USERFONT_WOFF);
         if (!saneData) {
-            LogMessage(aProxy, "rejected by sanitizer");
+            LogMessage(aFamily, aProxy, "rejected by sanitizer");
         }
         if (saneData) {
             // The sanitizer ensures that we have a valid sfnt and a usable
             // name table, so this should never fail unless we're out of
             // memory, and GetFullNameFromSFNT is not directly exposed to
             // arbitrary/malicious data from the web.
             gfxFontUtils::GetFullNameFromSFNT(saneData, saneLen,
                                               originalFullName);
             // Here ownership of saneData is passed to the platform,
             // which will delete it when no longer required
             fe = gfxPlatform::GetPlatform()->MakePlatformFont(aProxy,
                                                               saneData,
                                                               saneLen);
             if (!fe) {
-                LogMessage(aProxy, "not usable by platform");
+                LogMessage(aFamily, aProxy, "not usable by platform");
             }
         }
     } else {
         // FIXME: this code can be removed once we remove the pref to
         // disable the sanitizer; the PrepareOpenTypeData and
         // ValidateSFNTHeaders functions will then be obsolete.
         aFontData = PrepareOpenTypeData(aFontData, &aLength);
 
@@ -732,23 +726,23 @@ gfxUserFontSet::LoadFont(gfxProxyFontEnt
                 gfxFontUtils::GetFullNameFromSFNT(aFontData, aLength,
                                                   originalFullName);
                 // Here ownership of aFontData is passed to the platform,
                 // which will delete it when no longer required
                 fe = gfxPlatform::GetPlatform()->MakePlatformFont(aProxy,
                                                                   aFontData,
                                                                   aLength);
                 if (!fe) {
-                    LogMessage(aProxy, "not usable by platform");
+                    LogMessage(aFamily, aProxy, "not usable by platform");
                 }
                 aFontData = nullptr; // we must NOT free this!
             } else {
                 // the data was unusable, so just discard it
                 // (error will be reported below, if logging is enabled)
-                LogMessage(aProxy, "SFNT header or tables invalid");
+                LogMessage(aFamily, aProxy, "SFNT header or tables invalid");
             }
         }
     }
 
     if (aFontData) {
         NS_Free((void*)aFontData);
         aFontData = nullptr;
     }
@@ -756,46 +750,44 @@ gfxUserFontSet::LoadFont(gfxProxyFontEnt
     if (fe) {
         // copy OpenType feature/language settings from the proxy to the
         // newly-created font entry
         fe->mFeatureSettings.AppendElements(aProxy->mFeatureSettings);
         fe->mLanguageOverride = aProxy->mLanguageOverride;
         StoreUserFontData(fe, aProxy, originalFullName,
                           &metadata, metaOrigLen);
 #ifdef PR_LOGGING
-        // must do this before ReplaceFontEntry() because that will
-        // clear the proxy's mFamily pointer!
         if (LOG_ENABLED()) {
             nsAutoCString fontURI;
             aProxy->mSrcList[aProxy->mSrcIndex].mURI->GetSpec(fontURI);
             LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
                  this, aProxy->mSrcIndex, fontURI.get(),
-                 NS_ConvertUTF16toUTF8(aProxy->mFamily->Name()).get(),
+                 NS_ConvertUTF16toUTF8(aFamily->Name()).get(),
                  uint32_t(mGeneration)));
         }
 #endif
         UserFontCache::CacheFont(fe);
-        ReplaceFontEntry(aProxy, fe);
+        ReplaceFontEntry(aFamily, aProxy, fe);
     } else {
 #ifdef PR_LOGGING
         if (LOG_ENABLED()) {
             nsAutoCString fontURI;
             aProxy->mSrcList[aProxy->mSrcIndex].mURI->GetSpec(fontURI);
             LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s)"
                  " error making platform font\n",
                  this, aProxy->mSrcIndex, fontURI.get(),
-                 NS_ConvertUTF16toUTF8(aProxy->mFamily->Name()).get()));
+                 NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
         }
 #endif
     }
 
     return fe;
 }
 
-gfxMixedFontFamily*
+gfxFontFamily*
 gfxUserFontSet::GetFamily(const nsAString& aFamilyName) const
 {
     nsAutoString key(aFamilyName);
     ToLowerCase(key);
 
     return mFontFamilies.GetWeak(key);
 }
 
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -74,61 +74,48 @@ public:
     gfxMixedFontFamily(const nsAString& aName)
         : gfxFontFamily(aName) { }
 
     virtual ~gfxMixedFontFamily() { }
 
     void AddFontEntry(gfxFontEntry *aFontEntry) {
         nsRefPtr<gfxFontEntry> fe = aFontEntry;
         mAvailableFonts.AppendElement(fe);
-        aFontEntry->SetFamily(this);
         ResetCharacterMap();
     }
 
     void ReplaceFontEntry(gfxFontEntry *aOldFontEntry,
                           gfxFontEntry *aNewFontEntry) {
         uint32_t numFonts = mAvailableFonts.Length();
         for (uint32_t i = 0; i < numFonts; i++) {
             gfxFontEntry *fe = mAvailableFonts[i];
             if (fe == aOldFontEntry) {
-                aOldFontEntry->SetFamily(nullptr);
                 // note that this may delete aOldFontEntry, if there's no
                 // other reference to it except from its family
                 mAvailableFonts[i] = aNewFontEntry;
-                aNewFontEntry->SetFamily(this);
                 break;
             }
         }
         ResetCharacterMap();
     }
 
     void RemoveFontEntry(gfxFontEntry *aFontEntry) {
         uint32_t numFonts = mAvailableFonts.Length();
         for (uint32_t i = 0; i < numFonts; i++) {
             gfxFontEntry *fe = mAvailableFonts[i];
             if (fe == aFontEntry) {
-                aFontEntry->SetFamily(nullptr);
                 mAvailableFonts.RemoveElementAt(i);
                 break;
             }
         }
         ResetCharacterMap();
     }
 
-    // clear family pointer for all entries and remove them from the family;
-    // we need to do this explicitly before inserting the entries into a new
-    // family, in case the old one is not actually deleted until later
+    // remove entries from the family
     void DetachFontEntries() {
-        uint32_t i = mAvailableFonts.Length();
-        while (i--) {
-            gfxFontEntry *fe = mAvailableFonts[i];
-            if (fe) {
-                fe->SetFamily(nullptr);
-            }
-        }
         mAvailableFonts.Clear();
     }
 
     // temp method to determine if all proxies are loaded
     bool AllLoaded() 
     {
         uint32_t numFonts = mAvailableFonts.Length();
         for (uint32_t i = 0; i < numFonts; i++) {
@@ -192,46 +179,51 @@ public:
     void AddFontFace(const nsAString& aFamilyName, gfxFontEntry* aFontEntry);
 
     // Whether there is a face with this family name
     bool HasFamily(const nsAString& aFamilyName) const
     {
         return GetFamily(aFamilyName) != nullptr;
     }
 
-    // lookup a font entry for a given style, returns null if not loaded
-    gfxFontEntry *FindFontEntry(const nsAString& aName,
+    gfxFontFamily *GetFamily(const nsAString& aName) const;
+
+    // Lookup a font entry for a given style, returns null if not loaded.
+    // aFamily must be a family returned by our GetFamily method.
+    gfxFontEntry *FindFontEntry(gfxFontFamily *aFamily,
                                 const gfxFontStyle& aFontStyle,
-                                bool& aFoundFamily,
                                 bool& aNeedsBold,
                                 bool& aWaitForUserFont);
 
     // check whether the given source is allowed to be loaded
     virtual nsresult CheckFontLoad(const gfxFontFaceSrc *aFontFaceSrc,
                                    nsIPrincipal **aPrincipal) = 0;
 
     // initialize the process that loads external font data, which upon 
     // completion will call OnLoadComplete method
-    virtual nsresult StartLoad(gfxProxyFontEntry *aProxy,
+    virtual nsresult StartLoad(gfxMixedFontFamily *aFamily,
+                               gfxProxyFontEntry *aProxy,
                                const gfxFontFaceSrc *aFontFaceSrc) = 0;
 
     // when download has been completed, pass back data here
     // aDownloadStatus == NS_OK ==> download succeeded, error otherwise
     // returns true if platform font creation sucessful (or local()
     // reference was next in line)
     // Ownership of aFontData is passed in here; the font set must
     // ensure that it is eventually deleted with NS_Free().
-    bool OnLoadComplete(gfxProxyFontEntry *aProxy,
-                          const uint8_t *aFontData, uint32_t aLength,
-                          nsresult aDownloadStatus);
+    bool OnLoadComplete(gfxMixedFontFamily *aFamily,
+                        gfxProxyFontEntry *aProxy,
+                        const uint8_t *aFontData, uint32_t aLength,
+                        nsresult aDownloadStatus);
 
     // Replace a proxy with a real fontEntry; this is implemented in
     // nsUserFontSet in order to keep track of the entry corresponding
     // to each @font-face rule.
-    virtual void ReplaceFontEntry(gfxProxyFontEntry *aProxy,
+    virtual void ReplaceFontEntry(gfxMixedFontFamily *aFamily,
+                                  gfxProxyFontEntry *aProxy,
                                   gfxFontEntry *aFontEntry) = 0;
 
     // generation - each time a face is loaded, generation is
     // incremented so that the change can be recognized 
     uint64_t GetGeneration() { return mGeneration; }
 
     // increment the generation on font load
     void IncrementGeneration();
@@ -300,17 +292,17 @@ public:
             static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
 
             static PLDHashNumber HashKey(const KeyTypePointer aKey) {
                 uint32_t principalHash;
                 aKey->mPrincipal->GetHashValue(&principalHash);
                 return mozilla::HashGeneric(principalHash,
                                             nsURIHashKey::HashKey(aKey->mURI),
                                             HashFeatures(aKey->mFontEntry->mFeatureSettings),
-                                            ( aKey->mFontEntry->mItalic |
+                                            ((uint32_t)aKey->mFontEntry->mItalic |
                                              (aKey->mFontEntry->mWeight << 1) |
                                              (aKey->mFontEntry->mStretch << 10) ) ^
                                              aKey->mFontEntry->mLanguageOverride);
             }
 
             enum { ALLOW_MEMMOVE = false };
 
             gfxFontEntry* GetFontEntry() const { return mFontEntry; }
@@ -332,40 +324,42 @@ public:
         };
 
         static nsTHashtable<Entry> *sUserFonts;
     };
 
 protected:
     // for a given proxy font entry, attempt to load the next resource
     // in the src list
-    LoadStatus LoadNext(gfxProxyFontEntry *aProxyEntry);
+    LoadStatus LoadNext(gfxMixedFontFamily *aFamily,
+                        gfxProxyFontEntry *aProxyEntry);
 
     // helper method for creating a platform font
     // returns font entry if platform font creation successful
     // Ownership of aFontData is passed in here; the font set must
     // ensure that it is eventually deleted with NS_Free().
-    gfxFontEntry* LoadFont(gfxProxyFontEntry *aProxy,
+    gfxFontEntry* LoadFont(gfxMixedFontFamily *aFamily,
+                           gfxProxyFontEntry *aProxy,
                            const uint8_t *aFontData, uint32_t &aLength);
 
     // parse data for a data URL
     virtual nsresult SyncLoadFontData(gfxProxyFontEntry *aFontToLoad,
                                       const gfxFontFaceSrc *aFontFaceSrc,
                                       uint8_t* &aBuffer,
                                       uint32_t &aBufferLength) = 0;
 
-    gfxMixedFontFamily *GetFamily(const nsAString& aName) const;
-
     // report a problem of some kind (implemented in nsUserFontSet)
-    virtual nsresult LogMessage(gfxProxyFontEntry *aProxy,
+    virtual nsresult LogMessage(gfxMixedFontFamily *aFamily,
+                                gfxProxyFontEntry *aProxy,
                                 const char *aMessage,
                                 uint32_t aFlags = nsIScriptError::errorFlag,
                                 nsresult aStatus = NS_OK) = 0;
 
-    const uint8_t* SanitizeOpenTypeData(gfxProxyFontEntry *aProxy,
+    const uint8_t* SanitizeOpenTypeData(gfxMixedFontFamily *aFamily,
+                                        gfxProxyFontEntry *aProxy,
                                         const uint8_t* aData,
                                         uint32_t aLength,
                                         uint32_t& aSaneLength,
                                         bool aIsCompressed);
 
 #ifdef MOZ_OTS_REPORT_ERRORS
     static bool OTSMessage(void *aUserData, const char *format, ...);
 #endif
--- a/layout/inspector/src/nsFontFace.cpp
+++ b/layout/inspector/src/nsFontFace.cpp
@@ -3,23 +3,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #define _IMPL_NS_LAYOUT
 
 #include "nsFontFace.h"
 #include "nsIDOMCSSFontFaceRule.h"
 #include "nsCSSRules.h"
 #include "gfxUserFontSet.h"
+#include "nsFontFaceLoader.h"
 #include "zlib.h"
 
 nsFontFace::nsFontFace(gfxFontEntry*      aFontEntry,
-                       uint8_t            aMatchType,
-                       nsCSSFontFaceRule* aRule)
+                       gfxFontGroup*      aFontGroup,
+                       uint8_t            aMatchType)
   : mFontEntry(aFontEntry),
-    mRule(aRule),
+    mFontGroup(aFontGroup),
     mMatchType(aMatchType)
 {
 }
 
 nsFontFace::~nsFontFace()
 {
 }
 
@@ -70,25 +71,75 @@ nsFontFace::GetName(nsAString & aName)
   }
   return NS_OK;
 }
 
 /* readonly attribute DOMString CSSFamilyName; */
 NS_IMETHODIMP
 nsFontFace::GetCSSFamilyName(nsAString & aCSSFamilyName)
 {
+  if (mFontEntry->IsUserFont()) {
+    // for a user font, find CSS family name from the @font-face rule
+    nsUserFontSet* fontSet =
+      static_cast<nsUserFontSet*>(mFontGroup->GetUserFontSet());
+    if (fontSet) {
+      nsCSSFontFaceRule* rule = fontSet->FindRuleForEntry(mFontEntry);
+      if (rule) {
+        nsCOMPtr<nsIDOMCSSStyleDeclaration> style;
+        nsresult rv = rule->GetStyle(getter_AddRefs(style));
+        if (NS_SUCCEEDED(rv)) {
+          nsString familyName;
+          rv = style->GetPropertyValue(NS_LITERAL_STRING("font-family"),
+                                       aCSSFamilyName);
+          if (NS_SUCCEEDED(rv)) {
+            // GetPropertyValue gives us the name in "quotes"; strip them off.
+            // XXX What about possible CSS escapes - should we unescape here?
+            // Or don't we care, as this is just for display/debugging use?
+            if (aCSSFamilyName[0] == '"' &&
+                aCSSFamilyName[aCSSFamilyName.Length() - 1] == '"') {
+              aCSSFamilyName.Truncate(aCSSFamilyName.Length() - 1);
+              aCSSFamilyName.Cut(0, 1);
+            }
+            return NS_OK;
+          }
+        }
+      }
+    }
+  }
+
+  // look through the font-group's list for this entry
+  uint32_t count = mFontGroup->FontListLength();
+  for (uint32_t i = 0; i < count; ++i) {
+    if (mFontGroup->GetFontAt(i)->GetFontEntry() == mFontEntry) {
+      aCSSFamilyName = mFontGroup->GetFamilyNameAt(i);
+      return NS_OK;
+    }
+  }
+
+  // if it wasn't found there, query the font entry itself
   aCSSFamilyName = mFontEntry->FamilyName();
   return NS_OK;
 }
 
 /* readonly attribute nsIDOMCSSFontFaceRule rule; */
 NS_IMETHODIMP
 nsFontFace::GetRule(nsIDOMCSSFontFaceRule **aRule)
 {
-  NS_IF_ADDREF(*aRule = mRule.get());
+  // check whether this font entry is associated with an @font-face rule
+  // in the relevant font group's user font set
+  nsCSSFontFaceRule* rule = nullptr;
+  if (mFontEntry->IsUserFont()) {
+    nsUserFontSet* fontSet =
+      static_cast<nsUserFontSet*>(mFontGroup->GetUserFontSet());
+    if (fontSet) {
+      rule = fontSet->FindRuleForEntry(mFontEntry);
+    }
+  }
+
+  NS_IF_ADDREF(*aRule = rule);
   return NS_OK;
 }
 
 /* readonly attribute long srcIndex; */
 NS_IMETHODIMP
 nsFontFace::GetSrcIndex(int32_t * aSrcIndex)
 {
   if (mFontEntry->IsUserFont()) {
--- a/layout/inspector/src/nsFontFace.h
+++ b/layout/inspector/src/nsFontFace.h
@@ -13,25 +13,25 @@ class nsCSSFontFaceRule;
 
 class nsFontFace : public nsIDOMFontFace
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMFONTFACE
 
   nsFontFace(gfxFontEntry*      aFontEntry,
-             uint8_t            aMatchInfo,
-             nsCSSFontFaceRule* aRule);
+             gfxFontGroup*      aFontGroup,
+             uint8_t            aMatchInfo);
   virtual ~nsFontFace();
 
   gfxFontEntry* GetFontEntry() const { return mFontEntry.get(); }
 
   void AddMatchType(uint8_t aMatchType) {
     mMatchType |= aMatchType;
   }
 
 protected:
   nsRefPtr<gfxFontEntry> mFontEntry;
-  nsRefPtr<nsCSSFontFaceRule> mRule;
+  nsRefPtr<gfxFontGroup> mFontGroup;
   uint8_t mMatchType;
 };
 
 #endif // __nsFontFace_h__
--- a/layout/inspector/src/nsFontFaceList.cpp
+++ b/layout/inspector/src/nsFontFaceList.cpp
@@ -81,24 +81,18 @@ nsFontFaceList::AddFontsFromTextRun(gfxT
     gfxFontEntry *fe = iter.GetGlyphRun()->mFont->GetFontEntry();
     // if we have already listed this face, just make sure the match type is
     // recorded
     nsFontFace* existingFace =
       static_cast<nsFontFace*>(mFontFaces.GetWeak(fe));
     if (existingFace) {
       existingFace->AddMatchType(iter.GetGlyphRun()->mMatchType);
     } else {
-      // A new font entry we haven't seen before;
-      // check whether this font entry is associated with an @font-face rule
-      nsRefPtr<nsCSSFontFaceRule> rule;
-      nsUserFontSet* fontSet =
-        static_cast<nsUserFontSet*>(aFrame->PresContext()->GetUserFontSet());
-      if (fontSet) {
-        rule = fontSet->FindRuleForEntry(fe);
-      }
+      // A new font entry we haven't seen before
       nsCOMPtr<nsFontFace> ff =
-        new nsFontFace(fe, iter.GetGlyphRun()->mMatchType, rule);
+        new nsFontFace(fe, aTextRun->GetFontGroup(),
+                       iter.GetGlyphRun()->mMatchType);
       mFontFaces.Put(fe, ff);
     }
   }
 
   return NS_OK;
 }
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -920,22 +920,22 @@ SetFontFamily(nsStyleContext*      aStyl
     nsRefPtr<nsFontMetrics> fm;
     aRenderingContext.DeviceContext()->GetMetricsFor(font,
       aStyleContext->GetStyleFont()->mLanguage,
       aStyleContext->PresContext()->GetUserFontSet(),
       *getter_AddRefs(fm));
     // Set the font if it is an unicode table
     // or if the same family name has been found
     if (aGlyphTable == &gGlyphTableList->mUnicodeTable ||
-        fm->GetThebesFontGroup()->GetFontAt(0)->GetFontEntry()->
-        FamilyName() == family) {
+        fm->GetThebesFontGroup()->GetFamilyNameAt(0) == family) {
       aFont.name = family;
       aRenderingContext.SetFont(fm);
-    } else
-        return false; // We did not set the font
+    } else {
+      return false; // We did not set the font
+    }
   }
   return true;
 }
 
 class nsMathMLChar::StretchEnumContext {
 public:
   StretchEnumContext(nsMathMLChar*        aChar,
                      nsPresContext*       aPresContext,
--- a/layout/style/nsFontFaceLoader.cpp
+++ b/layout/style/nsFontFaceLoader.cpp
@@ -53,22 +53,27 @@ GetFontDownloaderLog()
   return sLog;
 }
 #endif /* PR_LOGGING */
 
 #define LOG(args) PR_LOG(GetFontDownloaderLog(), PR_LOG_DEBUG, args)
 #define LOG_ENABLED() PR_LOG_TEST(GetFontDownloaderLog(), PR_LOG_DEBUG)
 
 
-nsFontFaceLoader::nsFontFaceLoader(gfxProxyFontEntry *aProxy, nsIURI *aFontURI,
-                                   nsUserFontSet *aFontSet, nsIChannel *aChannel)
-  : mFontEntry(aProxy), mFontURI(aFontURI), mFontSet(aFontSet),
+nsFontFaceLoader::nsFontFaceLoader(gfxMixedFontFamily *aFontFamily,
+                                   gfxProxyFontEntry *aProxy,
+                                   nsIURI *aFontURI,
+                                   nsUserFontSet *aFontSet,
+                                   nsIChannel *aChannel)
+  : mFontFamily(aFontFamily),
+    mFontEntry(aProxy),
+    mFontURI(aFontURI),
+    mFontSet(aFontSet),
     mChannel(aChannel)
 {
-  mFontFamily = aProxy->Family();
 }
 
 nsFontFaceLoader::~nsFontFaceLoader()
 {
   if (mFontEntry) {
     mFontEntry->mLoader = nullptr;
   }
   if (mLoadTimer) {
@@ -209,19 +214,20 @@ nsFontFaceLoader::OnStreamComplete(nsISt
   }
 
   // The userFontSet is responsible for freeing the downloaded data
   // (aString) when finished with it; the pointer is no longer valid
   // after OnLoadComplete returns.
   // This is called even in the case of a failed download (HTTP 404, etc),
   // as there may still be data to be freed (e.g. an error page),
   // and we need the fontSet to initiate loading the next source.
-  bool fontUpdate = userFontSet->OnLoadComplete(mFontEntry,
-                                                  aString, aStringLen,
-                                                  aStatus);
+  bool fontUpdate = userFontSet->OnLoadComplete(mFontFamily,
+                                                mFontEntry,
+                                                aString, aStringLen,
+                                                aStatus);
 
   // when new font loaded, need to reflow
   if (fontUpdate) {
     // Update layout for the presence of the new font.  Since this is
     // asynchronous, reflows will coalesce.
     ctx->UserFontSetUpdated();
     LOG(("fontdownloader (%p) reflow\n", this));
   }
@@ -307,17 +313,18 @@ nsUserFontSet::Destroy()
 
 void
 nsUserFontSet::RemoveLoader(nsFontFaceLoader *aLoader)
 {
   mLoaders.RemoveEntry(aLoader);
 }
 
 nsresult
-nsUserFontSet::StartLoad(gfxProxyFontEntry *aProxy,
+nsUserFontSet::StartLoad(gfxMixedFontFamily *aFamily,
+                         gfxProxyFontEntry *aProxy,
                          const gfxFontFaceSrc *aFontFaceSrc)
 {
   nsresult rv;
 
   nsIPresShell *ps = mPresContext->PresShell();
   if (!ps)
     return NS_ERROR_FAILURE;
 
@@ -341,17 +348,17 @@ nsUserFontSet::StartLoad(gfxProxyFontEnt
                      loadGroup,
                      nullptr,
                      nsIRequest::LOAD_NORMAL,
                      channelPolicy);
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsRefPtr<nsFontFaceLoader> fontLoader =
-    new nsFontFaceLoader(aProxy, aFontFaceSrc->mURI, this, channel);
+    new nsFontFaceLoader(aFamily, aProxy, aFontFaceSrc->mURI, this, channel);
 
   if (!fontLoader)
     return NS_ERROR_OUT_OF_MEMORY;
 
 #ifdef PR_LOGGING
   if (LOG_ENABLED()) {
     nsAutoCString fontURI, referrerURI;
     aFontFaceSrc->mURI->GetSpec(fontURI);
@@ -658,56 +665,54 @@ nsUserFontSet::InsertRule(nsCSSFontFaceR
       mRules.AppendElement(ruleRec);
     }
     // this was a new rule and fontEntry, so note that the set was modified
     aFontSetModified = true;
   }
 }
 
 void
-nsUserFontSet::ReplaceFontEntry(gfxProxyFontEntry *aProxy,
+nsUserFontSet::ReplaceFontEntry(gfxMixedFontFamily *aFamily,
+                                gfxProxyFontEntry *aProxy,
                                 gfxFontEntry *aFontEntry)
 {
   for (uint32_t i = 0; i < mRules.Length(); ++i) {
     if (mRules[i].mFontEntry == aProxy) {
       mRules[i].mFontEntry = aFontEntry;
       break;
     }
   }
-  gfxMixedFontFamily *family =
-    static_cast<gfxMixedFontFamily*>(aProxy->Family());
-  if (family) {
-    family->ReplaceFontEntry(aProxy, aFontEntry);
-  }
+  aFamily->ReplaceFontEntry(aProxy, aFontEntry);
 }
 
 nsCSSFontFaceRule*
 nsUserFontSet::FindRuleForEntry(gfxFontEntry *aFontEntry)
 {
   for (uint32_t i = 0; i < mRules.Length(); ++i) {
     if (mRules[i].mFontEntry == aFontEntry) {
       return mRules[i].mContainer.mRule;
     }
   }
   return nullptr;
 }
 
 nsresult
-nsUserFontSet::LogMessage(gfxProxyFontEntry *aProxy,
+nsUserFontSet::LogMessage(gfxMixedFontFamily *aFamily,
+                          gfxProxyFontEntry *aProxy,
                           const char        *aMessage,
                           uint32_t          aFlags,
                           nsresult          aStatus)
 {
   nsCOMPtr<nsIConsoleService>
     console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
   if (!console) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  NS_ConvertUTF16toUTF8 familyName(aProxy->FamilyName());
+  NS_ConvertUTF16toUTF8 familyName(aFamily->Name());
   nsAutoCString fontURI;
   if (aProxy->mSrcIndex == aProxy->mSrcList.Length()) {
     fontURI.AppendLiteral("(end of source list)");
   } else {
     if (aProxy->mSrcList[aProxy->mSrcIndex].mURI) {
       aProxy->mSrcList[aProxy->mSrcIndex].mURI->GetSpec(fontURI);
     } else {
       fontURI.AppendLiteral("(invalid URI)");
--- a/layout/style/nsFontFaceLoader.h
+++ b/layout/style/nsFontFaceLoader.h
@@ -34,28 +34,30 @@ public:
   nsUserFontSet(nsPresContext *aContext);
   ~nsUserFontSet();
 
   // Called when this font set is no longer associated with a presentation.
   void Destroy();
 
   // starts loading process, creating and initializing a nsFontFaceLoader obj
   // returns whether load process successfully started or not
-  nsresult StartLoad(gfxProxyFontEntry *aFontToLoad,
+  nsresult StartLoad(gfxMixedFontFamily *aFamily,
+                     gfxProxyFontEntry *aFontToLoad,
                      const gfxFontFaceSrc *aFontFaceSrc);
 
   // Called by nsFontFaceLoader when the loader has completed normally.
   // It's removed from the mLoaders set.
   void RemoveLoader(nsFontFaceLoader *aLoader);
 
   bool UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules);
 
   nsPresContext *GetPresContext() { return mPresContext; }
 
-  virtual void ReplaceFontEntry(gfxProxyFontEntry *aProxy,
+  virtual void ReplaceFontEntry(gfxMixedFontFamily *aFamily,
+                                gfxProxyFontEntry *aProxy,
                                 gfxFontEntry *aFontEntry);
 
   nsCSSFontFaceRule *FindRuleForEntry(gfxFontEntry *aFontEntry);
 
 protected:
   // The font-set keeps track of the collection of rules, and their
   // corresponding font entries (whether proxies or real entries),
   // so that we can update the set without having to throw away
@@ -64,17 +66,18 @@ protected:
     nsRefPtr<gfxFontEntry>       mFontEntry;
     nsFontFaceRuleContainer      mContainer;
   };
 
   void InsertRule(nsCSSFontFaceRule *aRule, uint8_t aSheetType,
                   nsTArray<FontFaceRuleRecord>& oldRules,
                   bool& aFontSetModified);
 
-  virtual nsresult LogMessage(gfxProxyFontEntry *aProxy,
+  virtual nsresult LogMessage(gfxMixedFontFamily *aFamily,
+                              gfxProxyFontEntry *aProxy,
                               const char *aMessage,
                               uint32_t aFlags = nsIScriptError::errorFlag,
                               nsresult aStatus = NS_OK);
 
   virtual nsresult CheckFontLoad(const gfxFontFaceSrc *aFontFaceSrc,
                                  nsIPrincipal **aPrincipal);
 
   virtual nsresult SyncLoadFontData(gfxProxyFontEntry *aFontToLoad,
@@ -90,19 +93,20 @@ protected:
   nsTHashtable< nsPtrHashKey<nsFontFaceLoader> > mLoaders;
 
   nsTArray<FontFaceRuleRecord>   mRules;
 };
 
 class nsFontFaceLoader : public nsIStreamLoaderObserver
 {
 public:
+  nsFontFaceLoader(gfxMixedFontFamily *aFontFamily,
+                   gfxProxyFontEntry *aFontToLoad, nsIURI *aFontURI, 
+                   nsUserFontSet *aFontSet, nsIChannel *aChannel);
 
-  nsFontFaceLoader(gfxProxyFontEntry *aFontToLoad, nsIURI *aFontURI, 
-                   nsUserFontSet *aFontSet, nsIChannel *aChannel);
   virtual ~nsFontFaceLoader();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISTREAMLOADEROBSERVER 
 
   // initiate the load
   nsresult Init();
   // cancel the load and remove its reference to mFontSet
@@ -114,18 +118,18 @@ public:
 
   static void LoadTimerCallback(nsITimer *aTimer, void *aClosure);
 
   static nsresult CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
                                    nsIURI* aTargetURI,
                                    nsISupports* aContext);
 
 private:
+  nsRefPtr<gfxMixedFontFamily> mFontFamily;
   nsRefPtr<gfxProxyFontEntry>  mFontEntry;
-  nsRefPtr<gfxFontFamily>      mFontFamily;
   nsCOMPtr<nsIURI>        mFontURI;
   nsRefPtr<nsUserFontSet> mFontSet;
   nsCOMPtr<nsIChannel>    mChannel;
   nsCOMPtr<nsITimer>      mLoadTimer;
 
   nsIStreamLoader        *mStreamLoader;
 };