Bug 1514869 - patch 2 - Adapt platform-font-list code to work with either the existing in-process font list or cross-process shared font list. r=jwatt
authorJonathan Kew <jkew@mozilla.com>
Sat, 27 Apr 2019 15:37:58 +0000
changeset 530571 095b3edec3c8ba9318c71d0acc91e10ce57818dc
parent 530570 21ef00977ab69cd330d727d582fef291276391c4
child 530572 c154853c599ae8fe77062a06475f6b7c5e6da226
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwatt
bugs1514869
milestone68.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 1514869 - patch 2 - Adapt platform-font-list code to work with either the existing in-process font list or cross-process shared font list. r=jwatt Differential Revision: https://phabricator.services.mozilla.com/D22938
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
gfx/thebes/gfxFT2FontList.cpp
gfx/thebes/gfxFcPlatformFontList.cpp
gfx/thebes/gfxFcPlatformFontList.h
gfx/thebes/gfxFontEntry.cpp
gfx/thebes/gfxFontEntry.h
gfx/thebes/gfxGDIFontList.cpp
gfx/thebes/gfxGDIFontList.h
gfx/thebes/gfxMacPlatformFontList.h
gfx/thebes/gfxMacPlatformFontList.mm
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxPlatformFontList.h
gfx/thebes/gfxPrefs.h
gfx/thebes/gfxTextRun.cpp
gfx/thebes/gfxTextRun.h
gfx/thebes/gfxUserFontSet.h
layout/style/PostTraversalTask.cpp
layout/style/PostTraversalTask.h
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -245,16 +245,17 @@
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/ipc/CrashReporterClient.h"
 #include "mozilla/net/NeckoMessageUtils.h"
 #include "mozilla/widget/PuppetBidiKeyboard.h"
 #include "mozilla/RemoteSpellCheckEngineChild.h"
 #include "GMPServiceChild.h"
 #include "GfxInfoBase.h"
 #include "gfxPlatform.h"
+#include "gfxPlatformFontList.h"
 #include "nscore.h"  // for NS_FREE_PERMANENT_DATA
 #include "VRManagerChild.h"
 #include "private/pprio.h"
 #include "nsString.h"
 #include "MMPrinter.h"
 
 #ifdef MOZ_WIDGET_GTK
 #  include "nsAppRunner.h"
@@ -2455,16 +2456,22 @@ mozilla::ipc::IPCResult ContentChild::Re
     mSharedData =
         new SharedMap(ContentProcessMessageManager::Get()->GetParentObject(),
                       aMapFile, aMapSize, std::move(blobImpls));
   }
 
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult ContentChild::RecvFontListChanged() {
+  gfxPlatformFontList::PlatformFontList()->FontListChanged();
+
+  return IPC_OK();
+}
+
 mozilla::ipc::IPCResult ContentChild::RecvGeolocationUpdate(
     nsIDOMGeoPosition* aPosition) {
   RefPtr<nsGeolocationService> gs =
       nsGeolocationService::GetGeolocationService();
   if (!gs) {
     return IPC_OK();
   }
   gs->Update(aPosition);
@@ -2491,16 +2498,21 @@ mozilla::ipc::IPCResult ContentChild::Re
 
 mozilla::ipc::IPCResult ContentChild::RecvUpdateFontList(
     InfallibleTArray<SystemFontListEntry>&& aFontList) {
   mFontList = std::move(aFontList);
   gfxPlatform::GetPlatform()->UpdateFontList();
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult ContentChild::RecvRebuildFontList() {
+  gfxPlatform::GetPlatform()->UpdateFontList();
+  return IPC_OK();
+}
+
 mozilla::ipc::IPCResult ContentChild::RecvUpdateAppLocales(
     nsTArray<nsCString>&& aAppLocales) {
   LocaleService::GetInstance()->AssignAppLocales(aAppLocales);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult ContentChild::RecvUpdateRequestedLocales(
     nsTArray<nsCString>&& aRequestedLocales) {
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -362,28 +362,31 @@ class ContentChild final : public PConte
 
   mozilla::ipc::IPCResult RecvRegisterStringBundles(
       nsTArray<StringBundleDescriptor>&& stringBundles);
 
   mozilla::ipc::IPCResult RecvUpdateSharedData(
       const FileDescriptor& aMapFile, const uint32_t& aMapSize,
       nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys);
 
+  mozilla::ipc::IPCResult RecvFontListChanged();
+
   mozilla::ipc::IPCResult RecvGeolocationUpdate(nsIDOMGeoPosition* aPosition);
 
   // MOZ_CAN_RUN_SCRIPT_BOUNDARY because we don't have MOZ_CAN_RUN_SCRIPT bits
   // in IPC code yet.
   MOZ_CAN_RUN_SCRIPT_BOUNDARY
   mozilla::ipc::IPCResult RecvGeolocationError(const uint16_t& errorCode);
 
   mozilla::ipc::IPCResult RecvUpdateDictionaryList(
       InfallibleTArray<nsString>&& aDictionaries);
 
   mozilla::ipc::IPCResult RecvUpdateFontList(
       InfallibleTArray<SystemFontListEntry>&& aFontList);
+  mozilla::ipc::IPCResult RecvRebuildFontList();
 
   mozilla::ipc::IPCResult RecvUpdateAppLocales(
       nsTArray<nsCString>&& aAppLocales);
   mozilla::ipc::IPCResult RecvUpdateRequestedLocales(
       nsTArray<nsCString>&& aRequestedLocales);
 
   mozilla::ipc::IPCResult RecvClearSiteDataReloadNeeded(
       const nsString& aOrigin);
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1242,16 +1242,22 @@ void ContentParent::BroadcastStringBundl
   AutoTArray<StringBundleDescriptor, 1> array;
   array.AppendElement(aBundle);
 
   for (auto* cp : AllProcesses(eLive)) {
     Unused << cp->SendRegisterStringBundles(array);
   }
 }
 
+void ContentParent::BroadcastFontListChanged() {
+  for (auto* cp : AllProcesses(eLive)) {
+    Unused << cp->SendFontListChanged();
+  }
+}
+
 const nsAString& ContentParent::GetRemoteType() const { return mRemoteType; }
 
 void ContentParent::Init() {
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     size_t length = ArrayLength(sObserverTopics);
     for (size_t i = 0; i < length; ++i) {
       obs->AddObserver(this, sObserverTopics[i], false);
@@ -4457,16 +4463,22 @@ void ContentParent::NotifyUpdatedFonts()
   InfallibleTArray<SystemFontListEntry> fontList;
   gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
 
   for (auto* cp : AllProcesses(eLive)) {
     Unused << cp->SendUpdateFontList(fontList);
   }
 }
 
+void ContentParent::NotifyRebuildFontList() {
+  for (auto* cp : AllProcesses(eLive)) {
+    Unused << cp->SendRebuildFontList();
+  }
+}
+
 /*static*/
 void ContentParent::UnregisterRemoteFrame(const TabId& aTabId,
                                           const ContentParentId& aCpId,
                                           bool aMarkedDestroying) {
   if (XRE_IsParentProcess()) {
     ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
     ContentParent* cp = cpm->GetContentProcessById(aCpId);
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -214,16 +214,18 @@ class ContentParent final : public PCont
                                       uint64_t aNextRemoteTabId);
 
   static void GetAll(nsTArray<ContentParent*>& aArray);
 
   static void GetAllEvenIfDead(nsTArray<ContentParent*>& aArray);
 
   static void BroadcastStringBundle(const StringBundleDescriptor&);
 
+  static void BroadcastFontListChanged();
+
   const nsAString& GetRemoteType() const;
 
   virtual void DoGetRemoteType(nsAString& aRemoteType,
                                ErrorResult& aError) const override {
     aRemoteType = GetRemoteType();
   }
 
   enum CPIteratorPolicy { eLive, eAll };
@@ -272,16 +274,17 @@ class ContentParent final : public PCont
     return ContentParentIterator(aPolicy, first);
   }
 
   static bool IgnoreIPCPrincipal();
 
   static void NotifyUpdatedDictionaries();
 
   static void NotifyUpdatedFonts();
+  static void NotifyRebuildFontList();
 
 #if defined(XP_WIN)
   /**
    * Windows helper for firing off an update window request to a plugin
    * instance.
    *
    * aWidget - the eWindowType_plugin_ipc_chrome widget associated with
    *           this plugin window.
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -490,16 +490,29 @@ child:
     async GeolocationUpdate(nsIDOMGeoPosition aPosition);
 
     async GeolocationError(uint16_t errorCode);
 
     async UpdateDictionaryList(nsString[] dictionaries);
 
     async UpdateFontList(SystemFontListEntry[] fontList);
 
+    /**
+     * The shared font list has been reinitialized by the parent;
+     * child processes must discard and recreate their mappings to it.
+     */
+    async RebuildFontList();
+
+    /**
+     * The shared font list has been modified, potentially adding matches
+     * for src:local() names that were previously not known, so content
+     * may need to be reflowed.
+     */
+    async FontListChanged();
+
     async UpdateAppLocales(nsCString[] appLocales);
     async UpdateRequestedLocales(nsCString[] requestedLocales);
 
     async ClearSiteDataReloadNeeded(nsString origin);
 
     async RegisterStringBundles(StringBundleDescriptor[] stringBundles);
 
     async UpdateSharedData(FileDescriptor mapFile, uint32_t aSize,
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -835,35 +835,33 @@ gfxDWriteFontList::gfxDWriteFontList() :
 
 // 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.
 
 FontFamily gfxDWriteFontList::GetDefaultFontForPlatform(
     const gfxFontStyle* aStyle) {
   // try Arial first
-  gfxFontFamily* ff;
-  if ((ff = FindFamily(NS_LITERAL_CSTRING("Arial")))) {
-    return FontFamily(ff);
+  FontFamily ff;
+  ff = FindFamily(NS_LITERAL_CSTRING("Arial"));
+  if (!ff.IsNull()) {
+    return ff;
   }
 
   // otherwise, use local default
   NONCLIENTMETRICSW ncm;
   ncm.cbSize = sizeof(ncm);
   BOOL status =
       ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
 
   if (status) {
     ff = FindFamily(NS_ConvertUTF16toUTF8(ncm.lfMessageFont.lfFaceName));
-    if (ff) {
-      return FontFamily(ff);
-    }
   }
 
-  return FontFamily();
+  return ff;
 }
 
 gfxFontEntry* gfxDWriteFontList::LookupLocalFont(
     const nsACString& aFontName, WeightRange aWeightForEntry,
     StretchRange aStretchForEntry, SlantStyleRange aStyleForEntry) {
   gfxFontEntry* lookup;
 
   lookup = LookupInFaceNameLists(aFontName);
@@ -1286,47 +1284,37 @@ void gfxDWriteFontList::GetDirectWriteSu
     if (nullptr != (ff = mFontFamilies.GetWeak(actualFontName))) {
       mFontSubstitutes.Put(substituteName, ff);
     } else {
       mNonExistingFonts.AppendElement(substituteName);
     }
   }
 }
 
-bool gfxDWriteFontList::GetStandardFamilyName(const nsCString& aFontName,
-                                              nsACString& aFamilyName) {
-  gfxFontFamily* family = FindFamily(aFontName);
-  if (family) {
-    family->LocalizedName(aFamilyName);
-    return true;
-  }
-
-  return false;
-}
-
-bool gfxDWriteFontList::FindAndAddFamilies(const nsACString& aFamily,
+bool gfxDWriteFontList::FindAndAddFamilies(StyleGenericFontFamily aGeneric,
+                                           const nsACString& aFamily,
                                            nsTArray<FamilyAndGeneric>* aOutput,
                                            FindFamiliesFlags aFlags,
                                            gfxFontStyle* aStyle,
                                            gfxFloat aDevToCssSize) {
   nsAutoCString keyName(aFamily);
   BuildKeyNameFromFontName(keyName);
 
   gfxFontFamily* ff = mFontSubstitutes.GetWeak(keyName);
   if (ff) {
-    aOutput->AppendElement(FamilyAndGeneric(ff));
+    aOutput->AppendElement(FamilyAndGeneric(ff, aGeneric));
     return true;
   }
 
   if (mNonExistingFonts.Contains(keyName)) {
     return false;
   }
 
-  return gfxPlatformFontList::FindAndAddFamilies(aFamily, aOutput, aFlags,
-                                                 aStyle, aDevToCssSize);
+  return gfxPlatformFontList::FindAndAddFamilies(aGeneric, aFamily, aOutput,
+                                                 aFlags, aStyle, aDevToCssSize);
 }
 
 void gfxDWriteFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                                                FontListSizes* aSizes) const {
   gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 
   // We are a singleton, so include the font loader singleton's memory.
   MOZ_ASSERT(static_cast<const gfxPlatformFontList*>(this) ==
@@ -1467,22 +1455,30 @@ gfxFontEntry* gfxDWriteFontList::Platfor
 
   // call the draw method to invoke the DirectWrite layout functions
   // which determine the fallback font
   hr = fallbackLayout->Draw(nullptr, mFallbackRenderer, 50.0f, 50.0f);
   if (FAILED(hr)) {
     return nullptr;
   }
 
-  gfxFontFamily* family = FindFamily(mFallbackRenderer->FallbackFamilyName());
-  if (family) {
-    gfxFontEntry* fontEntry;
-    fontEntry = family->FindFontForStyle(*aMatchStyle);
+  FontFamily family = FindFamily(mFallbackRenderer->FallbackFamilyName());
+  if (!family.IsNull()) {
+    gfxFontEntry* fontEntry = nullptr;
+    if (family.mIsShared) {
+      auto face =
+          family.mShared->FindFaceForStyle(SharedFontList(), *aMatchStyle);
+      if (face) {
+        fontEntry = GetOrCreateFontEntry(face, family.mShared);
+      }
+    } else {
+      fontEntry = family.mUnshared->FindFontForStyle(*aMatchStyle);
+    }
     if (fontEntry && fontEntry->HasCharacter(aCh)) {
-      *aMatchedFamily = FontFamily(family);
+      *aMatchedFamily = family;
       return fontEntry;
     }
     Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, true);
   }
 
   return nullptr;
 }
 
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -377,23 +377,21 @@ class gfxDWriteFontList : public gfxPlat
 
   virtual gfxFontEntry* MakePlatformFont(const nsACString& aFontName,
                                          WeightRange aWeightForEntry,
                                          StretchRange aStretchForEntry,
                                          SlantStyleRange aStyleForEntry,
                                          const uint8_t* aFontData,
                                          uint32_t aLength);
 
-  bool GetStandardFamilyName(const nsCString& aFontName,
-                             nsACString& aFamilyName);
-
   IDWriteGdiInterop* GetGDIInterop() { return mGDIInterop; }
   bool UseGDIFontTableAccess() { return mGDIFontTableAccess; }
 
-  bool FindAndAddFamilies(const nsACString& aFamily,
+  bool FindAndAddFamilies(mozilla::StyleGenericFontFamily aGeneric,
+                          const nsACString& aFamily,
                           nsTArray<FamilyAndGeneric>* aOutput,
                           FindFamiliesFlags aFlags,
                           gfxFontStyle* aStyle = nullptr,
                           gfxFloat aDevToCssSize = 1.0) override;
 
   gfxFloat GetForceGDIClassicMaxFontSize() {
     return mForceGDIClassicMaxFontSize;
   }
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -1502,25 +1502,25 @@ searchDone:
     fe->mIsLocalUserFont = true;
   }
 
   return fe;
 }
 
 FontFamily gfxFT2FontList::GetDefaultFontForPlatform(
     const gfxFontStyle* aStyle) {
-  gfxFontFamily* ff = nullptr;
+  FontFamily ff;
 #if defined(MOZ_WIDGET_ANDROID)
   ff = FindFamily(NS_LITERAL_CSTRING("Roboto"));
-  if (!ff) {
+  if (ff.IsNull()) {
     ff = FindFamily(NS_LITERAL_CSTRING("Droid Sans"));
   }
 #endif
   /* TODO: what about Qt or other platforms that may use this? */
-  return FontFamily(ff);
+  return ff;
 }
 
 gfxFontEntry* gfxFT2FontList::MakePlatformFont(const nsACString& aFontName,
                                                WeightRange aWeightForEntry,
                                                StretchRange aStretchForEntry,
                                                SlantStyleRange aStyleForEntry,
                                                const uint8_t* aFontData,
                                                uint32_t aLength) {
--- a/gfx/thebes/gfxFcPlatformFontList.cpp
+++ b/gfx/thebes/gfxFcPlatformFontList.cpp
@@ -1783,18 +1783,19 @@ gfxFontEntry* gfxFcPlatformFontList::Mak
   }
 
   return new gfxFontconfigFontEntry(aFontName, aWeightForEntry,
                                     aStretchForEntry, aStyleForEntry, aFontData,
                                     aLength, face);
 }
 
 bool gfxFcPlatformFontList::FindAndAddFamilies(
-    const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
-    FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) {
+    StyleGenericFontFamily aGeneric, const nsACString& aFamily,
+    nsTArray<FamilyAndGeneric>* aOutput, FindFamiliesFlags aFlags,
+    gfxFontStyle* aStyle, gfxFloat aDevToCssSize) {
   nsAutoCString familyName(aFamily);
   ToLowerCase(familyName);
   nsAtom* language = (aStyle ? aStyle->language.get() : nullptr);
 
   if (!(aFlags & FindFamiliesFlags::eQuotedFamilyName)) {
     // deprecated generic names are explicitly converted to standard generics
     bool isDeprecatedGeneric = false;
     if (familyName.EqualsLiteral("sans") ||
@@ -1863,17 +1864,18 @@ bool gfxFcPlatformFontList::FindAndAddFa
   FcChar8* substName = nullptr;
   for (int i = 0; FcPatternGetString(fontWithSentinel, FC_FAMILY, i,
                                      &substName) == FcResultMatch;
        i++) {
     if (sentinelFirstFamily && FcStrCmp(substName, sentinelFirstFamily) == 0) {
       break;
     }
     gfxPlatformFontList::FindAndAddFamilies(
-        nsDependentCString(ToCharPtr(substName)), &cachedFamilies, aFlags);
+        aGeneric, nsDependentCString(ToCharPtr(substName)), &cachedFamilies,
+        aFlags);
   }
 
   // Cache the resulting list, so we don't have to do this again.
   mFcSubstituteCache.Put(familyName, cachedFamilies);
 
   if (cachedFamilies.IsEmpty()) {
     return false;
   }
@@ -1968,17 +1970,17 @@ bool gfxFcPlatformFontList::GetStandardF
     }
   }
 
   // didn't find localized name, leave family name blank
   return true;
 }
 
 void gfxFcPlatformFontList::AddGenericFonts(
-    mozilla::StyleGenericFontFamily aGenericType, nsAtom* aLanguage,
+    StyleGenericFontFamily aGenericType, nsAtom* aLanguage,
     nsTArray<FamilyAndGeneric>& aFamilyList) {
   bool usePrefFontList = false;
 
   const char* generic = GetGenericName(aGenericType);
   NS_ASSERTION(generic, "weird generic font type");
   if (!generic) {
     return;
   }
@@ -2126,17 +2128,18 @@ gfxPlatformFontList::PrefFontList* gfxFc
     FcPattern* font = faces->fonts[i];
     FcChar8* mappedGeneric = nullptr;
 
     FcPatternGetString(font, FC_FAMILY, 0, &mappedGeneric);
     if (mappedGeneric) {
       nsAutoCString mappedGenericName(ToCharPtr(mappedGeneric));
       AutoTArray<FamilyAndGeneric, 1> genericFamilies;
       if (gfxPlatformFontList::FindAndAddFamilies(
-              mappedGenericName, &genericFamilies, FindFamiliesFlags(0))) {
+              StyleGenericFontFamily::None, mappedGenericName, &genericFamilies,
+              FindFamiliesFlags(0))) {
         MOZ_ASSERT(genericFamilies.Length() == 1, "expected a single family");
         if (!prefFonts->Contains(genericFamilies[0].mFamily)) {
           prefFonts->AppendElement(genericFamilies[0].mFamily);
           bool foundLang = !fcLang.IsEmpty() &&
                            PatternHasLang(font, ToFcChar8Ptr(fcLang.get()));
           foundFontWithLang = foundFontWithLang || foundLang;
           // check to see if the list is full
           if (prefFonts->Length() >= limit) {
--- a/gfx/thebes/gfxFcPlatformFontList.h
+++ b/gfx/thebes/gfxFcPlatformFontList.h
@@ -284,17 +284,18 @@ class gfxFcPlatformFontList : public gfx
 
   gfxFontEntry* MakePlatformFont(const nsACString& aFontName,
                                  WeightRange aWeightForEntry,
                                  StretchRange aStretchForEntry,
                                  SlantStyleRange aStyleForEntry,
                                  const uint8_t* aFontData,
                                  uint32_t aLength) override;
 
-  bool FindAndAddFamilies(const nsACString& aFamily,
+  bool FindAndAddFamilies(mozilla::StyleGenericFontFamily aGeneric,
+                          const nsACString& aFamily,
                           nsTArray<FamilyAndGeneric>* aOutput,
                           FindFamiliesFlags aFlags,
                           gfxFontStyle* aStyle = nullptr,
                           gfxFloat aDevToCssSize = 1.0) override;
 
   bool GetStandardFamilyName(const nsCString& aFontName,
                              nsACString& aFamilyName) override;
 
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -136,21 +136,23 @@ gfxFontEntry::~gfxFontEntry() {
   // By the time the entry is destroyed, all font instances that were
   // using it should already have been deleted, and so the HB and/or Gr
   // face objects should have been released.
   MOZ_ASSERT(!mHBFace);
   MOZ_ASSERT(!mGrFaceInitialized);
 }
 
 bool gfxFontEntry::TestCharacterMap(uint32_t aCh) {
-  if (!mCharacterMap) {
+  if (!mCharacterMap && !mShmemCharacterMap) {
     ReadCMAP();
-    NS_ASSERTION(mCharacterMap, "failed to initialize character map");
+    MOZ_ASSERT(mCharacterMap || mShmemCharacterMap,
+               "failed to initialize character map");
   }
-  return mCharacterMap->test(aCh);
+  return mShmemCharacterMap ? mShmemCharacterMap->test(aCh)
+                            : mCharacterMap->test(aCh);
 }
 
 nsresult gfxFontEntry::InitializeUVSMap() {
   // mUVSOffset will not be initialized
   // until cmap is initialized.
   if (!mCharacterMap) {
     ReadCMAP();
     NS_ASSERTION(mCharacterMap, "failed to initialize character map");
@@ -1689,18 +1691,19 @@ bool gfxFontFamily::CheckForLegacyFamily
   return added;
 }
 
 void gfxFontFamily::ReadFaceNames(gfxPlatformFontList* aPlatformFontList,
                                   bool aNeedFullnamePostscriptNames,
                                   FontInfoData* aFontInfoData) {
   // if all needed names have already been read, skip
   if (mOtherFamilyNamesInitialized &&
-      (mFaceNamesInitialized || !aNeedFullnamePostscriptNames))
+      (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
     return;
+  }
 
   bool asyncFontLoaderDisabled = false;
 
   if (!mOtherFamilyNamesInitialized && aFontInfoData &&
       aFontInfoData->mLoadOtherNames && !asyncFontLoaderDisabled) {
     AutoTArray<nsCString, 4> otherFamilyNames;
     bool foundOtherNames =
         aFontInfoData->GetOtherFamilyNames(mName, otherFamilyNames);
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -196,24 +196,28 @@ class gfxFontEntry {
     if (!mCheckedForGraphiteTables) {
       CheckForGraphiteTables();
       mCheckedForGraphiteTables = true;
     }
     return mHasGraphiteTables;
   }
 
   inline bool HasCmapTable() {
-    if (!mCharacterMap) {
+    if (!mCharacterMap && !mShmemCharacterMap) {
       ReadCMAP();
-      NS_ASSERTION(mCharacterMap, "failed to initialize character map");
+      NS_ASSERTION(mCharacterMap || mShmemCharacterMap,
+                   "failed to initialize character map");
     }
     return mHasCmapTable;
   }
 
   inline bool HasCharacter(uint32_t ch) {
+    if (mShmemCharacterMap) {
+      return mShmemCharacterMap->test(ch);
+    }
     if (mCharacterMap && mCharacterMap->test(ch)) {
       return true;
     }
     return TestCharacterMap(ch);
   }
 
   virtual bool SkipDuringSystemFallback() { return false; }
   nsresult InitializeUVSMap();
@@ -396,16 +400,19 @@ class gfxFontEntry {
   // This is only called on platforms where we use FreeType.
   virtual FT_MM_Var* GetMMVar() { return nullptr; }
 
   nsCString mName;
   nsCString mFamilyName;
 
   RefPtr<gfxCharacterMap> mCharacterMap;
 
+  mozilla::fontlist::Face* mShmemFace = nullptr;
+  const SharedBitSet* mShmemCharacterMap = nullptr;
+
   mozilla::UniquePtr<uint8_t[]> mUVSData;
   mozilla::UniquePtr<gfxUserFontData> mUserFontData;
   mozilla::UniquePtr<gfxSVGGlyphs> mSVGGlyphs;
   // list of gfxFonts that are using SVG glyphs
   nsTArray<gfxFont*> mFontsUsingSVGGlyphs;
   nsTArray<gfxFontFeature> mFeatureSettings;
   nsTArray<gfxFontVariation> mVariationSettings;
   mozilla::UniquePtr<nsDataHashtable<nsUint32HashKey, bool>> mSupportedFeatures;
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -815,63 +815,64 @@ gfxFontEntry* gfxGDIFontList::MakePlatfo
 
   if (fe) {
     fe->mIsDataUserFont = true;
   }
 
   return fe;
 }
 
-bool gfxGDIFontList::FindAndAddFamilies(const nsACString& aFamily,
+bool gfxGDIFontList::FindAndAddFamilies(StyleGenericFontFamily aGeneric,
+                                        const nsACString& aFamily,
                                         nsTArray<FamilyAndGeneric>* aOutput,
                                         FindFamiliesFlags aFlags,
                                         gfxFontStyle* aStyle,
                                         gfxFloat aDevToCssSize) {
   NS_ConvertUTF8toUTF16 key16(aFamily);
   BuildKeyNameFromFontName(key16);
   NS_ConvertUTF16toUTF8 keyName(key16);
 
   gfxFontFamily* ff = mFontSubstitutes.GetWeak(keyName);
   if (ff) {
-    aOutput->AppendElement(FamilyAndGeneric(ff));
+    aOutput->AppendElement(FamilyAndGeneric(ff, aGeneric));
     return true;
   }
 
   if (mNonExistingFonts.Contains(keyName)) {
     return false;
   }
 
-  return gfxPlatformFontList::FindAndAddFamilies(aFamily, aOutput, aFlags,
-                                                 aStyle, aDevToCssSize);
+  return gfxPlatformFontList::FindAndAddFamilies(aGeneric, aFamily, aOutput,
+                                                 aFlags, aStyle, aDevToCssSize);
 }
 
 FontFamily gfxGDIFontList::GetDefaultFontForPlatform(
     const gfxFontStyle* aStyle) {
-  gfxFontFamily* ff = nullptr;
+  FontFamily ff;
 
   // this really shouldn't fail to find a font....
   NONCLIENTMETRICSW ncm;
   ncm.cbSize = sizeof(ncm);
   BOOL status =
       ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
   if (status) {
     ff = FindFamily(NS_ConvertUTF16toUTF8(ncm.lfMessageFont.lfFaceName));
-    if (ff) {
-      return FontFamily(ff);
+    if (!ff.IsNull()) {
+      return ff;
     }
   }
 
   // ...but just in case, try another (long-deprecated) approach as well
   HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
   LOGFONTW logFont;
   if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) {
     ff = FindFamily(NS_ConvertUTF16toUTF8(logFont.lfFaceName));
   }
 
-  return FontFamily(ff);
+  return ff;
 }
 
 void gfxGDIFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                                             FontListSizes* aSizes) const {
   gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
   aSizes->mFontListSize +=
       SizeOfFontFamilyTableExcludingThis(mFontSubstitutes, aMallocSizeOf);
   aSizes->mFontListSize +=
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -294,17 +294,18 @@ class gfxGDIFontList : public gfxPlatfor
     return static_cast<gfxGDIFontList*>(sPlatformFontList);
   }
 
   // initialize font lists
   virtual nsresult InitFontListForPlatform() override;
 
   gfxFontFamily* CreateFontFamily(const nsACString& aName) const override;
 
-  bool FindAndAddFamilies(const nsACString& aFamily,
+  bool FindAndAddFamilies(mozilla::StyleGenericFontFamily aGeneric,
+                          const nsACString& aFamily,
                           nsTArray<FamilyAndGeneric>* aOutput,
                           FindFamiliesFlags aFlags,
                           gfxFontStyle* aStyle = nullptr,
                           gfxFloat aDevToCssSize = 1.0) override;
 
   virtual gfxFontEntry* LookupLocalFont(const nsACString& aFontName,
                                         WeightRange aWeightForEntry,
                                         StretchRange aStretchForEntry,
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -135,32 +135,30 @@ class gfxMacPlatformFontList : public gf
   static gfxMacPlatformFontList* PlatformFontList() {
     return static_cast<gfxMacPlatformFontList*>(sPlatformFontList);
   }
 
   gfxFontFamily* CreateFontFamily(const nsACString& aName) const override;
 
   static int32_t AppleWeightToCSSWeight(int32_t aAppleWeight);
 
-  bool GetStandardFamilyName(const nsCString& aFontName,
-                             nsACString& aFamilyName) override;
-
   gfxFontEntry* LookupLocalFont(const nsACString& aFontName,
                                 WeightRange aWeightForEntry,
                                 StretchRange aStretchForEntry,
                                 SlantStyleRange aStyleForEntry) override;
 
   gfxFontEntry* MakePlatformFont(const nsACString& aFontName,
                                  WeightRange aWeightForEntry,
                                  StretchRange aStretchForEntry,
                                  SlantStyleRange aStyleForEntry,
                                  const uint8_t* aFontData,
                                  uint32_t aLength) override;
 
-  bool FindAndAddFamilies(const nsACString& aFamily,
+  bool FindAndAddFamilies(mozilla::StyleGenericFontFamily aGeneric,
+                          const nsACString& aFamily,
                           nsTArray<FamilyAndGeneric>* aOutput,
                           FindFamiliesFlags aFlags,
                           gfxFontStyle* aStyle = nullptr,
                           gfxFloat aDevToCssSize = 1.0) override;
 
   // lookup the system font for a particular system font type and set
   // the name and style characteristics
   void LookupSystemFont(mozilla::LookAndFeel::FontID aSystemFontID,
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -1246,27 +1246,16 @@ gfxFontFamily* gfxMacPlatformFontList::F
   // lookup in user-exposed family name list
   if ((familyEntry = mFontFamilies.GetWeak(key))) {
     return CheckFamily(familyEntry);
   }
 
   return nullptr;
 }
 
-bool gfxMacPlatformFontList::GetStandardFamilyName(const nsCString& aFontName,
-                                                   nsACString& aFamilyName) {
-  gfxFontFamily* family = FindFamily(aFontName);
-  if (family) {
-    family->LocalizedName(aFamilyName);
-    return true;
-  }
-
-  return false;
-}
-
 void gfxMacPlatformFontList::RegisteredFontsChangedNotificationCallback(
     CFNotificationCenterRef center, void* observer, CFStringRef name, const void* object,
     CFDictionaryRef userInfo) {
   if (!::CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification)) {
     return;
   }
 
   gfxMacPlatformFontList* fl = static_cast<gfxMacPlatformFontList*>(observer);
@@ -1360,17 +1349,17 @@ gfxFontEntry* gfxMacPlatformFontList::Pl
 
 FontFamily gfxMacPlatformFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle) {
   nsAutoreleasePool localPool;
 
   NSString* defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
   nsAutoString familyName;
 
   GetStringForNSString(defaultFamily, familyName);
-  return FontFamily(FindFamily(NS_ConvertUTF16toUTF8(familyName)));
+  return FindFamily(NS_ConvertUTF16toUTF8(familyName));
 }
 
 int32_t gfxMacPlatformFontList::AppleWeightToCSSWeight(int32_t aAppleWeight) {
   if (aAppleWeight < 1)
     aAppleWeight = 1;
   else if (aAppleWeight > kAppleMaxWeight)
     aAppleWeight = kAppleMaxWeight;
   return gAppleWeightToCSSWeight[aAppleWeight];
@@ -1442,32 +1431,34 @@ gfxFontEntry* gfxMacPlatformFontList::Ma
 
   return nullptr;
 }
 
 // Webkit code uses a system font meta name, so mimic that here
 // WebCore/platform/graphics/mac/FontCacheMac.mm
 static const char kSystemFont_system[] = "-apple-system";
 
-bool gfxMacPlatformFontList::FindAndAddFamilies(const nsACString& aFamily,
+bool gfxMacPlatformFontList::FindAndAddFamilies(mozilla::StyleGenericFontFamily aGeneric,
+                                                const nsACString& aFamily,
                                                 nsTArray<FamilyAndGeneric>* aOutput,
                                                 FindFamiliesFlags aFlags, gfxFontStyle* aStyle,
                                                 gfxFloat aDevToCssSize) {
   // search for special system font name, -apple-system
   if (aFamily.EqualsLiteral(kSystemFont_system)) {
     if (mUseSizeSensitiveSystemFont && aStyle &&
         (aStyle->size * aDevToCssSize) >= kTextDisplayCrossover) {
       aOutput->AppendElement(FindSystemFontFamily(mSystemDisplayFontFamilyName));
       return true;
     }
     aOutput->AppendElement(FindSystemFontFamily(mSystemTextFontFamilyName));
     return true;
   }
 
-  return gfxPlatformFontList::FindAndAddFamilies(aFamily, aOutput, aFlags, aStyle, aDevToCssSize);
+  return gfxPlatformFontList::FindAndAddFamilies(aGeneric, aFamily, aOutput, aFlags, aStyle,
+                                                 aDevToCssSize);
 }
 
 void gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID,
                                               nsACString& aSystemFontName,
                                               gfxFontStyle& aFontStyle) {
   // code moved here from widget/cocoa/nsLookAndFeel.mm
   NSFont* font = nullptr;
   char* systemFontName = nullptr;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1710,21 +1710,27 @@ void gfxPlatform::GetStandardFamilyName(
 }
 
 nsAutoCString gfxPlatform::GetDefaultFontName(
     const nsACString& aLangGroup, const nsACString& aGenericFamily) {
   // To benefit from Return Value Optimization, all paths here must return
   // this one variable:
   nsAutoCString result;
 
-  gfxFontFamily* fontFamily =
+  FamilyAndGeneric fam =
       gfxPlatformFontList::PlatformFontList()->GetDefaultFontFamily(
           aLangGroup, aGenericFamily);
-  if (fontFamily) {
-    fontFamily->LocalizedName(result);
+  if (fam.mFamily.mIsShared) {
+    if (fam.mFamily.mShared) {
+      fontlist::FontList* fontList =
+          gfxPlatformFontList::PlatformFontList()->SharedFontList();
+      result = fam.mFamily.mShared->DisplayName().AsString(fontList);
+    }
+  } else if (fam.mFamily.mUnshared) {
+    fam.mFamily.mUnshared->LocalizedName(result);
   }  // (else, leave 'result' empty)
 
   return result;
 }
 
 bool gfxPlatform::DownloadableFontsEnabled() {
   if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
     mAllowDownloadableFonts =
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Logging.h"
 #include "mozilla/intl/LocaleService.h"
 #include "mozilla/intl/MozLocale.h"
 #include "mozilla/intl/OSPreferences.h"
 
 #include "gfxPlatformFontList.h"
+#include "gfxPrefs.h"
 #include "gfxTextRun.h"
 #include "gfxUserFontSet.h"
 #include "SharedFontList-impl.h"
 
 #include "nsCRT.h"
 #include "nsGkAtoms.h"
 #include "nsServiceManagerUtils.h"
 #include "nsUnicharUtils.h"
@@ -22,18 +23,28 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
+#include "mozilla/dom/BlobImpl.h"
+#include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/ContentProcessMessageManager.h"
+#include "mozilla/dom/IPCBlobUtils.h"
 #include "mozilla/gfx/2D.h"
+#include "mozilla/ipc/FileDescriptorUtils.h"
+#include "mozilla/ResultExtensions.h"
+#include "mozilla/Unused.h"
+
+#include "base/eintr_wrapper.h"
+#include "base/file_util.h"
 
 #include <locale.h>
 
 using namespace mozilla;
 using mozilla::intl::Locale;
 using mozilla::intl::LocaleService;
 using mozilla::intl::OSPreferences;
 
@@ -177,16 +188,17 @@ NS_IMETHODIMP
 gfxPlatformFontList::MemoryReporter::CollectReports(
     nsIHandleReportCallback* aHandleReport, nsISupports* aData,
     bool aAnonymize) {
   FontListSizes sizes;
   sizes.mFontListSize = 0;
   sizes.mFontTableCacheSize = 0;
   sizes.mCharMapsSize = 0;
   sizes.mLoaderSize = 0;
+  sizes.mSharedSize = 0;
 
   gfxPlatformFontList::PlatformFontList()->AddSizeOfIncludingThis(
       &FontListMallocSizeOf, &sizes);
 
   MOZ_COLLECT_REPORT(
       "explicit/gfx/font-list", KIND_HEAP, UNITS_BYTES, sizes.mFontListSize,
       "Memory used to manage the list of font families and faces.");
 
@@ -202,16 +214,22 @@ gfxPlatformFontList::MemoryReporter::Col
   }
 
   if (sizes.mLoaderSize) {
     MOZ_COLLECT_REPORT("explicit/gfx/font-loader", KIND_HEAP, UNITS_BYTES,
                        sizes.mLoaderSize,
                        "Memory used for (platform-specific) font loader.");
   }
 
+  if (sizes.mSharedSize) {
+    MOZ_COLLECT_REPORT(
+        "font-list-shmem", KIND_NONHEAP, UNITS_BYTES, sizes.mSharedSize,
+        "Shared memory for system font list and character coverage data.");
+  }
+
   return NS_OK;
 }
 
 gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
     : mFontFamiliesMutex("gfxPlatformFontList::mFontFamiliesMutex"),
       mFontFamilies(64),
       mOtherFamilyNames(16),
       mSharedCmaps(8),
@@ -305,16 +323,50 @@ void gfxPlatformFontList::ApplyWhitelist
     nsAutoCString fontFamilyName(iter.Key());
     ToLowerCase(fontFamilyName);
     if (!familyNamesWhitelist.Contains(fontFamilyName)) {
       iter.Remove();
     }
   }
 }
 
+void gfxPlatformFontList::ApplyWhitelist(
+    nsTArray<fontlist::Family::InitData>& aFamilies) {
+  nsTArray<nsCString> list;
+  gfxFontUtils::GetPrefsFontList(kFontSystemWhitelistPref, list);
+  mFontFamilyWhitelistActive = !list.IsEmpty();
+  if (!mFontFamilyWhitelistActive) {
+    return;
+  }
+  nsTHashtable<nsCStringHashKey> familyNamesWhitelist;
+  for (const auto& item : list) {
+    nsAutoCString key;
+    ToLowerCase(item, key);
+    familyNamesWhitelist.PutEntry(key);
+  }
+  int count = int(aFamilies.Length());
+  // Find the first non-hidden family; we won't delete this, if no other
+  // non-hidden family has been kept.
+  int firstNonHidden = 0;
+  while (firstNonHidden < count && aFamilies[firstNonHidden].mHidden) {
+    ++firstNonHidden;
+  }
+  bool keptNonHidden = false;
+  for (int i = count - 1; i >= firstNonHidden; --i) {
+    if (aFamilies[i].mHidden) {
+      continue;
+    }
+    if (familyNamesWhitelist.Contains(aFamilies[i].mKey)) {
+      keptNonHidden = true;
+    } else if (keptNonHidden || i > firstNonHidden) {
+      aFamilies.RemoveElementAt(i);
+    }
+  }
+}
+
 bool gfxPlatformFontList::AddWithLegacyFamilyName(const nsACString& aLegacyName,
                                                   gfxFontEntry* aFontEntry) {
   bool added = false;
   nsAutoCString key;
   ToLowerCase(aLegacyName, key);
   gfxFontFamily* family = mOtherFamilyNames.GetWeak(key);
   if (!family) {
     family = CreateFontFamily(aLegacyName);
@@ -360,39 +412,87 @@ nsresult gfxPlatformFontList::InitFontLi
   // 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
 
   sPlatformFontList = this;
 
-  nsresult rv = InitFontListForPlatform();
-  if (NS_FAILED(rv)) {
-    return rv;
+  // Try to initialize the cross-process shared font list if enabled by prefs,
+  // but not if we're running in Safe Mode.
+  if (gfxPrefs::SharedFontList() && !gfxPlatform::InSafeMode()) {
+    for (auto i = mFontEntries.Iter(); !i.Done(); i.Next()) {
+      i.Data()->mShmemCharacterMap = nullptr;
+      i.Data()->mShmemFace = nullptr;
+      i.Data()->mFamilyName = NS_LITERAL_CSTRING("");
+    }
+    mFontEntries.Clear();
+    mShmemCharMaps.Clear();
+    bool oldSharedList = mSharedFontList != nullptr;
+    mSharedFontList.reset(new fontlist::FontList(mFontlistInitCount));
+    InitSharedFontListForPlatform();
+    if (mSharedFontList->Initialized()) {
+      if (mLocalNameTable.Count()) {
+        SharedFontList()->SetLocalNames(mLocalNameTable);
+        mLocalNameTable.Clear();
+      }
+    } else {
+      // something went wrong, fall back to in-process list
+      mSharedFontList.reset(nullptr);
+    }
+    if (oldSharedList) {
+      if (XRE_IsParentProcess()) {
+        // notify all children of the change
+        mozilla::dom::ContentParent::NotifyRebuildFontList();
+      }
+    }
   }
 
-  ApplyWhitelist();
+  if (!SharedFontList()) {
+    nsresult rv = InitFontListForPlatform();
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    ApplyWhitelist();
+  }
+
   return NS_OK;
 }
 
+void gfxPlatformFontList::FontListChanged() {
+  MOZ_ASSERT(!XRE_IsParentProcess());
+  if (SharedFontList() && SharedFontList()->NumLocalFaces()) {
+    // If we're using a shared local face-name list, this may have changed.
+    RebuildLocalFonts();
+  }
+  ForceGlobalReflow();
+}
+
 void gfxPlatformFontList::GenerateFontListKey(const nsACString& aKeyName,
                                               nsACString& aResult) {
   aResult = aKeyName;
   ToLowerCase(aResult);
 }
 
 #define OTHERNAMES_TIMEOUT 200
 
 void gfxPlatformFontList::InitOtherFamilyNames(
     bool aDeferOtherFamilyNamesLoading) {
   if (mOtherFamilyNamesInitialized) {
     return;
   }
 
+  if (SharedFontList() && !XRE_IsParentProcess()) {
+    dom::ContentChild::GetSingleton()->SendInitOtherFamilyNames(
+        SharedFontList()->GetGeneration(), aDeferOtherFamilyNamesLoading,
+        &mOtherFamilyNamesInitialized);
+    return;
+  }
+
   // If the font loader delay has been set to zero, we don't defer loading
   // additional family names (regardless of the aDefer... parameter), as we
   // take this to mean availability of font info is to be prioritized over
   // potential startup perf or main-thread jank.
   // (This is used so we can reliably run reftests that depend on localized
   // font-family names being available.)
   if (aDeferOtherFamilyNamesLoading &&
       Preferences::GetUint(FONT_LOADER_DELAY_PREF) > 0) {
@@ -491,16 +591,47 @@ gfxFontEntry* gfxPlatformFontList::Looku
       }
       mFaceNamesMissed->PutEntry(aFaceName);
     }
   }
 
   return lookup;
 }
 
+gfxFontEntry* gfxPlatformFontList::LookupInSharedFaceNameList(
+    const nsACString& aFaceName, WeightRange aWeightForEntry,
+    StretchRange aStretchForEntry, SlantStyleRange aStyleForEntry) {
+  nsAutoCString keyName(aFaceName);
+  ToLowerCase(keyName);
+  fontlist::FontList* list = SharedFontList();
+  fontlist::Family* family = nullptr;
+  fontlist::Face* face = nullptr;
+  if (list->NumLocalFaces()) {
+    fontlist::LocalFaceRec* rec = list->FindLocalFace(keyName);
+    if (rec) {
+      family = &list->Families()[rec->mFamilyIndex];
+      face = static_cast<fontlist::Face*>(
+          family->Faces(list)[rec->mFaceIndex].ToPtr(list));
+    }
+  } else {
+    list->SearchForLocalFace(keyName, &family, &face);
+  }
+  if (!face || !family) {
+    return nullptr;
+  }
+  gfxFontEntry* fe = CreateFontEntry(face, family);
+  if (fe) {
+    fe->mIsLocalUserFont = true;
+    fe->mWeightRange = aWeightForEntry;
+    fe->mStretchRange = aStretchForEntry;
+    fe->mStyleRange = aStyleForEntry;
+  }
+  return fe;
+}
+
 void gfxPlatformFontList::PreloadNamesList() {
   AutoTArray<nsCString, 10> preloadFonts;
   gfxFontUtils::GetPrefsFontList("font.preload-names-list", preloadFonts);
 
   uint32_t numFonts = preloadFonts.Length();
   for (uint32_t i = 0; i < numFonts; i++) {
     nsAutoCString key;
     GenerateFontListKey(preloadFonts[i], key);
@@ -519,23 +650,39 @@ void gfxPlatformFontList::LoadBadUnderli
   for (auto& fam : mBadUnderlineFamilyNames) {
     ToLowerCase(fam);
   }
   mBadUnderlineFamilyNames.Compact();
   mBadUnderlineFamilyNames.Sort();
 }
 
 void gfxPlatformFontList::UpdateFontList() {
+  MOZ_ASSERT(NS_IsMainThread());
   InitFontList();
   RebuildLocalFonts();
 }
 
 void gfxPlatformFontList::GetFontList(nsAtom* aLangGroup,
                                       const nsACString& aGenericFamily,
                                       nsTArray<nsString>& aListOfFonts) {
+  if (SharedFontList()) {
+    fontlist::FontList* list = SharedFontList();
+    const fontlist::Family* families = list->Families();
+    for (uint32_t i = 0; i < list->NumFamilies(); i++) {
+      auto& f = families[i];
+      if (f.IsHidden()) {
+        continue;
+      }
+      // XXX TODO: filter families for aGenericFamily, if supported by platform
+      aListOfFonts.AppendElement(
+          NS_ConvertUTF8toUTF16(f.DisplayName().AsString(list)));
+    }
+    return;
+  }
+
   MutexAutoLock lock(mFontFamiliesMutex);
   for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
     RefPtr<gfxFontFamily>& family = iter.Data();
     if (family->FilterForFontList(aLangGroup, aGenericFamily)) {
       nsAutoCString localizedFamilyName;
       family->LocalizedName(localizedFamilyName);
       aListOfFonts.AppendElement(NS_ConvertUTF8toUTF16(localizedFamilyName));
     }
@@ -563,18 +710,27 @@ gfxFontEntry* gfxPlatformFontList::Syste
     return nullptr;
   }
 
   // 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) {
-    if (!mReplacementCharFallbackFamily.mIsShared &&
-        mReplacementCharFallbackFamily.mUnshared) {
+    if (mReplacementCharFallbackFamily.mIsShared &&
+        mReplacementCharFallbackFamily.mShared) {
+      fontlist::Face* face =
+          mReplacementCharFallbackFamily.mShared->FindFaceForStyle(
+              SharedFontList(), *aStyle);
+      if (face) {
+        fontEntry =
+            GetOrCreateFontEntry(face, mReplacementCharFallbackFamily.mShared);
+      }
+    } else if (!mReplacementCharFallbackFamily.mIsShared &&
+               mReplacementCharFallbackFamily.mUnshared) {
       fontEntry =
           mReplacementCharFallbackFamily.mUnshared->FindFontForStyle(*aStyle);
     }
 
     // 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->HasCharacter(aCh)) {
       return fontEntry;
@@ -639,26 +795,43 @@ gfxFontEntry* gfxPlatformFontList::Syste
 
 gfxFontEntry* gfxPlatformFontList::CommonFontFallback(
     uint32_t aCh, uint32_t aNextCh, Script aRunScript,
     const gfxFontStyle* aMatchStyle, FontFamily* aMatchedFamily) {
   AutoTArray<const char*, NUM_FALLBACK_FONTS> defaultFallbacks;
   gfxPlatform::GetPlatform()->GetCommonFallbackFonts(aCh, aNextCh, aRunScript,
                                                      defaultFallbacks);
   GlobalFontMatch data(aCh, *aMatchStyle);
-  for (const auto name : defaultFallbacks) {
-    gfxFontFamily* fallback =
-        FindFamilyByCanonicalName(nsDependentCString(name));
-    if (fallback) {
-      fallback->FindFontForChar(&data);
+  if (SharedFontList()) {
+    for (const auto name : defaultFallbacks) {
+      fontlist::Family* family = FindSharedFamily(nsDependentCString(name));
+      if (!family) {
+        continue;
+      }
+      if (family->IsHidden()) {
+        continue;
+      }
+      family->SearchAllFontsForChar(SharedFontList(), &data);
       if (data.mBestMatch) {
-        *aMatchedFamily = FontFamily(fallback);
+        *aMatchedFamily = FontFamily(family);
         return data.mBestMatch;
       }
     }
+  } else {
+    for (const auto name : defaultFallbacks) {
+      gfxFontFamily* fallback =
+          FindFamilyByCanonicalName(nsDependentCString(name));
+      if (fallback) {
+        fallback->FindFontForChar(&data);
+        if (data.mBestMatch) {
+          *aMatchedFamily = FontFamily(fallback);
+          return data.mBestMatch;
+        }
+      }
+    }
   }
   return nullptr;
 }
 
 gfxFontEntry* gfxPlatformFontList::GlobalFontFallback(
     const uint32_t aCh, Script aRunScript, const gfxFontStyle* aMatchStyle,
     uint32_t& aCmapCount, FontFamily* aMatchedFamily) {
   bool useCmaps = IsFontFamilyWhitelistActive() ||
@@ -669,32 +842,54 @@ gfxFontEntry* gfxPlatformFontList::Globa
                                                   aMatchedFamily);
     if (fe) {
       return fe;
     }
   }
 
   // otherwise, try to find it among local fonts
   GlobalFontMatch data(aCh, *aMatchStyle);
+  if (SharedFontList()) {
+    fontlist::Family* families = SharedFontList()->Families();
+    for (uint32_t i = 0; i < SharedFontList()->NumFamilies(); i++) {
+      fontlist::Family& family = families[i];
+      if (family.IsHidden()) {
+        continue;
+      }
+      family.SearchAllFontsForChar(SharedFontList(), &data);
+      if (data.mMatchDistance == 0.0) {
+        // no better style match is possible, so stop searching
+        break;
+      }
+    }
+    if (data.mBestMatch) {
+      *aMatchedFamily = FontFamily(data.mMatchedSharedFamily);
+      return data.mBestMatch;
+    }
+  } else {
+    // iterate over all font families to find a font that support the
+    // character
+    for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
+      RefPtr<gfxFontFamily>& family = iter.Data();
+      // evaluate all fonts in this family for a match
+      family->FindFontForChar(&data);
+      if (data.mMatchDistance == 0.0) {
+        // no better style match is possible, so stop searching
+        break;
+      }
+    }
 
-  // iterate over all font families to find a font that support the character
-  for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
-    RefPtr<gfxFontFamily>& family = iter.Data();
-    // evaluate all fonts in this family for a match
-    family->FindFontForChar(&data);
-    if (data.mMatchDistance == 0.0) {
-      // no better style match is possible, so stop searching
-      break;
+    aCmapCount = data.mCmapsTested;
+    if (data.mBestMatch) {
+      *aMatchedFamily = FontFamily(data.mMatchedFamily);
+      return data.mBestMatch;
     }
   }
 
-  aCmapCount = data.mCmapsTested;
-  *aMatchedFamily = FontFamily(data.mMatchedFamily);
-
-  return data.mBestMatch;
+  return nullptr;
 }
 
 gfxFontFamily* gfxPlatformFontList::CheckFamily(gfxFontFamily* aFamily) {
   if (aFamily && !aFamily->HasStyles()) {
     aFamily->FindStyleVariations();
     aFamily->CheckForSimpleFamily();
   }
 
@@ -705,21 +900,54 @@ gfxFontFamily* gfxPlatformFontList::Chec
     mFontFamilies.Remove(key);
     return nullptr;
   }
 
   return aFamily;
 }
 
 bool gfxPlatformFontList::FindAndAddFamilies(
-    const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
-    FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) {
+    StyleGenericFontFamily aGeneric, const nsACString& aFamily,
+    nsTArray<FamilyAndGeneric>* aOutput, FindFamiliesFlags aFlags,
+    gfxFontStyle* aStyle, gfxFloat aDevToCssSize) {
   nsAutoCString key;
   GenerateFontListKey(aFamily, key);
 
+  if (SharedFontList()) {
+    fontlist::Family* family = SharedFontList()->FindFamily(key);
+    if (family) {
+      aOutput->AppendElement(FamilyAndGeneric(family, aGeneric));
+      return true;
+    }
+    // If not found, and other family names have not yet been initialized,
+    // initialize the rest of the list and try again. This is done lazily
+    // since reading name table entries is expensive.
+    // Although ASCII localized family names are possible they don't occur
+    // in practice, so avoid pulling in names at startup.
+    if (!mOtherFamilyNamesInitialized && !IsASCII(aFamily)) {
+      InitOtherFamilyNames(
+          !(aFlags & FindFamiliesFlags::eForceOtherFamilyNamesLoading));
+      family = SharedFontList()->FindFamily(key);
+      if (family) {
+        aOutput->AppendElement(FamilyAndGeneric(family, aGeneric));
+        return true;
+      }
+      if (!family && !mOtherFamilyNamesInitialized &&
+          !(aFlags & FindFamiliesFlags::eNoAddToNamesMissedWhenSearching)) {
+        // localized family names load timed out, add name to list of
+        // names to check after localized names are loaded
+        if (!mOtherNamesMissed) {
+          mOtherNamesMissed = MakeUnique<nsTHashtable<nsCStringHashKey>>(2);
+        }
+        mOtherNamesMissed->PutEntry(key);
+      }
+    }
+    return false;
+  }
+
   NS_ASSERTION(mFontFamilies.Count() != 0,
                "system font list was not initialized correctly");
 
   // lookup in canonical (i.e. English) family name list
   gfxFontFamily* familyEntry = mFontFamilies.GetWeak(key);
 
   // if not found, lookup in other family names list (mostly localized names)
   if (!familyEntry) {
@@ -760,42 +988,88 @@ bool gfxPlatformFontList::FindAndAddFami
     int32_t index = aFamily.Length();
     while (--index > 0) {
       if (data[index] == ' ') {
         break;
       }
     }
     if (index > 0) {
       gfxFontFamily* base =
-          FindFamily(Substring(aFamily, 0, index),
-                     FindFamiliesFlags::eNoSearchForLegacyFamilyNames);
+          FindUnsharedFamily(Substring(aFamily, 0, index),
+                             FindFamiliesFlags::eNoSearchForLegacyFamilyNames);
       // If we found the "base" family name, and if it has members with
       // legacy names, this will add corresponding font-family entries to
       // the mOtherFamilyNames list; then retry the legacy-family search.
       if (base && base->CheckForLegacyFamilyNames(this)) {
         familyEntry = mOtherFamilyNames.GetWeak(key);
       }
     }
   }
 
   if (familyEntry) {
-    aOutput->AppendElement(FamilyAndGeneric(familyEntry));
+    aOutput->AppendElement(FamilyAndGeneric(familyEntry, aGeneric));
     return true;
   }
 
   return false;
 }
 
+fontlist::Family* gfxPlatformFontList::FindSharedFamily(
+    const nsACString& aFamily, FindFamiliesFlags aFlags, gfxFontStyle* aStyle,
+    gfxFloat aDevToCss) {
+  if (!SharedFontList()) {
+    return nullptr;
+  }
+  AutoTArray<FamilyAndGeneric, 1> families;
+  if (!FindAndAddFamilies(StyleGenericFontFamily::None, aFamily, &families,
+                          aFlags, aStyle, aDevToCss) ||
+      !families[0].mFamily.mIsShared) {
+    return nullptr;
+  }
+  fontlist::Family* family = families[0].mFamily.mShared;
+  if (!family->IsInitialized()) {
+    if (!InitializeFamily(family)) {
+      return nullptr;
+    }
+  }
+  return family;
+}
+
+bool gfxPlatformFontList::InitializeFamily(fontlist::Family* aFamily) {
+  MOZ_ASSERT(SharedFontList());
+  auto list = SharedFontList();
+  if (!XRE_IsParentProcess()) {
+    uint32_t index = aFamily - list->Families();
+    MOZ_ASSERT(index < list->NumFamilies());
+    dom::ContentChild::GetSingleton()->SendInitializeFamily(
+        list->GetGeneration(), index);
+    return aFamily->IsInitialized();
+  }
+  AutoTArray<fontlist::Face::InitData, 16> faceList;
+  GetFacesInitDataForFamily(aFamily, faceList);
+  aFamily->AddFaces(list, faceList);
+  return aFamily->IsInitialized();
+}
+
 gfxFontEntry* gfxPlatformFontList::FindFontForFamily(
     const nsACString& aFamily, const gfxFontStyle* aStyle) {
-  gfxFontFamily* familyEntry = FindFamily(aFamily);
-
-  if (familyEntry) return familyEntry->FindFontForStyle(*aStyle);
-
-  return nullptr;
+  nsAutoCString key;
+  GenerateFontListKey(aFamily, key);
+  FontFamily family = FindFamily(key);
+  if (family.IsNull()) {
+    return nullptr;
+  }
+  if (family.mIsShared) {
+    auto face = family.mShared->FindFaceForStyle(SharedFontList(), *aStyle);
+    if (!face) {
+      return nullptr;
+    }
+    return GetOrCreateFontEntry(face, family.mShared);
+  }
+  return family.mUnshared->FindFontForStyle(*aStyle);
 }
 
 gfxFontEntry* gfxPlatformFontList::GetOrCreateFontEntry(
     fontlist::Face* aFace, const fontlist::Family* aFamily) {
   gfxFontEntry* fe = mFontEntries.GetWeak(aFace);
   if (!fe) {
     fe = CreateFontEntry(aFace, aFamily);
     mFontEntries.Put(aFace, fe);
@@ -835,43 +1109,65 @@ void gfxPlatformFontList::AddPostscriptN
     mExtraNames->mPostscriptNames.Put(aPostscriptName, aFontEntry);
     LOG_FONTLIST(("(fontlist-postscript) name: %s, psname: %s\n",
                   aFontEntry->Name().get(), aPostscriptName.get()));
   }
 }
 
 bool gfxPlatformFontList::GetStandardFamilyName(const nsCString& aFontName,
                                                 nsACString& aFamilyName) {
-  aFamilyName.Truncate();
-  gfxFontFamily* ff = FindFamily(aFontName);
-  if (!ff) {
+  FontFamily family = FindFamily(aFontName);
+  if (family.IsNull()) {
     return false;
   }
-  aFamilyName = ff->Name();
+  if (family.mIsShared) {
+    aFamilyName = family.mShared->DisplayName().AsString(SharedFontList());
+    return true;
+  }
+  family.mUnshared->LocalizedName(aFamilyName);
   return true;
 }
 
-gfxFontFamily* gfxPlatformFontList::GetDefaultFontFamily(
+FamilyAndGeneric gfxPlatformFontList::GetDefaultFontFamily(
     const nsACString& aLangGroup, const nsACString& aGenericFamily) {
   if (NS_WARN_IF(aLangGroup.IsEmpty()) ||
       NS_WARN_IF(aGenericFamily.IsEmpty())) {
-    return nullptr;
+    return FamilyAndGeneric();
   }
 
   AutoTArray<nsCString, 4> names;
   gfxFontUtils::AppendPrefsFontList(
       NameListPref(aGenericFamily, aLangGroup).get(), names);
 
   for (const nsCString& name : names) {
-    gfxFontFamily* fontFamily = FindFamily(name);
-    if (fontFamily) {
-      return fontFamily;
+    FontFamily family = FindFamily(name);
+    if (!family.IsNull()) {
+      return FamilyAndGeneric(family);
     }
   }
-  return nullptr;
+
+  return FamilyAndGeneric();
+}
+
+ShmemCharMapHashEntry::ShmemCharMapHashEntry(const gfxSparseBitSet* aCharMap)
+    : mList(gfxPlatformFontList::PlatformFontList()->SharedFontList()),
+      mCharMap(),
+      mHash(aCharMap->GetChecksum()) {
+  size_t len = SharedBitSet::RequiredSize(*aCharMap);
+  mCharMap = mList->Alloc(len);
+  SharedBitSet::Create(mCharMap.ToPtr(mList), len, *aCharMap);
+}
+
+fontlist::Pointer gfxPlatformFontList::GetShmemCharMap(
+    const gfxSparseBitSet* aCmap) {
+  auto* entry = mShmemCharMaps.GetEntry(aCmap);
+  if (!entry) {
+    entry = mShmemCharMaps.PutEntry(aCmap);
+  }
+  return entry->GetCharMap();
 }
 
 gfxCharacterMap* gfxPlatformFontList::FindCharMap(gfxCharacterMap* aCmap) {
   aCmap->CalcHash();
   gfxCharacterMap* cmap = AddCmap(aCmap);
   cmap->mShared = true;
   return cmap;
 }
@@ -916,51 +1212,56 @@ void gfxPlatformFontList::ResolveGeneric
 
   // load fonts for "font.name-list.generic.lang"
   gfxFontUtils::AppendPrefsFontList(NameListPref(generic, langGroupStr).get(),
                                     genericFamilies);
 
   nsAtom* langGroup = GetLangGroupForPrefLang(aPrefLang);
   NS_ASSERTION(langGroup, "null lang group for pref lang");
 
-  gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(
-      genericFamilies, langGroup, aGenericFamilies);
+  GetFontFamiliesFromGenericFamilies(aGenericType, genericFamilies, langGroup,
+                                     aGenericFamilies);
 
 #if 0  // dump out generic mappings
-    printf("%s ===> ", prefFontName.get());
+    printf("%s ===> ", NamePref(generic, langGroupStr).get());
     for (uint32_t k = 0; k < aGenericFamilies->Length(); k++) {
         if (k > 0) printf(", ");
-        printf("%s", aGenericFamilies[k]->Name().get());
+        printf("%s", (*aGenericFamilies)[k].mIsShared
+            ? (*aGenericFamilies)[k].mShared->DisplayName().AsString(SharedFontList()).get()
+            : (*aGenericFamilies)[k].mUnshared->Name().get());
     }
     printf("\n");
 #endif
 }
 
 void gfxPlatformFontList::ResolveEmojiFontNames(
     PrefFontList* aGenericFamilies) {
   // emoji preference has no lang name
   AutoTArray<nsCString, 4> genericFamilies;
 
   nsAutoCString prefFontListName("font.name-list.emoji");
   gfxFontUtils::AppendPrefsFontList(prefFontListName.get(), genericFamilies);
 
-  gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(
-      genericFamilies, nullptr, aGenericFamilies);
+  GetFontFamiliesFromGenericFamilies(StyleGenericFontFamily::MozEmoji,
+                                     genericFamilies, nullptr,
+                                     aGenericFamilies);
 }
 
 void gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(
+    StyleGenericFontFamily aGenericType,
     nsTArray<nsCString>& aGenericNameFamilies, nsAtom* aLangGroup,
     PrefFontList* aGenericFamilies) {
   // lookup and add platform fonts uniquely
   for (const nsCString& genericFamily : aGenericNameFamilies) {
     gfxFontStyle style;
     style.language = aLangGroup;
     style.systemFont = false;
     AutoTArray<FamilyAndGeneric, 10> families;
-    FindAndAddFamilies(genericFamily, &families, FindFamiliesFlags(0), &style);
+    FindAndAddFamilies(aGenericType, genericFamily, &families,
+                       FindFamiliesFlags(0), &style);
     for (const FamilyAndGeneric& f : families) {
       if (!aGenericFamilies->Contains(f.mFamily)) {
         aGenericFamilies->AppendElement(f.mFamily);
       }
     }
   }
 }
 
@@ -983,17 +1284,17 @@ gfxPlatformFontList::PrefFontList* gfxPl
     prefFonts = new PrefFontList;
     ResolveGenericFontNames(aGenericType, aPrefLang, prefFonts);
     mLangGroupPrefFonts[aPrefLang][index].reset(prefFonts);
   }
   return prefFonts;
 }
 
 void gfxPlatformFontList::AddGenericFonts(
-    mozilla::StyleGenericFontFamily aGenericType, nsAtom* aLanguage,
+    StyleGenericFontFamily aGenericType, nsAtom* aLanguage,
     nsTArray<FamilyAndGeneric>& aFamilyList) {
   // map lang ==> langGroup
   nsAtom* langGroup = GetLangGroup(aLanguage);
 
   // langGroup ==> prefLang
   eFontPrefLang prefLang = GetFontPrefLangFor(langGroup);
 
   // lookup pref fonts
@@ -1200,18 +1501,18 @@ void gfxPlatformFontList::AppendCJKPrefL
                                              uint32_t& aLen,
                                              eFontPrefLang aCharLang,
                                              eFontPrefLang aPageLang) {
   // prefer the lang specified by the page *if* CJK
   if (IsLangCJK(aPageLang)) {
     AppendPrefLang(aPrefLangs, aLen, aPageLang);
   }
 
-  // if not set up, set up the default CJK order, based on accept lang settings
-  // and locale
+  // if not set up, set up the default CJK order, based on accept lang
+  // settings and locale
   if (mCJKPrefLangs.Length() == 0) {
     // temp array
     eFontPrefLang tempPrefLangs[kMaxLenPrefLangList];
     uint32_t tempLen = 0;
 
     // Add the CJK pref fonts from accept languages, the order should be same
     // order
     nsAutoCString list;
@@ -1336,17 +1637,17 @@ void gfxPlatformFontList::AppendPrefLang
   }
 
   if (i == aLen) {
     aPrefLangs[aLen] = aAddLang;
     aLen++;
   }
 }
 
-mozilla::StyleGenericFontFamily gfxPlatformFontList::GetDefaultGeneric(
+StyleGenericFontFamily gfxPlatformFontList::GetDefaultGeneric(
     eFontPrefLang aLang) {
   if (aLang == eFontPrefLang_Emoji) {
     return StyleGenericFontFamily::MozEmoji;
   }
 
   // initialize lang group pref font defaults (i.e. serif/sans-serif)
   if (MOZ_UNLIKELY(mDefaultGenericsLangGroup.IsEmpty())) {
     mDefaultGenericsLangGroup.AppendElements(ArrayLength(gPrefLangNames));
@@ -1366,31 +1667,43 @@ mozilla::StyleGenericFontFamily gfxPlatf
   if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) {
     return mDefaultGenericsLangGroup[uint32_t(aLang)];
   }
   return StyleGenericFontFamily::Serif;
 }
 
 FontFamily gfxPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle) {
   FontFamily family = GetDefaultFontForPlatform(aStyle);
-  if (!family.mIsShared && family.mUnshared) {
+  if (!family.IsNull()) {
     return family;
   }
   // Something has gone wrong and we were unable to retrieve a default font
   // from the platform. (Likely the whitelist has blocked all potential
-  // default fonts.) As a last resort, we return the first font listed in
-  // mFontFamilies.
+  // default fonts.) As a last resort, we return the first font in our list.
+  if (SharedFontList()) {
+    MOZ_RELEASE_ASSERT(SharedFontList()->NumFamilies() > 0);
+    return FontFamily(SharedFontList()->Families());
+  }
+  MOZ_RELEASE_ASSERT(mFontFamilies.Count() > 0);
   return FontFamily(mFontFamilies.Iter().Data());
 }
 
 void gfxPlatformFontList::GetFontFamilyNames(
     nsTArray<nsCString>& aFontFamilyNames) {
-  for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
-    RefPtr<gfxFontFamily>& family = iter.Data();
-    aFontFamilyNames.AppendElement(family->Name());
+  if (SharedFontList()) {
+    fontlist::FontList* list = SharedFontList();
+    const fontlist::Family* families = list->Families();
+    for (uint32_t i = 0, n = list->NumFamilies(); i < n; i++) {
+      aFontFamilyNames.AppendElement(families[i].DisplayName().AsString(list));
+    }
+  } else {
+    for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
+      RefPtr<gfxFontFamily>& family = iter.Data();
+      aFontFamilyNames.AppendElement(family->Name());
+    }
   }
 }
 
 nsAtom* gfxPlatformFontList::GetLangGroup(nsAtom* aLanguage) {
   // map lang ==> langGroup
   nsAtom* langGroup = nullptr;
   if (aLanguage) {
     langGroup = mLangService->GetLanguageGroup(aLanguage);
@@ -1436,36 +1749,50 @@ void gfxPlatformFontList::InitLoader() {
 }
 
 #define FONT_LOADER_MAX_TIMESLICE \
   100  // max time for one pass through RunLoader = 100ms
 
 bool gfxPlatformFontList::LoadFontInfo() {
   TimeStamp start = TimeStamp::Now();
   uint32_t i, endIndex = mNumFamilies;
-  bool loadCmaps = !UsesSystemFallback() ||
-                   gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
+  fontlist::FontList* list = SharedFontList();
+  bool loadCmaps =
+    !list && (!UsesSystemFallback() ||
+              gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback());
 
   // for each font family, load in various font info
   for (i = mStartIndex; i < endIndex; i++) {
     nsAutoCString key;
-    gfxFontFamily* familyEntry;
     GenerateFontListKey(mFontInfo->mFontFamiliesToLoad[i], key);
 
-    // lookup in canonical (i.e. English) family name list
-    if (!(familyEntry = mFontFamilies.GetWeak(key))) {
-      continue;
-    }
+    if (list) {
+      fontlist::Family* family = list->FindFamily(key);
+      if (!family) {
+        continue;
+      }
+      if (family->IsHidden()) {
+        continue;
+      }
+      ReadFaceNamesForFamily(family, NeedFullnamePostscriptNames());
+    } else {
+      // lookup in canonical (i.e. English) family name list
+      gfxFontFamily* familyEntry = mFontFamilies.GetWeak(key);
+      if (!familyEntry) {
+        continue;
+      }
 
-    // read in face names
-    familyEntry->ReadFaceNames(this, NeedFullnamePostscriptNames(), mFontInfo);
+      // read in face names
+      familyEntry->ReadFaceNames(this, NeedFullnamePostscriptNames(),
+                                 mFontInfo);
 
-    // load the cmaps if needed
-    if (loadCmaps) {
-      familyEntry->ReadAllCMAPs(mFontInfo);
+      // load the cmaps if needed
+      if (loadCmaps) {
+        familyEntry->ReadAllCMAPs(mFontInfo);
+      }
     }
 
     // limit the time spent reading fonts in one pass
     TimeDuration elapsed = TimeStamp::Now() - start;
     if (elapsed.ToMilliseconds() > FONT_LOADER_MAX_TIMESLICE &&
         i + 1 != endIndex) {
       endIndex = i + 1;
       break;
@@ -1504,19 +1831,20 @@ void gfxPlatformFontList::CleanupLoader(
         break;
       }
     }
     mFaceNamesMissed = nullptr;
   }
 
   if (mOtherNamesMissed) {
     for (auto it = mOtherNamesMissed->Iter(); !it.Done(); it.Next()) {
-      if (FindFamily(it.Get()->GetKey(),
-                     (FindFamiliesFlags::eForceOtherFamilyNamesLoading |
-                      FindFamiliesFlags::eNoAddToNamesMissedWhenSearching))) {
+      if (FindUnsharedFamily(
+              it.Get()->GetKey(),
+              (FindFamiliesFlags::eForceOtherFamilyNamesLoading |
+               FindFamiliesFlags::eNoAddToNamesMissedWhenSearching))) {
         forceReflow = true;
         ForceGlobalReflow();
         break;
       }
     }
     mOtherNamesMissed = nullptr;
   }
 
@@ -1538,16 +1866,20 @@ void gfxPlatformFontList::CleanupLoader(
 void gfxPlatformFontList::GetPrefsAndStartLoader() {
   uint32_t delay = std::max(1u, Preferences::GetUint(FONT_LOADER_DELAY_PREF));
   uint32_t interval =
       std::max(1u, Preferences::GetUint(FONT_LOADER_INTERVAL_PREF));
 
   StartLoader(delay, interval);
 }
 
+void gfxPlatformFontList::ForceGlobalReflow() {
+  gfxPlatform::ForceGlobalReflow();
+}
+
 void gfxPlatformFontList::RebuildLocalFonts() {
   for (auto it = mUserFontSetList.Iter(); !it.Done(); it.Next()) {
     it.Get()->GetKey()->RebuildLocalRules();
   }
 }
 
 void gfxPlatformFontList::ClearLangGroupPrefFonts() {
   for (uint32_t i = eFontPrefLang_First;
@@ -1631,16 +1963,30 @@ void gfxPlatformFontList::AddSizeOfExclu
   }
 
   aSizes->mFontListSize +=
       mSharedCmaps.ShallowSizeOfExcludingThis(aMallocSizeOf);
   for (auto iter = mSharedCmaps.ConstIter(); !iter.Done(); iter.Next()) {
     aSizes->mCharMapsSize +=
         iter.Get()->GetKey()->SizeOfIncludingThis(aMallocSizeOf);
   }
+
+  aSizes->mFontListSize +=
+      mFontEntries.ShallowSizeOfExcludingThis(aMallocSizeOf);
+  for (auto iter = mFontEntries.ConstIter(); !iter.Done(); iter.Next()) {
+    iter.Data()->AddSizeOfIncludingThis(aMallocSizeOf, aSizes);
+  }
+
+  if (SharedFontList()) {
+    aSizes->mFontListSize +=
+        SharedFontList()->SizeOfIncludingThis(aMallocSizeOf);
+    if (XRE_IsParentProcess()) {
+      aSizes->mSharedSize += SharedFontList()->AllocatedShmemSize();
+    }
+  }
 }
 
 void gfxPlatformFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
                                                  FontListSizes* aSizes) const {
   aSizes->mFontListSize += aMallocSizeOf(this);
   AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
 
@@ -1653,23 +1999,36 @@ void gfxPlatformFontList::InitOtherFamil
   if (mOtherFamilyNamesInitialized) {
     return;
   }
 
   if (aDeferOtherFamilyNamesLoading) {
     TimeStamp start = TimeStamp::Now();
     bool timedOut = false;
 
-    for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
-      RefPtr<gfxFontFamily>& family = iter.Data();
-      family->ReadOtherFamilyNames(this);
-      TimeDuration elapsed = TimeStamp::Now() - start;
-      if (elapsed.ToMilliseconds() > OTHERNAMES_TIMEOUT) {
-        timedOut = true;
-        break;
+    auto list = SharedFontList();
+    if (list) {
+      for (auto& f : mozilla::Range<fontlist::Family>(list->Families(),
+                                                      list->NumFamilies())) {
+        ReadFaceNamesForFamily(&f, false);
+        TimeDuration elapsed = TimeStamp::Now() - start;
+        if (elapsed.ToMilliseconds() > OTHERNAMES_TIMEOUT) {
+          timedOut = true;
+          break;
+        }
+      }
+    } else {
+      for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
+        RefPtr<gfxFontFamily>& family = iter.Data();
+        family->ReadOtherFamilyNames(this);
+        TimeDuration elapsed = TimeStamp::Now() - start;
+        if (elapsed.ToMilliseconds() > OTHERNAMES_TIMEOUT) {
+          timedOut = true;
+          break;
+        }
       }
     }
 
     if (!timedOut) {
       mOtherFamilyNamesInitialized = true;
       CancelInitOtherFamilyNamesTask();
     }
     TimeStamp end = TimeStamp::Now();
@@ -1679,19 +2038,27 @@ void gfxPlatformFontList::InitOtherFamil
     if (LOG_FONTINIT_ENABLED()) {
       TimeDuration elapsed = end - start;
       LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
                     elapsed.ToMilliseconds(), (timedOut ? "timeout" : "")));
     }
   } else {
     TimeStamp start = TimeStamp::Now();
 
-    for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
-      RefPtr<gfxFontFamily>& family = iter.Data();
-      family->ReadOtherFamilyNames(this);
+    auto list = SharedFontList();
+    if (list) {
+      for (auto& f : mozilla::Range<fontlist::Family>(list->Families(),
+                                                      list->NumFamilies())) {
+        ReadFaceNamesForFamily(&f, false);
+      }
+    } else {
+      for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
+        RefPtr<gfxFontFamily>& family = iter.Data();
+        family->ReadOtherFamilyNames(this);
+      }
     }
 
     mOtherFamilyNamesInitialized = true;
     CancelInitOtherFamilyNamesTask();
 
     TimeStamp end = TimeStamp::Now();
     Telemetry::AccumulateTimeDelta(
         Telemetry::FONTLIST_INITOTHERFAMILYNAMES_NO_DEFERRING, start, end);
@@ -1705,56 +2072,93 @@ void gfxPlatformFontList::InitOtherFamil
   }
 }
 
 void gfxPlatformFontList::CancelInitOtherFamilyNamesTask() {
   if (mPendingOtherFamilyNameTask) {
     mPendingOtherFamilyNameTask->Cancel();
     mPendingOtherFamilyNameTask = nullptr;
   }
+  auto list = SharedFontList();
+  if (list) {
+    bool forceReflow = false;
+    if (!mAliasTable.IsEmpty()) {
+      list->SetAliases(mAliasTable);
+      mAliasTable.Clear();
+      forceReflow = true;
+    }
+    if (mLocalNameTable.Count()) {
+      list->SetLocalNames(mLocalNameTable);
+      mLocalNameTable.Clear();
+      forceReflow = true;
+    }
+    if (forceReflow) {
+      dom::ContentParent::BroadcastFontListChanged();
+    }
+  }
 }
 
 void gfxPlatformFontList::ShareFontListShmBlockToProcess(
     uint32_t aGeneration, uint32_t aIndex, /*base::ProcessId*/ uint32_t aPid,
     /*mozilla::ipc::SharedMemoryBasic::Handle*/ void* aOut) {
-  MOZ_ASSERT(SharedFontList());
+  auto list = SharedFontList();
+  if (!list) {
+    return;
+  }
   auto out = static_cast<mozilla::ipc::SharedMemoryBasic::Handle*>(aOut);
-  if (!aGeneration || SharedFontList()->GetGeneration() == aGeneration) {
-    SharedFontList()->ShareShmBlockToProcess(aIndex, aPid, out);
+  if (!aGeneration || list->GetGeneration() == aGeneration) {
+    list->ShareShmBlockToProcess(aIndex, aPid, out);
   } else {
     *out = mozilla::ipc::SharedMemoryBasic::NULLHandle();
   }
 }
 
 void gfxPlatformFontList::InitializeFamily(uint32_t aGeneration,
                                            uint32_t aFamilyIndex) {
-  MOZ_ASSERT(SharedFontList());
-  if (SharedFontList()->GetGeneration() != aGeneration) {
+  auto list = SharedFontList();
+  MOZ_ASSERT(list);
+  if (!list) {
+    return;
+  }
+  if (list->GetGeneration() != aGeneration) {
     return;
   }
-  if (aFamilyIndex >= SharedFontList()->NumFamilies()) {
+  if (aFamilyIndex >= list->NumFamilies()) {
     return;
   }
-  Unused << InitializeFamily(SharedFontList()->Families() + aFamilyIndex);
+  fontlist::Family* family = list->Families() + aFamilyIndex;
+  if (!family->IsInitialized()) {
+    Unused << InitializeFamily(family);
+  }
 }
 
 void gfxPlatformFontList::SetCharacterMap(uint32_t aGeneration,
                                           const fontlist::Pointer& aFacePtr,
                                           const gfxSparseBitSet& aMap) {
-  MOZ_ASSERT(SharedFontList());
-  if (SharedFontList()->GetGeneration() != aGeneration) {
+  auto list = SharedFontList();
+  MOZ_ASSERT(list);
+  if (!list) {
     return;
   }
-  fontlist::Face* face =
-      static_cast<fontlist::Face*>(aFacePtr.ToPtr(SharedFontList()));
-  face->SetCharacterMap(SharedFontList(), &aMap);
+  if (list->GetGeneration() != aGeneration) {
+    return;
+  }
+  fontlist::Face* face = static_cast<fontlist::Face*>(aFacePtr.ToPtr(list));
+  if (face) {
+    face->SetCharacterMap(list, &aMap);
+  }
 }
 
 void gfxPlatformFontList::InitOtherFamilyNames(uint32_t aGeneration,
                                                bool aDefer) {
-  if (SharedFontList()->GetGeneration() != aGeneration) {
+  auto list = SharedFontList();
+  MOZ_ASSERT(list);
+  if (!list) {
+    return;
+  }
+  if (list->GetGeneration() != aGeneration) {
     return;
   }
   InitOtherFamilyNames(aDefer);
 }
 
 #undef LOG
 #undef LOG_ENABLED
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFXPLATFORMFONTLIST_H_
 #define GFXPLATFORMFONTLIST_H_
 
+#include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
 #include "nsRefPtrHashtable.h"
 #include "nsTHashtable.h"
 
 #include "gfxFontUtils.h"
 #include "gfxFontInfoLoader.h"
 #include "gfxFont.h"
 #include "gfxFontConstants.h"
@@ -62,16 +63,73 @@ class CharMapHashKey : public PLDHashEnt
   enum { ALLOW_MEMMOVE = true };
 
  protected:
   // charMaps are not owned by the shared cmap cache, but it will be notified
   // by gfxCharacterMap::Release() when an entry is about to be deleted
   gfxCharacterMap* MOZ_NON_OWNING_REF mCharMap;
 };
 
+/**
+ * A helper class used to create a SharedBitSet instance in a FontList's shared
+ * memory, while ensuring that we avoid bloating memory by avoiding creating
+ * duplicate instances.
+ */
+class ShmemCharMapHashEntry final : public PLDHashEntryHdr {
+ public:
+  typedef const gfxSparseBitSet* KeyType;
+  typedef const gfxSparseBitSet* KeyTypePointer;
+
+  /**
+   * Creation from a gfxSparseBitSet creates not only the ShmemCharMapHashEntry
+   * itself, but also a SharedBitSet in shared memory.
+   * Only the parent process creates and manages these entries.
+   */
+  explicit ShmemCharMapHashEntry(const gfxSparseBitSet* aCharMap);
+
+  ShmemCharMapHashEntry(const ShmemCharMapHashEntry& aOther)
+      : mList(aOther.mList), mCharMap(aOther.mCharMap), mHash(aOther.mHash) {}
+
+  ~ShmemCharMapHashEntry() = default;
+
+  /**
+   * Return a shared-memory Pointer that refers to the wrapped SharedBitSet.
+   * This can be passed to content processes to give them access to the same
+   * SharedBitSet as the parent stored.
+   */
+  mozilla::fontlist::Pointer GetCharMap() const { return mCharMap; }
+
+  bool KeyEquals(KeyType aCharMap) const {
+    // mHash is a 32-bit Adler checksum of the bitset; if it doesn't match we
+    // can immediately reject it as non-matching, but if it is equal we still
+    // need to do a full equality check below.
+    if (mHash != aCharMap->GetChecksum()) {
+      return false;
+    }
+
+    return static_cast<const SharedBitSet*>(mCharMap.ToPtr(mList))
+        ->Equals(aCharMap);
+  }
+
+  static KeyTypePointer KeyToPointer(KeyType aCharMap) { return aCharMap; }
+  static PLDHashNumber HashKey(KeyType aCharMap) {
+    return aCharMap->GetChecksum();
+  }
+
+  enum { ALLOW_MEMMOVE = true };
+
+ private:
+  // charMaps are stored in the shared memory that FontList objects point to,
+  // and are never deleted until the FontList (all referencing font lists,
+  // actually) have gone away.
+  mozilla::fontlist::FontList* mList;
+  mozilla::fontlist::Pointer mCharMap;
+  uint32_t mHash;
+};
+
 // gfxPlatformFontList is an abstract class for the global font list on the
 // system; concrete subclasses for each platform implement the actual interface
 // to the system fonts. This class exists because we cannot rely on the platform
 // font-finding APIs to behave in sensible/similar ways, particularly with rich,
 // complex OpenType families, so we do our own font family/style management here
 // instead.
 
 // Much of this is based on the old gfxQuartzFontCache, but adapted for use on
@@ -80,16 +138,17 @@ class CharMapHashKey : public PLDHashEnt
 struct FontListSizes {
   uint32_t mFontListSize;  // size of the font list and dependent objects
                            // (font family and face names, etc), but NOT
                            // including the font table cache and the cmaps
   uint32_t
       mFontTableCacheSize;  // memory used for the gfxFontEntry table caches
   uint32_t mCharMapsSize;   // memory used for cmap coverage info
   uint32_t mLoaderSize;     // memory used for (platform-specific) loader
+  uint32_t mSharedSize;     // shared-memory use (reported by parent only)
 };
 
 class gfxUserFontSet;
 
 class gfxPlatformFontList : public gfxFontInfoLoader {
   friend class InitOtherFamilyNamesRunnable;
 
  public:
@@ -119,16 +178,26 @@ class gfxPlatformFontList : public gfxFo
     sPlatformFontList = nullptr;
   }
 
   virtual ~gfxPlatformFontList();
 
   // initialize font lists
   nsresult InitFontList();
 
+  void FontListChanged();
+
+  /**
+   * Gathers (from a platform's underlying font system) the information needed
+   * to initialize a fontlist::Family with its Face members.
+   */
+  virtual void GetFacesInitDataForFamily(
+      const mozilla::fontlist::Family* aFamily,
+      nsTArray<mozilla::fontlist::Face::InitData>& aFaces) const {}
+
   virtual void GetFontList(nsAtom* aLangGroup, const nsACString& aGenericFamily,
                            nsTArray<nsString>& aListOfFonts);
 
   void UpdateFontList();
 
   virtual void ClearLangGroupPrefFonts();
 
   virtual void GetFontFamilyList(nsTArray<RefPtr<gfxFontFamily>>& aFamilyArray);
@@ -160,17 +229,18 @@ class gfxPlatformFontList : public gfxFo
     // If set, the family name was quoted and so must not be treated as a CSS
     // generic.
     eQuotedFamilyName = 1 << 3
   };
 
   // Find family(ies) matching aFamily and append to the aOutput array
   // (there may be multiple results in the case of fontconfig aliases, etc).
   // Return true if any match was found and appended, false if none.
-  virtual bool FindAndAddFamilies(const nsACString& aFamily,
+  virtual bool FindAndAddFamilies(mozilla::StyleGenericFontFamily aGeneric,
+                                  const nsACString& aFamily,
                                   nsTArray<FamilyAndGeneric>* aOutput,
                                   FindFamiliesFlags aFlags,
                                   gfxFontStyle* aStyle = nullptr,
                                   gfxFloat aDevToCssSize = 1.0);
 
   gfxFontEntry* FindFontForFamily(const nsACString& aFamily,
                                   const gfxFontStyle* aStyle);
 
@@ -185,20 +255,17 @@ class gfxPlatformFontList : public gfxFo
   void ShareFontListShmBlockToProcess(
       uint32_t aGeneration, uint32_t aIndex, /*base::ProcessId*/ uint32_t aPid,
       /*mozilla::ipc::SharedMemoryBasic::Handle*/ void* aOut);
 
   void SetCharacterMap(uint32_t aGeneration,
                        const mozilla::fontlist::Pointer& aFacePtr,
                        const gfxSparseBitSet& aMap);
 
-  MOZ_MUST_USE bool InitializeFamily(mozilla::fontlist::Family* aFamily) {
-    // To be implemented in patch 2 of the SharedFontList series.
-    return false;
-  }
+  MOZ_MUST_USE bool InitializeFamily(mozilla::fontlist::Family* aFamily);
   void InitializeFamily(uint32_t aGeneration, uint32_t aFamilyIndex);
 
   // name lookup table methods
 
   void AddOtherFamilyName(gfxFontFamily* aFamilyEntry,
                           nsCString& aOtherFamilyName);
 
   void AddFullname(gfxFontEntry* aFontEntry, const nsCString& aFullname);
@@ -259,29 +326,26 @@ class gfxPlatformFontList : public gfxFo
 
   // get the standard family name on the platform for a given font name
   // (platforms may override, eg Mac)
   virtual bool GetStandardFamilyName(const nsCString& aFontName,
                                      nsACString& aFamilyName);
 
   // get the default font name which is available on the system from
   // font.name-list.*.  if there are no available fonts in the pref,
-  // returns nullptr.
-  gfxFontFamily* GetDefaultFontFamily(const nsACString& aLangGroup,
-                                      const nsACString& aGenericFamily);
+  // returns an empty FamilyAndGeneric record.
+  FamilyAndGeneric GetDefaultFontFamily(const nsACString& aLangGroup,
+                                        const nsACString& aGenericFamily);
 
   virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                       FontListSizes* aSizes) const;
   virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                       FontListSizes* aSizes) const;
 
-  mozilla::fontlist::Pointer GetShmemCharMap(const gfxSparseBitSet* aCharMap) {
-    // To be implemented in patch 2 of the SharedFontList series.
-    return mozilla::fontlist::Pointer::Null();
-  }
+  mozilla::fontlist::Pointer GetShmemCharMap(const gfxSparseBitSet* aCmap);
 
   // search for existing cmap that matches the input
   // return the input if no match is found
   gfxCharacterMap* FindCharMap(gfxCharacterMap* aCmap);
 
   // add a cmap to the shared cmap set
   gfxCharacterMap* AddCmap(const gfxCharacterMap* aCharMap);
 
@@ -439,26 +503,52 @@ class gfxPlatformFontList : public gfxFo
 
   typedef PrefNameMaker<false> NamePref;
   typedef PrefNameMaker<true> NameListPref;
 
   explicit gfxPlatformFontList(bool aNeedFullnamePostscriptNames = true);
 
   static gfxPlatformFontList* sPlatformFontList;
 
-  // Convenience method to return the first matching family (if any) as found
-  // by FindAndAddFamilies().
-  gfxFontFamily* FindFamily(const nsACString& aFamily,
-                            FindFamiliesFlags aFlags = FindFamiliesFlags(0),
-                            gfxFontStyle* aStyle = nullptr,
-                            gfxFloat aDevToCssSize = 1.0) {
+  /**
+   * Convenience method to return the first matching family (if any) as found
+   * by FindAndAddFamilies(). The family will be initialized (synchronously)
+   * if this has not already been done, so the returned pointer, if non-null,
+   * is ready for use.
+   */
+  mozilla::fontlist::Family* FindSharedFamily(
+      const nsACString& aFamily,
+      FindFamiliesFlags aFlags = FindFamiliesFlags(0),
+      gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0);
+
+  gfxFontFamily* FindUnsharedFamily(
+      const nsACString& aFamily,
+      FindFamiliesFlags aFlags = FindFamiliesFlags(0),
+      gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) {
+    if (SharedFontList()) {
+      return nullptr;
+    }
     AutoTArray<FamilyAndGeneric, 1> families;
-    return FindAndAddFamilies(aFamily, &families, aFlags, aStyle, aDevToCssSize)
-               ? families[0].mFamily.mUnshared
-               : nullptr;
+    if (FindAndAddFamilies(mozilla::StyleGenericFontFamily::None, aFamily,
+                           &families, aFlags, aStyle, aDevToCssSize)) {
+      return families[0].mFamily.mUnshared;
+    }
+    return nullptr;
+  }
+
+  FontFamily FindFamily(const nsACString& aFamily,
+                        FindFamiliesFlags aFlags = FindFamiliesFlags(0),
+                        gfxFontStyle* aStyle = nullptr,
+                        gfxFloat aDevToCssSize = 1.0) {
+    if (SharedFontList()) {
+      return FontFamily(
+          FindSharedFamily(aFamily, aFlags, aStyle, aDevToCssSize));
+    }
+    return FontFamily(
+        FindUnsharedFamily(aFamily, aFlags, aStyle, aDevToCssSize));
   }
 
   // Lookup family name in global family list without substitutions or
   // localized family name lookup. Used for common font fallback families.
   gfxFontFamily* FindFamilyByCanonicalName(const nsACString& aFamily) {
     nsAutoCString key;
     gfxFontFamily* familyEntry;
     GenerateFontListKey(aFamily, key);
@@ -510,16 +600,21 @@ class gfxPlatformFontList : public gfxFo
 
   // helper method for finding fullname/postscript names in facename lists
   gfxFontEntry* FindFaceName(const nsACString& aFaceName);
 
   // look up a font by name, for cases where platform font list
   // maintains explicit mappings of fullname/psname ==> font
   virtual gfxFontEntry* LookupInFaceNameLists(const nsACString& aFontName);
 
+  gfxFontEntry* LookupInSharedFaceNameList(const nsACString& aFaceName,
+                                           WeightRange aWeightForEntry,
+                                           StretchRange aStretchForEntry,
+                                           SlantStyleRange aStyleForEntry);
+
   // commonly used fonts for which the name table should be loaded at startup
   virtual void PreloadNamesList();
 
   // load the bad underline blacklist from pref.
   void LoadBadUnderlineList();
 
   void GenerateFontListKey(const nsACString& aKeyName, nsACString& aResult);
 
@@ -532,44 +627,67 @@ class gfxPlatformFontList : public gfxFo
   void InitLoader() override;
   bool LoadFontInfo() override;
   void CleanupLoader() override;
 
   // read the loader initialization prefs, and start it
   void GetPrefsAndStartLoader();
 
   // for font list changes that affect all documents
-  void ForceGlobalReflow() { gfxPlatform::ForceGlobalReflow(); }
+  void ForceGlobalReflow();
 
   void RebuildLocalFonts();
 
   void ResolveGenericFontNames(mozilla::StyleGenericFontFamily aGenericType,
                                eFontPrefLang aPrefLang,
                                PrefFontList* aGenericFamilies);
 
   void ResolveEmojiFontNames(PrefFontList* aGenericFamilies);
 
-  void GetFontFamiliesFromGenericFamilies(nsTArray<nsCString>& aGenericFamilies,
-                                          nsAtom* aLangGroup,
-                                          PrefFontList* aFontFamilies);
+  void GetFontFamiliesFromGenericFamilies(
+      mozilla::StyleGenericFontFamily aGenericType,
+      nsTArray<nsCString>& aGenericNameFamilies, nsAtom* aLangGroup,
+      PrefFontList* aFontFamilies);
 
   virtual nsresult InitFontListForPlatform() = 0;
+  virtual void InitSharedFontListForPlatform() {}
 
   virtual gfxFontEntry* CreateFontEntry(
       mozilla::fontlist::Face* aFace,
       const mozilla::fontlist::Family* aFamily) {
     return nullptr;
   }
 
+  /**
+   * Methods to apply the font.system.whitelist anti-fingerprinting pref,
+   * by filtering the list of installed fonts so that only whitelisted families
+   * are exposed.
+   * There are separate implementations of this for the per-process font list
+   * and for the shared-memory font list.
+   */
   void ApplyWhitelist();
+  void ApplyWhitelist(nsTArray<mozilla::fontlist::Family::InitData>& aFamilies);
 
   // Create a new gfxFontFamily of the appropriate subclass for the platform,
   // used when AddWithLegacyFamilyName needs to create a new family.
   virtual gfxFontFamily* CreateFontFamily(const nsACString& aName) const = 0;
 
+  /**
+   * For the post-startup font info loader task.
+   * Perform platform-specific work to read alternate names (if any) for a
+   * font family, recording them in mAliasTable. Once alternate names have been
+   * loaded for all families, the accumulated records are stored in the shared
+   * font list's mAliases list.
+   * Some platforms (currently Linux/fontconfig) may load alternate names as
+   * part of initially populating the font list with family records, in which
+   * case this method is unused.
+   */
+  virtual void ReadFaceNamesForFamily(mozilla::fontlist::Family* aFamily,
+                                      bool aNeedFullnamePostscriptNames) {}
+
   typedef nsRefPtrHashtable<nsCStringHashKey, gfxFontFamily> FontFamilyTable;
   typedef nsRefPtrHashtable<nsCStringHashKey, gfxFontEntry> FontEntryTable;
 
   // used by memory reporter to accumulate sizes of family names in the table
   static size_t SizeOfFontFamilyTableExcludingThis(
       const FontFamilyTable& aTable, mozilla::MallocSizeOf aMallocSizeOf);
   static size_t SizeOfFontEntryTableExcludingThis(
       const FontEntryTable& aTable, mozilla::MallocSizeOf aMallocSizeOf);
@@ -632,16 +750,18 @@ class gfxPlatformFontList : public gfxFo
 
   // Sorted array of lowercased family names; use ContainsSorted to test
   nsTArray<nsCString> mBadUnderlineFamilyNames;
 
   // character map data shared across families
   // contains weak ptrs to cmaps shared by font entry objects
   nsTHashtable<CharMapHashKey> mSharedCmaps;
 
+  nsTHashtable<ShmemCharMapHashEntry> mShmemCharMaps;
+
   // data used as part of the font cmap loading process
   nsTArray<RefPtr<gfxFontFamily>> mFontFamiliesToLoad;
   uint32_t mStartIndex;
   uint32_t mNumFamilies;
 
   // xxx - info for diagnosing no default font aborts
   // see bugs 636957, 1070983, 1189129
   uint32_t mFontlistInitCount;  // num times InitFontList called
@@ -650,16 +770,21 @@ class gfxPlatformFontList : public gfxFo
 
   nsLanguageAtomService* mLangService;
 
   nsTArray<uint32_t> mCJKPrefLangs;
   nsTArray<mozilla::StyleGenericFontFamily> mDefaultGenericsLangGroup;
 
   mozilla::UniquePtr<mozilla::fontlist::FontList> mSharedFontList;
 
+  nsClassHashtable<nsCStringHashKey, nsTArray<mozilla::fontlist::Pointer>>
+      mAliasTable;
+  nsDataHashtable<nsCStringHashKey, mozilla::fontlist::LocalFaceRec::InitData>
+      mLocalNameTable;
+
   nsRefPtrHashtable<nsPtrHashKey<mozilla::fontlist::Face>, gfxFontEntry>
       mFontEntries;
 
   bool mFontFamilyWhitelistActive;
 };
 
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(gfxPlatformFontList::FindFamiliesFlags)
 
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -497,16 +497,17 @@ class gfxPrefs final {
   DECL_GFX_PREF(Once, "gfx.direct3d11.enable-debug-layer",     Direct3D11EnableDebugLayer, bool, false);
   DECL_GFX_PREF(Once, "gfx.direct3d11.break-on-error",         Direct3D11BreakOnError, bool, false);
   DECL_GFX_PREF(Once, "gfx.direct3d11.sleep-on-create-device", Direct3D11SleepOnCreateDevice, int32_t, 0);
   DECL_GFX_PREF(Live, "gfx.downloadable_fonts.keep_color_bitmaps", KeepColorBitmaps, bool, false);
   DECL_GFX_PREF(Live, "gfx.downloadable_fonts.validate_variation_tables", ValidateVariationTables, bool, true);
   DECL_GFX_PREF(Live, "gfx.downloadable_fonts.otl_validation", ValidateOTLTables, bool, true);
   DECL_GFX_PREF(Live, "gfx.draw-color-bars",                   CompositorDrawColorBars, bool, false);
   DECL_GFX_PREF(Once, "gfx.e10s.hide-plugins-for-scroll",      HidePluginsForScroll, bool, true);
+  DECL_GFX_PREF(Once, "gfx.e10s.font-list.shared",             SharedFontList, bool, false);
   DECL_GFX_PREF(Live, "gfx.layerscope.enabled",                LayerScopeEnabled, bool, false);
   DECL_GFX_PREF(Live, "gfx.layerscope.port",                   LayerScopePort, int32_t, 23456);
   // Note that        "gfx.logging.level" is defined in Logging.h.
   DECL_GFX_PREF(Live, "gfx.logging.level",                     GfxLoggingLevel, int32_t, mozilla::gfx::LOG_DEFAULT);
   DECL_GFX_PREF(Once, "gfx.logging.crash.length",              GfxLoggingCrashLength, uint32_t, 16);
   DECL_GFX_PREF(Live, "gfx.logging.painted-pixel-count.enabled",GfxLoggingPaintedPixelCountEnabled, bool, false);
   // The maximums here are quite conservative, we can tighten them if problems show up.
   DECL_GFX_PREF(Once, "gfx.logging.texture-usage.enabled",     GfxLoggingTextureUsageEnabled, bool, false);
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -19,16 +19,17 @@
 #include "gfxScriptItemizer.h"
 #include "nsUnicodeProperties.h"
 #include "nsStyleConsts.h"
 #include "nsStyleUtil.h"
 #include "mozilla/Likely.h"
 #include "gfx2DGlue.h"
 #include "mozilla/gfx/Logging.h"  // for gfxCriticalError
 #include "mozilla/UniquePtr.h"
+#include "mozilla/Unused.h"
 #include "TextDrawTarget.h"
 
 #ifdef XP_WIN
 #  include "gfxWindowsPlatform.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::gfx;
@@ -1728,17 +1729,21 @@ void gfxFontGroup::BuildFontList() {
                          fonts);
     if (mTextPerf) {
       mTextPerf->current.genericLookups++;
     }
   }
 
   // build the fontlist from the specified families
   for (const auto& f : fonts) {
-    AddFamilyToFontList(f.mFamily.mUnshared, f.mGeneric);
+    if (f.mFamily.mIsShared) {
+      AddFamilyToFontList(f.mFamily.mShared, f.mGeneric);
+    } else {
+      AddFamilyToFontList(f.mFamily.mUnshared, f.mGeneric);
+    }
   }
 }
 
 void gfxFontGroup::AddPlatformFont(const nsACString& aName, bool aQuotedName,
                                    nsTArray<FamilyAndGeneric>& aFamilyList) {
   // 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
@@ -1750,17 +1755,17 @@ void gfxFontGroup::AddPlatformFont(const
     if (family) {
       aFamilyList.AppendElement(family);
       return;
     }
   }
 
   // Not known in the user font set ==> check system fonts
   gfxPlatformFontList::PlatformFontList()->FindAndAddFamilies(
-      aName, &aFamilyList,
+      StyleGenericFontFamily::None, aName, &aFamilyList,
       aQuotedName ? gfxPlatformFontList::FindFamiliesFlags::eQuotedFamilyName
                   : gfxPlatformFontList::FindFamiliesFlags(0),
       &mStyle, mDevToCssSize);
 }
 
 void gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily,
                                        StyleGenericFontFamily aGeneric) {
   if (!aFamily) {
@@ -1782,16 +1787,44 @@ void gfxFontGroup::AddFamilyToFontList(g
   // for a family marked as "check fallback faces", only mark the last
   // entry so that fallbacks for a family are only checked once
   if (aFamily->CheckForFallbackFaces() && !fontEntryList.IsEmpty() &&
       !mFonts.IsEmpty()) {
     mFonts.LastElement().SetCheckForFallbackFaces();
   }
 }
 
+void gfxFontGroup::AddFamilyToFontList(fontlist::Family* aFamily,
+                                       StyleGenericFontFamily aGeneric) {
+  gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
+  if (!aFamily->IsInitialized()) {
+    if (!NS_IsMainThread()) {
+      // If we need to initialize a Family record, but we're on a style
+      // worker thread, we have to defer it.
+      ServoStyleSet* set = ServoStyleSet::Current();
+      MOZ_ASSERT(set);
+      set->AppendTask(PostTraversalTask::InitializeFamily(aFamily));
+      set->AppendTask(PostTraversalTask::FontInfoUpdate(set));
+      return;
+    }
+    if (!pfl->InitializeFamily(aFamily)) {
+      return;
+    }
+  }
+  AutoTArray<fontlist::Face*, 4> faceList;
+  aFamily->FindAllFacesForStyle(pfl->SharedFontList(), mStyle, faceList);
+  for (auto face : faceList) {
+    gfxFontEntry* fe = pfl->GetOrCreateFontEntry(face, aFamily);
+    if (fe && !HasFont(fe)) {
+      FamilyFace ff(aFamily, fe, aGeneric);
+      mFonts.AppendElement(ff);
+    }
+  }
+}
+
 bool gfxFontGroup::HasFont(const gfxFontEntry* aFontEntry) {
   uint32_t count = mFonts.Length();
   for (uint32_t i = 0; i < count; ++i) {
     if (mFonts[i].FontEntry() == aFontEntry) {
       return true;
     }
   }
   return false;
@@ -1810,17 +1843,17 @@ gfxFont* gfxFontGroup::GetFontAt(int32_t
   gfxFont* font = ff.Font();
   if (!font) {
     gfxFontEntry* fe = mFonts[i].FontEntry();
     gfxCharacterMap* unicodeRangeMap = nullptr;
     if (fe->mIsUserFontContainer) {
       gfxUserFontEntry* ufe = static_cast<gfxUserFontEntry*>(fe);
       if (ufe->LoadState() == gfxUserFontEntry::STATUS_NOT_LOADED &&
           ufe->CharacterInUnicodeRange(aCh) && !mSkipDrawing &&
-          !FontLoadingForFamily(ff.Family(), aCh)) {
+          !FontLoadingForFamily(ff, aCh)) {
         ufe->Load();
         ff.CheckState(mSkipDrawing);
       }
       fe = ufe->GetPlatformFontEntry();
       if (!fe) {
         return nullptr;
       }
       unicodeRangeMap = ufe->GetUnicodeRangeMap();
@@ -1871,72 +1904,123 @@ bool gfxFontGroup::FamilyFace::EqualsUse
       return true;
     }
   } else if (fe == aUserFont) {
     return true;
   }
   return false;
 }
 
-bool gfxFontGroup::FontLoadingForFamily(gfxFontFamily* aFamily,
+bool gfxFontGroup::FontLoadingForFamily(const FamilyFace& aFamily,
                                         uint32_t aCh) const {
+  if (aFamily.IsSharedFamily()) {
+    return false;
+  }
   uint32_t count = mFonts.Length();
   for (uint32_t i = 0; i < count; ++i) {
     const FamilyFace& ff = mFonts[i];
-    if (ff.IsLoading() && ff.Family() == aFamily) {
+    if (!ff.IsSharedFamily() && ff.IsLoading() &&
+        ff.OwnedFamily() == aFamily.OwnedFamily()) {
       const gfxUserFontEntry* ufe =
           static_cast<gfxUserFontEntry*>(ff.FontEntry());
       if (ufe->CharacterInUnicodeRange(aCh)) {
         return true;
       }
     }
   }
   return false;
 }
 
 gfxFont* gfxFontGroup::GetDefaultFont() {
   if (mDefaultFont) {
     return mDefaultFont.get();
   }
 
   gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
-  FontFamily defaultFamily = pfl->GetDefaultFont(&mStyle);
-  NS_ASSERTION(!defaultFamily.mIsShared && defaultFamily.mUnshared,
-               "invalid default font returned by GetDefaultFont");
-
-  if (defaultFamily.mUnshared) {
-    gfxFontEntry* fe = defaultFamily.mUnshared->FindFontForStyle(mStyle, true);
-    if (fe) {
-      mDefaultFont = fe->FindOrMakeFont(&mStyle);
+  FontFamily family = pfl->GetDefaultFont(&mStyle);
+  MOZ_ASSERT(!family.IsNull(),
+             "invalid default font returned by GetDefaultFont");
+
+  gfxFontEntry* fe = nullptr;
+  if (family.mIsShared) {
+    fontlist::Family* fam = family.mShared;
+    if (!fam->IsInitialized()) {
+      // If this fails, FindFaceForStyle will just safely return nullptr
+      Unused << pfl->InitializeFamily(fam);
     }
+    fontlist::Face* face = fam->FindFaceForStyle(pfl->SharedFontList(), mStyle);
+    if (face) {
+      fe = pfl->GetOrCreateFontEntry(face, fam);
+    }
+  } else {
+    fe = family.mUnshared->FindFontForStyle(mStyle);
+  }
+  if (fe) {
+    mDefaultFont = fe->FindOrMakeFont(&mStyle);
   }
 
   uint32_t numInits, loaderState;
   pfl->GetFontlistInitInfo(numInits, loaderState);
-  NS_ASSERTION(numInits != 0,
-               "must initialize system fontlist before getting default font!");
+
+  MOZ_ASSERT(numInits != 0,
+             "must initialize system fontlist before getting default font!");
 
   uint32_t numFonts = 0;
   if (!mDefaultFont) {
     // 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.
     // (see bug 554544)
-    AutoTArray<RefPtr<gfxFontFamily>, 200> familyList;
-    pfl->GetFontFamilyList(familyList);
-    numFonts = familyList.Length();
-    for (uint32_t i = 0; i < numFonts; ++i) {
-      gfxFontEntry* fe = familyList[i]->FindFontForStyle(mStyle, true);
-      if (fe) {
-        mDefaultFont = fe->FindOrMakeFont(&mStyle);
-        if (mDefaultFont) {
-          break;
+    if (pfl->SharedFontList()) {
+      fontlist::FontList* list = pfl->SharedFontList();
+      numFonts = list->NumFamilies();
+      fontlist::Family* families = list->Families();
+      for (uint32_t i = 0; i < numFonts; ++i) {
+        fontlist::Family* fam = &families[i];
+        if (!fam->IsInitialized()) {
+          Unused << pfl->InitializeFamily(fam);
+        }
+        fontlist::Face* face =
+            fam->FindFaceForStyle(pfl->SharedFontList(), mStyle);
+        if (face) {
+          fe = pfl->GetOrCreateFontEntry(face, fam);
+          if (fe) {
+            mDefaultFont = fe->FindOrMakeFont(&mStyle);
+            if (mDefaultFont) {
+              break;
+            }
+            NS_WARNING("FindOrMakeFont failed");
+          }
         }
       }
+    } else {
+      AutoTArray<RefPtr<gfxFontFamily>, 200> familyList;
+      pfl->GetFontFamilyList(familyList);
+      numFonts = familyList.Length();
+      for (uint32_t i = 0; i < numFonts; ++i) {
+        gfxFontEntry* fe = familyList[i]->FindFontForStyle(mStyle, true);
+        if (fe) {
+          mDefaultFont = fe->FindOrMakeFont(&mStyle);
+          if (mDefaultFont) {
+            break;
+          }
+        }
+      }
+    }
+  }
+
+  if (!mDefaultFont && pfl->SharedFontList() && !XRE_IsParentProcess()) {
+    // If we're a content process, it's possible this is failing because the
+    // chrome process has just updated the shared font list and we haven't yet
+    // refreshed our reference to it. If that's the case, update and retry.
+    uint32_t oldGeneration = pfl->SharedFontList()->GetGeneration();
+    pfl->UpdateFontList();
+    if (pfl->SharedFontList()->GetGeneration() != oldGeneration) {
+      return GetDefaultFont();
     }
   }
 
   if (!mDefaultFont) {
     // an empty font list at this point is fatal; we're not going to
     // be able to do even the most basic layout operations
 
     // annotate crash report with fontlist info
@@ -1984,17 +2068,17 @@ gfxFont* gfxFontGroup::GetFirstValidFont
     // Need to build a font, loading userfont if not loaded. In
     // cases where unicode range might apply, use the character
     // provided.
     if (ff.IsUserFontContainer()) {
       gfxUserFontEntry* ufe =
           static_cast<gfxUserFontEntry*>(mFonts[i].FontEntry());
       bool inRange = ufe->CharacterInUnicodeRange(aCh);
       if (ufe->LoadState() == gfxUserFontEntry::STATUS_NOT_LOADED && inRange &&
-          !mSkipDrawing && !FontLoadingForFamily(ff.Family(), aCh)) {
+          !mSkipDrawing && !FontLoadingForFamily(ff, aCh)) {
         ufe->Load();
         ff.CheckState(mSkipDrawing);
       }
       if (ufe->LoadState() != gfxUserFontEntry::STATUS_LOADED || !inRange) {
         continue;
       }
     }
 
@@ -2630,25 +2714,49 @@ gfxFont* gfxFontGroup::FindFallbackFaceF
   aFamily->SearchAllFontsForChar(&data);
   gfxFontEntry* fe = data.mBestMatch;
   if (!fe) {
     return nullptr;
   }
   return fe->FindOrMakeFont(&mStyle);
 }
 
+gfxFont* gfxFontGroup::FindFallbackFaceForChar(fontlist::Family* aFamily,
+                                               uint32_t aCh) {
+  fontlist::FontList* list =
+      gfxPlatformFontList::PlatformFontList()->SharedFontList();
+  GlobalFontMatch data(aCh, mStyle);
+  aFamily->SearchAllFontsForChar(list, &data);
+  gfxFontEntry* fe = data.mBestMatch;
+  if (!fe) {
+    return nullptr;
+  }
+  return fe->FindOrMakeFont(&mStyle);
+}
+
+gfxFont* gfxFontGroup::FindFallbackFaceForChar(const FamilyFace& aFamily,
+                                               uint32_t aCh) {
+  if (aFamily.IsSharedFamily()) {
+    return FindFallbackFaceForChar(aFamily.SharedFamily(), aCh);
+  }
+  return FindFallbackFaceForChar(aFamily.OwnedFamily(), aCh);
+}
+
 gfxFloat gfxFontGroup::GetUnderlineOffset() {
   if (mUnderlineOffset == UNDERLINE_OFFSET_NOT_SET) {
     // if the fontlist contains a bad underline font, make the underline
     // offset the min of the first valid font and bad font underline offsets
     uint32_t len = mFonts.Length();
     for (uint32_t i = 0; i < len; i++) {
       FamilyFace& ff = mFonts[i];
       if (!ff.IsUserFontContainer() && !ff.FontEntry()->IsUserFont() &&
-          ff.Family() && ff.Family()->IsBadUnderlineFamily()) {
+          ((ff.IsSharedFamily() && ff.SharedFamily() &&
+            ff.SharedFamily()->IsBadUnderlineFamily()) ||
+           (!ff.IsSharedFamily() && ff.OwnedFamily() &&
+            ff.OwnedFamily()->IsBadUnderlineFamily()))) {
         gfxFont* font = GetFontAt(i);
         if (!font) {
           continue;
         }
         gfxFloat bad =
             font->GetMetrics(nsFontMetrics::eHorizontal).underlineOffset;
         gfxFloat first = GetFirstValidFont()
                              ->GetMetrics(nsFontMetrics::eHorizontal)
@@ -2712,23 +2820,23 @@ gfxFont* gfxFontGroup::FindFontForChar(u
     if (firstFont) {
       if (firstFont->HasCharacter(aCh)) {
         *aMatchType = {FontMatchType::Kind::kFontGroup, mFonts[0].Generic()};
         return firstFont;
       }
 
       gfxFont* font = nullptr;
       if (mFonts[0].CheckForFallbackFaces()) {
-        font = FindFallbackFaceForChar(mFonts[0].Family(), aCh);
+        font = FindFallbackFaceForChar(mFonts[0], aCh);
       } else if (!firstFont->GetFontEntry()->IsUserFont()) {
         // For platform fonts (but not userfonts), we may need to do
         // fallback within the family to handle cases where some faces
         // such as Italic or Black have reduced character sets compared
         // to the family's Regular face.
-        font = FindFallbackFaceForChar(mFonts[0].Family(), aCh);
+        font = FindFallbackFaceForChar(mFonts[0], aCh);
       }
       if (font) {
         *aMatchType = {FontMatchType::Kind::kFontGroup, mFonts[0].Generic()};
         return font;
       }
     }
 
     // we don't need to check the first font again below
@@ -2792,17 +2900,17 @@ gfxFont* gfxFontGroup::FindFontForChar(u
       // never match a character outside the defined unicode range
       if (!ufe->CharacterInUnicodeRange(aCh)) {
         continue;
       }
 
       // load if not already loaded but only if no other font in similar
       // range within family is loading
       if (ufe->LoadState() == gfxUserFontEntry::STATUS_NOT_LOADED &&
-          !mSkipDrawing && !FontLoadingForFamily(ff.Family(), aCh)) {
+          !mSkipDrawing && !FontLoadingForFamily(ff, aCh)) {
         ufe->Load();
         ff.CheckState(mSkipDrawing);
       }
       gfxFontEntry* pfe = ufe->GetPlatformFontEntry();
       if (pfe && pfe->HasCharacter(aCh)) {
         font = GetFontAt(i, aCh);
         if (font) {
           *aMatchType = {FontMatchType::Kind::kFontGroup, mFonts[i].Generic()};
@@ -2816,33 +2924,42 @@ gfxFont* gfxFontGroup::FindFontForChar(u
       if (font) {
         *aMatchType = {FontMatchType::Kind::kFontGroup, mFonts[i].Generic()};
         return font;
       }
     }
 
     // check other family faces if needed
     if (ff.CheckForFallbackFaces()) {
-      NS_ASSERTION(i == 0 ? true
-                          : !mFonts[i - 1].CheckForFallbackFaces() ||
-                                !mFonts[i - 1].Family()->Name().Equals(
-                                    ff.Family()->Name()),
+#ifdef DEBUG
+      if (i > 0) {
+        fontlist::FontList* list =
+            gfxPlatformFontList::PlatformFontList()->SharedFontList();
+        nsCString s1 = mFonts[i - 1].IsSharedFamily()
+                           ? mFonts[i - 1].SharedFamily()->Key().AsString(list)
+                           : mFonts[i - 1].OwnedFamily()->Name();
+        nsCString s2 = ff.IsSharedFamily()
+                           ? ff.SharedFamily()->Key().AsString(list)
+                           : ff.OwnedFamily()->Name();
+        MOZ_ASSERT(!mFonts[i - 1].CheckForFallbackFaces() || !s1.Equals(s2),
                    "should only do fallback once per font family");
-      font = FindFallbackFaceForChar(ff.Family(), aCh);
+      }
+#endif
+      font = FindFallbackFaceForChar(ff, aCh);
       if (font) {
         *aMatchType = {FontMatchType::Kind::kFontGroup, ff.Generic()};
         return font;
       }
     } else {
       // For platform fonts, but not user fonts, consider intra-family
       // fallback to handle styles with reduced character sets (see
       // also above).
       fe = ff.FontEntry();
       if (!fe->mIsUserFontContainer && !fe->IsUserFont()) {
-        font = FindFallbackFaceForChar(ff.Family(), aCh);
+        font = FindFallbackFaceForChar(ff, aCh);
         if (font) {
           *aMatchType = {FontMatchType::Kind::kFontGroup, ff.Generic()};
           return font;
         }
       }
     }
   }
 
@@ -3192,17 +3309,30 @@ gfxFont* gfxFontGroup::WhichPrefFontSupp
       // if a pref font is used, it's likely to be used again in the same text
       // run. the style doesn't change so the face lookup can be cached rather
       // than calling FindOrMakeFont repeatedly.  speeds up FindFontForChar
       // lookup times for subsequent pref font lookups
       if (family == mLastPrefFamily && mLastPrefFont->HasCharacter(aCh)) {
         return mLastPrefFont;
       }
 
-      gfxFontEntry* fe = family.mUnshared->FindFontForStyle(mStyle);
+      gfxFontEntry* fe = nullptr;
+      if (family.mIsShared) {
+        fontlist::Family* fam = family.mShared;
+        if (!fam->IsInitialized()) {
+          Unused << pfl->InitializeFamily(fam);
+        }
+        fontlist::Face* face =
+            fam->FindFaceForStyle(pfl->SharedFontList(), mStyle);
+        if (face) {
+          fe = pfl->GetOrCreateFontEntry(face, fam);
+        }
+      } else {
+        fe = family.mUnshared->FindFontForStyle(mStyle);
+      }
       if (!fe) {
         continue;
       }
 
       // if ch in cmap, create and return a gfxFont
       if (fe->HasCharacter(aCh)) {
         gfxFont* prefFont = fe->FindOrMakeFont(&mStyle);
         if (!prefFont) {
@@ -3212,17 +3342,19 @@ gfxFont* gfxFontGroup::WhichPrefFontSupp
         mLastPrefFont = prefFont;
         mLastPrefLang = charLang;
         mLastPrefFirstFont = (i == 0 && j == 0);
         return prefFont;
       }
 
       // If the char was not available, see if we can fall back to an
       // alternative face in the same family.
-      gfxFont* prefFont = FindFallbackFaceForChar(family.mUnshared, aCh);
+      gfxFont* prefFont = family.mIsShared
+                              ? FindFallbackFaceForChar(family.mShared, aCh)
+                              : FindFallbackFaceForChar(family.mUnshared, aCh);
       if (prefFont) {
         mLastPrefFamily = family;
         mLastPrefFont = prefFont;
         mLastPrefLang = charLang;
         mLastPrefFirstFont = (i == 0 && j == 0);
         return prefFont;
       }
     }
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -10,16 +10,17 @@
 #include <stdint.h>
 
 #include "gfxTypes.h"
 #include "gfxPoint.h"
 #include "gfxFont.h"
 #include "gfxFontConstants.h"
 #include "gfxSkipChars.h"
 #include "gfxPlatform.h"
+#include "gfxPlatformFontList.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/RefPtr.h"
 #include "nsPoint.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsTextFrameUtils.h"
 #include "DrawMode.h"
 #include "harfbuzz/hb.h"
@@ -35,16 +36,17 @@ class gfxContext;
 class gfxFontGroup;
 class gfxUserFontEntry;
 class gfxUserFontSet;
 class nsAtom;
 class nsLanguageAtomService;
 class gfxMissingFontRecorder;
 
 namespace mozilla {
+class PostTraversalTask;
 class SVGContextPaint;
 enum class StyleHyphens : uint8_t;
 };  // namespace mozilla
 
 /**
  * Callback for Draw() to use when drawing text with mode
  * DrawMode::GLYPH_PATH.
  */
@@ -986,16 +988,18 @@ class gfxFontGroup final : public gfxTex
   // (which might use a different appUnitsPerDev value or flags) for the font
   // group, or until UpdateUserFonts is called, or the fontgroup is destroyed.
   // Get it/use it/forget it :) - don't keep a reference that might go stale.
   gfxTextRun* GetEllipsisTextRun(
       int32_t aAppUnitsPerDevPixel, mozilla::gfx::ShapedTextFlags aFlags,
       LazyReferenceDrawTargetGetter& aRefDrawTargetGetter);
 
  protected:
+  friend class mozilla::PostTraversalTask;
+
   struct TextRange {
     TextRange(uint32_t aStart, uint32_t aEnd, gfxFont* aFont,
               FontMatchType aMatchType,
               mozilla::gfx::ShapedTextFlags aOrientation)
         : start(aStart),
           end(aEnd),
           font(aFont),
           matchType(aMatchType),
@@ -1017,151 +1021,239 @@ class gfxFontGroup final : public gfxTex
   template <typename T>
   void ComputeRanges(nsTArray<TextRange>& aRanges, const T* aString,
                      uint32_t aLength, Script aRunScript,
                      mozilla::gfx::ShapedTextFlags aOrientation);
 
   class FamilyFace {
    public:
     FamilyFace()
-        : mFamily(nullptr),
+        : mOwnedFamily(nullptr),
           mFontEntry(nullptr),
           mGeneric(mozilla::StyleGenericFontFamily::None),
           mFontCreated(false),
           mLoading(false),
           mInvalid(false),
-          mCheckForFallbackFaces(false) {}
+          mCheckForFallbackFaces(false),
+          mIsSharedFamily(false),
+          mHasFontEntry(false) {}
 
     FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont,
                mozilla::StyleGenericFontFamily aGeneric)
-        : mFamily(aFamily),
+        : mOwnedFamily(aFamily),
           mGeneric(aGeneric),
           mFontCreated(true),
           mLoading(false),
           mInvalid(false),
-          mCheckForFallbackFaces(false) {
+          mCheckForFallbackFaces(false),
+          mIsSharedFamily(false),
+          mHasFontEntry(false) {
       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");
+      NS_IF_ADDREF(aFamily);
       mFont = aFont;
       NS_ADDREF(aFont);
     }
 
     FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry,
                mozilla::StyleGenericFontFamily aGeneric)
-        : mFamily(aFamily),
+        : mOwnedFamily(aFamily),
           mGeneric(aGeneric),
           mFontCreated(false),
           mLoading(false),
           mInvalid(false),
-          mCheckForFallbackFaces(false) {
+          mCheckForFallbackFaces(false),
+          mIsSharedFamily(false),
+          mHasFontEntry(true) {
       NS_ASSERTION(aFontEntry, "font entry pointer must not be null");
       NS_ASSERTION(!aFamily || aFamily->ContainsFace(aFontEntry),
                    "font is not a member of the given family");
+      NS_IF_ADDREF(aFamily);
+      mFontEntry = aFontEntry;
+      NS_ADDREF(aFontEntry);
+    }
+
+    FamilyFace(mozilla::fontlist::Family* aFamily, gfxFontEntry* aFontEntry,
+               mozilla::StyleGenericFontFamily aGeneric)
+        : mSharedFamily(aFamily),
+          mGeneric(aGeneric),
+          mFontCreated(false),
+          mLoading(false),
+          mInvalid(false),
+          mCheckForFallbackFaces(false),
+          mIsSharedFamily(true),
+          mHasFontEntry(true) {
+      MOZ_ASSERT(aFamily && aFontEntry && aFontEntry->mShmemFace);
       mFontEntry = aFontEntry;
       NS_ADDREF(aFontEntry);
     }
 
     FamilyFace(const FamilyFace& aOtherFamilyFace)
-        : mFamily(aOtherFamilyFace.mFamily),
-          mGeneric(aOtherFamilyFace.mGeneric),
+        : mGeneric(aOtherFamilyFace.mGeneric),
           mFontCreated(aOtherFamilyFace.mFontCreated),
           mLoading(aOtherFamilyFace.mLoading),
           mInvalid(aOtherFamilyFace.mInvalid),
-          mCheckForFallbackFaces(aOtherFamilyFace.mCheckForFallbackFaces) {
-      if (mFontCreated) {
-        mFont = aOtherFamilyFace.mFont;
-        NS_ADDREF(mFont);
+          mCheckForFallbackFaces(aOtherFamilyFace.mCheckForFallbackFaces),
+          mIsSharedFamily(aOtherFamilyFace.mIsSharedFamily),
+          mHasFontEntry(aOtherFamilyFace.mHasFontEntry) {
+      if (mIsSharedFamily) {
+        mSharedFamily = aOtherFamilyFace.mSharedFamily;
+        if (mFontCreated) {
+          mFont = aOtherFamilyFace.mFont;
+          NS_ADDREF(mFont);
+        } else if (mHasFontEntry) {
+          mFontEntry = aOtherFamilyFace.mFontEntry;
+          NS_ADDREF(mFontEntry);
+        } else {
+          mSharedFace = aOtherFamilyFace.mSharedFace;
+        }
       } else {
-        mFontEntry = aOtherFamilyFace.mFontEntry;
-        NS_IF_ADDREF(mFontEntry);
+        mOwnedFamily = aOtherFamilyFace.mOwnedFamily;
+        NS_IF_ADDREF(mOwnedFamily);
+        if (mFontCreated) {
+          mFont = aOtherFamilyFace.mFont;
+          NS_ADDREF(mFont);
+        } else {
+          mFontEntry = aOtherFamilyFace.mFontEntry;
+          NS_IF_ADDREF(mFontEntry);
+        }
       }
     }
 
     ~FamilyFace() {
       if (mFontCreated) {
         NS_RELEASE(mFont);
-      } else {
-        NS_IF_RELEASE(mFontEntry);
+      }
+      if (!mIsSharedFamily) {
+        NS_IF_RELEASE(mOwnedFamily);
+      }
+      if (mHasFontEntry) {
+        NS_RELEASE(mFontEntry);
       }
     }
 
     FamilyFace& operator=(const FamilyFace& aOther) {
       if (mFontCreated) {
         NS_RELEASE(mFont);
-      } else {
-        NS_IF_RELEASE(mFontEntry);
+      }
+      if (!mIsSharedFamily) {
+        NS_IF_RELEASE(mOwnedFamily);
+      }
+      if (mHasFontEntry) {
+        NS_RELEASE(mFontEntry);
       }
 
-      mFamily = aOther.mFamily;
       mGeneric = aOther.mGeneric;
       mFontCreated = aOther.mFontCreated;
       mLoading = aOther.mLoading;
       mInvalid = aOther.mInvalid;
+      mIsSharedFamily = aOther.mIsSharedFamily;
+      mHasFontEntry = aOther.mHasFontEntry;
 
-      if (mFontCreated) {
-        mFont = aOther.mFont;
-        NS_ADDREF(mFont);
+      if (mIsSharedFamily) {
+        mSharedFamily = aOther.mSharedFamily;
+        if (mFontCreated) {
+          mFont = aOther.mFont;
+          NS_ADDREF(mFont);
+        } else if (mHasFontEntry) {
+          mFontEntry = aOther.mFontEntry;
+          NS_ADDREF(mFontEntry);
+        } else {
+          mSharedFace = aOther.mSharedFace;
+        }
       } else {
-        mFontEntry = aOther.mFontEntry;
-        NS_IF_ADDREF(mFontEntry);
+        mOwnedFamily = aOther.mOwnedFamily;
+        NS_IF_ADDREF(mOwnedFamily);
+        if (mFontCreated) {
+          mFont = aOther.mFont;
+          NS_ADDREF(mFont);
+        } else {
+          mFontEntry = aOther.mFontEntry;
+          NS_IF_ADDREF(mFontEntry);
+        }
       }
 
       return *this;
     }
 
-    gfxFontFamily* Family() const { return mFamily.get(); }
+    gfxFontFamily* OwnedFamily() const {
+      MOZ_ASSERT(!mIsSharedFamily);
+      return mOwnedFamily;
+    }
+    mozilla::fontlist::Family* SharedFamily() const {
+      MOZ_ASSERT(mIsSharedFamily);
+      return mSharedFamily;
+    }
     gfxFont* Font() const { return mFontCreated ? mFont : nullptr; }
 
     gfxFontEntry* FontEntry() const {
-      return mFontCreated ? mFont->GetFontEntry() : mFontEntry;
+      if (mFontCreated) {
+        return mFont->GetFontEntry();
+      }
+      if (mHasFontEntry) {
+        return mFontEntry;
+      }
+      if (mIsSharedFamily) {
+        return gfxPlatformFontList::PlatformFontList()->GetOrCreateFontEntry(
+            mSharedFace, SharedFamily());
+      }
+      return nullptr;
     }
 
     mozilla::StyleGenericFontFamily Generic() const { return mGeneric; }
 
+    bool IsSharedFamily() const { return mIsSharedFamily; }
     bool IsUserFontContainer() const {
       return FontEntry()->mIsUserFontContainer;
     }
     bool IsLoading() const { return mLoading; }
     bool IsInvalid() const { return mInvalid; }
     void CheckState(bool& aSkipDrawing);
     void SetLoading(bool aIsLoading) { mLoading = aIsLoading; }
     void SetInvalid() { mInvalid = true; }
     bool CheckForFallbackFaces() const { return mCheckForFallbackFaces; }
     void SetCheckForFallbackFaces() { mCheckForFallbackFaces = true; }
 
     void SetFont(gfxFont* aFont) {
       NS_ASSERTION(aFont, "font pointer must not be null");
       NS_ADDREF(aFont);
       if (mFontCreated) {
         NS_RELEASE(mFont);
-      } else {
-        NS_IF_RELEASE(mFontEntry);
+      } else if (mHasFontEntry) {
+        NS_RELEASE(mFontEntry);
+        mHasFontEntry = false;
       }
       mFont = aFont;
       mFontCreated = true;
       mLoading = false;
     }
 
     bool EqualsUserFont(const gfxUserFontEntry* aUserFont) const;
 
    private:
-    RefPtr<gfxFontFamily> mFamily;
+    union {
+      gfxFontFamily* MOZ_OWNING_REF mOwnedFamily;
+      mozilla::fontlist::Family* MOZ_NON_OWNING_REF mSharedFamily;
+    };
     // either a font or a font entry exists
     union {
       // Whichever of these fields is actually present will be a strong
       // reference, with refcounting handled manually.
       gfxFont* MOZ_OWNING_REF mFont;
       gfxFontEntry* MOZ_OWNING_REF mFontEntry;
+      mozilla::fontlist::Face* MOZ_NON_OWNING_REF mSharedFace;
     };
     mozilla::StyleGenericFontFamily mGeneric;
     bool mFontCreated : 1;
     bool mLoading : 1;
     bool mInvalid : 1;
     bool mCheckForFallbackFaces : 1;
+    bool mIsSharedFamily : 1;
+    bool mHasFontEntry : 1;
   };
 
   // List of font families, either named or generic.
   // Generic names map to system pref fonts based on language.
   mozilla::FontFamilyList mFamilyList;
 
   // Fontlist containing a font entry for each family found. gfxFont objects
   // are created as needed and userfont loads are initiated when needed.
@@ -1218,17 +1310,17 @@ class gfxFontGroup final : public gfxTex
 
   // Get the font at index i within the fontlist.
   // Will initiate userfont load if not already loaded.
   // May return null if userfont not loaded or if font invalid
   gfxFont* GetFontAt(int32_t i, uint32_t aCh = 0x20);
 
   // Whether there's a font loading for a given family in the fontlist
   // for a given character
-  bool FontLoadingForFamily(gfxFontFamily* aFamily, uint32_t aCh) const;
+  bool FontLoadingForFamily(const FamilyFace& aFamily, uint32_t aCh) const;
 
   // will always return a font or force a shutdown
   gfxFont* GetDefaultFont();
 
   // Init this font group's font metrics. If there no bad fonts, you don't need
   // to call this. But if there are one or more bad fonts which have bad
   // underline offset, you should call this with the *first* bad font.
   void InitMetricsForBadFont(gfxFont* aBadFont);
@@ -1246,27 +1338,34 @@ class gfxFontGroup final : public gfxTex
   void InitScriptRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
                      const T* aString, uint32_t aScriptRunStart,
                      uint32_t aScriptRunEnd, Script aRunScript,
                      gfxMissingFontRecorder* aMFR);
 
   // Helper for font-matching:
   // search all faces in a family for a fallback in cases where it's unclear
   // whether the family might have a font for a given character
+  gfxFont* FindFallbackFaceForChar(const FamilyFace& aFamily, uint32_t aCh);
+
+  gfxFont* FindFallbackFaceForChar(mozilla::fontlist::Family* aFamily,
+                                   uint32_t aCh);
+
   gfxFont* FindFallbackFaceForChar(gfxFontFamily* aFamily, uint32_t aCh);
 
   // helper methods for looking up fonts
 
   // lookup and add a font with a given name (i.e. *not* a generic!)
   void AddPlatformFont(const nsACString& aName, bool aQuotedName,
                        nsTArray<FamilyAndGeneric>& aFamilyList);
 
   // do style selection and add entries to list
   void AddFamilyToFontList(gfxFontFamily* aFamily,
                            mozilla::StyleGenericFontFamily aGeneric);
+  void AddFamilyToFontList(mozilla::fontlist::Family* aFamily,
+                           mozilla::StyleGenericFontFamily aGeneric);
 };
 
 // A "missing font recorder" is to be used during text-run creation to keep
 // a record of any scripts encountered for which font coverage was lacking;
 // when Flush() is called, it sends a notification that front-end code can use
 // to download fonts on demand (or whatever else it wants to do).
 
 #define GFX_MISSING_FONTS_NOTIFY_PREF "gfx.missing_fonts.notify"
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -1,31 +1,35 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_USER_FONT_SET_H
 #define GFX_USER_FONT_SET_H
 
-#include "gfxFont.h"
+#include "gfxFontEntry.h"
 #include "gfxFontFamilyList.h"
 #include "gfxFontSrcPrincipal.h"
 #include "gfxFontSrcURI.h"
 #include "nsRefPtrHashtable.h"
 #include "nsCOMPtr.h"
-#include "nsIURI.h"
+#include "nsIMemoryReporter.h"
 #include "nsIPrincipal.h"
+#include "nsIRunnable.h"
 #include "nsIScriptError.h"
+#include "nsIURI.h"
 #include "nsURIHashKey.h"
 #include "mozilla/FontPropertyTypes.h"
 #include "mozilla/ServoStyleConsts.h"
 #include "mozilla/net/ReferrerPolicy.h"
 #include "gfxFontConstants.h"
 
+class gfxFont;
+
 namespace mozilla {
 class PostTraversalTask;
 }  // namespace mozilla
 class nsFontFaceLoader;
 
 //#define DEBUG_USERFONT_CACHE
 
 class gfxFontFaceBufferSource {
--- a/layout/style/PostTraversalTask.cpp
+++ b/layout/style/PostTraversalTask.cpp
@@ -3,17 +3,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PostTraversalTask.h"
 
 #include "mozilla/dom/FontFace.h"
 #include "mozilla/dom/FontFaceSet.h"
-#include "gfxUserFontSet.h"
+#include "gfxPlatformFontList.h"
+#include "gfxTextRun.h"
+#include "ServoStyleSet.h"
+#include "nsPresContext.h"
 
 namespace mozilla {
 
 using namespace dom;
 
 void PostTraversalTask::Run() {
   switch (mType) {
     case Type::ResolveFontFaceLoadedPromise:
@@ -32,12 +35,25 @@ void PostTraversalTask::Run() {
     case Type::DispatchFontFaceSetCheckLoadingFinishedAfterDelay:
       static_cast<FontFaceSet*>(mTarget)
           ->DispatchCheckLoadingFinishedAfterDelay();
       break;
 
     case Type::LoadFontEntry:
       static_cast<gfxUserFontEntry*>(mTarget)->ContinueLoad();
       break;
+
+    case Type::InitializeFamily:
+      Unused << gfxPlatformFontList::PlatformFontList()->InitializeFamily(
+          static_cast<fontlist::Family*>(mTarget));
+      break;
+
+    case Type::FontInfoUpdate:
+      nsPresContext* pc =
+          static_cast<ServoStyleSet*>(mTarget)->GetPresContext();
+      if (pc) {
+        pc->ForceReflowForFontInfoUpdate();
+      }
+      break;
   }
 }
 
 }  // namespace mozilla
--- a/layout/style/PostTraversalTask.h
+++ b/layout/style/PostTraversalTask.h
@@ -7,20 +7,24 @@
 #ifndef mozilla_PostTraversalTask_h
 #define mozilla_PostTraversalTask_h
 
 #include "nscore.h"
 
 /* a task to be performed immediately after a Servo traversal */
 
 namespace mozilla {
+class ServoStyleSet;
 namespace dom {
 class FontFace;
 class FontFaceSet;
 }  // namespace dom
+namespace fontlist {
+struct Family;
+}  // namespace fontlist
 }  // namespace mozilla
 class gfxUserFontEntry;
 
 namespace mozilla {
 
 /**
  * A PostTraversalTask is a task to be performed immediately after a Servo
  * traversal.  There are just a few tasks we need to perform, so we use this
@@ -63,16 +67,28 @@ class PostTraversalTask {
   }
 
   static PostTraversalTask LoadFontEntry(gfxUserFontEntry* aFontEntry) {
     auto task = PostTraversalTask(Type::LoadFontEntry);
     task.mTarget = aFontEntry;
     return task;
   }
 
+  static PostTraversalTask InitializeFamily(fontlist::Family* aFamily) {
+    auto task = PostTraversalTask(Type::InitializeFamily);
+    task.mTarget = aFamily;
+    return task;
+  }
+
+  static PostTraversalTask FontInfoUpdate(ServoStyleSet* aSet) {
+    auto task = PostTraversalTask(Type::FontInfoUpdate);
+    task.mTarget = aSet;
+    return task;
+  }
+
   void Run();
 
  private:
   // For any new raw pointer type that we need to store in a PostTraversalTask,
   // please add an assertion that class' destructor that we are not in a Servo
   // traversal, to protect against the possibility of having dangling pointers.
   enum class Type {
     // mTarget (FontFace*)
@@ -85,16 +101,22 @@ class PostTraversalTask {
     // mTarget (FontFaceSet*)
     DispatchLoadingEventAndReplaceReadyPromise,
 
     // mTarget (FontFaceSet*)
     DispatchFontFaceSetCheckLoadingFinishedAfterDelay,
 
     // mTarget (gfxUserFontEntry*)
     LoadFontEntry,
+
+    // mTarget (fontlist::Family*)
+    InitializeFamily,
+
+    // mTarget (ServoStyleSet*)
+    FontInfoUpdate,
   };
 
   explicit PostTraversalTask(Type aType)
       : mType(aType), mTarget(nullptr), mResult(NS_OK) {}
 
   Type mType;
   void* mTarget;
   nsresult mResult;
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -95,16 +95,17 @@ class MOZ_RAII AutoPrepareTraversal {
 }  // namespace mozilla
 
 ServoStyleSet::ServoStyleSet(Document& aDocument) : mDocument(&aDocument) {
   PreferenceSheet::EnsureInitialized();
   mRawSet.reset(Servo_StyleSet_Init(&aDocument));
 }
 
 ServoStyleSet::~ServoStyleSet() {
+  MOZ_ASSERT(!IsInServoTraversal());
   EnumerateStyleSheets([&](StyleSheet& aSheet) { aSheet.DropStyleSet(this); });
 }
 
 nsPresContext* ServoStyleSet::GetPresContext() {
   return mDocument->GetPresContext();
 }
 
 template <typename Functor>
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -426,16 +426,17 @@ class ServoStyleSet {
   already_AddRefed<ComputedStyle> ReparentComputedStyle(
       ComputedStyle* aComputedStyle, ComputedStyle* aNewParent,
       ComputedStyle* aNewParentIgnoringFirstLine,
       ComputedStyle* aNewLayoutParent, dom::Element* aElement);
 
  private:
   friend class AutoSetInServoTraversal;
   friend class AutoPrepareTraversal;
+  friend class PostTraversalTask;
 
   bool ShouldTraverseInParallel() const;
 
   /**
    * Gets the pending snapshots to handle from the restyle manager.
    */
   const SnapshotTable& Snapshots();