diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index e51e13c347a..633cc4adccb 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -15,6 +15,7 @@ #include "mozilla/CSSStyleSheet.h" #include "mozilla/EventStates.h" #include "mozilla/MemoryReporting.h" +#include "mozilla/RuleProcessorCache.h" #include "nsIDocumentInlines.h" #include "nsRuleWalker.h" #include "nsStyleContext.h" @@ -181,6 +182,19 @@ nsStyleSet::~nsStyleSet() static_cast(mSheets[type][i])->DropStyleSet(this); } } + + // drop reference to cached rule processors + nsCSSRuleProcessor* rp; + rp = static_cast(mRuleProcessors[eAgentSheet].get()); + if (rp) { + MOZ_ASSERT(rp->IsShared()); + rp->ReleaseStyleSetRef(); + } + rp = static_cast(mRuleProcessors[eUserSheet].get()); + if (rp) { + MOZ_ASSERT(rp->IsShared()); + rp->ReleaseStyleSetRef(); + } } size_t @@ -190,7 +204,16 @@ nsStyleSet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const for (int i = 0; i < eSheetTypeCount; i++) { if (mRuleProcessors[i]) { - n += mRuleProcessors[i]->SizeOfIncludingThis(aMallocSizeOf); + bool shared = false; + if (i == eAgentSheet || i == eUserSheet) { + // The only two origins we consider caching rule processors for. + nsCSSRuleProcessor* rp = + static_cast(mRuleProcessors[i].get()); + shared = rp->IsShared(); + } + if (!shared) { + n += mRuleProcessors[i]->SizeOfIncludingThis(aMallocSizeOf); + } } // mSheets is a C-style array of nsCOMArrays. We do not own the sheets in // the nsCOMArrays (either the nsLayoutStyleSheetCache singleton or our @@ -364,7 +387,15 @@ nsStyleSet::GatherRuleProcessors(sheetType aType) { nsCOMPtr oldRuleProcessor(mRuleProcessors[aType]); nsTArray> oldScopedDocRuleProcessors; - + if (aType == eAgentSheet || aType == eUserSheet) { + // drop reference to cached rule processor + nsCSSRuleProcessor* rp = + static_cast(mRuleProcessors[aType].get()); + if (rp) { + MOZ_ASSERT(rp->IsShared()); + rp->ReleaseStyleSetRef(); + } + } mRuleProcessors[aType] = nullptr; if (aType == eScopedDocSheet) { for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) { @@ -477,10 +508,43 @@ nsStyleSet::GatherRuleProcessors(sheetType aType) if (mSheets[aType].Count()) { switch (aType) { case eAgentSheet: - case eUserSheet: + case eUserSheet: { + // levels containing non-scoped CSS style sheets whose rule processors + // we want to re-use + nsCOMArray& sheets = mSheets[aType]; + nsTArray> cssSheets(sheets.Count()); + for (int32_t i = 0, i_end = sheets.Count(); i < i_end; ++i) { + nsRefPtr cssSheet = do_QueryObject(sheets[i]); + NS_ASSERTION(cssSheet, "not a CSS sheet"); + cssSheets.AppendElement(cssSheet); + } + nsTArray cssSheetsRaw(cssSheets.Length()); + for (int32_t i = 0, i_end = cssSheets.Length(); i < i_end; ++i) { + cssSheetsRaw.AppendElement(cssSheets[i]); + } + nsCSSRuleProcessor* rp = + RuleProcessorCache::GetRuleProcessor(cssSheetsRaw, PresContext()); + if (!rp) { + rp = new nsCSSRuleProcessor(cssSheets, uint8_t(aType), nullptr, + static_cast( + oldRuleProcessor.get()), + true /* aIsShared */); + nsTArray documentRules; + nsDocumentRuleResultCacheKey cacheKey; + rp->TakeDocumentRulesAndCacheKey(PresContext(), + documentRules, cacheKey); + RuleProcessorCache::PutRuleProcessor(cssSheetsRaw, + Move(documentRules), + cacheKey, rp); + } + mRuleProcessors[aType] = rp; + rp->AddStyleSetRef(); + break; + } case eDocSheet: case eOverrideSheet: { - // levels containing CSS stylesheets (apart from eScopedDocSheet) + // levels containing non-scoped CSS stylesheets whose rule processors + // we don't want to re-use nsCOMArray& sheets = mSheets[aType]; nsTArray> cssSheets(sheets.Count()); for (int32_t i = 0, i_end = sheets.Count(); i < i_end; ++i) {