Bug 1362599 - Remember which languages were used and force-cache when reset; r?heycam draft
authorManish Goregaokar <manishearth@gmail.com>
Fri, 05 May 2017 17:10:38 -0700
changeset 582008 3657d528da92a7afdc2acf81cfdb4673806bd8d0
parent 582007 437c2cf0736a96d43f47778ce3e196913056f929
child 629647 bf7346a81d69883e77567b9fe94e68152adb655c
push id59948
push userbmo:manishearth@gmail.com
push dateSat, 20 May 2017 19:11:55 +0000
reviewersheycam
bugs1362599
milestone55.0a1
Bug 1362599 - Remember which languages were used and force-cache when reset; r?heycam MozReview-Commit-ID: 8cPRd8xUHEp
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/style/ServoSpecifiedValues.cpp
layout/style/ServoStyleSet.cpp
servo/ports/geckolib/glue.rs
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -232,16 +232,17 @@ nsPresContext::nsPresContext(nsIDocument
     mFocusTextColor(mDefaultColor),
     mBodyTextColor(mDefaultColor),
     mViewportScrollbarOverrideNode(nullptr),
     mViewportStyleScrollbar(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO),
     mFocusRingWidth(1),
     mExistThrottledUpdates(false),
     // mImageAnimationMode is initialised below, in constructor body
     mImageAnimationModePref(imgIContainer::kNormalAnimMode),
+    mFontGroupCacheDirty(true),
     mInterruptChecksToSkip(0),
     mElementsRestyled(0),
     mFramesConstructed(0),
     mFramesReflowed(0),
     mInteractionTimeEnabled(true),
     mTelemetryScrollLastY(0),
     mTelemetryScrollMaxY(0),
     mTelemetryScrollTotalY(0),
@@ -618,16 +619,17 @@ nsPresContext::GetUserPreferences()
 
   // * use fonts?
   mUseDocumentFonts =
     Preferences::GetInt("browser.display.use_document_fonts") != 0;
 
   mPrefScrollbarSide = Preferences::GetInt("layout.scrollbar.side");
 
   mLangGroupFontPrefs.Reset();
+  mFontGroupCacheDirty = true;
   StaticPresData::Get()->ResetCachedFontPrefs();
 
   // * image animation
   const nsAdoptingCString& animatePref =
     Preferences::GetCString("image.animation_mode");
   if (animatePref.EqualsLiteral("normal"))
     mImageAnimationModePref = imgIContainer::kNormalAnimMode;
   else if (animatePref.EqualsLiteral("none"))
@@ -1061,16 +1063,17 @@ nsPresContext::UpdateCharSet(const nsCSt
     mLanguage = mLangService->LookupCharSet(aCharSet);
     // this will be a language group (or script) code rather than a true language code
 
     // bug 39570: moved from nsLanguageAtomService::LookupCharSet()
     if (mLanguage == nsGkAtoms::Unicode) {
       mLanguage = mLangService->GetLocaleLanguage();
     }
     mLangGroupFontPrefs.Reset();
+    mFontGroupCacheDirty = true;
   }
 
   switch (GET_BIDI_OPTION_TEXTTYPE(GetBidi())) {
 
     case IBMBIDI_TEXTTYPE_LOGICAL:
       SetVisualMode(false);
       break;
 
@@ -1971,16 +1974,43 @@ void nsPresContext::StopEmulatingMedium(
   nsIAtom* previousMedium = Medium();
   mIsEmulatingMedia = false;
   if (Medium() != previousMedium) {
     MediaFeatureValuesChanged(nsRestyleHint(0), nsChangeHint(0));
   }
 }
 
 void
+nsPresContext::ForceCacheLang(nsIAtom *aLanguage)
+{
+  // force it to be cached
+  GetDefaultFont(kPresContext_DefaultVariableFont_ID, aLanguage);
+  if (!mLanguagesUsed.Contains(aLanguage)) {
+    mLanguagesUsed.PutEntry(aLanguage);
+  }
+}
+
+void
+nsPresContext::CacheAllLangs()
+{
+  if (mFontGroupCacheDirty) {
+    nsCOMPtr<nsIAtom> thisLang = nsStyleFont::GetLanguage(this);
+    GetDefaultFont(kPresContext_DefaultVariableFont_ID, thisLang.get());
+    GetDefaultFont(kPresContext_DefaultVariableFont_ID, nsGkAtoms::x_math);
+    // https://bugzilla.mozilla.org/show_bug.cgi?id=1362599#c12
+    GetDefaultFont(kPresContext_DefaultVariableFont_ID, nsGkAtoms::Unicode);
+    for (auto iter = mLanguagesUsed.Iter(); !iter.Done(); iter.Next()) {
+
+      GetDefaultFont(kPresContext_DefaultVariableFont_ID, iter.Get()->GetKey());
+    }
+  }
+  mFontGroupCacheDirty = false;
+}
+
+void
 nsPresContext::RebuildAllStyleData(nsChangeHint aExtraHint,
                                    nsRestyleHint aRestyleHint)
 {
   if (!mShell) {
     // We must have been torn down. Nothing to do here.
     return;
   }
 
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -368,16 +368,19 @@ public:
   const nsFont* GetDefaultFont(uint8_t aFontID,
                                nsIAtom *aLanguage) const
   {
     nsIAtom* lang = aLanguage ? aLanguage : mLanguage.get();
     return StaticPresData::Get()->GetDefaultFontHelper(aFontID, lang,
                                                        GetFontPrefsForLang(lang));
   }
 
+  void ForceCacheLang(nsIAtom *aLanguage);
+  void CacheAllLangs();
+
   /** Get a cached boolean pref, by its type */
   // *  - initially created for bugs 31816, 20760, 22963
   bool GetCachedBoolPref(nsPresContext_CachedBoolPrefType aPrefType) const
   {
     // If called with a constant parameter, the compiler should optimize
     // this switch statement away.
     switch (aPrefType) {
     case kPresContext_UseDocumentFonts:
@@ -1415,16 +1418,19 @@ protected:
 
   // Most documents will only use one (or very few) language groups. Rather
   // than have the overhead of a hash lookup, we simply look along what will
   // typically be a very short (usually of length 1) linked list. There are 31
   // language groups, so in the worst case scenario we'll need to traverse 31
   // link items.
   LangGroupFontPrefs    mLangGroupFontPrefs;
 
+  bool mFontGroupCacheDirty;
+  nsTHashtable<nsRefPtrHashKey<nsIAtom>> mLanguagesUsed;
+
   nscoord               mBorderWidthTable[3];
 
   uint32_t              mInterruptChecksToSkip;
 
   // Counters for tests and tools that want to detect frame construction
   // or reflow.
   uint64_t              mElementsRestyled;
   uint64_t              mFramesConstructed;
--- a/layout/style/ServoSpecifiedValues.cpp
+++ b/layout/style/ServoSpecifiedValues.cpp
@@ -46,18 +46,17 @@ void
 ServoSpecifiedValues::SetIdentStringValue(nsCSSPropertyID aId,
                                           const nsString& aValue)
 {
   nsCOMPtr<nsIAtom> atom = NS_Atomize(aValue);
   Servo_DeclarationBlock_SetIdentStringValue(mDecl, aId, atom);
   if (aId == eCSSProperty__x_lang) {
     // This forces the lang prefs result to be cached
     // so that we can access them off main thread during traversal
-    mPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
-                                 atom);
+    mPresContext->ForceCacheLang(atom);
   }
 }
 
 void
 ServoSpecifiedValues::SetKeywordValue(nsCSSPropertyID aId, int32_t aValue)
 {
   Servo_DeclarationBlock_SetKeywordValue(mDecl, aId, aValue);
 }
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -262,16 +262,17 @@ ServoStyleSet::PreTraverseSync()
   // This is lazily computed and pseudo matching needs to access
   // it so force computation early.
   mPresContext->Document()->GetDocumentState();
 
   // Ensure that the @font-face data is not stale
   mPresContext->Document()->GetUserFontSet();
 
   UpdateStylistIfNeeded();
+  mPresContext->CacheAllLangs();
 }
 
 void
 ServoStyleSet::PreTraverse(Element* aRoot)
 {
   PreTraverseSync();
 
   // Process animation stuff that we should avoid doing during the parallel
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -1632,16 +1632,17 @@ pub extern "C" fn Servo_DeclarationBlock
                                                              *mut nsIAtom) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands::_x_lang::computed_value::T as Lang;
 
     let long = get_longhand_from_id!(property);
     let prop = match_wrap_declared! { long,
         XLang => Lang(Atom::from(value)),
     };
+
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
         decls.push(prop, Importance::Normal);
     })
 }
 
 #[no_mangle]
 #[allow(unreachable_code)]
 pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations: