From cbb019a8628de1342e1f1c170c8c56ac1f062a5e Mon Sep 17 00:00:00 2001 From: Francis Dominic Fajardo Date: Tue, 22 Jul 2025 14:03:22 +0800 Subject: [PATCH] Issue #2828 - Part 11: Detach weighted rule data from cascade layer --- layout/style/RuleCascadeData.cpp | 123 ++++++++++++++++++------------- layout/style/RuleCascadeData.h | 23 ++++-- 2 files changed, 89 insertions(+), 57 deletions(-) diff --git a/layout/style/RuleCascadeData.cpp b/layout/style/RuleCascadeData.cpp index b834271e29..465225d792 100644 --- a/layout/style/RuleCascadeData.cpp +++ b/layout/style/RuleCascadeData.cpp @@ -7,7 +7,7 @@ // We want page-sized arenas so there's no fragmentation involved. // Including plarena.h must come first to avoid it being included by some // header file thereby making PL_ARENA_CONST_ALIGN_MASK ineffective. -#define NS_CASCADELAYER_ARENA_BLOCK_SIZE (4096) +#define NS_WEIGHTEDRULEDATA_ARENA_BLOCK_SIZE (4096) #include "plarena.h" #include "RuleCascadeData.h" @@ -1536,7 +1536,8 @@ InitWeightEntry(PLDHashEntryHdr* hdr, const void* key) new (KnownNotNull, entry) RuleByWeightEntry(); } -/* static */ const PLDHashTableOps CascadeLayer::sRulesByWeightOps = { +/* static */ const PLDHashTableOps +CascadeLayer::WeightedRuleData::sRulesByWeightOps = { HashIntKey, MatchWeightEntry, PLDHashTable::MoveEntryStub, @@ -1544,6 +1545,72 @@ InitWeightEntry(PLDHashEntryHdr* hdr, const void* key) InitWeightEntry }; +CascadeLayer::WeightedRuleData::WeightedRuleData() + : mRulesByWeight(&sRulesByWeightOps, sizeof(RuleByWeightEntry), 32) +{ + // Initialize our arena + PL_INIT_ARENA_POOL( + &mArena, "WeightedRuleDataArena", NS_WEIGHTEDRULEDATA_ARENA_BLOCK_SIZE); +} + +CascadeLayer::WeightedRuleData::~WeightedRuleData() +{ + PL_FinishArenaPool(&mArena); +} + +static int +CompareWeightData(const void* aArg1, const void* aArg2, void* closure) +{ + const PerWeightData* arg1 = static_cast(aArg1); + const PerWeightData* arg2 = static_cast(aArg2); + return arg1->mWeight - arg2->mWeight; // put lower weight first +} + +UniquePtr +CascadeLayer::WeightedRuleData::Consume(nsTArray& aStyleRules) +{ + for (css::StyleRule* styleRule : aStyleRules) { + for (nsCSSSelectorList* sel = styleRule->Selector(); sel; + sel = sel->mNext) { + int32_t weight = sel->mWeight; + auto entry = static_cast( + mRulesByWeight.Add(NS_INT32_TO_PTR(weight), fallible)); + if (!entry) { + return nullptr; + } + entry->data.mWeight = weight; + // entry->data.mRuleSelectorPairs should be linked in forward order; + // entry->data.mTail is the slot to write to. + auto* newItem = + new (mArena) PerWeightDataListItem(styleRule, sel->mSelectors); + if (newItem) { + *(entry->data.mTail) = newItem; + entry->data.mTail = &newItem->mNext; + } + } + } + + // There's no point in keeping pointers to the style rules around + // after we've consumed them, so clear the array. + aStyleRules.Clear(); + + // Sort the hash table of per-weight linked lists by weight. + uint32_t weightCount = mRulesByWeight.EntryCount(); + auto weightArray = MakeUnique(weightCount); + int32_t j = 0; + for (auto iter = mRulesByWeight.Iter(); !iter.Done(); iter.Next()) { + auto entry = static_cast(iter.Get()); + weightArray[j++] = entry->data; + } + NS_QuickSort(weightArray.get(), + weightCount, + sizeof(PerWeightData), + CompareWeightData, + nullptr); + + return weightArray; +} + CascadeLayer::CascadeLayer(nsPresContext* aPresContext, #ifdef DEBUG CascadeLayer* aParent, @@ -1564,21 +1631,15 @@ CascadeLayer::CascadeLayer(nsPresContext* aPresContext, , mDocumentCacheKey(aDocumentKey) , mSheetType(aSheetType) , mMustGatherDocumentRules(aMustGatherDocumentRules) - , mRulesByWeight(&sRulesByWeightOps, sizeof(RuleByWeightEntry), 32) , mCacheKey(aCacheKey) { mData = new RuleCascadeData(eCompatibility_NavQuirks == mPresContext->CompatibilityMode()); - - // Initialize our arena - PL_INIT_ARENA_POOL( - &mArena, "CascadeLayerArena", NS_CASCADELAYER_ARENA_BLOCK_SIZE); } CascadeLayer::~CascadeLayer() { delete mData; - PL_FinishArenaPool(&mArena); } CascadeLayer* @@ -1635,57 +1696,17 @@ CascadeLayer::CreateAnonymousChildLayer() return childLayer; } -static int -CompareWeightData(const void* aArg1, const void* aArg2, void* closure) -{ - const PerWeightData* arg1 = static_cast(aArg1); - const PerWeightData* arg2 = static_cast(aArg2); - return arg1->mWeight - arg2->mWeight; // put lower weight first -} - void CascadeLayer::AddRules() { MOZ_ASSERT(!mRulesAdded, "Rule cascade data already filled"); - for (css::StyleRule* styleRule : mStyleRules) { - for (nsCSSSelectorList* sel = styleRule->Selector(); sel; - sel = sel->mNext) { - int32_t weight = sel->mWeight; - auto entry = static_cast( - mRulesByWeight.Add(NS_INT32_TO_PTR(weight), fallible)); - if (!entry) { - return; - } - entry->data.mWeight = weight; - // entry->data.mRuleSelectorPairs should be linked in forward order; - // entry->data.mTail is the slot to write to. - auto* newItem = - new (mArena) PerWeightDataListItem(styleRule, sel->mSelectors); - if (newItem) { - *(entry->data.mTail) = newItem; - entry->data.mTail = &newItem->mNext; - } - } - } - - // Sort the hash table of per-weight linked lists by weight. - uint32_t weightCount = mRulesByWeight.EntryCount(); - auto weightArray = MakeUnique(weightCount); - int32_t j = 0; - for (auto iter = mRulesByWeight.Iter(); !iter.Done(); iter.Next()) { - auto entry = static_cast(iter.Get()); - weightArray[j++] = entry->data; - } - NS_QuickSort(weightArray.get(), - weightCount, - sizeof(PerWeightData), - CompareWeightData, - nullptr); + WeightedRuleData ruleData; + auto weightArray = ruleData.Consume(mStyleRules); // Put things into the rule hash. // The primary sort is by weight... - for (uint32_t i = 0; i < weightCount; ++i) { + for (uint32_t i = 0; i < ruleData.mRulesByWeight.EntryCount(); ++i) { // and the secondary sort is by order. mRuleSelectorPairs is already in // the right order.. for (PerWeightDataListItem* cur = weightArray[i].mRuleSelectorPairs; cur; diff --git a/layout/style/RuleCascadeData.h b/layout/style/RuleCascadeData.h index 952aed27f3..1986377924 100644 --- a/layout/style/RuleCascadeData.h +++ b/layout/style/RuleCascadeData.h @@ -26,6 +26,7 @@ using namespace mozilla; using namespace mozilla::dom; struct nsFontFaceRuleContainer; +struct PerWeightData; /** * A struct representing a given CSS rule and a particular selector @@ -350,11 +351,6 @@ struct CascadeLayer SheetType mSheetType; bool mMustGatherDocumentRules; - PLArenaPool mArena; - // Hooray, a manual PLDHashTable since nsClassHashtable doesn't - // provide a getter that gives me a *reference* to the value. - PLDHashTable mRulesByWeight; // of PerWeightDataListItem linked lists - #ifdef DEBUG CascadeLayer* mParent; #endif @@ -370,7 +366,22 @@ struct CascadeLayer void AddRules(); private: - static const PLDHashTableOps sRulesByWeightOps; + struct WeightedRuleData + { + WeightedRuleData(); + ~WeightedRuleData(); + + UniquePtr Consume(nsTArray& aStyleRules); + + PLArenaPool mArena; + // Hooray, a manual PLDHashTable since nsClassHashtable doesn't + // provide a getter that gives me a *reference* to the value. + PLDHashTable mRulesByWeight; // of PerWeightDataListItem linked lists + + private: + static const PLDHashTableOps sRulesByWeightOps; + }; + }; #endif /* RuleCascadeData_h___ */