Bug 1368531 - Put the task gfxPlatformFontList::InitOtherFamilyNames() into idle queue. r=jfkthame
authorJerryShih <hshih@mozilla.com>
Wed, 02 Aug 2017 20:33:00 -0400
changeset 372651 a9acfba1bc3cb1ff544ef6ebd53376bce4a9a96d
parent 372650 b651936901f8efbacb137a377a03154b1a0193ad
child 372652 dd577e997eb3b6a26e647935167f966c3e15c60f
push id93355
push userryanvm@gmail.com
push dateThu, 03 Aug 2017 13:08:24 +0000
treeherdermozilla-inbound@a9acfba1bc3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs1368531
milestone57.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 1368531 - Put the task gfxPlatformFontList::InitOtherFamilyNames() into idle queue. r=jfkthame Add a boolean value in FindFamily() to check if gecko needs to defer the InitOtherFamilyNames() task into idle queue. Add a new telemetry data FONTLIST_INITOTHERFAMILYNAMES_NO_DEFERRING for the execution time of InitOtherFamilyNames() running regularly at main thread instead of in idle queue. MozReview-Commit-ID: A3YPDcHtXrX
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
gfx/thebes/gfxFcPlatformFontList.cpp
gfx/thebes/gfxFcPlatformFontList.h
gfx/thebes/gfxGDIFontList.cpp
gfx/thebes/gfxGDIFontList.h
gfx/thebes/gfxMacPlatformFontList.h
gfx/thebes/gfxMacPlatformFontList.mm
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxPlatformFontList.h
gfx/thebes/gfxTextRun.cpp
toolkit/components/telemetry/Histograms.json
toolkit/components/telemetry/histogram-whitelists.json
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -1261,33 +1261,37 @@ gfxDWriteFontList::GetStandardFamilyName
     }
 
     return false;
 }
 
 bool
 gfxDWriteFontList::FindAndAddFamilies(const nsAString& aFamily,
                                       nsTArray<gfxFontFamily*>* aOutput,
+                                      bool aDeferOtherFamilyNamesLoading,
                                       gfxFontStyle* aStyle,
                                       gfxFloat aDevToCssSize)
 {
     nsAutoString keyName(aFamily);
     BuildKeyNameFromFontName(keyName);
 
     gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
     if (ff) {
         aOutput->AppendElement(ff);
         return true;
     }
 
     if (mNonExistingFonts.Contains(keyName)) {
         return false;
     }
 
-    return gfxPlatformFontList::FindAndAddFamilies(aFamily, aOutput, aStyle,
+    return gfxPlatformFontList::FindAndAddFamilies(aFamily,
+                                                   aOutput,
+                                                   aDeferOtherFamilyNamesLoading,
+                                                   aStyle,
                                                    aDevToCssSize);
 }
 
 void
 gfxDWriteFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                                           FontListSizes* aSizes) const
 {
     gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -374,16 +374,17 @@ public:
     bool GetStandardFamilyName(const nsAString& aFontName,
                                  nsAString& aFamilyName);
 
     IDWriteGdiInterop *GetGDIInterop() { return mGDIInterop; }
     bool UseGDIFontTableAccess() { return mGDIFontTableAccess; }
 
     bool FindAndAddFamilies(const nsAString& aFamily,
                             nsTArray<gfxFontFamily*>* aOutput,
+                            bool aDeferOtherFamilyNamesLoading,
                             gfxFontStyle* aStyle = nullptr,
                             gfxFloat aDevToCssSize = 1.0) override;
 
     gfxFloat GetForceGDIClassicMaxFontSize() { return mForceGDIClassicMaxFontSize; }
 
     virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const;
     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
--- a/gfx/thebes/gfxFcPlatformFontList.cpp
+++ b/gfx/thebes/gfxFcPlatformFontList.cpp
@@ -1478,16 +1478,17 @@ gfxFcPlatformFontList::MakePlatformFont(
 
     return new gfxFontconfigFontEntry(aFontName, aWeight, aStretch,
                                       aStyle, aFontData, face);
 }
 
 bool
 gfxFcPlatformFontList::FindAndAddFamilies(const nsAString& aFamily,
                                           nsTArray<gfxFontFamily*>* aOutput,
+                                          bool aDeferOtherFamilyNamesLoading,
                                           gfxFontStyle* aStyle,
                                           gfxFloat aDevToCssSize)
 {
     nsAutoString familyName(aFamily);
     ToLowerCase(familyName);
     nsIAtom* language = (aStyle ? aStyle->language.get() : nullptr);
 
     // deprecated generic names are explicitly converted to standard generics
@@ -1560,17 +1561,19 @@ gfxFcPlatformFontList::FindAndAddFamilie
                             i, &substName) == FcResultMatch;
          i++)
     {
         NS_ConvertUTF8toUTF16 subst(ToCharPtr(substName));
         if (sentinelFirstFamily &&
             FcStrCmp(substName, sentinelFirstFamily) == 0) {
             break;
         }
-        gfxPlatformFontList::FindAndAddFamilies(subst, &cachedFamilies);
+        gfxPlatformFontList::FindAndAddFamilies(subst,
+                                                &cachedFamilies,
+                                                aDeferOtherFamilyNamesLoading);
     }
 
     // Cache the resulting list, so we don't have to do this again.
     mFcSubstituteCache.Put(familyToFind, cachedFamilies);
 
     if (cachedFamilies.IsEmpty()) {
         return false;
     }
@@ -1842,17 +1845,18 @@ gfxFcPlatformFontList::FindGenericFamili
         FcPattern* font = faces->fonts[i];
         FcChar8* mappedGeneric = nullptr;
 
         FcPatternGetString(font, FC_FAMILY, 0, &mappedGeneric);
         if (mappedGeneric) {
             NS_ConvertUTF8toUTF16 mappedGenericName(ToCharPtr(mappedGeneric));
             AutoTArray<gfxFontFamily*,1> genericFamilies;
             if (gfxPlatformFontList::FindAndAddFamilies(mappedGenericName,
-                                                        &genericFamilies)) {
+                                                        &genericFamilies,
+                                                        true)) {
                 MOZ_ASSERT(genericFamilies.Length() == 1,
                            "expected a single family");
                 if (!prefFonts->Contains(genericFamilies[0])) {
                     prefFonts->AppendElement(genericFamilies[0]);
                     bool foundLang =
                         !fcLang.IsEmpty() &&
                         PatternHasLang(font, ToFcChar8Ptr(fcLang.get()));
                     foundFontWithLang = foundFontWithLang || foundLang;
--- a/gfx/thebes/gfxFcPlatformFontList.h
+++ b/gfx/thebes/gfxFcPlatformFontList.h
@@ -246,16 +246,17 @@ public:
     MakePlatformFont(const nsAString& aFontName, uint16_t aWeight,
                      int16_t aStretch,
                      uint8_t aStyle,
                      const uint8_t* aFontData,
                      uint32_t aLength) override;
 
     bool FindAndAddFamilies(const nsAString& aFamily,
                             nsTArray<gfxFontFamily*>* aOutput,
+                            bool aDeferOtherFamilyNamesLoading,
                             gfxFontStyle* aStyle = nullptr,
                             gfxFloat aDevToCssSize = 1.0) override;
 
     bool GetStandardFamilyName(const nsAString& aFontName,
                                nsAString& aFamilyName) override;
 
     FcConfig* GetLastConfig() const { return mLastConfig; }
 
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -907,33 +907,37 @@ gfxGDIFontList::MakePlatformFont(const n
     }
 
     return fe;
 }
 
 bool
 gfxGDIFontList::FindAndAddFamilies(const nsAString& aFamily,
                                    nsTArray<gfxFontFamily*>* aOutput,
+                                   bool aDeferOtherFamilyNamesLoading,
                                    gfxFontStyle* aStyle,
                                    gfxFloat aDevToCssSize)
 {
     nsAutoString keyName(aFamily);
     BuildKeyNameFromFontName(keyName);
 
     gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
     if (ff) {
         aOutput->AppendElement(ff);
         return true;
     }
 
     if (mNonExistingFonts.Contains(keyName)) {
         return false;
     }
 
-    return gfxPlatformFontList::FindAndAddFamilies(aFamily, aOutput, aStyle,
+    return gfxPlatformFontList::FindAndAddFamilies(aFamily,
+                                                   aOutput,
+                                                   aDeferOtherFamilyNamesLoading,
+                                                   aStyle,
                                                    aDevToCssSize);
 }
 
 gfxFontFamily*
 gfxGDIFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle)
 {
     gfxFontFamily *ff = nullptr;
 
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -304,16 +304,17 @@ public:
         return static_cast<gfxGDIFontList*>(sPlatformFontList);
     }
 
     // initialize font lists
     virtual nsresult InitFontListForPlatform() override;
 
     bool FindAndAddFamilies(const nsAString& aFamily,
                             nsTArray<gfxFontFamily*>* aOutput,
+                            bool aDeferOtherFamilyNamesLoading,
                             gfxFontStyle* aStyle = nullptr,
                             gfxFloat aDevToCssSize = 1.0) override;
 
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
                                           uint16_t aWeight,
                                           int16_t aStretch,
                                           uint8_t aStyle);
 
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -101,16 +101,17 @@ public:
                                    uint16_t aWeight,
                                    int16_t aStretch,
                                    uint8_t aStyle,
                                    const uint8_t* aFontData,
                                    uint32_t aLength) override;
 
     bool FindAndAddFamilies(const nsAString& aFamily,
                             nsTArray<gfxFontFamily*>* aOutput,
+                            bool aDeferOtherFamilyNamesLoading,
                             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,
                           nsAString& aSystemFontName,
                           gfxFontStyle &aFontStyle,
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -1248,31 +1248,35 @@ gfxMacPlatformFontList::MakePlatformFont
 
 // 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 nsAString& aFamily,
                                            nsTArray<gfxFontFamily*>* aOutput,
+                                           bool aDeferOtherFamilyNamesLoading,
                                            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, aStyle,
+    return gfxPlatformFontList::FindAndAddFamilies(aFamily,
+                                                   aOutput,
+                                                   aDeferOtherFamilyNamesLoading,
+                                                   aStyle,
                                                    aDevToCssSize);
 }
 
 void
 gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID,
                                          nsAString& aSystemFontName,
                                          gfxFontStyle &aFontStyle,
                                          float aDevPixPerCSSPixel)
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -261,19 +261,21 @@ gfxPlatformFontList::InitFontList()
     gfxFontCache *fontCache = gfxFontCache::GetCache();
     if (fontCache) {
         fontCache->AgeAllGenerations();
         fontCache->FlushShapedWordCaches();
     }
 
     gfxPlatform::PurgeSkiaFontCache();
 
+    CancelInitOtherFamilyNamesTask();
     mFontFamilies.Clear();
     mOtherFamilyNames.Clear();
     mOtherFamilyNamesInitialized = false;
+
     if (mExtraNames) {
         mExtraNames->mFullnames.Clear();
         mExtraNames->mPostscriptNames.Clear();
     }
     mFaceNameListsInitialized = false;
     ClearLangGroupPrefFonts();
     mReplacementCharFallbackFamily = nullptr;
     CancelLoader();
@@ -299,47 +301,30 @@ gfxPlatformFontList::GenerateFontListKey
 {
     aResult = aKeyName;
     ToLowerCase(aResult);
 }
 
 #define OTHERNAMES_TIMEOUT 200
 
 void
-gfxPlatformFontList::InitOtherFamilyNames()
+gfxPlatformFontList::InitOtherFamilyNames(bool aDeferOtherFamilyNamesLoading)
 {
     if (mOtherFamilyNamesInitialized) {
         return;
     }
 
-    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;
+    if (aDeferOtherFamilyNamesLoading) {
+        if (!mPendingOtherFamilyNameTask) {
+            RefPtr<mozilla::CancelableRunnable> task = new InitOtherFamilyNamesRunnable();
+            mPendingOtherFamilyNameTask = task;
+            NS_IdleDispatchToCurrentThread(task.forget());
         }
-    }
-
-    if (!timedOut) {
-        mOtherFamilyNamesInitialized = true;
-    }
-    TimeStamp end = TimeStamp::Now();
-    Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES,
-                                   start, end);
-
-    if (LOG_FONTINIT_ENABLED()) {
-        TimeDuration elapsed = end - start;
-        LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
-                      elapsed.ToMilliseconds(),
-                      (timedOut ? "timeout" : "")));
+    } else {
+        InitOtherFamilyNamesInternal(false);
     }
 }
 
 // time limit for loading facename lists (ms)
 #define NAMELIST_TIMEOUT  200
 
 gfxFontEntry*
 gfxPlatformFontList::SearchFamiliesForFaceName(const nsAString& aFaceName)
@@ -362,18 +347,18 @@ gfxPlatformFontList::SearchFamiliesForFa
         if (firstChar && ToLowerCase(key.CharAt(0)) != firstChar) {
             continue;
         }
 
         family->ReadFaceNames(this, NeedFullnamePostscriptNames());
 
         TimeDuration elapsed = TimeStamp::Now() - start;
         if (elapsed.ToMilliseconds() > NAMELIST_TIMEOUT) {
-           timedOut = true;
-           break;
+            timedOut = true;
+            break;
         }
     }
 
     lookup = FindFaceName(aFaceName);
 
     TimeStamp end = TimeStamp::Now();
     Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITFACENAMELISTS,
                                    start, end);
@@ -692,19 +677,20 @@ gfxPlatformFontList::CheckFamily(gfxFont
         GenerateFontListKey(aFamily->Name(), key);
         mFontFamilies.Remove(key);
         return nullptr;
     }
 
     return aFamily;
 }
 
-bool 
+bool
 gfxPlatformFontList::FindAndAddFamilies(const nsAString& aFamily,
                                         nsTArray<gfxFontFamily*>* aOutput,
+                                        bool aDeferOtherFamilyNamesLoading,
                                         gfxFontStyle* aStyle,
                                         gfxFloat aDevToCssSize)
 {
     nsAutoString key;
     GenerateFontListKey(aFamily, key);
 
     NS_ASSERTION(mFontFamilies.Count() != 0, "system font list was not initialized correctly");
 
@@ -717,17 +703,17 @@ gfxPlatformFontList::FindAndAddFamilies(
     }
 
     // if still not found and other family names not yet fully 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 (!familyEntry && !mOtherFamilyNamesInitialized && !IsASCII(aFamily)) {
-        InitOtherFamilyNames();
+        InitOtherFamilyNames(aDeferOtherFamilyNamesLoading);
         familyEntry = mOtherFamilyNames.GetWeak(key);
         if (!familyEntry && !mOtherFamilyNamesInitialized) {
             // localized family names load timed out, add name to list of
             // names to check after localized names are loaded
             if (!mOtherNamesMissed) {
                 mOtherNamesMissed = MakeUnique<nsTHashtable<nsStringHashKey>>(2);
             }
             mOtherNamesMissed->PutEntry(key);
@@ -891,17 +877,17 @@ gfxPlatformFontList::ResolveGenericFontN
     NS_ASSERTION(langGroup, "null lang group for pref lang");
 
     // lookup and add platform fonts uniquely
     for (const nsString& genericFamily : genericFamilies) {
         gfxFontStyle style;
         style.language = langGroup;
         style.systemFont = false;
         AutoTArray<gfxFontFamily*,10> families;
-        FindAndAddFamilies(genericFamily, &families, &style);
+        FindAndAddFamilies(genericFamily, &families, true, &style);
         for (gfxFontFamily* f : families) {
             if (!aGenericFamilies->Contains(f)) {
                 aGenericFamilies->AppendElement(f);
             }
         }
     }
 
 #if 0  // dump out generic mappings
@@ -1490,23 +1476,24 @@ gfxPlatformFontList::LoadFontInfo()
     if (LOG_FONTINIT_ENABLED()) {
         TimeDuration elapsed = TimeStamp::Now() - start;
         LOG_FONTINIT(("(fontinit) fontloader load pass %8.2f ms done %s\n",
                       elapsed.ToMilliseconds(), (done ? "true" : "false")));
     }
 
     if (done) {
         mOtherFamilyNamesInitialized = true;
+        CancelInitOtherFamilyNamesTask();
         mFaceNameListsInitialized = true;
     }
 
     return done;
 }
 
-void 
+void
 gfxPlatformFontList::CleanupLoader()
 {
     mFontFamiliesToLoad.Clear();
     mNumFamilies = 0;
     bool rebuilt = false, forceReflow = false;
 
     // if had missed face names that are now available, force reflow all
     if (mFaceNamesMissed) {
@@ -1517,17 +1504,17 @@ gfxPlatformFontList::CleanupLoader()
                 break;
             }
         }
         mFaceNamesMissed = nullptr;
     }
 
     if (mOtherNamesMissed) {
         for (auto it = mOtherNamesMissed->Iter(); !it.Done(); it.Next()) {
-            if (FindFamily(it.Get()->GetKey())) {
+            if (FindFamily(it.Get()->GetKey(), false)) {
                 forceReflow = true;
                 ForceGlobalReflow();
                 break;
             }
         }
         mOtherNamesMissed = nullptr;
     }
 
@@ -1686,10 +1673,77 @@ gfxPlatformFontList::AddSizeOfIncludingT
 }
 
 bool
 gfxPlatformFontList::IsFontFamilyWhitelistActive()
 {
     return mFontFamilyWhitelistActive;
 }
 
+void
+gfxPlatformFontList::InitOtherFamilyNamesInternal(bool aDeferOtherFamilyNamesLoading)
+{
+    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;
+            }
+        }
+
+        if (!timedOut) {
+            mOtherFamilyNamesInitialized = true;
+            CancelInitOtherFamilyNamesTask();
+        }
+        TimeStamp end = TimeStamp::Now();
+        Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES,
+                                       start, end);
+
+        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);
+        }
+
+        mOtherFamilyNamesInitialized = true;
+        CancelInitOtherFamilyNamesTask();
+
+        TimeStamp end = TimeStamp::Now();
+        Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES_NO_DEFERRING,
+                                       start, end);
+
+        if (LOG_FONTINIT_ENABLED()) {
+            TimeDuration elapsed = end - start;
+            LOG_FONTINIT(("(fontinit) InitOtherFamilyNames without deferring took %8.2f ms",
+                          elapsed.ToMilliseconds()));
+        }
+    }
+}
+
+void
+gfxPlatformFontList::CancelInitOtherFamilyNamesTask()
+{
+    if (mPendingOtherFamilyNameTask) {
+        mPendingOtherFamilyNameTask->Cancel();
+        mPendingOtherFamilyNameTask = nullptr;
+    }
+}
+
 #undef LOG
 #undef LOG_ENABLED
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -85,16 +85,18 @@ struct FontListSizes {
     uint32_t mFontTableCacheSize; // memory used for the gfxFontEntry table caches
     uint32_t mCharMapsSize; // memory used for cmap coverage info
 };
 
 class gfxUserFontSet;
 
 class gfxPlatformFontList : public gfxFontInfoLoader
 {
+    friend class InitOtherFamilyNamesRunnable;
+
 public:
     typedef mozilla::unicode::Script Script;
 
     static gfxPlatformFontList* PlatformFontList() {
         return sPlatformFontList;
     }
 
     static nsresult Init() {
@@ -132,16 +134,17 @@ public:
                           const gfxFontStyle* aStyle);
 
     // 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 nsAString& aFamily,
                        nsTArray<gfxFontFamily*>* aOutput,
+                       bool aDeferOtherFamilyNamesLoading,
                        gfxFontStyle* aStyle = nullptr,
                        gfxFloat aDevToCssSize = 1.0);
 
     gfxFontEntry* FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold);
 
     // name lookup table methods
 
     void AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString& aOtherFamilyName);
@@ -257,16 +260,52 @@ public:
     // Returns true if the font family whitelist is not empty.
     bool IsFontFamilyWhitelistActive();
 
     static void FontWhitelistPrefChanged(const char *aPref, void *aClosure) {
         gfxPlatformFontList::PlatformFontList()->UpdateFontList();
     }
 
 protected:
+    class InitOtherFamilyNamesRunnable : public mozilla::CancelableRunnable
+    {
+    public:
+        InitOtherFamilyNamesRunnable()
+            : CancelableRunnable("gfxPlatformFontList::InitOtherFamilyNamesRunnable")
+            , mIsCanceled(false)
+        {
+        }
+
+        NS_IMETHOD Run() override
+        {
+            if (mIsCanceled) {
+                return NS_OK;
+            }
+
+            gfxPlatformFontList* fontList = gfxPlatformFontList::PlatformFontList();
+            if (!fontList) {
+                return NS_OK;
+            }
+
+            fontList->InitOtherFamilyNamesInternal(true);
+
+            return NS_OK;
+        }
+
+        virtual nsresult Cancel() override
+        {
+            mIsCanceled = true;
+
+            return NS_OK;
+        }
+
+    private:
+        bool mIsCanceled;
+    };
+
     class MemoryReporter final : public nsIMemoryReporter
     {
         ~MemoryReporter() {}
     public:
         NS_DECL_ISUPPORTS
         NS_DECL_NSIMEMORYREPORTER
     };
 
@@ -313,22 +352,27 @@ protected:
 
     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 nsAString& aFamily, gfxFontStyle* aStyle = nullptr,
+    FindFamily(const nsAString& aFamily,
+               bool aDeferOtherFamilyNamesLoading = true,
+               gfxFontStyle* aStyle = nullptr,
                gfxFloat aDevToCssSize = 1.0)
     {
         AutoTArray<gfxFontFamily*,1> families;
-        return FindAndAddFamilies(aFamily, &families, aStyle, aDevToCssSize)
-               ? families[0] : nullptr;
+        return FindAndAddFamilies(aFamily,
+                                  &families,
+                                  aDeferOtherFamilyNamesLoading,
+                                  aStyle,
+                                  aDevToCssSize) ? families[0] : nullptr;
     }
 
     // Lookup family name in global family list without substitutions or
     // localized family name lookup. Used for common font fallback families.
     gfxFontFamily* FindFamilyByCanonicalName(const nsAString& aFamily) {
         nsAutoString key;
         gfxFontFamily *familyEntry;
         GenerateFontListKey(aFamily, key);
@@ -369,17 +413,19 @@ protected:
 
     void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen,
                             eFontPrefLang aCharLang, eFontPrefLang aPageLang);
 
     // verifies that a family contains a non-zero font count
     gfxFontFamily* CheckFamily(gfxFontFamily *aFamily);
 
     // initialize localized family names
-    void InitOtherFamilyNames();
+    void InitOtherFamilyNames(bool aDeferOtherFamilyNamesLoading);
+    void InitOtherFamilyNamesInternal(bool aDeferOtherFamilyNamesLoading);
+    void CancelInitOtherFamilyNamesTask();
 
     // search through font families, looking for a given name, initializing
     // facename lists along the way. first checks all families with names
     // close to face name, then searchs all families if not found.
     gfxFontEntry* SearchFamiliesForFaceName(const nsAString& aFaceName);
 
     // helper method for finding fullname/postscript names in facename lists
     gfxFontEntry* FindFaceName(const nsAString& aFaceName);
@@ -449,16 +495,19 @@ protected:
 
     // other family name ==> family entry (not unique, can have multiple names per
     // family entry, only names *other* than the canonical names are stored here)
     FontFamilyTable mOtherFamilyNames;
 
     // flag set after InitOtherFamilyNames is called upon first name lookup miss
     bool mOtherFamilyNamesInitialized;
 
+    // The pending InitOtherFamilyNames() task.
+    RefPtr<mozilla::CancelableRunnable> mPendingOtherFamilyNameTask;
+
     // flag set after fullname and Postcript name lists are populated
     bool mFaceNameListsInitialized;
 
     struct ExtraNames {
       ExtraNames() : mFullnames(64), mPostscriptNames(64) {}
 
       // fullname ==> font entry (unique, one name per font entry)
       FontEntryTable mFullnames;
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -1868,17 +1868,17 @@ gfxFontGroup::AddPlatformFont(const nsAS
         if (family) {
             aFamilyList.AppendElement(family);
             return;
         }
     }
 
     // Not known in the user font set ==> check system fonts
     gfxPlatformFontList::PlatformFontList()
-        ->FindAndAddFamilies(aName, &aFamilyList, &mStyle, mDevToCssSize);
+        ->FindAndAddFamilies(aName, &aFamilyList, true, &mStyle, mDevToCssSize);
 }
 
 void
 gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily)
 {
     NS_ASSERTION(aFamily, "trying to add a null font family to fontlist");
     AutoTArray<gfxFontEntry*,4> fontEntryList;
     bool needsBold;
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -1569,16 +1569,24 @@
   "FONTLIST_INITOTHERFAMILYNAMES": {
     "record_in_processes": ["main", "content"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 30000,
     "n_buckets": 50,
     "description": "Time(ms) spent on reading other family names from all fonts"
   },
+  "FONTLIST_INITOTHERFAMILYNAMES_NO_DEFERRING": {
+    "record_in_processes": ["main", "content"],
+    "expires_in_version": "never",
+    "kind": "exponential",
+    "high": 30000,
+    "n_buckets": 50,
+    "description": "Time(ms) spent on reading other family names from all fonts for no timeout case"
+  },
   "FONTLIST_INITFACENAMELISTS": {
     "record_in_processes": ["main", "content"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 30000,
     "n_buckets": 50,
     "description": "Time(ms) spent on reading family names from all fonts"
   },
--- a/toolkit/components/telemetry/histogram-whitelists.json
+++ b/toolkit/components/telemetry/histogram-whitelists.json
@@ -228,16 +228,17 @@
     "FENNEC_SYNC_NUMBER_OF_SYNCS_FAILED_BACKOFF",
     "FENNEC_SYNC_NUMBER_OF_SYNCS_STARTED",
     "FENNEC_TABQUEUE_QUEUESIZE",
     "FENNEC_TOPSITES_LOADER_TIME_MS",
     "FENNEC_WAS_KILLED",
     "FETCH_IS_MAINTHREAD",
     "FONTLIST_INITFACENAMELISTS",
     "FONTLIST_INITOTHERFAMILYNAMES",
+    "FONTLIST_INITOTHERFAMILYNAMES_NO_DEFERRING",
     "FONT_CACHE_HIT",
     "FORCED_DEVICE_RESET_REASON",
     "FX_BOOKMARKS_TOOLBAR_INIT_MS",
     "FX_BROWSER_FULLSCREEN_USED",
     "FX_GESTURE_COMPRESS_SNAPSHOT_OF_PAGE",
     "FX_GESTURE_INSTALL_SNAPSHOT_OF_PAGE",
     "FX_NEW_WINDOW_MS",
     "FX_PAGE_LOAD_MS",
@@ -871,16 +872,17 @@
     "FENNEC_SYNC_NUMBER_OF_SYNCS_STARTED",
     "FENNEC_TABQUEUE_QUEUESIZE",
     "FENNEC_TOPSITES_LOADER_TIME_MS",
     "FENNEC_WAS_KILLED",
     "FETCH_IS_MAINTHREAD",
     "FIND_PLUGINS",
     "FONTLIST_INITFACENAMELISTS",
     "FONTLIST_INITOTHERFAMILYNAMES",
+    "FONTLIST_INITOTHERFAMILYNAMES_NO_DEFERRING",
     "FONT_CACHE_HIT",
     "FORCED_DEVICE_RESET_REASON",
     "FORGET_SKIPPABLE_MAX",
     "FX_BOOKMARKS_TOOLBAR_INIT_MS",
     "FX_BROWSER_FULLSCREEN_USED",
     "FX_GESTURE_COMPRESS_SNAPSHOT_OF_PAGE",
     "FX_GESTURE_INSTALL_SNAPSHOT_OF_PAGE",
     "FX_NEW_WINDOW_MS",