Bug 752394 - time out localized font family name initialization, reflow if needed after font loader thread completes. r=jfkthame
authorJohn Daggett <jdaggett@mozilla.com>
Wed, 23 Apr 2014 14:20:21 +0900
changeset 180093 555db81b5607ffdedc12e1eb2eead34f93e232d8
parent 180092 0c4cbcc72ae4cd8f6bacda2b695b1deea2a4ebd1
child 180094 b747c35ac54b17258559111b0bc1ddee32f12c2d
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersjfkthame
bugs752394
milestone31.0a1
Bug 752394 - time out localized font family name initialization, reflow if needed after font loader thread completes. r=jfkthame
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxPlatformFontList.h
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -176,47 +176,77 @@ gfxPlatformFontList::InitFontList()
 
 void
 gfxPlatformFontList::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
 {
     aResult = aKeyName;
     ToLowerCase(aResult);
 }
 
+struct InitOtherNamesData {
+    InitOtherNamesData(gfxPlatformFontList *aFontList,
+                       TimeStamp aStartTime)
+        : mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false)
+    {}
+
+    gfxPlatformFontList *mFontList;
+    TimeStamp mStartTime;
+    bool mTimedOut;
+};
+
 void 
 gfxPlatformFontList::InitOtherFamilyNames()
 {
-    mOtherFamilyNamesInitialized = true;
+    if (mOtherFamilyNamesInitialized) {
+        return;
+    }
+
     TimeStamp start = TimeStamp::Now();
 
     // iterate over all font families and read in other family names
-    mFontFamilies.Enumerate(gfxPlatformFontList::InitOtherFamilyNamesProc, this);
+    InitOtherNamesData otherNamesData(this, start);
 
+    mFontFamilies.Enumerate(gfxPlatformFontList::InitOtherFamilyNamesProc,
+                            &otherNamesData);
+
+    if (!otherNamesData.mTimedOut) {
+        mOtherFamilyNamesInitialized = true;
+    }
     TimeStamp end = TimeStamp::Now();
     Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITOTHERFAMILYNAMES,
                                    start, end);
+
 #ifdef PR_LOGGING
     if (LOG_FONTINIT_ENABLED()) {
         TimeDuration elapsed = end - start;
-        LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms",
-                      elapsed.ToMilliseconds()));
+        LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
+                      elapsed.ToMilliseconds(),
+                      (otherNamesData.mTimedOut ? "timeout" : "")));
     }
 #endif
 }
 
+#define OTHERNAMES_TIMEOUT 200
+
 PLDHashOperator
 gfxPlatformFontList::InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
                                               nsRefPtr<gfxFontFamily>& aFamilyEntry,
                                               void* userArg)
 {
-    gfxPlatformFontList *fc = static_cast<gfxPlatformFontList*>(userArg);
-    aFamilyEntry->ReadOtherFamilyNames(fc);
+    InitOtherNamesData *data = static_cast<InitOtherNamesData*>(userArg);
+
+    aFamilyEntry->ReadOtherFamilyNames(data->mFontList);
+    TimeDuration elapsed = TimeStamp::Now() - data->mStartTime;
+    if (elapsed.ToMilliseconds() > OTHERNAMES_TIMEOUT) {
+        data->mTimedOut = true;
+        return PL_DHASH_STOP;
+    }
     return PL_DHASH_NEXT;
 }
-
+ 
 struct ReadFaceNamesData {
     ReadFaceNamesData(gfxPlatformFontList *aFontList, TimeStamp aStartTime)
         : mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false)
     {}
 
     gfxPlatformFontList *mFontList;
     TimeStamp mStartTime;
     bool mTimedOut;
@@ -703,16 +733,23 @@ gfxPlatformFontList::FindFamily(const ns
     // 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();
         if ((familyEntry = mOtherFamilyNames.GetWeak(key)) != nullptr) {
             return CheckFamily(familyEntry);
+        } else if (!mOtherFamilyNamesInitialized) {
+            // localized family names load timed out, add name to list of
+            // names to check after localized names are loaded
+            if (!mOtherNamesMissed) {
+                mOtherNamesMissed = new nsTHashtable<nsStringHashKey>(4);
+            }
+            mOtherNamesMissed->PutEntry(key);
         }
     }
 
     return nullptr;
 }
 
 gfxFontEntry*
 gfxPlatformFontList::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold)
@@ -925,47 +962,81 @@ gfxPlatformFontList::LookupMissedFaceNam
 
     if (data->mFontList->FindFaceName(aKey->GetKey())) {
         data->mFoundName = true;
         return PL_DHASH_STOP;
     }
     return PL_DHASH_NEXT;
 }
 
+struct LookupMissedOtherNamesData {
+    LookupMissedOtherNamesData(gfxPlatformFontList *aFontList)
+        : mFontList(aFontList), mFoundName(false) {}
+
+    gfxPlatformFontList *mFontList;
+    bool mFoundName;
+};
+
+/*static*/ PLDHashOperator
+gfxPlatformFontList::LookupMissedOtherNamesProc(nsStringHashKey *aKey,
+                                                void *aUserArg)
+{
+    LookupMissedOtherNamesData *data =
+        reinterpret_cast<LookupMissedOtherNamesData*>(aUserArg);
+
+    if (data->mFontList->FindFamily(aKey->GetKey())) {
+        data->mFoundName = true;
+        return PL_DHASH_STOP;
+    }
+    return PL_DHASH_NEXT;
+}
+
 void 
 gfxPlatformFontList::CleanupLoader()
 {
     mFontFamiliesToLoad.Clear();
     mNumFamilies = 0;
-    bool rebuilt = false;
+    bool rebuilt = false, forceReflow = false;
 
     // if had missed face names that are now available, force reflow all
     if (mFaceNamesMissed &&
         mFaceNamesMissed->Count() != 0) {
         LookupMissedFaceNamesData namedata(this);
         mFaceNamesMissed->EnumerateEntries(LookupMissedFaceNamesProc, &namedata);
         if (namedata.mFoundName) {
             rebuilt = true;
             mUserFontSetList.EnumerateEntries(RebuildLocalFonts, nullptr);
         }
         mFaceNamesMissed = nullptr;
     }
 
+    if (mOtherNamesMissed) {
+        LookupMissedOtherNamesData othernamesdata(this);
+        mOtherNamesMissed->EnumerateEntries(LookupMissedOtherNamesProc,
+                                            &othernamesdata);
+        mOtherNamesMissed = nullptr;
+        if (othernamesdata.mFoundName) {
+            forceReflow = true;
+            ForceGlobalReflow();
+        }
+    }
+
 #ifdef PR_LOGGING
     if (LOG_FONTINIT_ENABLED() && mFontInfo) {
         LOG_FONTINIT(("(fontinit) fontloader load thread took %8.2f ms "
                       "%d families %d fonts %d cmaps "
-                      "%d facenames %d othernames %s",
+                      "%d facenames %d othernames %s %s",
                       mLoadTime.ToMilliseconds(),
                       mFontInfo->mLoadStats.families,
                       mFontInfo->mLoadStats.fonts,
                       mFontInfo->mLoadStats.cmaps,
                       mFontInfo->mLoadStats.facenames,
                       mFontInfo->mLoadStats.othernames,
-                      (rebuilt ? "(userfont sets rebuilt)" : "")));
+                      (rebuilt ? "(userfont sets rebuilt)" : ""),
+                      (forceReflow ? "(global reflow)" : "")));
     }
 #endif
 
     gfxFontInfoLoader::CleanupLoader();
 }
 
 void
 gfxPlatformFontList::GetPrefsAndStartLoader()
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -220,17 +220,17 @@ protected:
 
     // whether system-based font fallback is used or not
     // if system fallback is used, no need to load all cmaps
     virtual bool UsesSystemFallback() { return false; }
 
     // verifies that a family contains a non-zero font count
     gfxFontFamily* CheckFamily(gfxFontFamily *aFamily);
 
-    // separate initialization for reading in name tables, since this is expensive
+    // initialize localized family names
     void InitOtherFamilyNames();
 
     static PLDHashOperator
     InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
                              nsRefPtr<gfxFontFamily>& aFamilyEntry,
                              void* userArg);
 
     // search through font families, looking for a given name, initializing
@@ -248,16 +248,19 @@ protected:
 
     // look up a font by name, for cases where platform font list
     // maintains explicit mappings of fullname/psname ==> font
     virtual gfxFontEntry* LookupInFaceNameLists(const nsAString& aFontName);
 
     static PLDHashOperator LookupMissedFaceNamesProc(nsStringHashKey *aKey,
                                                      void *aUserArg);
 
+    static PLDHashOperator LookupMissedOtherNamesProc(nsStringHashKey *aKey,
+                                                      void *aUserArg);
+
     // 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();
 
     // explicitly set fixed-pitch flag for all faces
     void SetFixedPitch(const nsAString& aFamilyName);
@@ -309,16 +312,19 @@ protected:
       // Postscript name ==> font entry (unique, one name per font entry)
       nsRefPtrHashtable<nsStringHashKey, gfxFontEntry> mPostscriptNames;
     };
     nsAutoPtr<ExtraNames> mExtraNames;
 
     // face names missed when face name loading takes a long time
     nsAutoPtr<nsTHashtable<nsStringHashKey> > mFaceNamesMissed;
 
+    // localized family names missed when face name loading takes a long time
+    nsAutoPtr<nsTHashtable<nsStringHashKey> > mOtherNamesMissed;
+
     // cached pref font lists
     // maps list of family names ==> array of family entries, one per lang group
     nsDataHashtable<nsUint32HashKey, nsTArray<nsRefPtr<gfxFontFamily> > > mPrefFonts;
 
     // when system-wide font lookup fails for a character, cache it to skip future searches
     gfxSparseBitSet mCodepointsWithNoFonts;
 
     // the family to use for U+FFFD fallback, to avoid expensive search every time