/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */ /* * the container for the style sheets that apply to a presentation, and * the internal API that the style system exposes for creating (and * potentially re-creating) style contexts */ #ifndef nsStyleSet_h_ #define nsStyleSet_h_ #include "mozilla/AtomArray.h" #include "mozilla/Attributes.h" #include "mozilla/StyleSheetInlines.h" #include "mozilla/EnumeratedArray.h" #include "mozilla/LinkedList.h" #include "mozilla/MemoryReporting.h" #include "mozilla/ServoTypes.h" #include "mozilla/SheetType.h" #include "nsIStyleRuleProcessor.h" #include "nsBindingManager.h" #include "nsRuleNode.h" #include "nsTArray.h" #include "nsCOMArray.h" #include "nsIStyleRule.h" #include "nsCSSAnonBoxes.h" class gfxFontFeatureValueSet; class nsCSSKeyframesRule; class nsCSSFontFeatureValuesRule; class nsCSSPageRule; class nsCSSCounterStyleRule; class nsICSSPseudoComparator; class nsRuleWalker; struct ElementDependentRuleProcessorData; struct nsFontFaceRuleContainer; struct TreeMatchContext; namespace mozilla { class CSSStyleSheet; enum class CSSPseudoElementType : uint8_t; class EventStates; namespace dom { class ShadowRoot; } // namespace dom } // namespace mozilla class nsEmptyStyleRule final : public nsIStyleRule { private: ~nsEmptyStyleRule() {} public: NS_DECL_ISUPPORTS virtual void MapRuleInfoInto(nsRuleData* aRuleData) override; virtual bool MightMapInheritedStyleData() override; virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty, nsCSSValue* aValue) override; #ifdef DEBUG virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override; #endif }; class nsInitialStyleRule final : public nsIStyleRule { private: ~nsInitialStyleRule() {} public: NS_DECL_ISUPPORTS virtual void MapRuleInfoInto(nsRuleData* aRuleData) override; virtual bool MightMapInheritedStyleData() override; virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty, nsCSSValue* aValue) override; #ifdef DEBUG virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override; #endif }; class nsDisableTextZoomStyleRule final : public nsIStyleRule { private: ~nsDisableTextZoomStyleRule() {} public: NS_DECL_ISUPPORTS virtual void MapRuleInfoInto(nsRuleData* aRuleData) override; virtual bool MightMapInheritedStyleData() override; virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty, nsCSSValue* aValue) override; #ifdef DEBUG virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override; #endif }; // The style set object is created by the document viewer and ownership is // then handed off to the PresShell. Only the PresShell should delete a // style set. class nsStyleSet final { public: nsStyleSet(); ~nsStyleSet(); void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const; void Init(nsPresContext* aPresContext); nsRuleNode* GetRuleTree() { return mRuleTree; } // get a style context for a non-pseudo frame. already_AddRefed ResolveStyleFor(mozilla::dom::Element* aElement, mozilla::GeckoStyleContext* aParentContext); already_AddRefed ResolveStyleFor(mozilla::dom::Element* aElement, mozilla::GeckoStyleContext* aParentContext, mozilla::LazyComputeBehavior) { return ResolveStyleFor(aElement, aParentContext); } already_AddRefed ResolveCleanStyleFor(mozilla::dom::Element* aElement, mozilla::GeckoStyleContext* aParentContext, mozilla::LazyComputeBehavior) { return ResolveStyleFor(aElement, aParentContext); } already_AddRefed ResolveStyleFor(mozilla::dom::Element* aElement, mozilla::GeckoStyleContext* aParentContext, TreeMatchContext& aTreeMatchContext); already_AddRefed ResolveStyleFor(mozilla::dom::Element* aElement, mozilla::GeckoStyleContext* aParentContext, mozilla::LazyComputeBehavior aMayCompute, TreeMatchContext& aTreeMatchContext) { return ResolveStyleFor(aElement, aParentContext, aTreeMatchContext); } // Get a style context (with the given parent) for the // sequence of style rules in the |aRules| array. already_AddRefed ResolveStyleForRules(mozilla::GeckoStyleContext* aParentContext, const nsTArray< nsCOMPtr > &aRules); // Get a style context that represents aBaseContext, but as though // it additionally matched the rules in the aRules array (in that // order, as more specific than any other rules). // // One of the following must hold: // 1. The resulting style context must be used only on a temporary // basis, and it must never be put into the style context tree // (and, in particular, we must never call // ResolveStyleWithReplacement with it as the old context, which // might happen if it is put in the style context tree), or // 2. The additional rules must be appropriate for the transitions // level of the cascade, which is the highest level of the cascade. // (This is the case for one current caller, the cover rule used // for CSS transitions.) already_AddRefed ResolveStyleByAddingRules(mozilla::GeckoStyleContext* aBaseContext, const nsCOMArray &aRules); // Resolve style by making replacements in the list of style rules as // described by aReplacements, but otherwise maintaining the status // quo. // aPseudoElement must follow the same rules as for // ResolvePseudoElementStyle, and be null for non-pseudo-element cases enum { // flags for aFlags // Skip starting CSS animations that result from the style. eSkipStartingAnimations = (1<<0), }; already_AddRefed ResolveStyleWithReplacement(mozilla::dom::Element* aElement, mozilla::dom::Element* aPseudoElement, mozilla::GeckoStyleContext* aNewParentContext, mozilla::GeckoStyleContext* aOldStyleContext, nsRestyleHint aReplacements, uint32_t aFlags = 0); // Resolve style by returning a style context with the specified // animation data removed. It is allowable to remove all animation // data with eRestyle_AllHintsWithAnimations, or by using any other // hints that are allowed by ResolveStyleWithReplacement. already_AddRefed ResolveStyleByRemovingAnimation(mozilla::dom::Element* aElement, mozilla::GeckoStyleContext* aStyleContext, nsRestyleHint aWhichToRemove); // Similar to the above, but resolving style without all animation data in // the first place. already_AddRefed ResolveStyleWithoutAnimation(mozilla::dom::Element* aTarget, mozilla::GeckoStyleContext* aParentContext); // Pseudo-element version of the above, ResolveStyleWithoutAnimation. already_AddRefed ResolvePseudoElementStyleWithoutAnimation( mozilla::dom::Element* aParentElement, mozilla::CSSPseudoElementType aType, mozilla::GeckoStyleContext* aParentContext, mozilla::dom::Element* aPseudoElement); // Get a style context for a text node (which no rules will match). // // The returned style context will have nsCSSAnonBoxes::mozText as its pseudo. // // (Perhaps mozText should go away and we shouldn't even create style // contexts for such content nodes, when text-combine-upright is not // present. However, not doing any rule matching for them is a first step.) already_AddRefed ResolveStyleForText(nsIContent* aTextNode, mozilla::GeckoStyleContext* aParentContext); // Get a style context for a first-letter continuation (which no rules will // match). // // The returned style context will have // nsCSSAnonBoxes::firstLetterContinuation as its pseudo. // // (Perhaps nsCSSAnonBoxes::firstLetterContinuation should go away and we // shouldn't even create style contexts for such frames. However, not doing // any rule matching for them is a first step. And right now we do use this // style context for some things) already_AddRefed ResolveStyleForFirstLetterContinuation(mozilla::GeckoStyleContext* aParentContext); // Get a style context for a placeholder frame (which no rules will match). // // The returned style context will have nsCSSAnonBoxes::oofPlaceholder as // its pseudo. // // (Perhaps nsCSSAnonBoxes::oofPlaceholder should go away and we shouldn't // even create style contexts for placeholders. However, not doing any rule // matching for them is a first step.) already_AddRefed ResolveStyleForPlaceholder(); // Get a style context for a pseudo-element. aParentElement must be // non-null. aPseudoID is the CSSPseudoElementType for the // pseudo-element. aPseudoElement must be non-null if the pseudo-element // type is one that allows user action pseudo-classes after it or allows // style attributes; otherwise, it is ignored. already_AddRefed ResolvePseudoElementStyle(mozilla::dom::Element* aParentElement, mozilla::CSSPseudoElementType aType, mozilla::GeckoStyleContext* aParentContext, mozilla::dom::Element* aPseudoElement); // This functions just like ResolvePseudoElementStyle except that it will // return nullptr if there are no explicit style rules for that // pseudo element. already_AddRefed ProbePseudoElementStyle(mozilla::dom::Element* aParentElement, mozilla::CSSPseudoElementType aType, mozilla::GeckoStyleContext* aParentContext); already_AddRefed ProbePseudoElementStyle(mozilla::dom::Element* aParentElement, mozilla::CSSPseudoElementType aType, mozilla::GeckoStyleContext* aParentContext, TreeMatchContext& aTreeMatchContext); /** * Bit-flags that can be passed to GetContext in its parameter 'aFlags'. */ enum { eNoFlags = 0, eIsLink = 1 << 0, eIsVisitedLink = 1 << 1, eDoAnimation = 1 << 2, // Indicates that we should skip the flex/grid item specific chunk of // ApplyStyleFixups(). This is useful if our parent has "display: flex" // or "display: grid" but we can tell we're not going to honor that (e.g. if // it's the outer frame of a button widget, and we're the inline frame for // the button's label). eSkipParentDisplayBasedStyleFixup = 1 << 3 }; // Get a style context for an anonymous box. aPseudoTag is the pseudo-tag to // use and must be non-null. It must be an anon box, and must be one that // inherits style from the given aParentContext. already_AddRefed ResolveInheritingAnonymousBoxStyle(nsAtom* aPseudoTag, mozilla::GeckoStyleContext* aParentContext); // Get a style context for an anonymous box that does not inherit style from // anything. aPseudoTag is the pseudo-tag to use and must be non-null. It // must be an anon box, and must be a non-inheriting one. already_AddRefed ResolveNonInheritingAnonymousBoxStyle(nsAtom* aPseudoTag); #ifdef MOZ_XUL // Get a style context for a XUL tree pseudo. aPseudoTag is the // pseudo-tag to use and must be non-null. aParentContent must be // non-null. already_AddRefed ResolveXULTreePseudoStyle(mozilla::dom::Element* aParentElement, nsICSSAnonBoxPseudo* aPseudoTag, mozilla::GeckoStyleContext* aParentContext, const mozilla::AtomArray& aInputWord); #endif // Append all the currently-active font face rules to aArray. Return // true for success and false for failure. bool AppendFontFaceRules(nsTArray& aArray); // Return the winning (in the cascade) @keyframes rule for the given name. nsCSSKeyframesRule* KeyframesRuleForName(nsAtom* aName); // Return the winning (in the cascade) @counter-style rule for the given name. nsCSSCounterStyleRule* CounterStyleRuleForName(nsAtom* aName); // Return gfxFontFeatureValueSet from font feature values rules. already_AddRefed BuildFontFeatureValueSet(); // Append all the currently-active font feature values rules to aArray. // Return true for success and false for failure. bool AppendFontFeatureValuesRules( nsTArray& aArray); // Append all the currently-active page rules to aArray. Return // true for success and false for failure. bool AppendPageRules(nsTArray& aArray); // Begin ignoring style context destruction, to avoid lots of unnecessary // work on document teardown. void BeginShutdown(); // Free all of the data associated with this style set. void Shutdown(); void RuleAdded(mozilla::CSSStyleSheet& aSheet, mozilla::css::Rule&) { SheetChanged(aSheet); } void RuleRemoved(mozilla::CSSStyleSheet& aSheet, mozilla::css::Rule&) { SheetChanged(aSheet); } void RuleChanged(mozilla::CSSStyleSheet& aSheet, mozilla::css::Rule*) { SheetChanged(aSheet); } // Notes that a style sheet has changed. void RecordStyleSheetChange(mozilla::CSSStyleSheet* aSheet, mozilla::StyleSheet::ChangeType) { SheetChanged(*aSheet); } void SheetChanged(mozilla::CSSStyleSheet&); // Notes that style sheets have changed in a shadow root. void RecordShadowStyleChange(mozilla::dom::ShadowRoot* aShadowRoot); bool StyleSheetsHaveChanged() const { return mStylesHaveChanged || !mChangedScopeStyleRoots.IsEmpty(); } void InvalidateStyleForCSSRuleChanges(); // Get a new style context that lives in a different parent // The new context will be the same as the old if the new parent is the // same as the old parent. // aElement should be non-null if this is a style context for an // element or pseudo-element; in the latter case it should be the // real element the pseudo-element is for. already_AddRefed ReparentStyleContext(mozilla::GeckoStyleContext* aStyleContext, mozilla::GeckoStyleContext* aNewParentContext, mozilla::dom::Element* aElement); // Test if style is dependent on a document state. bool HasDocumentStateDependentStyle(nsIContent* aContent, mozilla::EventStates aStateMask); // Test if style is dependent on content state nsRestyleHint HasStateDependentStyle(mozilla::dom::Element* aElement, mozilla::EventStates aStateMask); nsRestyleHint HasStateDependentStyle(mozilla::dom::Element* aElement, mozilla::CSSPseudoElementType aPseudoType, mozilla::dom::Element* aPseudoElement, mozilla::EventStates aStateMask); // Test if style is dependent on the presence of an attribute. nsRestyleHint HasAttributeDependentStyle(mozilla::dom::Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute, int32_t aModType, bool aAttrHasChanged, const nsAttrValue* aOtherValue, mozilla::RestyleHintData& aRestyleHintDataResult); /* * Do any processing that needs to happen as a result of a change in * the characteristics of the medium, and return restyle hint needed * for the change. */ nsRestyleHint MediumFeaturesChanged(bool aViewportChanged); // APIs to manipulate the style sheet lists. The sheets in each // list are stored with the most significant sheet last. nsresult AppendStyleSheet(mozilla::SheetType aType, mozilla::CSSStyleSheet* aSheet); nsresult PrependStyleSheet(mozilla::SheetType aType, mozilla::CSSStyleSheet* aSheet); nsresult RemoveStyleSheet(mozilla::SheetType aType, mozilla::CSSStyleSheet* aSheet); nsresult ReplaceSheets(mozilla::SheetType aType, const nsTArray>& aNewSheets); nsresult InsertStyleSheetBefore(mozilla::SheetType aType, mozilla::CSSStyleSheet* aNewSheet, mozilla::CSSStyleSheet* aReferenceSheet); // Enable/Disable entire author style level (Doc, ScopedDoc & PresHint levels) bool GetAuthorStyleDisabled() const; nsresult SetAuthorStyleDisabled(bool aStyleDisabled); int32_t SheetCount(mozilla::SheetType aType) const { return mSheets[aType].Length(); } mozilla::CSSStyleSheet* StyleSheetAt(mozilla::SheetType aType, int32_t aIndex) const { return mSheets[aType][aIndex]; } void AppendAllXBLStyleSheets(nsTArray& aArray) const; nsresult RemoveDocStyleSheet(mozilla::CSSStyleSheet* aSheet); nsresult AddDocStyleSheet(mozilla::CSSStyleSheet* aSheet, nsIDocument* aDocument); void BeginUpdate(); nsresult EndUpdate(); // Methods for reconstructing the tree; BeginReconstruct basically moves the // old rule tree root and style context roots out of the way, // and EndReconstruct destroys the old rule tree when we're done nsresult BeginReconstruct(); // Note: EndReconstruct should not be called if BeginReconstruct fails void EndReconstruct(); bool IsInRuleTreeReconstruct() const { return mInReconstruct; } void RootStyleContextAdded() { ++mRootStyleContextCount; } void RootStyleContextRemoved() { MOZ_ASSERT(mRootStyleContextCount > 0); --mRootStyleContextCount; } // Return whether the rule tree has cached data such that we need to // do dynamic change handling for changes that change the results of // media queries or require rebuilding all style data. // We don't care whether we have cached rule processors or whether // they have cached rule cascades; getting the rule cascades again in // order to do rule matching will get the correct rule cascade. bool HasCachedStyleData() const { return (mRuleTree && mRuleTree->TreeHasCachedData()) || mRootStyleContextCount > 0; } // Notify the style set that a rulenode is no longer in use, or was // just created and is not in use yet. static const uint32_t kGCInterval = 300; void RuleNodeUnused(nsRuleNode* aNode, bool aMayGC) { ++mUnusedRuleNodeCount; mUnusedRuleNodeList.insertBack(aNode); if (aMayGC && mUnusedRuleNodeCount >= kGCInterval && !mInGC && !mInReconstruct) { GCRuleTrees(); } } // Notify the style set that a rulenode that wasn't in use now is void RuleNodeInUse(nsRuleNode* aNode) { MOZ_ASSERT(mUnusedRuleNodeCount > 0); --mUnusedRuleNodeCount; aNode->removeFrom(mUnusedRuleNodeList); } // Returns true if a restyle of the document is needed due to cloning // sheet inners. bool EnsureUniqueInnerOnCSSSheets(); // Called by StyleSheet::EnsureUniqueInner to let us know it cloned // its inner. void SetNeedsRestyleAfterEnsureUniqueInner() { mNeedsRestyleAfterEnsureUniqueInner = true; } nsIStyleRule* InitialStyleRule(); bool HasRuleProcessorUsedByMultipleStyleSets(mozilla::SheetType aSheetType); // Tells the RestyleManager for the document using this style set // to drop any nsCSSSelector pointers it has. void ClearSelectors(); void SetUsesViewportUnits(bool aValue) { mUsesViewportUnits = aValue; } private: nsStyleSet(const nsStyleSet& aCopy) = delete; nsStyleSet& operator=(const nsStyleSet& aCopy) = delete; // Free all the rules with reference-count zero. This continues iterating // over the free list until it is empty, which allows immediate collection // of nodes whose reference-count drops to zero during the destruction of // a child node. This allows the collection of entire trees at once, since // children hold their parents alive. void GCRuleTrees(); nsresult DirtyRuleProcessors(mozilla::SheetType aType); // Update the rule processor list after a change to the style sheet list. nsresult GatherRuleProcessors(mozilla::SheetType aType); void AddImportantRules(nsRuleNode* aCurrLevelNode, nsRuleNode* aLastPrevLevelNode, nsRuleWalker* aRuleWalker); // Move aRuleWalker forward by the appropriate rule if we need to add // a rule due to property restrictions on pseudo-elements. void WalkRestrictionRule(mozilla::CSSPseudoElementType aPseudoType, nsRuleWalker* aRuleWalker); void WalkDisableTextZoomRule(mozilla::dom::Element* aElement, nsRuleWalker* aRuleWalker); #ifdef DEBUG // Just like AddImportantRules except it doesn't actually add anything; it // just asserts that there are no important rules between aCurrLevelNode and // aLastPrevLevelNode. void AssertNoImportantRules(nsRuleNode* aCurrLevelNode, nsRuleNode* aLastPrevLevelNode); // Just like AddImportantRules except it doesn't actually add anything; it // just asserts that there are no CSS rules between aCurrLevelNode and // aLastPrevLevelNode. Mostly useful for the preshint level. void AssertNoCSSRules(nsRuleNode* aCurrLevelNode, nsRuleNode* aLastPrevLevelNode); #endif // Enumerate the rules in a way that cares about the order of the // rules. // aElement is the element the rules are for. It might be null. aData // is the closure to pass to aCollectorFunc. If aContent is not null, // aData must be a RuleProcessorData* void FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc, RuleProcessorData* aData, mozilla::dom::Element* aElement, nsRuleWalker* aRuleWalker); // Enumerate all the rules in a way that doesn't care about the order // of the rules and break out if the enumeration is halted. void WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc, ElementDependentRuleProcessorData* aData, bool aWalkAllXBLStylesheets); // Helper for ResolveStyleWithReplacement // aPseudoElement must follow the same rules as for // ResolvePseudoElementStyle, and be null for non-pseudo-element cases nsRuleNode* RuleNodeWithReplacement(mozilla::dom::Element* aElement, mozilla::dom::Element* aPseudoElement, nsRuleNode* aOldRuleNode, mozilla::CSSPseudoElementType aPseudoType, nsRestyleHint aReplacements); already_AddRefed GetContext(mozilla::GeckoStyleContext* aParentContext, nsRuleNode* aRuleNode, nsRuleNode* aVisitedRuleNode, nsAtom* aPseudoTag, mozilla::CSSPseudoElementType aPseudoType, mozilla::dom::Element* aElementForAnimation, uint32_t aFlags); enum AnimationFlag { eWithAnimation, eWithoutAnimation, }; already_AddRefed ResolveStyleForInternal(mozilla::dom::Element* aElement, mozilla::GeckoStyleContext* aParentContext, TreeMatchContext& aTreeMatchContext, AnimationFlag aAnimationFlag); already_AddRefed ResolvePseudoElementStyleInternal(mozilla::dom::Element* aParentElement, mozilla::CSSPseudoElementType aType, mozilla::GeckoStyleContext* aParentContext, mozilla::dom::Element* aPseudoElement, AnimationFlag aAnimationFlag); nsPresContext* PresContext() { return mRuleTree->PresContext(); } // Clear our cached mNonInheritingStyleContexts. We do this when we want to // make sure those style contexts won't live too long (e.g. at ruletree // reconstruct or shutdown time). void ClearNonInheritingStyleContexts(); // The sheets in each array in mSheets are stored with the most significant // sheet last. // The arrays for ePresHintSheet, eStyleAttrSheet, eTransitionSheet, // eAnimationSheet are always empty. // (FIXME: We should reduce the storage needed for them.) mozilla::EnumeratedArray>> mSheets; // mRuleProcessors[eScopedDocSheet] is always null; rule processors // for scoped style sheets are stored in mScopedDocSheetRuleProcessors. mozilla::EnumeratedArray> mRuleProcessors; // Rule processors for HTML5 scoped style sheets, one per scope. nsTArray > mScopedDocSheetRuleProcessors; RefPtr mBindingManager; RefPtr mRuleTree; // This is the root of our rule tree. It is a // lexicographic tree of matched rules that style // contexts use to look up properties. // List of subtrees rooted at style scope roots that need to be restyled. // When a change to a scoped style sheet is made, we add the style scope // root to this array rather than setting mStylesHaveChanged = true, since // we know we don't need to restyle the whole document. However, if in the // same update block we have already had other changes that require // the whole document to be restyled (i.e., mStylesHaveChanged is already // true), then we don't bother adding the scope root here. AutoTArray,1> mChangedScopeStyleRoots; uint16_t mBatching; // Indicates that the whole document must be restyled. Changes to scoped // style sheets are recorded in mChangedScopeStyleRoots rather than here // in mStylesHaveChanged. unsigned mStylesHaveChanged : 1; unsigned mInShutdown : 1; unsigned mInGC : 1; unsigned mAuthorStyleDisabled: 1; unsigned mInReconstruct : 1; unsigned mNeedsRestyleAfterEnsureUniqueInner : 1; // Does the associated document use viewport units (vw/vh/vmin/vmax)? unsigned mUsesViewportUnits : 1; unsigned mDirty : int(mozilla::SheetType::Count); // one bit per sheet type uint32_t mRootStyleContextCount; #ifdef DEBUG // In debug builds, we stash a weak pointer here to the old root during // reconstruction. During GC, we check for this pointer, and null it out // when we encounter it. This allows us to assert that the old root (and // thus all of its subtree) was GCed after reconstruction, which implies // that there are no style contexts holding on to old rule nodes. nsRuleNode* mOldRootNode; #endif // Track our rule nodes with zero refcount. When this hits a threshold, we // sweep and free. Keeping unused rule nodes around for a bit allows us to // reuse them in many cases. mozilla::LinkedList mUnusedRuleNodeList; uint32_t mUnusedRuleNodeCount; // Empty style rules to force things that restrict which properties // apply into different branches of the rule tree. RefPtr mFirstLineRule, mFirstLetterRule, mPlaceholderRule; // Style rule which sets all properties to their initial values for // determining when context-sensitive values are in use. RefPtr mInitialStyleRule; // Style rule that sets the internal -x-text-zoom property on // elements to disable the effect of text zooming. RefPtr mDisableTextZoomStyleRule; // Stores pointers to our cached style contexts for non-inheriting anonymous // boxes. mozilla::EnumeratedArray> mNonInheritingStyleContexts; }; #ifdef MOZILLA_INTERNAL_API inline void nsRuleNode::AddRef() { if (mRefCnt++ == 0) { MOZ_ASSERT(mPresContext->StyleSet()->IsGecko(), "ServoStyleSets should not have rule nodes"); mPresContext->StyleSet()->AsGecko()->RuleNodeInUse(this); } } inline void nsRuleNode::Release() { if (--mRefCnt == 0) { MOZ_ASSERT(mPresContext->StyleSet()->IsGecko(), "ServoStyleSets should not have rule nodes"); mPresContext->StyleSet()->AsGecko()->RuleNodeUnused(this, /* aMayGC = */ true); } } #endif #endif