/* -*- 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/. */ /** * Code responsible for managing style changes: tracking what style * changes need to happen, scheduling them, and doing them. */ #ifndef mozilla_GeckoRestyleManager_h #define mozilla_GeckoRestyleManager_h #include "mozilla/RestyleLogging.h" #include "mozilla/RestyleManager.h" #include "nsISupportsImpl.h" #include "nsChangeHint.h" #include "RestyleTracker.h" #include "nsPresContext.h" #include "nsRefreshDriver.h" #include "nsRefPtrHashtable.h" #include "nsTransitionManager.h" class nsIFrame; class nsStyleChangeList; struct TreeMatchContext; namespace mozilla { enum class CSSPseudoElementType : uint8_t; class EventStates; struct UndisplayedNode; namespace dom { class Element; } // namespace dom class GeckoRestyleManager final : public RestyleManager { public: typedef RestyleManager base_type; friend class RestyleTracker; friend class ElementRestyler; explicit GeckoRestyleManager(nsPresContext* aPresContext); protected: ~GeckoRestyleManager() override { MOZ_ASSERT(!mReframingStyleContexts, "temporary member should be nulled out before destruction"); } public: // Forwarded nsIDocumentObserver method, to handle restyling (and // passing the notification to the frame). void ContentStateChanged(nsIContent* aContent, EventStates aStateMask); // Forwarded nsIMutationObserver method, to handle restyling. void AttributeWillChange(Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute, int32_t aModType, const nsAttrValue* aNewValue); // Forwarded nsIMutationObserver method, to handle restyling (and // passing the notification to the frame). void AttributeChanged(Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute, int32_t aModType, const nsAttrValue* aOldValue); // Whether rule matching should skip styles associated with animation bool SkipAnimationRules() const { return mSkipAnimationRules; } void SetSkipAnimationRules(bool aSkipAnimationRules) { mSkipAnimationRules = aSkipAnimationRules; } /** * Reparent the style contexts of this frame subtree. The parent frame of * aFrame must be changed to the new parent before this function is called; * the new parent style context will be automatically computed based on the * new position in the frame tree. * * @param aFrame the root of the subtree to reparent. Must not be null. */ nsresult ReparentStyleContext(nsIFrame* aFrame); private: /** * Reparent the descendants of aFrame. This is used by ReparentStyleContext * and shouldn't be called by anyone else. aProviderChild, if non-null, is a * child that was the style parent for aFrame and hence shouldn't be * reparented. */ void ReparentFrameDescendants(nsIFrame* aFrame, nsIFrame* aProviderChild); public: void ClearSelectors() { mPendingRestyles.ClearSelectors(); } void PostRestyleEventForLazyConstruction() { PostRestyleEventInternal(); } private: void PostRestyleEventInternal(); // Used when restyling an element with a frame. void ComputeAndProcessStyleChange(nsIFrame* aFrame, nsChangeHint aMinChange, RestyleTracker& aRestyleTracker, nsRestyleHint aRestyleHint, const RestyleHintData& aRestyleHintData); // Used when restyling a display:contents element. void ComputeAndProcessStyleChange(GeckoStyleContext* aNewContext, Element* aElement, nsChangeHint aMinChange, RestyleTracker& aRestyleTracker, nsRestyleHint aRestyleHint, const RestyleHintData& aRestyleHintData); public: /** * In order to start CSS transitions on elements that are being * reframed, we need to stash their style contexts somewhere during * the reframing process. * * In all cases, the content node in the hash table is the real * content node, not the anonymous content node we create for ::before * or ::after. The content node passed to the Get and Put methods is, * however, the content node to be associate with the frame's style * context. */ typedef nsRefPtrHashtable, GeckoStyleContext> ReframingStyleContextTable; class MOZ_STACK_CLASS ReframingStyleContexts final { public: /** * Construct a ReframingStyleContexts object. The caller must * ensure that aRestyleManager lives at least as long as the * object. (This is generally easy since the caller is typically a * method of RestyleManager.) */ explicit ReframingStyleContexts(GeckoRestyleManager* aRestyleManager); ~ReframingStyleContexts(); void Put(nsIContent* aContent, GeckoStyleContext* aStyleContext) { MOZ_ASSERT(aContent); CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType(); if (pseudoType == CSSPseudoElementType::NotPseudo) { mElementContexts.Put(aContent, aStyleContext); } else if (pseudoType == CSSPseudoElementType::before) { MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore); mBeforePseudoContexts.Put(aContent->GetParent(), aStyleContext); } else if (pseudoType == CSSPseudoElementType::after) { MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter); mAfterPseudoContexts.Put(aContent->GetParent(), aStyleContext); } } GeckoStyleContext* Get(nsIContent* aContent, CSSPseudoElementType aPseudoType) { MOZ_ASSERT(aContent); if (aPseudoType == CSSPseudoElementType::NotPseudo) { return mElementContexts.GetWeak(aContent); } if (aPseudoType == CSSPseudoElementType::before) { MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore); return mBeforePseudoContexts.GetWeak(aContent->GetParent()); } if (aPseudoType == CSSPseudoElementType::after) { MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter); return mAfterPseudoContexts.GetWeak(aContent->GetParent()); } MOZ_ASSERT(false, "unexpected aPseudoType"); return nullptr; } private: GeckoRestyleManager* mRestyleManager; AutoRestore mRestorePointer; ReframingStyleContextTable mElementContexts; ReframingStyleContextTable mBeforePseudoContexts; ReframingStyleContextTable mAfterPseudoContexts; }; /** * Return the current ReframingStyleContexts struct, or null if we're * not currently in a restyling operation. */ ReframingStyleContexts* GetReframingStyleContexts() { return mReframingStyleContexts; } /** * Try initiating a transition for an element or a ::before or ::after * pseudo-element, given an old and new style context. This may * change the new style context if a transition is started. Returns * true if it does change aNewStyleContext. * * For the pseudo-elements, aContent must be the anonymous content * that we're creating for that pseudo-element, not the real element. */ static bool TryInitiatingTransition( nsPresContext* aPresContext, nsIContent* aContent, GeckoStyleContext* aOldStyleContext, RefPtr* aNewStyleContext /* inout */); public: // Process any pending restyles. This should be called after // CreateNeededFrames. // Note: It's the caller's responsibility to make sure to wrap a // ProcessPendingRestyles call in a view update batch and a script blocker. // This function does not call ProcessAttachedQueue() on the binding manager. // If the caller wants that to happen synchronously, it needs to handle that // itself. void ProcessPendingRestyles(); private: // ProcessPendingRestyles calls into one of our RestyleTracker // objects. It then calls back to these functions at the beginning // and end of its work. void BeginProcessingRestyles(RestyleTracker& aRestyleTracker); void EndProcessingRestyles(); public: // Update styles for animations that are running on the compositor and // whose updating is suppressed on the main thread (to save // unnecessary work), while leaving all other aspects of style // out-of-date. // // Performs an animation-only style flush to make styles from // throttled transitions up-to-date prior to processing an unrelated // style change, so that any transitions triggered by that style // change produce correct results. // // In more detail: when we're able to run animations on the // compositor, we sometimes "throttle" these animations by skipping // updating style data on the main thread. However, whenever we // process a normal (non-animation) style change, any changes in // computed style on elements that have transition-* properties set // may need to trigger new transitions; this process requires knowing // both the old and new values of the property. To do this correctly, // we need to have an up-to-date *old* value of the property on the // primary frame. So the purpose of the mini-flush is to update the // style for all throttled transitions and animations to the current // animation state without making any other updates, so that when we // process the queued style updates we'll have correct old data to // compare against. When we do this, we don't bother touching frames // other than primary frames. void UpdateOnlyAnimationStyles(); // Rebuilds all style data by throwing out the old rule tree and // building a new one, and additionally applying aExtraHint (which // must not contain nsChangeHint_ReconstructFrame) to the root frame. // // aRestyleHint says which restyle hint to use for the computation; // the only sensible values to use are eRestyle_Subtree (which says // that the rebuild must run selector matching) and nsRestyleHint(0) // (which says that rerunning selector matching is not required. (The // method adds eRestyle_ForceDescendants internally, and including it // in the restyle hint is harmless; some callers (e.g., // nsPresContext::MediaFeatureValuesChanged) might do this for their // own reasons.) void RebuildAllStyleData(nsChangeHint aExtraHint, nsRestyleHint aRestyleHint); /** * Notify the frame constructor that an element needs to have its * style recomputed. * @param aElement: The element to be restyled. * @param aRestyleHint: Which nodes need to have selector matching run * on them. * @param aMinChangeHint: A minimum change hint for aContent and its * descendants. * @param aRestyleHintData: Additional data to go with aRestyleHint. */ void PostRestyleEvent(Element* aElement, nsRestyleHint aRestyleHint, nsChangeHint aMinChangeHint, const RestyleHintData* aRestyleHintData = nullptr); public: /** * Asynchronously clear style data from the root frame downwards and ensure * it will all be rebuilt. This is safe to call anytime; it will schedule * a restyle and take effect next time style changes are flushed. * This method is used to recompute the style data when some change happens * outside of any style rules, like a color preference change or a change * in a system font size, or to fix things up when an optimization in the * style data has become invalid. We assume that the root frame will not * need to be reframed. * * For parameters, see RebuildAllStyleData. */ void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint, nsRestyleHint aRestyleHint); #ifdef DEBUG bool InRebuildAllStyleData() const { return mInRebuildAllStyleData; } #endif #ifdef RESTYLE_LOGGING /** * Returns whether a restyle event currently being processed by this * GeckoRestyleManager should be logged. */ bool ShouldLogRestyle() { return ShouldLogRestyle(PresContext()); } /** * Returns whether a restyle event currently being processed for the * document with the specified nsPresContext should be logged. */ static bool ShouldLogRestyle(nsPresContext* aPresContext) { return aPresContext->RestyleLoggingEnabled() && (!aPresContext->TransitionManager()->InAnimationOnlyStyleUpdate() || AnimationRestyleLoggingEnabled()); } static bool RestyleLoggingInitiallyEnabled() { static bool enabled = getenv("MOZ_DEBUG_RESTYLE") != 0; return enabled; } static bool AnimationRestyleLoggingEnabled() { static bool animations = getenv("MOZ_DEBUG_RESTYLE_ANIMATIONS") != 0; return animations; } // Set MOZ_DEBUG_RESTYLE_STRUCTS to a comma-separated string of // style struct names -- such as "Font,SVGReset" -- to log the style context // tree and those cached struct pointers before each restyle. This // function returns a bitfield of the structs named in the // environment variable. static uint32_t StructsToLog(); static nsCString StructNamesToString(uint32_t aSIDs); int32_t& LoggingDepth() { return mLoggingDepth; } #endif bool IsProcessingRestyles() { return mIsProcessingRestyles; } bool HasPendingRestyles() const; private: inline nsStyleSet* StyleSet() const { MOZ_ASSERT(PresContext()->StyleSet()->IsGecko(), "GeckoRestyleManager should only be used with a Gecko-flavored " "style backend"); return PresContext()->StyleSet()->AsGecko(); } /* aMinHint is the minimal change that should be made to the element */ // XXXbz do we really need the aPrimaryFrame argument here? void RestyleElement(Element* aElement, nsIFrame* aPrimaryFrame, nsChangeHint aMinHint, RestyleTracker& aRestyleTracker, nsRestyleHint aRestyleHint, const RestyleHintData& aRestyleHintData); void StartRebuildAllStyleData(RestyleTracker& aRestyleTracker); void FinishRebuildAllStyleData(); bool ShouldStartRebuildAllFor(RestyleTracker& aRestyleTracker) { // When we process our primary restyle tracker and we have a pending // rebuild-all, we need to process it. return mDoRebuildAllStyleData && &aRestyleTracker == &mPendingRestyles; } void ProcessRestyles(RestyleTracker& aRestyleTracker) { // Fast-path the common case (esp. for the animation restyle // tracker) of not having anything to do. if (aRestyleTracker.Count() || ShouldStartRebuildAllFor(aRestyleTracker)) { IncrementRestyleGeneration(); aRestyleTracker.DoProcessRestyles(); } } private: // True if we need to reconstruct the rule tree the next time we // process restyles. bool mDoRebuildAllStyleData : 1; // True if we're currently in the process of reconstructing the rule tree. bool mInRebuildAllStyleData : 1; // Whether rule matching should skip styles associated with animation bool mSkipAnimationRules : 1; bool mHavePendingNonAnimationRestyles : 1; nsChangeHint mRebuildAllExtraHint; nsRestyleHint mRebuildAllRestyleHint; ReframingStyleContexts* mReframingStyleContexts; RestyleTracker mPendingRestyles; // Are we currently in the middle of a call to ProcessRestyles? // This flag is used both as a debugging aid to assert that we are not // performing nested calls to ProcessPendingRestyles, as well as to ignore // redundant calls to IncrementAnimationGeneration. bool mIsProcessingRestyles; #ifdef RESTYLE_LOGGING int32_t mLoggingDepth; #endif }; /** * An ElementRestyler is created for *each* element in a subtree that we * recompute styles for. */ class ElementRestyler final { public: typedef mozilla::dom::Element Element; struct ContextToClear { RefPtr mStyleContext; uint32_t mStructs; }; // Construct for the root of the subtree that we're restyling. ElementRestyler(nsPresContext* aPresContext, nsIFrame* aFrame, nsStyleChangeList* aChangeList, nsChangeHint aHintsHandledByAncestors, RestyleTracker& aRestyleTracker, nsTArray& aSelectorsForDescendants, TreeMatchContext& aTreeMatchContext, nsTArray& aVisibleKidsOfHiddenElement, nsTArray& aContextsToClear, nsTArray>& aSwappedStructOwners); // Construct for an element whose parent is being restyled. enum ConstructorFlags { FOR_OUT_OF_FLOW_CHILD = 1 << 0 }; ElementRestyler(const ElementRestyler& aParentRestyler, nsIFrame* aFrame, uint32_t aConstructorFlags); // Construct for a frame whose parent is being restyled, but whose // style context is the parent style context for its parent frame. // (This is only used for table frames, whose style contexts are used // as the parent style context for their table wrapper frame. We should // probably try to get rid of this exception and have the inheritance go // the other way.) enum ParentContextFromChildFrame { PARENT_CONTEXT_FROM_CHILD_FRAME }; ElementRestyler(ParentContextFromChildFrame, const ElementRestyler& aParentFrameRestyler, nsIFrame* aFrame); // For restyling undisplayed content only (mFrame==null). ElementRestyler(nsPresContext* aPresContext, nsIContent* aContent, nsStyleChangeList* aChangeList, nsChangeHint aHintsHandledByAncestors, RestyleTracker& aRestyleTracker, nsTArray& aSelectorsForDescendants, TreeMatchContext& aTreeMatchContext, nsTArray& aVisibleKidsOfHiddenElement, nsTArray& aContextsToClear, nsTArray>& aSwappedStructOwners); /** * Restyle our frame's element and its subtree. * * Use eRestyle_Self for the aRestyleHint argument to mean * "reresolve our style context but not kids", use eRestyle_Subtree * to mean "reresolve our style context and kids", and use * nsRestyleHint(0) to mean recompute a new style context for our * current parent and existing rulenode, and the same for kids. */ void Restyle(nsRestyleHint aRestyleHint); /** * mHintsHandledBySelf changes over time; it starts off as nsChangeHint(0), * and by the end of Restyle it represents the hints that have been handled * for this frame. This method is intended to be called after Restyle, to * find out what hints have been handled for this frame. */ nsChangeHint HintsHandledForFrame() { return mHintsHandledBySelf; } /** * Called from GeckoRestyleManager::ComputeAndProcessStyleChange to restyle * children of a display:contents element. */ void RestyleChildrenOfDisplayContentsElement( nsIFrame* aParentFrame, GeckoStyleContext* aNewContext, nsChangeHint aMinHint, RestyleTracker& aRestyleTracker, nsRestyleHint aRestyleHint, const RestyleHintData& aRestyleHintData); /** * Re-resolve the style contexts for a frame tree, building aChangeList * based on the resulting style changes, plus aMinChange applied to aFrame. */ static void ComputeStyleChangeFor( nsIFrame* aFrame, nsStyleChangeList* aChangeList, nsChangeHint aMinChange, RestyleTracker& aRestyleTracker, nsRestyleHint aRestyleHint, const RestyleHintData& aRestyleHintData, nsTArray& aContextsToClear, nsTArray>& aSwappedStructOwners); #ifdef RESTYLE_LOGGING bool ShouldLogRestyle() { return GeckoRestyleManager::ShouldLogRestyle(mPresContext); } #endif private: inline nsStyleSet* StyleSet() const; // Enum class for the result of RestyleSelf, which indicates whether the // restyle procedure should continue to the children, and how. // // These values must be ordered so that later values imply that all // the work of the earlier values is also done. enum class RestyleResult : uint8_t { // default initial value eNone, // we left the old style context on the frame; do not restyle children eStop, // we got a new style context on this frame, but we know that children // do not depend on the changed values; do not restyle children eStopWithStyleChange, // continue restyling children eContinue, // continue restyling children with eRestyle_ForceDescendants set eContinueAndForceDescendants }; struct SwapInstruction { RefPtr mOldContext; RefPtr mNewContext; uint32_t mStructsToSwap; }; /** * First half of Restyle(). */ RestyleResult RestyleSelf(nsIFrame* aSelf, nsRestyleHint aRestyleHint, uint32_t* aSwappedStructs, nsTArray& aSwaps); /** * Restyle the children of this frame (and, in turn, their children). * * Second half of Restyle(). */ void RestyleChildren(nsRestyleHint aChildRestyleHint); /** * Returns true iff a selector in mSelectorsForDescendants matches aElement. * This is called when processing a eRestyle_SomeDescendants restyle hint. */ bool SelectorMatchesForRestyle(Element* aElement); /** * Returns true iff aRestyleHint indicates that we should be restyling. * Specifically, this will return true when eRestyle_Self or * eRestyle_Subtree is present, or if eRestyle_SomeDescendants is * present and the specified element matches one of the selectors in * mSelectorsForDescendants. */ bool MustRestyleSelf(nsRestyleHint aRestyleHint, Element* aElement); /** * Returns true iff aRestyleHint indicates that we can call * ReparentStyleContext rather than any other restyling method of * nsStyleSet that looks up a new rule node, and if we are * not in the process of reconstructing the whole rule tree. * This is used to check whether it is appropriate to call * ReparentStyleContext. */ bool CanReparentStyleContext(nsRestyleHint aRestyleHint); /** * Helpers for Restyle(). */ bool MoveStyleContextsForContentChildren( nsIFrame* aParent, GeckoStyleContext* aOldContext, nsTArray& aContextsToMove); bool MoveStyleContextsForChildren(GeckoStyleContext* aOldContext); /** * Helpers for RestyleSelf(). */ void CaptureChange(GeckoStyleContext* aOldContext, GeckoStyleContext* aNewContext, nsChangeHint aChangeToAssume, uint32_t* aEqualStructs, uint32_t* aSamePointerStructs); void ComputeRestyleResultFromFrame(nsIFrame* aSelf, RestyleResult& aRestyleResult, bool& aCanStopWithStyleChange); void ComputeRestyleResultFromNewContext(nsIFrame* aSelf, GeckoStyleContext* aNewContext, RestyleResult& aRestyleResult, bool& aCanStopWithStyleChange); // Helpers for RestyleChildren(). void RestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint); bool MustCheckUndisplayedContent(nsIFrame* aFrame, nsIContent*& aUndisplayedParent); /** * In the following two methods, aParentStyleContext is either * mFrame->StyleContext() if we have a frame, or a display:contents * style context if we don't. */ void DoRestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint, nsIContent* aParent, GeckoStyleContext* aParentStyleContext); void RestyleUndisplayedNodes(nsRestyleHint aChildRestyleHint, UndisplayedNode* aUndisplayed, nsIContent* aUndisplayedParent, GeckoStyleContext* aParentStyleContext, const StyleDisplay aDisplay); void MaybeReframeForBeforePseudo(); void MaybeReframeForAfterPseudo(nsIFrame* aFrame); void MaybeReframeForPseudo(CSSPseudoElementType aPseudoType, nsIFrame* aGenConParentFrame, nsIFrame* aFrame, nsIContent* aContent, GeckoStyleContext* aStyleContext); #ifdef DEBUG bool MustReframeForBeforePseudo(); bool MustReframeForAfterPseudo(nsIFrame* aFrame); #endif bool MustReframeForPseudo(CSSPseudoElementType aPseudoType, nsIFrame* aGenConParentFrame, nsIFrame* aFrame, nsIContent* aContent, GeckoStyleContext* aStyleContext); void RestyleContentChildren(nsIFrame* aParent, nsRestyleHint aChildRestyleHint); void InitializeAccessibilityNotifications(nsStyleContext* aNewContext); void SendAccessibilityNotifications(); enum DesiredA11yNotifications { eSkipNotifications, eSendAllNotifications, eNotifyIfShown }; enum A11yNotificationType { eDontNotify, eNotifyShown, eNotifyHidden }; // These methods handle the eRestyle_SomeDescendants hint by traversing // down the frame tree (and then when reaching undisplayed content, // the flattened content tree) find elements that match a selector // in mSelectorsForDescendants and call AddPendingRestyle for them. void ConditionallyRestyleChildren(); void ConditionallyRestyleChildren(nsIFrame* aFrame, Element* aRestyleRoot); void ConditionallyRestyleContentChildren(nsIFrame* aFrame, Element* aRestyleRoot); void ConditionallyRestyleUndisplayedDescendants(nsIFrame* aFrame, Element* aRestyleRoot); void DoConditionallyRestyleUndisplayedDescendants(nsIContent* aParent, Element* aRestyleRoot); void ConditionallyRestyleUndisplayedNodes(UndisplayedNode* aUndisplayed, nsIContent* aUndisplayedParent, const StyleDisplay aDisplay, Element* aRestyleRoot); void ConditionallyRestyleContentDescendants(Element* aElement, Element* aRestyleRoot); bool ConditionallyRestyle(nsIFrame* aFrame, Element* aRestyleRoot); bool ConditionallyRestyle(Element* aElement, Element* aRestyleRoot); #ifdef RESTYLE_LOGGING int32_t& LoggingDepth() { return mLoggingDepth; } #endif #ifdef DEBUG static nsCString RestyleResultToString(RestyleResult aRestyleResult); #endif private: nsPresContext* const mPresContext; nsIFrame* const mFrame; nsIContent* const mParentContent; // |mContent| is the node that we used for rule matching of // normal elements (not pseudo-elements) and for which we generate // framechange hints if we need them. nsIContent* const mContent; nsStyleChangeList* const mChangeList; // Hints that we computed on an ancestor (and which we already have // generated a change list entry for). When we traverse to children // after restyling an element, this field accumulates the hints // generated for that element. const nsChangeHint mHintsHandledByAncestors; // Hints that we have computed so far the current node. This is // initially zero, and accumulates hints for each same-style continuation // and {ib} split sibling we restyle for the node. nsChangeHint mHintsHandledBySelf; RestyleTracker& mRestyleTracker; nsTArray& mSelectorsForDescendants; TreeMatchContext& mTreeMatchContext; nsIFrame* mResolvedChild; // child that provides our parent style context // Array of style context subtrees in which we need to clear out cached // structs at the end of the restyle (after change hints have been // processed). nsTArray& mContextsToClear; // Style contexts that had old structs swapped into it and which should // stay alive until the end of the restyle. (See comment in // ElementRestyler::Restyle.) nsTArray>& mSwappedStructOwners; // Whether this is the root of the restyle. bool mIsRootOfRestyle; #ifdef ACCESSIBILITY const DesiredA11yNotifications mDesiredA11yNotifications; DesiredA11yNotifications mKidsDesiredA11yNotifications; A11yNotificationType mOurA11yNotification; nsTArray& mVisibleKidsOfHiddenElement; bool mWasFrameVisible; #endif #ifdef RESTYLE_LOGGING int32_t mLoggingDepth; #endif }; /** * This pushes any display:contents nodes onto a TreeMatchContext. * Use it before resolving style for kids of aParent where aParent * (and further ancestors) may be display:contents nodes which have * not yet been pushed onto TreeMatchContext. */ class MOZ_RAII AutoDisplayContentsAncestorPusher final { public: typedef mozilla::dom::Element Element; AutoDisplayContentsAncestorPusher(TreeMatchContext& aTreeMatchContext, nsPresContext* aPresContext, nsIContent* aParent); ~AutoDisplayContentsAncestorPusher(); bool IsEmpty() const { return mAncestors.Length() == 0; } private: TreeMatchContext& mTreeMatchContext; nsPresContext* const mPresContext; AutoTArray mAncestors; }; } // namespace mozilla #endif /* mozilla_GeckoRestyleManager_h */