diff --git a/dom/xbl/nsXBLPrototypeResources.cpp b/dom/xbl/nsXBLPrototypeResources.cpp index 0cd725e60dc6..b43ebaba4124 100644 --- a/dom/xbl/nsXBLPrototypeResources.cpp +++ b/dom/xbl/nsXBLPrototypeResources.cpp @@ -78,7 +78,6 @@ nsXBLPrototypeResources::FlushSkinSheets() // We have scoped stylesheets. Reload any chrome stylesheets we // encounter. (If they aren't skin sheets, it doesn't matter, since // they'll still be in the chrome cache. - mRuleProcessor = nullptr; nsTArray> oldSheets; @@ -144,7 +143,8 @@ nsXBLPrototypeResources::GatherRuleProcessor() { mRuleProcessor = new nsCSSRuleProcessor(mStyleSheetList, nsStyleSet::eDocSheet, - nullptr); + nullptr, + mRuleProcessor); } void diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index f17026f58393..1f363565f749 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -1087,7 +1087,9 @@ RuleCascadeData::AttributeListFor(nsIAtom* aAttribute) nsCSSRuleProcessor::nsCSSRuleProcessor(const sheet_array_type& aSheets, uint8_t aSheetType, - Element* aScopeElement) + Element* aScopeElement, + nsCSSRuleProcessor* + aPreviousCSSRuleProcessor) : mSheets(aSheets) , mRuleCascades(nullptr) , mLastPresContext(nullptr) diff --git a/layout/style/nsCSSRuleProcessor.h b/layout/style/nsCSSRuleProcessor.h index d711fe83579a..46b44fe1be21 100644 --- a/layout/style/nsCSSRuleProcessor.h +++ b/layout/style/nsCSSRuleProcessor.h @@ -52,9 +52,12 @@ public: // aScopeElement must be non-null iff aSheetType is // nsStyleSet::eScopedDocSheet. + // aPreviousCSSRuleProcessor is the rule processor (if any) that this + // one is replacing. nsCSSRuleProcessor(const sheet_array_type& aSheets, uint8_t aSheetType, - mozilla::dom::Element* aScopeElement); + mozilla::dom::Element* aScopeElement, + nsCSSRuleProcessor* aPreviousCSSRuleProcessor); NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS(nsCSSRuleProcessor) diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index 20029c924323..bb9f219f5776 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -352,6 +352,9 @@ SortStyleSheetsByScope(nsTArray& aSheets) nsresult nsStyleSet::GatherRuleProcessors(sheetType aType) { + nsCOMPtr oldRuleProcessor(mRuleProcessors[aType]); + nsTArray> oldScopedDocRuleProcessors; + mRuleProcessors[aType] = nullptr; if (aType == eScopedDocSheet) { for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) { @@ -360,7 +363,9 @@ nsStyleSet::GatherRuleProcessors(sheetType aType) static_cast(processor)->GetScopeElement(); scope->ClearIsScopedStyleRoot(); } - mScopedDocSheetRuleProcessors.Clear(); + + // Clear mScopedDocSheetRuleProcessors, but save it. + oldScopedDocRuleProcessors.SwapElements(mScopedDocSheetRuleProcessors); } if (mAuthorStyleDisabled && (aType == eDocSheet || aType == eScopedDocSheet || @@ -420,6 +425,21 @@ nsStyleSet::GatherRuleProcessors(sheetType aType) // adjacent and that ancestor scopes come before descendent scopes. SortStyleSheetsByScope(sheets); + // Put the old scoped rule processors in a hashtable so that we + // can retrieve them efficiently, even in edge cases like the + // simultaneous removal and addition of a large number of elements + // with scoped sheets. + nsDataHashtable, + nsCSSRuleProcessor*> oldScopedRuleProcessorHash; + for (size_t i = oldScopedDocRuleProcessors.Length(); i-- != 0; ) { + nsCSSRuleProcessor* oldRP = + static_cast(oldScopedDocRuleProcessors[i].get()); + Element* scope = oldRP->GetScopeElement(); + MOZ_ASSERT(!oldScopedRuleProcessorHash.Get(scope), + "duplicate rule processors for same scope element?"); + oldScopedRuleProcessorHash.Put(scope, oldRP); + } + uint32_t start = 0, end; do { // Find the range of style sheets with the same scope. @@ -434,8 +454,10 @@ nsStyleSet::GatherRuleProcessors(sheetType aType) // Create a rule processor for the scope. nsTArray> sheetsForScope; sheetsForScope.AppendElements(sheets.Elements() + start, end - start); + nsCSSRuleProcessor* oldRP = oldScopedRuleProcessorHash.Get(scope); mScopedDocSheetRuleProcessors.AppendElement - (new nsCSSRuleProcessor(sheetsForScope, uint8_t(aType), scope)); + (new nsCSSRuleProcessor(sheetsForScope, uint8_t(aType), scope, + oldRP)); start = end; } while (start < count); @@ -457,7 +479,9 @@ nsStyleSet::GatherRuleProcessors(sheetType aType) cssSheets.AppendElement(cssSheet); } mRuleProcessors[aType] = - new nsCSSRuleProcessor(cssSheets, uint8_t(aType), nullptr); + new nsCSSRuleProcessor(cssSheets, uint8_t(aType), nullptr, + static_cast( + oldRuleProcessor.get())); } break; default: