From e05d4d830697cb703b44edc434b969d66851f7c4 Mon Sep 17 00:00:00 2001 From: Francis Dominic Fajardo Date: Sat, 19 Jul 2025 01:45:14 +0800 Subject: [PATCH] Issue #2828 - Part 5: Implement child rule processors --- dom/animation/EffectCompositor.cpp | 6 + dom/animation/EffectCompositor.h | 2 + layout/style/CascadeLayerRuleProcessor.cpp | 329 ++++++++++++++++++ layout/style/CascadeLayerRuleProcessor.h | 138 ++++++++ layout/style/RuleCascadeData.cpp | 29 +- layout/style/RuleCascadeData.h | 19 +- .../style/SVGAttrAnimationRuleProcessor.cpp | 6 + layout/style/SVGAttrAnimationRuleProcessor.h | 2 + layout/style/moz.build | 2 + layout/style/nsCSSRuleProcessor.cpp | 226 ++++++------ layout/style/nsCSSRuleProcessor.h | 5 +- layout/style/nsHTMLCSSStyleSheet.cpp | 6 + layout/style/nsHTMLCSSStyleSheet.h | 2 + layout/style/nsHTMLStyleSheet.cpp | 6 + layout/style/nsHTMLStyleSheet.h | 2 + layout/style/nsIStyleRuleProcessor.h | 7 + 16 files changed, 632 insertions(+), 155 deletions(-) create mode 100644 layout/style/CascadeLayerRuleProcessor.cpp create mode 100644 layout/style/CascadeLayerRuleProcessor.h diff --git a/dom/animation/EffectCompositor.cpp b/dom/animation/EffectCompositor.cpp index 21f19d5974..b15ba761a6 100644 --- a/dom/animation/EffectCompositor.cpp +++ b/dom/animation/EffectCompositor.cpp @@ -838,6 +838,12 @@ EffectCompositor::AnimationStyleRuleProcessor::MediumFeaturesChanged( return false; } +nsTArray>* +EffectCompositor::AnimationStyleRuleProcessor::GetChildRuleProcessors() +{ + return nullptr; +} + void EffectCompositor::AnimationStyleRuleProcessor::RulesMatching( ElementRuleProcessorData* aData) diff --git a/dom/animation/EffectCompositor.h b/dom/animation/EffectCompositor.h index 9410264760..7d45ec7139 100644 --- a/dom/animation/EffectCompositor.h +++ b/dom/animation/EffectCompositor.h @@ -278,6 +278,8 @@ private: AttributeRuleProcessorData* aData, RestyleHintData& aRestyleHintDataResult) override; bool MediumFeaturesChanged(nsPresContext* aPresContext) override; + nsTArray>* GetChildRuleProcessors() + override; void RulesMatching(ElementRuleProcessorData* aData) override; void RulesMatching(PseudoElementRuleProcessorData* aData) override; void RulesMatching(AnonBoxRuleProcessorData* aData) override; diff --git a/layout/style/CascadeLayerRuleProcessor.cpp b/layout/style/CascadeLayerRuleProcessor.cpp new file mode 100644 index 0000000000..4edc50347f --- /dev/null +++ b/layout/style/CascadeLayerRuleProcessor.cpp @@ -0,0 +1,329 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * style rule processor for cascade layers + */ + +#include "nsAutoPtr.h" +#include "nsCSSRuleProcessor.h" +#include "nsRuleProcessorData.h" +#include +#include "nsIAtom.h" +#include "PLDHashTable.h" +#include "nsICSSPseudoComparator.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/css/StyleRule.h" +#include "mozilla/css/GroupRule.h" +#include "nsIDocument.h" +#include "nsPresContext.h" +#include "nsGkAtoms.h" +#include "nsUnicharUtils.h" +#include "nsError.h" +#include "nsRuleWalker.h" +#include "nsCSSPseudoClasses.h" +#include "nsCSSPseudoElements.h" +#include "nsIContent.h" +#include "nsCOMPtr.h" +#include "nsHashKeys.h" +#include "nsStyleUtil.h" +#include "nsQuickSort.h" +#include "nsAttrValue.h" +#include "nsAttrValueInlines.h" +#include "nsAttrName.h" +#include "nsTArray.h" +#include "nsContentUtils.h" +#include "nsIMediaList.h" +#include "nsCSSRules.h" +#include "nsStyleSet.h" +#include "mozilla/dom/Element.h" +#include "mozilla/dom/HTMLSlotElement.h" +#include "mozilla/dom/ShadowRoot.h" +#include "nsNthIndexCache.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/EventStates.h" +#include "mozilla/Preferences.h" +#include "mozilla/LookAndFeel.h" +#include "mozilla/Likely.h" +#include "mozilla/OperatorNewExtensions.h" +#include "mozilla/TypedEnumBits.h" +#include "RuleProcessorCache.h" +#include "nsIDOMMutationEvent.h" +#include "nsIMozBrowserFrame.h" +#include "RuleCascadeData.h" +#include "nsCSSRuleUtils.h" +#include "CascadeLayerRuleProcessor.h" + +using namespace mozilla; +using namespace mozilla::dom; + +// ------------------------------- +// Cascade layer style rule processor implementation +// + +CascadeLayerRuleProcessor::CascadeLayerRuleProcessor( + CascadeEnumData* aLayer) + : mLayer(aLayer) + , mCascade(aLayer->mData) +{ + MOZ_ASSERT(mLayer, + "Layer rule processor must have an attached cascade layer"); + MOZ_ASSERT(mCascade, "Cascade layer is missing its data"); +} + +/* virtual */ void +CascadeLayerRuleProcessor::RulesMatching(ElementRuleProcessorData* aData) +{ + if (mCascade) { + mCascade->RulesMatching(aData); + } +} + +/* virtual */ void +CascadeLayerRuleProcessor::RulesMatching( + PseudoElementRuleProcessorData* aData) +{ + if (mCascade) { + mCascade->RulesMatching(aData); + } +} + +/* virtual */ void +CascadeLayerRuleProcessor::RulesMatching(AnonBoxRuleProcessorData* aData) +{ + if (mCascade) { + mCascade->RulesMatching(aData); + } +} + +/* virtual */ void +CascadeLayerRuleProcessor::RulesMatching(XULTreeRuleProcessorData* aData) +{ + if (mCascade) { + mCascade->RulesMatching(aData); + } +} + +nsRestyleHint +CascadeLayerRuleProcessor::HasStateDependentStyle( + ElementDependentRuleProcessorData* aData, + Element* aStatefulElement, + CSSPseudoElementType aPseudoType, + EventStates aStateMask, + nsRestyleHint& aHint) +{ + if (mCascade) { + mCascade->HasStateDependentStyle( + aData, aStatefulElement, aPseudoType, aStateMask, aHint); + } + return aHint; +} + +nsRestyleHint +CascadeLayerRuleProcessor::HasStateDependentStyle( + ElementDependentRuleProcessorData* aData, + Element* aStatefulElement, + CSSPseudoElementType aPseudoType, + EventStates aStateMask) +{ + nsRestyleHint hint = nsRestyleHint(0); + return HasStateDependentStyle( + aData, aStatefulElement, aPseudoType, aStateMask, hint); +} + +/* virtual */ nsRestyleHint +CascadeLayerRuleProcessor::HasStateDependentStyle( + StateRuleProcessorData* aData) +{ + return HasStateDependentStyle( + aData, aData->mElement, CSSPseudoElementType::NotPseudo, aData->mStateMask); +} + +/* virtual */ nsRestyleHint +CascadeLayerRuleProcessor::HasStateDependentStyle( + PseudoElementStateRuleProcessorData* aData) +{ + return HasStateDependentStyle( + aData, aData->mPseudoElement, aData->mPseudoType, aData->mStateMask); +} + +/* virtual */ bool +CascadeLayerRuleProcessor::HasDocumentStateDependentStyle( + StateRuleProcessorData* aData) +{ + if (mCascade && mCascade->mSelectorDocumentStates.HasAtLeastOneOfStates( + aData->mStateMask)) { + return true; + } + + return false; +} + +nsRestyleHint +CascadeLayerRuleProcessor::HasAttributeDependentStyle( + AttributeRuleProcessorData* aData, + AttributeEnumData* aEnumData, + mozilla::RestyleHintData& aRestyleHintDataResult) +{ + // We could try making use of aData->mModType, but :not rules make it a bit + // of a pain to do so... So just ignore it for now. + + // Don't do our special handling of certain attributes if the attr + // hasn't changed yet. + if (aData->mAttrHasChanged) { + // check for the lwtheme and lwthemetextcolor attribute on root XUL elements + if ((aData->mAttribute == nsGkAtoms::lwtheme || + aData->mAttribute == nsGkAtoms::lwthemetextcolor) && + aData->mElement->GetNameSpaceID() == kNameSpaceID_XUL && + aData->mElement == aData->mElement->OwnerDoc()->GetRootElement()) { + aEnumData->change = nsRestyleHint(aEnumData->change | eRestyle_Subtree); + } + + // We don't know the namespace of the attribute, and xml:lang applies to + // all elements. If the lang attribute changes, we need to restyle our + // whole subtree, since the :lang selector on our descendants can examine + // our lang attribute. + if (aData->mAttribute == nsGkAtoms::lang) { + aEnumData->change = nsRestyleHint(aEnumData->change | eRestyle_Subtree); + } + } + if (mCascade) { + mCascade->HasAttributeDependentStyle(aData, aEnumData, aRestyleHintDataResult); + } + return aEnumData->change; +} + +/* virtual */ nsRestyleHint +CascadeLayerRuleProcessor::HasAttributeDependentStyle( + AttributeRuleProcessorData* aData, + mozilla::RestyleHintData& aRestyleHintDataResult) +{ + AttributeEnumData data(aData, aRestyleHintDataResult); + return HasAttributeDependentStyle(aData, &data, aRestyleHintDataResult); +} + +/* virtual */ bool +CascadeLayerRuleProcessor::MediumFeaturesChanged(nsPresContext* aPresContext) +{ + // This is handled by our parent rule processor, so we don't need to do + // anything here. + return false; +} + +/* virtual */ nsTArray>* +CascadeLayerRuleProcessor::GetChildRuleProcessors() +{ + return nullptr; +} + +/* virtual */ size_t +CascadeLayerRuleProcessor::SizeOfExcludingThis( + mozilla::MallocSizeOf aMallocSizeOf) const +{ + size_t n = 0; + n += mCascade->SizeOfIncludingThis(aMallocSizeOf); + // FIXME: size of attached cascade layer is not included. + + return n; +} + +/* virtual */ size_t +CascadeLayerRuleProcessor::SizeOfIncludingThis( + mozilla::MallocSizeOf aMallocSizeOf) const +{ + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); +} + +nsCSSKeyframesRule* +CascadeLayerRuleProcessor::KeyframesRuleForName(nsPresContext* aPresContext, + const nsString& aName) +{ + if (mCascade) { + return mCascade->mKeyframesRuleTable.Get(aName); + } + + return nullptr; +} + +nsCSSCounterStyleRule* +CascadeLayerRuleProcessor::CounterStyleRuleForName( + nsPresContext* aPresContext, + const nsAString& aName) +{ + if (mCascade) { + return mCascade->mCounterStyleRuleTable.Get(aName); + } + + return nullptr; +} + +// Append all the currently-active font face rules to aArray. Return +// true for success and false for failure. +bool +CascadeLayerRuleProcessor::AppendFontFaceRules( + nsPresContext* aPresContext, + nsTArray& aArray) +{ + if (mCascade) { + if (!aArray.AppendElements(mCascade->mFontFaceRules)) { + return false; + } + } + + return true; +} + +// Append all the currently-active page rules to aArray. Return +// true for success and false for failure. +bool +CascadeLayerRuleProcessor::AppendPageRules(nsPresContext* aPresContext, + nsTArray& aArray) +{ + if (mCascade) { + if (!aArray.AppendElements(mCascade->mPageRules)) { + return false; + } + } + + return true; +} + +bool +CascadeLayerRuleProcessor::AppendFontFeatureValuesRules( + nsPresContext* aPresContext, + nsTArray& aArray) +{ + if (mCascade) { + if (!aArray.AppendElements(mCascade->mFontFeatureValuesRules)) { + return false; + } + } + + return true; +} + +CascadeLayerRuleProcessor::~CascadeLayerRuleProcessor() +{ + mCascade = nullptr; + if (mLayer) { + delete mLayer; + } + mLayer = nullptr; +} + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CascadeLayerRuleProcessor) + NS_INTERFACE_MAP_ENTRY(nsIStyleRuleProcessor) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(CascadeLayerRuleProcessor) +NS_IMPL_CYCLE_COLLECTING_RELEASE(CascadeLayerRuleProcessor) + +NS_IMPL_CYCLE_COLLECTION_CLASS(CascadeLayerRuleProcessor) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CascadeLayerRuleProcessor) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CascadeLayerRuleProcessor) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/layout/style/CascadeLayerRuleProcessor.h b/layout/style/CascadeLayerRuleProcessor.h new file mode 100644 index 0000000000..93f0d3e0ca --- /dev/null +++ b/layout/style/CascadeLayerRuleProcessor.h @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * style rule processor for cascade layers + */ + +#ifndef CascadeLayerRuleProcessor_h_ +#define CascadeLayerRuleProcessor_h_ + +#include "mozilla/Attributes.h" +#include "mozilla/EventStates.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/RefCountType.h" +#include "mozilla/SheetType.h" +#include "mozilla/UniquePtr.h" +#include "nsExpirationTracker.h" +#include "nsIMediaList.h" +#include "nsIStyleRuleProcessor.h" +#include "nsRuleWalker.h" +#include "nsTArray.h" + +struct AttributeEnumData; +struct CascadeEnumData; +struct RuleCascadeData; +struct ElementDependentRuleProcessorData; +struct nsFontFaceRuleContainer; +struct ResolvedRuleCascades; +class nsCSSKeyframesRule; +class nsCSSPageRule; +class nsCSSFontFeatureValuesRule; +class nsCSSCounterStyleRule; + +namespace mozilla { +class CSSStyleSheet; +enum class CSSPseudoElementType : uint8_t; +namespace css { +class DocumentRule; +} // namespace css +} // namespace mozilla + +/** + * The cascade layer rule processor handles rules collected by the CSS style + * rule processor within the context of a specific cascade layer. It ensures + * rules are applied in the correct order, as defined by the CSS specification. + * + * It also handles unlayered rules, which are treated as belonging to an + * implicit base layer. + */ + +class CascadeLayerRuleProcessor : public nsIStyleRuleProcessor +{ +public: + CascadeLayerRuleProcessor(CascadeEnumData* aLayer); + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(CascadeLayerRuleProcessor) + +public: + // nsIStyleRuleProcessor + virtual void RulesMatching(ElementRuleProcessorData* aData) override; + + virtual void RulesMatching(PseudoElementRuleProcessorData* aData) override; + + virtual void RulesMatching(AnonBoxRuleProcessorData* aData) override; + + virtual void RulesMatching(XULTreeRuleProcessorData* aData) override; + + virtual nsRestyleHint HasStateDependentStyle( + StateRuleProcessorData* aData) override; + virtual nsRestyleHint HasStateDependentStyle( + PseudoElementStateRuleProcessorData* aData) override; + + virtual bool HasDocumentStateDependentStyle( + StateRuleProcessorData* aData) override; + + virtual nsRestyleHint HasAttributeDependentStyle( + AttributeRuleProcessorData* aData, + mozilla::RestyleHintData& aRestyleHintDataResult) override; + + virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) override; + + virtual nsTArray>* GetChildRuleProcessors() + override; + + virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const + MOZ_MUST_OVERRIDE override; + virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const + MOZ_MUST_OVERRIDE override; + + // The following API methods are consumed by nsStyleSet. + + nsCSSKeyframesRule* KeyframesRuleForName(nsPresContext* aPresContext, + const nsString& aName); + + nsCSSCounterStyleRule* CounterStyleRuleForName(nsPresContext* aPresContext, + const nsAString& aName); + + bool AppendFontFaceRules(nsPresContext* aPresContext, + nsTArray& aArray); + + bool AppendPageRules(nsPresContext* aPresContext, + nsTArray& aArray); + + bool AppendFontFeatureValuesRules( + nsPresContext* aPresContext, + nsTArray& aArray); + + // The following API methods are consumed by nsCSSRuleProcessor only. + nsRestyleHint HasAttributeDependentStyle( + AttributeRuleProcessorData* aData, + AttributeEnumData* aEnumData, + mozilla::RestyleHintData& aRestyleHintDataResult); + + nsRestyleHint HasStateDependentStyle( + ElementDependentRuleProcessorData* aData, + mozilla::dom::Element* aStatefulElement, + mozilla::CSSPseudoElementType aPseudoType, + mozilla::EventStates aStateMask, + nsRestyleHint& aHint); + +protected: + virtual ~CascadeLayerRuleProcessor(); + + CascadeEnumData* mLayer; + RuleCascadeData* mCascade; + +private: + nsRestyleHint HasStateDependentStyle( + ElementDependentRuleProcessorData* aData, + mozilla::dom::Element* aStatefulElement, + mozilla::CSSPseudoElementType aPseudoType, + mozilla::EventStates aStateMask); +}; + +#endif /* CascadeLayerRuleProcessor_h_ */ diff --git a/layout/style/RuleCascadeData.cpp b/layout/style/RuleCascadeData.cpp index fb39141acc..c2e2151212 100644 --- a/layout/style/RuleCascadeData.cpp +++ b/layout/style/RuleCascadeData.cpp @@ -1188,6 +1188,13 @@ RuleCascadeData::HasAttributeDependentStyle( AttributeEnumData* aEnumData, mozilla::RestyleHintData& aRestyleHintDataResult) { + // Since we get both before and after notifications for attributes, we + // don't have to ignore aData->mAttribute while matching. Just check + // whether we have selectors relevant to aData->mAttribute that we + // match. If this is the before change notification, that will catch + // rules we might stop matching; if the after change notification, the + // ones we might have started matching. + if (aData->mAttribute == nsGkAtoms::id) { nsIAtom* id = aData->mElement->GetID(); if (id) { @@ -1475,10 +1482,10 @@ size_t ResolvedRuleCascades::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { size_t n = aMallocSizeOf(this); - n += mOrderedData.ShallowSizeOfExcludingThis(aMallocSizeOf); - for (RuleCascadeData* data : mOrderedData) { - n += data->SizeOfIncludingThis(aMallocSizeOf); + for (uint32_t i = 0; i < mProcessors.Length(); i++) { + n += mProcessors[i]->SizeOfIncludingThis(aMallocSizeOf); } + n += mProcessors.ShallowSizeOfExcludingThis(aMallocSizeOf); return n; } @@ -1553,7 +1560,6 @@ CascadeEnumData::CascadeEnumData(nsPresContext* aPresContext, #ifdef DEBUG CascadeEnumData* aParent, #endif - nsAutoPtr& aContainer, bool aIsWeak, nsTArray& aDocumentRules, nsDocumentRuleResultCacheKey& aDocumentKey, @@ -1569,7 +1575,6 @@ CascadeEnumData::CascadeEnumData(nsPresContext* aPresContext, , mParent(aParent) , mIsRoot(false) #endif - , mContainer(aContainer) , mDocumentRules(aDocumentRules) , mDocumentCacheKey(aDocumentKey) , mSheetType(aSheetType) @@ -1581,14 +1586,12 @@ CascadeEnumData::CascadeEnumData(nsPresContext* aPresContext, } CascadeEnumData::CascadeEnumData(nsPresContext* aPresContext, - nsAutoPtr& aContainer, nsTArray& aDocumentRules, nsDocumentRuleResultCacheKey& aDocumentKey, SheetType aSheetType, bool aMustGatherDocumentRules, nsMediaQueryResultCacheKey& aCacheKey) : mPresContext(aPresContext) - , mContainer(aContainer) , mIsAnonymous(false) , mIsWeak(false) , mWasFlattened(false) @@ -1608,6 +1611,7 @@ CascadeEnumData::CascadeEnumData(nsPresContext* aPresContext, CascadeEnumData::~CascadeEnumData() { + delete mData; PL_FinishArenaPool(&mArena); } @@ -1628,7 +1632,6 @@ CascadeEnumData::CreateNamedChildLayer(const nsTArray& aPath) #ifdef DEBUG this, #endif - mContainer, false, mDocumentRules, mDocumentCacheKey, @@ -1659,7 +1662,6 @@ CascadeEnumData::CreateAnonymousChildLayer() #ifdef DEBUG this, #endif - mContainer, false, mDocumentRules, mDocumentCacheKey, @@ -1751,7 +1753,7 @@ CascadeEnumData::AddRules() } void -CascadeEnumData::Flatten() +CascadeEnumData::EnumerateAllLayers(nsLayerEnumFunc aFunc, void* aData) { if (mWasFlattened) { return; @@ -1759,16 +1761,15 @@ CascadeEnumData::Flatten() if (mPreLayers.Length() > 0) { for (CascadeEnumData* pre : mPreLayers) { - pre->Flatten(); + pre->EnumerateAllLayers(aFunc, aData); } } - mContainer->mOrderedData.AppendElement(mData); - AddRules(); + (*aFunc)(this, aData); if (mPostLayers.Length() > 0) { for (CascadeEnumData* post : mPostLayers) { - post->Flatten(); + post->EnumerateAllLayers(aFunc, aData); } } diff --git a/layout/style/RuleCascadeData.h b/layout/style/RuleCascadeData.h index 75e035d970..04bbafa67d 100644 --- a/layout/style/RuleCascadeData.h +++ b/layout/style/RuleCascadeData.h @@ -325,21 +325,17 @@ private: struct ResolvedRuleCascades { ResolvedRuleCascades(nsIAtom* aMedium) - : mUnlayered(nullptr) - , mCacheKey(aMedium) + : mCacheKey(aMedium) , mNext(nullptr) { } ~ResolvedRuleCascades() { - for (RuleCascadeData* data : mOrderedData) { - delete data; - } + mProcessors.Clear(); } - nsTArray mOrderedData; - RuleCascadeData* mUnlayered; + nsTArray> mProcessors; nsMediaQueryResultCacheKey mCacheKey; ResolvedRuleCascades* mNext; // for a different medium @@ -353,7 +349,6 @@ struct CascadeEnumData #ifdef DEBUG CascadeEnumData* aParent, #endif - nsAutoPtr& aContainer, bool aIsWeak, nsTArray& aDocumentRules, nsDocumentRuleResultCacheKey& aDocumentKey, @@ -362,7 +357,6 @@ struct CascadeEnumData nsMediaQueryResultCacheKey& aCacheKey); CascadeEnumData(nsPresContext* aPresContext, - nsAutoPtr& aContainer, nsTArray& aDocumentRules, nsDocumentRuleResultCacheKey& aDocumentKey, SheetType aSheetType, @@ -395,18 +389,19 @@ struct CascadeEnumData CascadeEnumData* mParent; bool mIsRoot; #endif - nsAutoPtr& mContainer; nsTArray mPreLayers; nsTArray mPostLayers; nsDataHashtable mLayers; CascadeEnumData* CreateNamedChildLayer(const nsTArray& aPath); CascadeEnumData* CreateAnonymousChildLayer(); - void Flatten(); + + typedef void (*nsLayerEnumFunc)(CascadeEnumData* aLayer, void* aData); + void EnumerateAllLayers(nsLayerEnumFunc aFunc, void* aData); + void AddRules(); private: void Initialize(); - void AddRules(); static const PLDHashTableOps sRulesByWeightOps; }; diff --git a/layout/style/SVGAttrAnimationRuleProcessor.cpp b/layout/style/SVGAttrAnimationRuleProcessor.cpp index 9eb31b1b23..bc0954d45e 100644 --- a/layout/style/SVGAttrAnimationRuleProcessor.cpp +++ b/layout/style/SVGAttrAnimationRuleProcessor.cpp @@ -75,6 +75,12 @@ SVGAttrAnimationRuleProcessor::MediumFeaturesChanged(nsPresContext* aPresContext return false; } +/* virtual */ nsTArray>* +SVGAttrAnimationRuleProcessor::GetChildRuleProcessors() +{ + return nullptr; +} + /* virtual */ void SVGAttrAnimationRuleProcessor::RulesMatching(PseudoElementRuleProcessorData* aData) { diff --git a/layout/style/SVGAttrAnimationRuleProcessor.h b/layout/style/SVGAttrAnimationRuleProcessor.h index 1750c761bd..b52ad3a4f4 100644 --- a/layout/style/SVGAttrAnimationRuleProcessor.h +++ b/layout/style/SVGAttrAnimationRuleProcessor.h @@ -47,6 +47,8 @@ public: HasAttributeDependentStyle(AttributeRuleProcessorData* aData, RestyleHintData& aRestyleHintDataResult) override; virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) override; + virtual nsTArray>* GetChildRuleProcessors() + override; virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_MUST_OVERRIDE override; virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) diff --git a/layout/style/moz.build b/layout/style/moz.build index 61912a7bcb..3bda0e0507 100644 --- a/layout/style/moz.build +++ b/layout/style/moz.build @@ -24,6 +24,7 @@ TEST_DIRS += ['test'] EXPORTS += [ '!nsStyleStructList.h', 'AnimationCommon.h', + 'CascadeLayerRuleProcessor.h', 'CounterStyleManager.h', 'nsAnimationManager.h', 'nsComputedDOMStylePropertyList.h', @@ -121,6 +122,7 @@ EXPORTS.mozilla.css += [ UNIFIED_SOURCES += [ 'AnimationCollection.cpp', 'AnimationCommon.cpp', + 'CascadeLayerRuleProcessor.cpp', 'CounterStyleManager.cpp', 'CSS.cpp', 'CSSLexer.cpp', diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index b5913181a3..87e3664073 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -55,6 +55,7 @@ #include "nsIMozBrowserFrame.h" #include "RuleCascadeData.h" #include "nsCSSRuleUtils.h" +#include "CascadeLayerRuleProcessor.h" using namespace mozilla; using namespace mozilla::dom; @@ -146,39 +147,30 @@ nsCSSRuleProcessor::ClearSheets() /* virtual */ void nsCSSRuleProcessor::RulesMatching(ElementRuleProcessorData *aData) { - ResolvedRuleCascades* resolvedCascade = GetRuleCascade(aData->mPresContext); - - if (!resolvedCascade) { - return; - } - for (RuleCascadeData* cascade : resolvedCascade->mOrderedData) { - cascade->RulesMatching(aData); + if (ResolvedRuleCascades* cascades = GetRuleCascade(aData->mPresContext)) { + for (nsCOMPtr processor : cascades->mProcessors) { + processor->RulesMatching(aData); + } } } /* virtual */ void nsCSSRuleProcessor::RulesMatching(PseudoElementRuleProcessorData* aData) { - ResolvedRuleCascades* resolvedCascade = GetRuleCascade(aData->mPresContext); - - if (!resolvedCascade) { - return; - } - for (RuleCascadeData* cascade : resolvedCascade->mOrderedData) { - cascade->RulesMatching(aData); + if (ResolvedRuleCascades* cascades = GetRuleCascade(aData->mPresContext)) { + for (nsCOMPtr processor : cascades->mProcessors) { + processor->RulesMatching(aData); + } } } /* virtual */ void nsCSSRuleProcessor::RulesMatching(AnonBoxRuleProcessorData* aData) { - ResolvedRuleCascades* resolvedCascade = GetRuleCascade(aData->mPresContext); - - if (!resolvedCascade) { - return; - } - for (RuleCascadeData* cascade : resolvedCascade->mOrderedData) { - cascade->RulesMatching(aData); + if (ResolvedRuleCascades* cascades = GetRuleCascade(aData->mPresContext)) { + for (nsCOMPtr processor : cascades->mProcessors) { + processor->RulesMatching(aData); + } } } @@ -186,13 +178,10 @@ nsCSSRuleProcessor::RulesMatching(AnonBoxRuleProcessorData* aData) /* virtual */ void nsCSSRuleProcessor::RulesMatching(XULTreeRuleProcessorData* aData) { - ResolvedRuleCascades* resolvedCascade = GetRuleCascade(aData->mPresContext); - - if (!resolvedCascade) { - return; - } - for (RuleCascadeData* cascade : resolvedCascade->mOrderedData) { - cascade->RulesMatching(aData); + if (ResolvedRuleCascades* cascades = GetRuleCascade(aData->mPresContext)) { + for (nsCOMPtr processor : cascades->mProcessors) { + processor->RulesMatching(aData); + } } } #endif @@ -207,19 +196,19 @@ nsCSSRuleProcessor::HasStateDependentStyle(ElementDependentRuleProcessorData* aD "mCurrentStyleScope will need to be saved and restored after the " "SelectorMatchesTree call"); - ResolvedRuleCascades* resolvedCascade = GetRuleCascade(aData->mPresContext); - nsRestyleHint hint = nsRestyleHint(0); - if (resolvedCascade) { - for (RuleCascadeData* cascade : resolvedCascade->mOrderedData) { - cascade->HasStateDependentStyle( + if (ResolvedRuleCascades* cascades = GetRuleCascade(aData->mPresContext)) { + for (nsCOMPtr processor : cascades->mProcessors) { + CascadeLayerRuleProcessor* layerProcessor = + static_cast(processor.get()); + layerProcessor->HasStateDependentStyle( aData, aStatefulElement, aPseudoType, aStateMask, hint); } } return hint; } -nsRestyleHint +/* virtual */ nsRestyleHint nsCSSRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData) { return HasStateDependentStyle(aData, @@ -228,7 +217,7 @@ nsCSSRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData) aData->mStateMask); } -nsRestyleHint +/* virtual */ nsRestyleHint nsCSSRuleProcessor::HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData) { return HasStateDependentStyle(aData, @@ -237,15 +226,12 @@ nsCSSRuleProcessor::HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData->mStateMask); } -bool +/* virtual */ bool nsCSSRuleProcessor::HasDocumentStateDependentStyle(StateRuleProcessorData* aData) { - ResolvedRuleCascades* resolvedCascade = GetRuleCascade(aData->mPresContext); - - if (resolvedCascade) { - for (RuleCascadeData* cascade : resolvedCascade->mOrderedData) { - if (cascade->mSelectorDocumentStates.HasAtLeastOneOfStates( - aData->mStateMask)) { + if (ResolvedRuleCascades* cascades = GetRuleCascade(aData->mPresContext)) { + for (nsCOMPtr processor : cascades->mProcessors) { + if (processor->HasDocumentStateDependentStyle(aData)) { return true; } } @@ -259,47 +245,15 @@ nsCSSRuleProcessor::HasAttributeDependentStyle( AttributeRuleProcessorData* aData, RestyleHintData& aRestyleHintDataResult) { - // We could try making use of aData->mModType, but :not rules make it a bit - // of a pain to do so... So just ignore it for now. - AttributeEnumData data(aData, aRestyleHintDataResult); - - // Don't do our special handling of certain attributes if the attr - // hasn't changed yet. - if (aData->mAttrHasChanged) { - // check for the lwtheme and lwthemetextcolor attribute on root XUL elements - if ((aData->mAttribute == nsGkAtoms::lwtheme || - aData->mAttribute == nsGkAtoms::lwthemetextcolor) && - aData->mElement->GetNameSpaceID() == kNameSpaceID_XUL && - aData->mElement == aData->mElement->OwnerDoc()->GetRootElement()) - { - data.change = nsRestyleHint(data.change | eRestyle_Subtree); - } - - // We don't know the namespace of the attribute, and xml:lang applies to - // all elements. If the lang attribute changes, we need to restyle our - // whole subtree, since the :lang selector on our descendants can examine - // our lang attribute. - if (aData->mAttribute == nsGkAtoms::lang) { - data.change = nsRestyleHint(data.change | eRestyle_Subtree); - } - } - - ResolvedRuleCascades* resolvedCascade = GetRuleCascade(aData->mPresContext); - - // Since we get both before and after notifications for attributes, we - // don't have to ignore aData->mAttribute while matching. Just check - // whether we have selectors relevant to aData->mAttribute that we - // match. If this is the before change notification, that will catch - // rules we might stop matching; if the after change notification, the - // ones we might have started matching. - if (resolvedCascade) { - for (RuleCascadeData* cascade : resolvedCascade->mOrderedData) { - cascade->HasAttributeDependentStyle( + if (ResolvedRuleCascades* cascades = GetRuleCascade(aData->mPresContext)) { + for (nsCOMPtr processor : cascades->mProcessors) { + CascadeLayerRuleProcessor* layerProcessor = + static_cast(processor.get()); + layerProcessor->HasAttributeDependentStyle( aData, &data, aRestyleHintDataResult); } } - return data.change; } @@ -341,13 +295,21 @@ nsCSSRuleProcessor::MediumFeaturesChanged(nsPresContext* aPresContext) return false; } +/* virtual */ nsTArray>* +nsCSSRuleProcessor::GetChildRuleProcessors() +{ + return mRuleCascades + ? &mRuleCascades->mProcessors + : nullptr; +} + UniquePtr nsCSSRuleProcessor::CloneMQCacheKey() { MOZ_ASSERT(!(mRuleCascades && mPreviousCacheKey)); ResolvedRuleCascades* c = mRuleCascades; - if (!c || !c->mUnlayered) { + if (!c) { // We might have an mPreviousCacheKey. It already comes from a call // to CloneMQCacheKey, so don't bother checking // HasFeatureConditions(). @@ -373,9 +335,9 @@ nsCSSRuleProcessor::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { size_t n = 0; n += mSheets.ShallowSizeOfExcludingThis(aMallocSizeOf); - for (ResolvedRuleCascades* cascade = mRuleCascades; cascade; - cascade = cascade->mNext) { - n += cascade->SizeOfIncludingThis(aMallocSizeOf); + for (ResolvedRuleCascades* cascades = mRuleCascades; cascades; + cascades = cascades->mNext) { + n += cascades->SizeOfIncludingThis(aMallocSizeOf); } return n; @@ -387,18 +349,16 @@ nsCSSRuleProcessor::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } -// Append all the currently-active font face rules to aArray. Return -// true for success and false for failure. bool nsCSSRuleProcessor::AppendFontFaceRules( nsPresContext *aPresContext, nsTArray& aArray) { - ResolvedRuleCascades* resolvedCascade = GetRuleCascade(aPresContext); - - if (resolvedCascade) { - for (RuleCascadeData* cascade : resolvedCascade->mOrderedData) { - if (!aArray.AppendElements(cascade->mFontFaceRules)) { + if (ResolvedRuleCascades* cascades = GetRuleCascade(aPresContext)) { + for (nsCOMPtr processor : cascades->mProcessors) { + CascadeLayerRuleProcessor* layerProcessor = + static_cast(processor.get()); + if (!layerProcessor->AppendFontFaceRules(aPresContext, aArray)) { return false; } } @@ -411,13 +371,14 @@ nsCSSKeyframesRule* nsCSSRuleProcessor::KeyframesRuleForName(nsPresContext* aPresContext, const nsString& aName) { - ResolvedRuleCascades* resolvedCascade = GetRuleCascade(aPresContext); - nsCSSKeyframesRule* rule = nullptr; - if (resolvedCascade) { - for (RuleCascadeData* cascade : resolvedCascade->mOrderedData) { + + if (ResolvedRuleCascades* cascades = GetRuleCascade(aPresContext)) { + for (nsCOMPtr processor : cascades->mProcessors) { + CascadeLayerRuleProcessor* layerProcessor = + static_cast(processor.get()); if (nsCSSKeyframesRule* newRule = - cascade->mKeyframesRuleTable.Get(aName)) { + layerProcessor->KeyframesRuleForName(aPresContext, aName)) { rule = newRule; } } @@ -430,13 +391,13 @@ nsCSSCounterStyleRule* nsCSSRuleProcessor::CounterStyleRuleForName(nsPresContext* aPresContext, const nsAString& aName) { - ResolvedRuleCascades* resolvedCascade = GetRuleCascade(aPresContext); - nsCSSCounterStyleRule* rule = nullptr; - if (resolvedCascade) { - for (RuleCascadeData* cascade : resolvedCascade->mOrderedData) { + if (ResolvedRuleCascades* cascades = GetRuleCascade(aPresContext)) { + for (nsCOMPtr processor : cascades->mProcessors) { + CascadeLayerRuleProcessor* layerProcessor = + static_cast(processor.get()); if (nsCSSCounterStyleRule* newRule = - cascade->mCounterStyleRuleTable.Get(aName)) { + layerProcessor->CounterStyleRuleForName(aPresContext, aName)) { rule = newRule; } } @@ -445,18 +406,16 @@ nsCSSRuleProcessor::CounterStyleRuleForName(nsPresContext* aPresContext, return rule; } -// Append all the currently-active page rules to aArray. Return -// true for success and false for failure. bool nsCSSRuleProcessor::AppendPageRules( nsPresContext* aPresContext, nsTArray& aArray) { - ResolvedRuleCascades* resolvedCascade = GetRuleCascade(aPresContext); - - if (resolvedCascade) { - for (RuleCascadeData* cascade : resolvedCascade->mOrderedData) { - if (!aArray.AppendElements(cascade->mPageRules)) { + if (ResolvedRuleCascades* cascades = GetRuleCascade(aPresContext)) { + for (nsCOMPtr processor : cascades->mProcessors) { + CascadeLayerRuleProcessor* layerProcessor = + static_cast(processor.get()); + if (!layerProcessor->AppendPageRules(aPresContext, aArray)) { return false; } } @@ -470,11 +429,11 @@ nsCSSRuleProcessor::AppendFontFeatureValuesRules( nsPresContext *aPresContext, nsTArray& aArray) { - ResolvedRuleCascades* resolvedCascade = GetRuleCascade(aPresContext); - - if (resolvedCascade) { - for (RuleCascadeData* cascade : resolvedCascade->mOrderedData) { - if (!aArray.AppendElements(cascade->mFontFeatureValuesRules)) { + if (ResolvedRuleCascades* cascades = GetRuleCascade(aPresContext)) { + for (nsCOMPtr processor : cascades->mProcessors) { + CascadeLayerRuleProcessor* layerProcessor = + static_cast(processor.get()); + if (!layerProcessor->AppendFontFeatureValuesRules(aPresContext, aArray)) { return false; } } @@ -733,6 +692,19 @@ nsCSSRuleProcessor::GetRuleCascade(nsPresContext* aPresContext) return mRuleCascades; } +/** + * This enumerates layers in a sheet and creates child rule processors + * for each layer. The child rule processors are created in the order + * that the layers are encountered. + */ +static void +CreateChildProcessorsEnumFunc(CascadeEnumData* aLayer, void* aData) +{ + aLayer->AddRules(); + ResolvedRuleCascades* data = static_cast(aData); + data->mProcessors.AppendElement(new CascadeLayerRuleProcessor(aLayer)); +} + void nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext) { @@ -760,24 +732,26 @@ nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext) mPreviousCacheKey = nullptr; if (mSheets.Length() != 0) { - nsAutoPtr resolvedCascade( + nsAutoPtr cascades( new ResolvedRuleCascades(aPresContext->Medium())); - CascadeEnumData unlayered(aPresContext, - resolvedCascade, - mDocumentRules, - mDocumentCacheKey, - mSheetType, - mMustGatherDocumentRules, - resolvedCascade->mCacheKey); - if (unlayered.mData) { + CascadeEnumData* unlayered(new CascadeEnumData(aPresContext, + mDocumentRules, + mDocumentCacheKey, + mSheetType, + mMustGatherDocumentRules, + cascades->mCacheKey)); + if (unlayered->mData) { for (uint32_t i = 0; i < mSheets.Length(); ++i) { - if (!CascadeSheet(mSheets.ElementAt(i), &unlayered)) { + if (!CascadeSheet(mSheets.ElementAt(i), unlayered)) { return; /* out of memory */ } } - unlayered.Flatten(); - resolvedCascade->mUnlayered = unlayered.mData; + // Ensure that the current one is always mRuleCascades. + cascades->mNext = mRuleCascades; + mRuleCascades = cascades.forget(); + + unlayered->EnumerateAllLayers(CreateChildProcessorsEnumFunc, mRuleCascades); // mMustGatherDocumentRules controls whether we build mDocumentRules // and mDocumentCacheKey so that they can be used as keys by the @@ -812,10 +786,6 @@ nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext) mDocumentRulesAndCacheKeyValid = true; #endif } - - // Ensure that the current one is always mRuleCascades. - resolvedCascade->mNext = mRuleCascades; - mRuleCascades = resolvedCascade.forget(); } } return; diff --git a/layout/style/nsCSSRuleProcessor.h b/layout/style/nsCSSRuleProcessor.h index 4d5efe00b9..92f0c42962 100644 --- a/layout/style/nsCSSRuleProcessor.h +++ b/layout/style/nsCSSRuleProcessor.h @@ -51,7 +51,7 @@ class DocumentRule; * is told when the rule processor is going away (via DropRuleProcessor). */ -class nsCSSRuleProcessor: public nsIStyleRuleProcessor { +class nsCSSRuleProcessor : public nsIStyleRuleProcessor { public: typedef nsTArray> sheet_array_type; @@ -99,6 +99,9 @@ public: virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) override; + virtual nsTArray>* GetChildRuleProcessors() + override; + /** * If this rule processor currently has a substantive media query * result cache key, return a copy of it. diff --git a/layout/style/nsHTMLCSSStyleSheet.cpp b/layout/style/nsHTMLCSSStyleSheet.cpp index 0246d6651a..cf27de3434 100644 --- a/layout/style/nsHTMLCSSStyleSheet.cpp +++ b/layout/style/nsHTMLCSSStyleSheet.cpp @@ -162,6 +162,12 @@ nsHTMLCSSStyleSheet::MediumFeaturesChanged(nsPresContext* aPresContext) return false; } +/* virtual */ nsTArray>* +nsHTMLCSSStyleSheet::GetChildRuleProcessors() +{ + return nullptr; +} + /* virtual */ size_t nsHTMLCSSStyleSheet::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { diff --git a/layout/style/nsHTMLCSSStyleSheet.h b/layout/style/nsHTMLCSSStyleSheet.h index 2b7ea7ae83..fd3bf58f28 100644 --- a/layout/style/nsHTMLCSSStyleSheet.h +++ b/layout/style/nsHTMLCSSStyleSheet.h @@ -47,6 +47,8 @@ public: HasAttributeDependentStyle(AttributeRuleProcessorData* aData, mozilla::RestyleHintData& aRestyleHintDataResult) override; virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) override; + virtual nsTArray>* GetChildRuleProcessors() + override; virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_MUST_OVERRIDE override; virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) diff --git a/layout/style/nsHTMLStyleSheet.cpp b/layout/style/nsHTMLStyleSheet.cpp index 053e74b8e0..0fdf6b3ab0 100644 --- a/layout/style/nsHTMLStyleSheet.cpp +++ b/layout/style/nsHTMLStyleSheet.cpp @@ -439,6 +439,12 @@ nsHTMLStyleSheet::MediumFeaturesChanged(nsPresContext* aPresContext) return false; } +/* virtual */ nsTArray>* +nsHTMLStyleSheet::GetChildRuleProcessors() +{ + return nullptr; +} + /* virtual */ size_t nsHTMLStyleSheet::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { diff --git a/layout/style/nsHTMLStyleSheet.h b/layout/style/nsHTMLStyleSheet.h index a522fc3b41..aeebec280e 100644 --- a/layout/style/nsHTMLStyleSheet.h +++ b/layout/style/nsHTMLStyleSheet.h @@ -47,6 +47,8 @@ public: HasAttributeDependentStyle(AttributeRuleProcessorData* aData, mozilla::RestyleHintData& aRestyleHintDataResult) override; virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) override; + virtual nsTArray>* GetChildRuleProcessors() + override; virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_MUST_OVERRIDE override; virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) diff --git a/layout/style/nsIStyleRuleProcessor.h b/layout/style/nsIStyleRuleProcessor.h index 2075050d40..5d5bc8c7c7 100644 --- a/layout/style/nsIStyleRuleProcessor.h +++ b/layout/style/nsIStyleRuleProcessor.h @@ -126,6 +126,13 @@ public: */ virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) = 0; + /** + * Returns an array of style rule processors if this origin supports + * cascade layers. The array will contain the rule processors for each + * layer in the order in which they should be applied. + */ + virtual nsTArray>* GetChildRuleProcessors() = 0; + /** * Report the size of this style rule processor to about:memory. A * processor may return 0.