Bug 1514869 - patch 5 - Implement DirectWrite backend for the shared font list. r=jwatt
authorJonathan Kew <jkew@mozilla.com>
Sat, 27 Apr 2019 15:39:25 +0000
changeset 471757 ba0672dcd82d09031cb5899716a5f90916438c42
parent 471756 d51c979e9930e3f20d601149c0cab64d748b872c
child 471758 0bad995bae2250682807c86f9d9abc23b0f2313c
push id35934
push usershindli@mozilla.com
push dateMon, 29 Apr 2019 21:53:38 +0000
treeherdermozilla-central@f6766ba4ac77 [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 5 - Implement DirectWrite backend for the shared font list. r=jwatt Differential Revision: https://phabricator.services.mozilla.com/D22941
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -482,17 +482,17 @@ hb_blob_t* gfxDWriteFontEntry::GetFontTa
 
   return nullptr;
 }
 
 nsresult gfxDWriteFontEntry::ReadCMAP(FontInfoData* aFontInfoData) {
   AUTO_PROFILER_LABEL("gfxDWriteFontEntry::ReadCMAP", GRAPHICS);
 
   // attempt this once, if errors occur leave a blank cmap
-  if (mCharacterMap) {
+  if (mCharacterMap || mShmemCharacterMap) {
     return NS_OK;
   }
 
   RefPtr<gfxCharacterMap> charmap;
   nsresult rv;
 
   if (aFontInfoData &&
       (charmap = GetCMAPFromFontInfo(aFontInfoData, mUVSOffset))) {
@@ -518,17 +518,27 @@ nsresult gfxDWriteFontEntry::ReadCMAP(Fo
     // by sites to represent a "Play" icon, but the glyph in Segoe UI Light
     // and Semibold on Windows 7 is too thin. (Ditto for leftward U+25C0.)
     // Fallback to Segoe UI Symbol is preferred.
     if (FamilyName().EqualsLiteral("Segoe UI")) {
       charmap->clear(0x25b6);
       charmap->clear(0x25c0);
     }
     gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
-    mCharacterMap = pfl->FindCharMap(charmap);
+    fontlist::FontList* sharedFontList = pfl->SharedFontList();
+    if (!IsUserFont() && mShmemFace) {
+      mShmemFace->SetCharacterMap(sharedFontList, charmap); // async
+      if (!TrySetShmemCharacterMap()) {
+        // Temporarily retain charmap, until the shared version is
+        // ready for use.
+        mCharacterMap = charmap;
+      }
+    } else {
+      mCharacterMap = pfl->FindCharMap(charmap);
+    }
   } else {
     // if error occurred, initialize to null cmap
     mCharacterMap = new gfxCharacterMap();
   }
 
   LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n",
                 mName.get(), charmap->SizeOfIncludingThis(moz_malloc_size_of),
                 charmap->mHash, mCharacterMap == charmap ? " new" : ""));
@@ -857,16 +867,21 @@ FontFamily gfxDWriteFontList::GetDefault
   }
 
   return ff;
 }
 
 gfxFontEntry* gfxDWriteFontList::LookupLocalFont(
     const nsACString& aFontName, WeightRange aWeightForEntry,
     StretchRange aStretchForEntry, SlantStyleRange aStyleForEntry) {
+  if (SharedFontList()) {
+    return LookupInSharedFaceNameList(aFontName, aWeightForEntry,
+                                      aStretchForEntry, aStyleForEntry);
+  }
+
   gfxFontEntry* lookup;
 
   lookup = LookupInFaceNameLists(aFontName);
   if (!lookup) {
     return nullptr;
   }
 
   gfxDWriteFontEntry* dwriteLookup = static_cast<gfxDWriteFontEntry*>(lookup);
@@ -911,22 +926,312 @@ gfxFontEntry* gfxDWriteFontList::MakePla
     // We don't know how to deal with 0 faces either.
     delete entry;
     return nullptr;
   }
 
   return entry;
 }
 
+gfxFontEntry* gfxDWriteFontList::CreateFontEntry(
+    fontlist::Face* aFace, const fontlist::Family* aFamily) {
+  IDWriteFontCollection* collection =
+      aFamily->IsBundled() ? mBundledFonts : mSystemFonts;
+  RefPtr<IDWriteFontFamily> family;
+  collection->GetFontFamily(aFamily->Index(), getter_AddRefs(family));
+  RefPtr<IDWriteFont> font;
+  family->GetFont(aFace->mIndex, getter_AddRefs(font));
+  nsAutoCString faceName;
+  HRESULT hr = GetDirectWriteFontName(font, faceName);
+  if (FAILED(hr)) {
+    return nullptr;
+  }
+  auto fe = new gfxDWriteFontEntry(faceName, font, !aFamily->IsBundled());
+  fe->mStyleRange = aFace->mStyle;
+  fe->mStretchRange = aFace->mStretch;
+  fe->mWeightRange = aFace->mWeight;
+  fe->mShmemFace = aFace;
+  fe->mIsBadUnderlineFont = aFamily->IsBadUnderlineFamily();
+  fe->mFamilyName = aFamily->DisplayName().AsString(SharedFontList());
+  fe->mForceGDIClassic = aFamily->IsForceClassic();
+  return fe;
+}
+
+void gfxDWriteFontList::AppendFamiliesFromCollection(
+    IDWriteFontCollection* aCollection,
+    nsTArray<fontlist::Family::InitData>& aFamilies,
+    const nsTArray<nsCString>* aForceClassicFams) {
+  for (unsigned i = 0; i < aCollection->GetFontFamilyCount(); ++i) {
+    RefPtr<IDWriteFontFamily> family;
+    aCollection->GetFontFamily(i, getter_AddRefs(family));
+    RefPtr<IDWriteLocalizedStrings> names;
+    HRESULT hr = family->GetFamilyNames(getter_AddRefs(names));
+    if (FAILED(hr)) {
+      continue;
+    }
+    nsAutoCString key, name;
+    if (!GetEnglishOrFirstName(name, names)) {
+      continue;
+    }
+    key = name;
+    BuildKeyNameFromFontName(key);
+    bool bad = mBadUnderlineFamilyNames.ContainsSorted(key);
+    bool classic = aForceClassicFams && aForceClassicFams->ContainsSorted(key);
+    aFamilies.AppendElement(fontlist::Family::InitData(
+        key, name, i, false, aCollection != mSystemFonts, bad, classic));
+  }
+}
+
+void gfxDWriteFontList::GetFacesInitDataForFamily(
+    const fontlist::Family* aFamily,
+    nsTArray<fontlist::Face::InitData>& aFaces) const {
+  IDWriteFontCollection* collection =
+      aFamily->IsBundled() ? mBundledFonts : mSystemFonts;
+  if (!collection) {
+    return;
+  }
+  RefPtr<IDWriteFontFamily> family;
+  collection->GetFontFamily(aFamily->Index(), getter_AddRefs(family));
+  for (unsigned i = 0; i < family->GetFontCount(); ++i) {
+    RefPtr<IDWriteFont> dwFont;
+    family->GetFont(i, getter_AddRefs(dwFont));
+    if (dwFont->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
+      continue;
+    }
+    DWRITE_FONT_STYLE dwstyle = dwFont->GetStyle();
+    // Ignore italic styles of Meiryo because "Meiryo (Bold) Italic" has
+    // non-italic style glyphs as Japanese characters.  However, using it
+    // causes serious problem if web pages wants some elements to be
+    // different style from others only with font-style.  For example,
+    // <em> and <i> should be rendered as italic in the default style.
+    if (dwstyle != DWRITE_FONT_STYLE_NORMAL &&
+        aFamily->Key().AsString(SharedFontList()).EqualsLiteral("meiryo")) {
+      continue;
+    }
+    WeightRange weight(FontWeight(dwFont->GetWeight()));
+    StretchRange stretch(FontStretchFromDWriteStretch(dwFont->GetStretch()));
+    // Try to read PSName as a unique face identifier; we leave the name blank
+    // if this fails, though the face may still be used.
+    nsAutoCString name;
+    if (FAILED(GetDirectWriteFaceName(dwFont, PSNAME_ID, name))) {
+      RefPtr<IDWriteFontFace> dwFontFace;
+      if (SUCCEEDED(dwFont->CreateFontFace(getter_AddRefs(dwFontFace)))) {
+        const char* data;
+        UINT32 size;
+        void* context;
+        BOOL exists;
+        if (SUCCEEDED(dwFontFace->TryGetFontTable(
+                NativeEndian::swapToBigEndian(TRUETYPE_TAG('n', 'a', 'm', 'e')),
+                (const void**)&data, &size, &context, &exists)) &&
+            exists) {
+          gfxFontUtils::ReadCanonicalName(
+              data, size, gfxFontUtils::NAME_ID_POSTSCRIPT, name);
+        }
+      }
+    }
+    SlantStyleRange slant(dwstyle == DWRITE_FONT_STYLE_NORMAL
+                              ? FontSlantStyle::Normal()
+                              : dwstyle == DWRITE_FONT_STYLE_ITALIC
+                                    ? FontSlantStyle::Italic()
+                                    : FontSlantStyle::Oblique());
+    aFaces.AppendElement(fontlist::Face::InitData{name, uint16_t(i), false,
+                                                  weight, stretch, slant});
+  }
+}
+
+bool gfxDWriteFontList::ReadFaceNames(fontlist::Family* aFamily,
+                                      fontlist::Face* aFace, nsCString& aPSName,
+                                      nsCString& aFullName) {
+  IDWriteFontCollection* collection =
+      aFamily->IsBundled() ? mBundledFonts : mSystemFonts;
+  RefPtr<IDWriteFontFamily> family;
+  if (FAILED(collection->GetFontFamily(aFamily->Index(),
+                                       getter_AddRefs(family)))) {
+    MOZ_ASSERT_UNREACHABLE("failed to get font-family");
+    return false;
+  }
+  RefPtr<IDWriteFont> dwFont;
+  if (FAILED(family->GetFont(aFace->mIndex, getter_AddRefs(dwFont)))) {
+    MOZ_ASSERT_UNREACHABLE("failed to get font from family");
+    return false;
+  }
+  HRESULT ps = GetDirectWriteFaceName(dwFont, PSNAME_ID, aPSName);
+  HRESULT full = GetDirectWriteFaceName(dwFont, FULLNAME_ID, aFullName);
+  if (FAILED(ps) || FAILED(full) || aPSName.IsEmpty() || aFullName.IsEmpty()) {
+    // We'll return true if either name was found, false if both fail.
+    // Note that on older Win7 systems, GetDirectWriteFaceName may "succeed"
+    // but return an empty string, so we have to check for non-empty strings
+    // to be sure we actually got a usable name.
+    bool result = (SUCCEEDED(ps) && !aPSName.IsEmpty()) ||
+                  (SUCCEEDED(full) && !aFullName.IsEmpty());
+    RefPtr<IDWriteFontFace> dwFontFace;
+    if (FAILED(dwFont->CreateFontFace(getter_AddRefs(dwFontFace)))) {
+      NS_WARNING("failed to create font face");
+      return result;
+    }
+    const char* data;
+    UINT32 size;
+    void* context;
+    BOOL exists;
+    if (FAILED(dwFontFace->TryGetFontTable(
+            NativeEndian::swapToBigEndian(TRUETYPE_TAG('n', 'a', 'm', 'e')),
+            (const void**)&data, &size, &context, &exists)) ||
+        !exists) {
+      NS_WARNING("failed to get name table");
+      return result;
+    }
+    if (FAILED(ps) || aPSName.IsEmpty()) {
+      if (NS_FAILED(gfxFontUtils::ReadCanonicalName(
+              data, size, gfxFontUtils::NAME_ID_POSTSCRIPT, aPSName))) {
+        NS_WARNING("failed to read psname");
+        result = SUCCEEDED(full) && !aFullName.IsEmpty();
+      }
+    }
+    if (FAILED(full) || aFullName.IsEmpty()) {
+      if (NS_FAILED(gfxFontUtils::ReadCanonicalName(
+              data, size, gfxFontUtils::NAME_ID_FULL, aFullName))) {
+        NS_WARNING("failed to read fullname");
+        result = SUCCEEDED(ps) && !aPSName.IsEmpty();
+      }
+    }
+    return result;
+  }
+  return true;
+}
+
+void gfxDWriteFontList::ReadFaceNamesForFamily(
+    fontlist::Family* aFamily, bool aNeedFullnamePostscriptNames) {
+  if (!aFamily->IsInitialized()) {
+    if (!InitializeFamily(aFamily)) {
+      return;
+    }
+  }
+  IDWriteFontCollection* collection =
+      aFamily->IsBundled() ? mBundledFonts : mSystemFonts;
+  RefPtr<IDWriteFontFamily> family;
+  if (FAILED(collection->GetFontFamily(aFamily->Index(),
+                                       getter_AddRefs(family)))) {
+    return;
+  }
+  fontlist::FontList* list = SharedFontList();
+  const fontlist::Pointer* facePtrs = aFamily->Faces(list);
+  nsAutoCString familyName(aFamily->DisplayName().AsString(list));
+  nsAutoCString key(aFamily->Key().AsString(list));
+
+  // Read PS-names and fullnames of the faces, and any alternate family names
+  // (either localizations or legacy subfamily names)
+  for (unsigned i = 0; i < aFamily->NumFaces(); ++i) {
+    auto face = static_cast<fontlist::Face*>(facePtrs[i].ToPtr(list));
+    RefPtr<IDWriteFont> dwFont;
+    if (FAILED(family->GetFont(face->mIndex, getter_AddRefs(dwFont)))) {
+      continue;
+    }
+    RefPtr<IDWriteFontFace> dwFontFace;
+    if (FAILED(dwFont->CreateFontFace(getter_AddRefs(dwFontFace)))) {
+      continue;
+    }
+
+    const char* data;
+    UINT32 size;
+    void* context;
+    BOOL exists;
+    if (FAILED(dwFontFace->TryGetFontTable(
+            NativeEndian::swapToBigEndian(TRUETYPE_TAG('n', 'a', 'm', 'e')),
+            (const void**)&data, &size, &context, &exists)) ||
+        !exists) {
+      continue;
+    }
+
+    AutoTArray<nsCString, 4> otherFamilyNames;
+    gfxFontUtils::ReadOtherFamilyNamesForFace(familyName, data, size,
+                                              otherFamilyNames, false);
+    for (const auto& alias : otherFamilyNames) {
+      auto af = mAliasTable.LookupOrAdd(alias);
+      af->AppendElement(facePtrs[i]);
+    }
+
+    nsAutoCString psname, fullname;
+    if (NS_SUCCEEDED(gfxFontUtils::ReadCanonicalName(
+            data, size, gfxFontUtils::NAME_ID_POSTSCRIPT, psname))) {
+      ToLowerCase(psname);
+      mLocalNameTable.Put(psname, fontlist::LocalFaceRec::InitData(key, i));
+    }
+    if (NS_SUCCEEDED(gfxFontUtils::ReadCanonicalName(
+            data, size, gfxFontUtils::NAME_ID_FULL, fullname))) {
+      ToLowerCase(fullname);
+      if (fullname != psname) {
+        mLocalNameTable.Put(fullname, fontlist::LocalFaceRec::InitData(key, i));
+      }
+    }
+
+    dwFontFace->ReleaseFontTable(context);
+  }
+}
+
 enum DWriteInitError {
   errGDIInterop = 1,
   errSystemFontCollection = 2,
   errNoFonts = 3
 };
 
+void gfxDWriteFontList::InitSharedFontListForPlatform() {
+  mGDIFontTableAccess = Preferences::GetBool(
+      "gfx.font_rendering.directwrite.use_gdi_table_loading", false);
+  mForceGDIClassicMaxFontSize = Preferences::GetInt(
+      "gfx.font_rendering.cleartype_params.force_gdi_classic_max_size",
+      mForceGDIClassicMaxFontSize);
+
+  mFontSubstitutes.Clear();
+  mNonExistingFonts.Clear();
+
+  RefPtr<IDWriteFactory> factory = Factory::GetDWriteFactory();
+  HRESULT hr = factory->GetGdiInterop(getter_AddRefs(mGDIInterop));
+  if (FAILED(hr)) {
+    Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM,
+                          uint32_t(errGDIInterop));
+    return;
+  }
+
+  mSystemFonts = Factory::GetDWriteSystemFonts(true);
+  NS_ASSERTION(mSystemFonts != nullptr, "GetSystemFontCollection failed!");
+#ifdef MOZ_BUNDLED_FONTS
+  mBundledFonts = CreateBundledFontsCollection(factory);
+#endif
+
+  if (XRE_IsParentProcess()) {
+    nsAutoCString classicFamilies;
+    AutoTArray<nsCString, 16> forceClassicFams;
+    nsresult rv = Preferences::GetCString(
+        "gfx.font_rendering.cleartype_params.force_gdi_classic_for_families",
+        classicFamilies);
+    if (NS_SUCCEEDED(rv)) {
+      nsCCharSeparatedTokenizer tokenizer(classicFamilies, ',');
+      while (tokenizer.hasMoreTokens()) {
+        nsAutoCString name(tokenizer.nextToken());
+        BuildKeyNameFromFontName(name);
+        forceClassicFams.AppendElement(name);
+      }
+      forceClassicFams.Sort();
+    }
+    nsTArray<fontlist::Family::InitData> families;
+    AppendFamiliesFromCollection(mSystemFonts, families, &forceClassicFams);
+#ifdef MOZ_BUNDLED_FONTS
+    if (mBundledFonts) {
+      AppendFamiliesFromCollection(mBundledFonts, families);
+    }
+#endif
+    ApplyWhitelist(families);
+    families.Sort();
+    SharedFontList()->SetFamilyNames(families);
+    GetPrefsAndStartLoader();
+  }
+  GetDirectWriteSubstitutes();
+  GetFontSubstitutes();
+}
+
 nsresult gfxDWriteFontList::InitFontListForPlatform() {
   LARGE_INTEGER frequency;           // ticks per second
   LARGE_INTEGER t1, t2, t3, t4, t5;  // ticks
   double elapsedTime, upTime;
   char nowTime[256], nowDate[256];
 
   if (LOG_FONTINIT_ENABLED()) {
     GetTimeFormatA(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT, nullptr, nullptr,
@@ -1239,22 +1544,36 @@ nsresult gfxDWriteFontList::GetFontSubst
     }
 
     NS_ConvertUTF16toUTF8 substituteName((char16_t*)aliasName);
     NS_ConvertUTF16toUTF8 actualFontName((char16_t*)actualName);
     RemoveCharsetFromFontSubstitute(substituteName);
     BuildKeyNameFromFontName(substituteName);
     RemoveCharsetFromFontSubstitute(actualFontName);
     BuildKeyNameFromFontName(actualFontName);
-    gfxFontFamily* ff;
-    if (!actualFontName.IsEmpty() &&
-        (ff = mFontFamilies.GetWeak(actualFontName))) {
-      mFontSubstitutes.Put(substituteName, ff);
+    if (SharedFontList()) {
+      if (SharedFontList()->FindFamily(substituteName)) {
+        continue;
+      }
+      if (SharedFontList()->FindFamily(actualFontName)) {
+        mSubstitutions.Put(substituteName, new nsCString(actualFontName));
+      } else if (mSubstitutions.Get(actualFontName)) {
+        mSubstitutions.Put(substituteName,
+                           new nsCString(*mSubstitutions.Get(actualFontName)));
+      } else {
+        mNonExistingFonts.AppendElement(substituteName);
+      }
     } else {
-      mNonExistingFonts.AppendElement(substituteName);
+      gfxFontFamily* ff;
+      if (!actualFontName.IsEmpty() &&
+          (ff = mFontFamilies.GetWeak(actualFontName))) {
+        mFontSubstitutes.Put(substituteName, ff);
+      } else {
+        mNonExistingFonts.AppendElement(substituteName);
+      }
     }
   }
   return NS_OK;
 }
 
 struct FontSubstitution {
   const char* aliasName;
   const char* actualName;
@@ -1268,52 +1587,72 @@ static const FontSubstitution sDirectWri
     {"Roman", "Times New Roman"},
     {"Script", "Mistral"}};
 
 void gfxDWriteFontList::GetDirectWriteSubstitutes() {
   for (uint32_t i = 0; i < ArrayLength(sDirectWriteSubs); ++i) {
     const FontSubstitution& sub(sDirectWriteSubs[i]);
     nsAutoCString substituteName(sub.aliasName);
     BuildKeyNameFromFontName(substituteName);
-    if (nullptr != mFontFamilies.GetWeak(substituteName)) {
-      // don't do the substitution if user actually has a usable font
-      // with this name installed
-      continue;
-    }
-    nsAutoCString actualFontName(sub.actualName);
-    BuildKeyNameFromFontName(actualFontName);
-    gfxFontFamily* ff;
-    if (nullptr != (ff = mFontFamilies.GetWeak(actualFontName))) {
-      mFontSubstitutes.Put(substituteName, ff);
+    if (SharedFontList()) {
+      if (SharedFontList()->FindFamily(substituteName)) {
+        continue;
+      }
+      nsAutoCString actualFontName(sub.actualName);
+      BuildKeyNameFromFontName(actualFontName);
+      if (SharedFontList()->FindFamily(actualFontName)) {
+        mSubstitutions.Put(substituteName, new nsCString(actualFontName));
+      } else {
+        mNonExistingFonts.AppendElement(substituteName);
+      }
     } else {
-      mNonExistingFonts.AppendElement(substituteName);
+      if (nullptr != mFontFamilies.GetWeak(substituteName)) {
+        // don't do the substitution if user actually has a usable font
+        // with this name installed
+        continue;
+      }
+      nsAutoCString actualFontName(sub.actualName);
+      BuildKeyNameFromFontName(actualFontName);
+      gfxFontFamily* ff;
+      if (nullptr != (ff = mFontFamilies.GetWeak(actualFontName))) {
+        mFontSubstitutes.Put(substituteName, ff);
+      } else {
+        mNonExistingFonts.AppendElement(substituteName);
+      }
     }
   }
 }
 
 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, aGeneric));
-    return true;
+  if (SharedFontList()) {
+    nsACString* subst = mSubstitutions.Get(keyName);
+    if (subst) {
+      keyName = *subst;
+    }
+  } else {
+    gfxFontFamily* ff = mFontSubstitutes.GetWeak(keyName);
+    if (ff) {
+      aOutput->AppendElement(FamilyAndGeneric(ff, aGeneric));
+      return true;
+    }
   }
 
   if (mNonExistingFonts.Contains(keyName)) {
     return false;
   }
 
-  return gfxPlatformFontList::FindAndAddFamilies(aGeneric, aFamily, aOutput,
+  return gfxPlatformFontList::FindAndAddFamilies(aGeneric, keyName, 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.
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -362,30 +362,46 @@ class gfxDWriteFontList : public gfxPlat
   gfxDWriteFontList();
 
   static gfxDWriteFontList* PlatformFontList() {
     return static_cast<gfxDWriteFontList*>(sPlatformFontList);
   }
 
   // initialize font lists
   nsresult InitFontListForPlatform() override;
+  void InitSharedFontListForPlatform() override;
 
   gfxFontFamily* CreateFontFamily(const nsACString& aName) const override;
 
-  virtual gfxFontEntry* LookupLocalFont(const nsACString& aFontName,
-                                        WeightRange aWeightForEntry,
-                                        StretchRange aStretchForEntry,
-                                        SlantStyleRange aStyleForEntry);
+  gfxFontEntry* CreateFontEntry(
+      mozilla::fontlist::Face* aFace,
+      const mozilla::fontlist::Family* aFamily) override;
+
+  void ReadFaceNamesForFamily(mozilla::fontlist::Family* aFamily,
+                              bool aNeedFullnamePostscriptNames) override;
+
+  bool ReadFaceNames(mozilla::fontlist::Family* aFamily,
+                     mozilla::fontlist::Face* aFace, nsCString& aPSName,
+                     nsCString& aFullName) override;
 
-  virtual gfxFontEntry* MakePlatformFont(const nsACString& aFontName,
-                                         WeightRange aWeightForEntry,
-                                         StretchRange aStretchForEntry,
-                                         SlantStyleRange aStyleForEntry,
-                                         const uint8_t* aFontData,
-                                         uint32_t aLength);
+  void GetFacesInitDataForFamily(
+      const mozilla::fontlist::Family* aFamily,
+      nsTArray<mozilla::fontlist::Face::InitData>& aFaces) const 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;
 
   IDWriteGdiInterop* GetGDIInterop() { return mGDIInterop; }
   bool UseGDIFontTableAccess() { return mGDIFontTableAccess; }
 
   bool FindAndAddFamilies(mozilla::StyleGenericFontFamily aGeneric,
                           const nsACString& aFamily,
                           nsTArray<FamilyAndGeneric>* aOutput,
                           FindFamiliesFlags aFlags,
@@ -417,32 +433,38 @@ class gfxDWriteFontList : public gfxPlat
   nsresult GetFontSubstitutes();
 
   void GetDirectWriteSubstitutes();
 
   virtual bool UsesSystemFallback() { return true; }
 
   void GetFontsFromCollection(IDWriteFontCollection* aCollection);
 
+  void AppendFamiliesFromCollection(
+      IDWriteFontCollection* aCollection,
+      nsTArray<mozilla::fontlist::Family::InitData>& aFamilies,
+      const nsTArray<nsCString>* aForceClassicFams = nullptr);
+
 #ifdef MOZ_BUNDLED_FONTS
   already_AddRefed<IDWriteFontCollection> CreateBundledFontsCollection(
       IDWriteFactory* aFactory);
 #endif
 
   /**
    * Fonts listed in the registry as substitutes but for which no actual
    * font family is found.
    */
   nsTArray<nsCString> mNonExistingFonts;
 
   /**
    * Table of font substitutes, we grab this from the registry to get
    * alternative font names.
    */
   FontFamilyTable mFontSubstitutes;
+  nsClassHashtable<nsCStringHashKey, nsCString> mSubstitutions;
 
   virtual already_AddRefed<FontInfoData> CreateFontInfoData();
 
   gfxFloat mForceGDIClassicMaxFontSize;
 
   // whether to use GDI font table access routines
   bool mGDIFontTableAccess;
   RefPtr<IDWriteGdiInterop> mGDIInterop;