tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RestyleManager.h (24249B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_RestyleManager_h
      8 #define mozilla_RestyleManager_h
      9 
     10 #include "mozilla/AutoRestore.h"
     11 #include "mozilla/OverflowChangedTracker.h"
     12 #include "mozilla/ServoElementSnapshot.h"
     13 #include "mozilla/ServoElementSnapshotTable.h"
     14 #include "nsChangeHint.h"
     15 #include "nsPresContext.h"
     16 #include "nsPresContextInlines.h"  // XXX Shouldn't be included by header though
     17 #include "nsStringFwd.h"
     18 #include "nsTHashSet.h"
     19 
     20 class nsAttrValue;
     21 class nsAtom;
     22 class nsIFrame;
     23 class nsStyleChangeList;
     24 class nsStyleChangeList;
     25 
     26 enum class AttrModType : uint8_t;  // Defined in nsIMutationObserver.h
     27 
     28 namespace mozilla {
     29 
     30 class ServoStyleSet;
     31 
     32 namespace dom {
     33 class Document;
     34 class Element;
     35 }  // namespace dom
     36 
     37 /**
     38 * A stack class used to pass some common restyle state in a slightly more
     39 * comfortable way than a bunch of individual arguments, and that also checks
     40 * that the change hint used for optimization is correctly used in debug mode.
     41 */
     42 class ServoRestyleState {
     43 public:
     44  ServoRestyleState(
     45      ServoStyleSet& aStyleSet, nsStyleChangeList& aChangeList,
     46      nsTArray<nsIFrame*>& aPendingWrapperRestyles,
     47      nsTArray<RefPtr<dom::Element>>& aPendingScrollAnchorSuppressions)
     48      : mStyleSet(aStyleSet),
     49        mChangeList(aChangeList),
     50        mPendingWrapperRestyles(aPendingWrapperRestyles),
     51        mPendingScrollAnchorSuppressions(aPendingScrollAnchorSuppressions),
     52        mPendingWrapperRestyleOffset(aPendingWrapperRestyles.Length()),
     53        mChangesHandled(nsChangeHint(0))
     54 #ifdef DEBUG
     55        // If !mOwner, then we wouldn't have processed our wrapper restyles,
     56        // because we only process those when handling an element with a frame.
     57        // But that's OK, because if we started our traversal at an element with
     58        // no frame (e.g. it's display:contents), that means the wrapper frames
     59        // in our list actually inherit from one of its ancestors, not from it,
     60        // and hence not restyling them is OK.
     61        ,
     62        mAssertWrapperRestyleLength(false)
     63 #endif  // DEBUG
     64  {
     65  }
     66 
     67  // We shouldn't assume that changes handled from our parent are handled for
     68  // our children too if we're out of flow since they aren't necessarily
     69  // parented in DOM order, and thus a change handled by a DOM ancestor doesn't
     70  // necessarily mean that it's handled for an ancestor frame.
     71  enum class CanUseHandledHints : bool { No = false, Yes };
     72 
     73  ServoRestyleState(const nsIFrame& aOwner, ServoRestyleState& aParentState,
     74                    nsChangeHint aHintForThisFrame,
     75                    CanUseHandledHints aCanUseHandledHints,
     76                    bool aAssertWrapperRestyleLength = true)
     77      : mStyleSet(aParentState.mStyleSet),
     78        mChangeList(aParentState.mChangeList),
     79        mPendingWrapperRestyles(aParentState.mPendingWrapperRestyles),
     80        mPendingScrollAnchorSuppressions(
     81            aParentState.mPendingScrollAnchorSuppressions),
     82        mPendingWrapperRestyleOffset(
     83            aParentState.mPendingWrapperRestyles.Length()),
     84        mChangesHandled(bool(aCanUseHandledHints)
     85                            ? aParentState.mChangesHandled | aHintForThisFrame
     86                            : aHintForThisFrame)
     87 #ifdef DEBUG
     88        ,
     89        mOwner(&aOwner),
     90        mAssertWrapperRestyleLength(aAssertWrapperRestyleLength)
     91 #endif
     92  {
     93    if (bool(aCanUseHandledHints)) {
     94      AssertOwner(aParentState);
     95    }
     96  }
     97 
     98  ~ServoRestyleState() {
     99    MOZ_ASSERT(
    100        !mAssertWrapperRestyleLength ||
    101            mPendingWrapperRestyles.Length() == mPendingWrapperRestyleOffset,
    102        "Someone forgot to call ProcessWrapperRestyles!");
    103  }
    104 
    105  nsStyleChangeList& ChangeList() { return mChangeList; }
    106  ServoStyleSet& StyleSet() { return mStyleSet; }
    107 
    108 #ifdef DEBUG
    109  void AssertOwner(const ServoRestyleState& aParentState) const;
    110  nsChangeHint ChangesHandledFor(const nsIFrame*) const;
    111 #else
    112  void AssertOwner(const ServoRestyleState&) const {}
    113  nsChangeHint ChangesHandledFor(const nsIFrame*) const {
    114    return mChangesHandled;
    115  }
    116 #endif
    117 
    118  // Add a pending wrapper restyle.  We don't have to do anything if the thing
    119  // being added is already last in the list, but otherwise we do want to add
    120  // it, in order for ProcessWrapperRestyles to work correctly.
    121  void AddPendingWrapperRestyle(nsIFrame* aWrapperFrame);
    122 
    123  // Process wrapper restyles for this restyle state.  This should be done
    124  // before it comes off the stack.
    125  void ProcessWrapperRestyles(nsIFrame* aParentFrame);
    126 
    127  // Get the table-aware parent for the given child.  This will walk through
    128  // outer table and cellcontent frames.
    129  static nsIFrame* TableAwareParentFor(const nsIFrame* aChild);
    130 
    131  // When the value of the position property changes such as we stop or start
    132  // being absolutely or fixed positioned, we need to suppress scroll anchoring
    133  // adjustments to avoid breaking websites.
    134  //
    135  // We do need to process all this once we're done with all our reframes,
    136  // to handle correctly the cases where we reconstruct an ancestor, like when
    137  // you reframe an ib-split (see bug 1559627 for example).
    138  //
    139  // This doesn't handle nested reframes. We'd need to rework quite some code to
    140  // do that, and so far it doesn't seem to be a problem in practice.
    141  void AddPendingScrollAnchorSuppression(dom::Element* aElement) {
    142    mPendingScrollAnchorSuppressions.AppendElement(aElement);
    143  }
    144 
    145 private:
    146  // Process a wrapper restyle at the given index, and restyles for any
    147  // wrappers nested in it.  Returns the number of entries from
    148  // mPendingWrapperRestyles that we processed.  The return value is always at
    149  // least 1.
    150  size_t ProcessMaybeNestedWrapperRestyle(nsIFrame* aParent, size_t aIndex);
    151 
    152  ServoStyleSet& mStyleSet;
    153  nsStyleChangeList& mChangeList;
    154 
    155  // A list of pending wrapper restyles.  Anonymous box wrapper frames that need
    156  // restyling are added to this list when their non-anonymous kids are
    157  // restyled.  This avoids us having to do linear searches along the frame tree
    158  // for these anonymous boxes.  The problem then becomes that we can have
    159  // multiple kids all with the same anonymous parent, and we don't want to
    160  // restyle it more than once.  We use mPendingWrapperRestyles to track which
    161  // anonymous wrapper boxes we've requested be restyled and which of them have
    162  // already been restyled.  We use a single array propagated through
    163  // ServoRestyleStates by reference, because in a situation like this:
    164  //
    165  //  <div style="display: table"><span></span></div>
    166  //
    167  // We have multiple wrappers to restyle (cell, row, table-row-group) and we
    168  // want to add them in to the list all at once but restyle them using
    169  // different ServoRestyleStates with different owners.  When this situation
    170  // occurs, the relevant frames will be placed in the array with ancestors
    171  // before descendants.
    172  nsTArray<nsIFrame*>& mPendingWrapperRestyles;
    173 
    174  nsTArray<RefPtr<dom::Element>>& mPendingScrollAnchorSuppressions;
    175 
    176  // Since we're given a possibly-nonempty mPendingWrapperRestyles to start
    177  // with, we need to keep track of where the part of it we're responsible for
    178  // starts.
    179  size_t mPendingWrapperRestyleOffset;
    180 
    181  const nsChangeHint mChangesHandled;
    182 
    183  // We track the "owner" frame of this restyle state, that is, the frame that
    184  // generated the last change that is stored in mChangesHandled, in order to
    185  // verify that we only use mChangesHandled for actual descendants of that
    186  // frame (given DOM order isn't always frame order, and that there are a few
    187  // special cases for stuff like wrapper frames, ::backdrop, and so on).
    188 #ifdef DEBUG
    189  const nsIFrame* mOwner{nullptr};
    190 #endif
    191 
    192  // Whether we should assert in our destructor that we've processed all of the
    193  // relevant wrapper restyles.
    194 #ifdef DEBUG
    195  const bool mAssertWrapperRestyleLength;
    196 #endif  // DEBUG
    197 };
    198 
    199 enum class ServoPostTraversalFlags : uint32_t;
    200 
    201 class RestyleManager {
    202  friend class dom::Document;
    203  friend class ServoStyleSet;
    204 
    205 public:
    206  typedef ServoElementSnapshotTable SnapshotTable;
    207  typedef mozilla::dom::Element Element;
    208 
    209  // Get an integer that increments every time we process pending restyles.
    210  // The value is never 0.
    211  uint64_t GetRestyleGeneration() const { return mRestyleGeneration; }
    212  // Unlike GetRestyleGeneration, which means the actual restyling count,
    213  // GetUndisplayedRestyleGeneration represents any possible DOM changes that
    214  // can cause restyling. This is needed for getComputedStyle to work with
    215  // non-styled (e.g. display: none) elements.
    216  uint64_t GetUndisplayedRestyleGeneration() const {
    217    return mUndisplayedRestyleGeneration;
    218  }
    219 
    220  void Disconnect() { mPresContext = nullptr; }
    221 
    222  ~RestyleManager() {
    223    MOZ_ASSERT(!mAnimationsWithDestroyedFrame,
    224               "leaving dangling pointers from AnimationsWithDestroyedFrame");
    225    MOZ_ASSERT(!mReentrantChanges);
    226  }
    227 
    228 #ifdef DEBUG
    229  static nsCString ChangeHintToString(nsChangeHint aHint);
    230 
    231  /**
    232   * DEBUG ONLY method to verify integrity of style tree versus frame tree
    233   */
    234  void DebugVerifyStyleTree(nsIFrame* aFrame);
    235 #endif
    236 
    237  void FlushOverflowChangedTracker() { mOverflowChangedTracker.Flush(); }
    238 
    239  // Should be called when a frame is going to be destroyed and
    240  // WillDestroyFrameTree hasn't been called yet.
    241  void NotifyDestroyingFrame(nsIFrame* aFrame) {
    242    mOverflowChangedTracker.RemoveFrame(aFrame);
    243    // If ProcessRestyledFrames is tracking frames which have been
    244    // destroyed (to avoid re-visiting them), add this one to its set.
    245    if (mDestroyedFrames) {
    246      mDestroyedFrames->Insert(aFrame);
    247    }
    248  }
    249 
    250  // Note: It's the caller's responsibility to make sure to wrap a
    251  // ProcessRestyledFrames call in a view update batch and a script blocker.
    252  // This function does not call ProcessAttachedQueue() on the binding manager.
    253  // If the caller wants that to happen synchronously, it needs to handle that
    254  // itself.
    255  void ProcessRestyledFrames(nsStyleChangeList& aChangeList);
    256 
    257  bool IsInStyleRefresh() const { return mInStyleRefresh; }
    258 
    259  // AnimationsWithDestroyedFrame is used to stop animations and transitions
    260  // on elements that have no frame at the end of the restyling process.
    261  // It only lives during the restyling process.
    262  class MOZ_STACK_CLASS AnimationsWithDestroyedFrame final {
    263   public:
    264    // Construct a AnimationsWithDestroyedFrame object.  The caller must
    265    // ensure that aRestyleManager lives at least as long as the
    266    // object.  (This is generally easy since the caller is typically a
    267    // method of RestyleManager.)
    268    explicit AnimationsWithDestroyedFrame(RestyleManager* aRestyleManager);
    269 
    270    // This method takes the content node for the generated content for
    271    // animation/transition on ::before and ::after, rather than the
    272    // content node for the real element.
    273    void Put(nsIContent* aContent, ComputedStyle* aComputedStyle);
    274    void StopAnimationsForElementsWithoutFrames();
    275 
    276   private:
    277    void StopAnimationsWithoutFrame(nsTArray<RefPtr<Element>>& aArray,
    278                                    const PseudoStyleRequest& aPseudoRequest);
    279 
    280    RestyleManager* mRestyleManager;
    281    AutoRestore<AnimationsWithDestroyedFrame*> mRestorePointer;
    282 
    283    // Below four arrays might include elements that have already had their
    284    // animations or transitions stopped.
    285    //
    286    // mContents holds either the real element and NotPseudo, or the parent
    287    // element rather than the content node for generated content (which might
    288    // change during a reframe).
    289    nsTArray<std::pair<RefPtr<Element>, PseudoStyleType>> mContents;
    290  };
    291 
    292  /**
    293   * Return the current AnimationsWithDestroyedFrame struct, or null if we're
    294   * not currently in a restyling operation.
    295   */
    296  AnimationsWithDestroyedFrame* GetAnimationsWithDestroyedFrame() {
    297    return mAnimationsWithDestroyedFrame;
    298  }
    299 
    300  void ContentInserted(nsIContent* aChild);
    301  void ContentAppended(nsIContent* aFirstNewContent);
    302 
    303  // Restyling for a content removal that is about to happen.
    304  void ContentWillBeRemoved(nsIContent* aOldChild);
    305 
    306  // Restyling for a ContentInserted (notification after insertion) or
    307  // for some CharacterDataChanged.
    308  void RestyleForInsertOrChange(nsIContent* aChild);
    309 
    310  // Restyle for a CharacterDataChanged notification. In practice this can only
    311  // affect :empty / :-moz-only-whitespace / :-moz-first-node / :-moz-last-node.
    312  void CharacterDataChanged(nsIContent*, const CharacterDataChangeInfo&);
    313 
    314  void PostRestyleEvent(dom::Element*, RestyleHint,
    315                        nsChangeHint aMinChangeHint);
    316 
    317  /**
    318   * Posts restyle hints for animations.
    319   * This is only called for the second traversal for CSS animations during
    320   * updating CSS animations in a SequentialTask.
    321   * This function does neither register a refresh observer nor flag that a
    322   * style flush is needed since this function is supposed to be called during
    323   * restyling process and this restyle event will be processed in the second
    324   * traversal of the same restyling process.
    325   */
    326  void PostRestyleEventForAnimations(dom::Element*, const PseudoStyleRequest&,
    327                                     RestyleHint);
    328 
    329  void NextRestyleIsForCSSRuleChanges() { mRestyleForCSSRuleChanges = true; }
    330 
    331  void RebuildAllStyleData(nsChangeHint aExtraHint, RestyleHint);
    332 
    333  void ProcessPendingRestyles();
    334  void ProcessAllPendingAttributeAndStateInvalidations();
    335 
    336  void ElementStateChanged(Element*, dom::ElementState);
    337 
    338  void CustomStatesWillChange(Element&);
    339  void CustomStateChanged(Element&, nsAtom* aState);
    340  void MaybeRestyleForNthOfCustomState(ServoStyleSet&, Element&,
    341                                       nsAtom* aState);
    342 
    343  /**
    344   * Posts restyle hints for siblings of an element and their descendants if the
    345   * element's parent has NODE_HAS_SLOW_SELECTOR_NTH_OF and the element has a
    346   * relevant state dependency.
    347   */
    348  void MaybeRestyleForNthOfState(ServoStyleSet& aStyleSet, dom::Element* aChild,
    349                                 dom::ElementState aChangedBits);
    350 
    351  void AttributeWillChange(Element* aElement, int32_t aNameSpaceID,
    352                           nsAtom* aAttribute, AttrModType aModType);
    353  void ClassAttributeWillBeChangedBySMIL(dom::Element* aElement);
    354  void AttributeChanged(dom::Element* aElement, int32_t aNameSpaceID,
    355                        nsAtom* aAttribute, AttrModType aModType,
    356                        const nsAttrValue* aOldValue);
    357 
    358  /**
    359   * Restyle an element's previous and/or next siblings.
    360   */
    361  void RestyleSiblingsForNthOf(dom::Element* aChild,
    362                               NodeSelectorFlags aParentFlags);
    363 
    364  /**
    365   * Posts restyle hints for siblings of an element and their descendants if the
    366   * element's parent has NODE_HAS_SLOW_SELECTOR_NTH_OF and the element has a
    367   * relevant attribute dependency.
    368   */
    369  void MaybeRestyleForNthOfAttribute(dom::Element* aChild, int32_t aNameSpaceID,
    370                                     nsAtom* aAttribute,
    371                                     const nsAttrValue* aOldValue);
    372 
    373  void MaybeRestyleForRelativeSelectorAttribute(dom::Element* aElement,
    374                                                int32_t aNameSpaceID,
    375                                                nsAtom* aAttribute,
    376                                                const nsAttrValue* aOldValue);
    377  void MaybeRestyleForRelativeSelectorState(ServoStyleSet& aStyleSet,
    378                                            dom::Element* aElement,
    379                                            dom::ElementState aChangedBits);
    380 
    381  // This is only used to reparent things when moving them in/out of the
    382  // ::first-line.
    383  void ReparentComputedStyleForFirstLine(nsIFrame*);
    384 
    385  /**
    386   * Performs a Servo animation-only traversal to compute style for all nodes
    387   * with the animation-only dirty bit in the document.
    388   *
    389   * This processes just the traversal for animation-only restyles and skips the
    390   * normal traversal for other restyles unrelated to animations.
    391   * This is used to bring throttled animations up-to-date such as when we need
    392   * to get correct position for transform animations that are throttled because
    393   * they are running on the compositor.
    394   *
    395   * This will traverse all of the document's style roots (that is, its document
    396   * element, and the roots of the document-level native anonymous content).
    397   */
    398  void UpdateOnlyAnimationStyles();
    399 
    400  // Get a counter that increments on every style change, that we use to
    401  // track whether off-main-thread animations are up-to-date.
    402  uint64_t GetAnimationGeneration() const { return mAnimationGeneration; }
    403 
    404  // Typically only style frames have animations associated with them so this
    405  // will likely return zero for anything that is not a style frame.
    406  static uint64_t GetAnimationGenerationForFrame(nsIFrame* aStyleFrame);
    407 
    408  // Update the animation generation count to mark that animation state
    409  // has changed.
    410  //
    411  // This is normally performed automatically by ProcessPendingRestyles
    412  // but it is also called when we have out-of-band changes to animations
    413  // such as changes made through the Web Animations API or cascading result
    414  // changes by modifying classes, etc.
    415  void IncrementAnimationGeneration() { ++mAnimationGeneration; }
    416 
    417  // Apply change hints for animations on the compositor.
    418  //
    419  // There are some cases where we forcibly apply change hints for animations
    420  // even if there is no change hint produced in order to synchronize with
    421  // animations running on the compositor.
    422  //
    423  // For example:
    424  //
    425  // a) Pausing animations via the Web Animations API
    426  // b) When the style before sending the animation to the compositor exactly
    427  // the same as the current style
    428  static void AddLayerChangesForAnimation(
    429      nsIFrame* aStyleFrame, nsIFrame* aPrimaryFrame, Element* aElement,
    430      nsChangeHint aHintForThisFrame, nsStyleChangeList& aChangeListToProcess);
    431 
    432  /**
    433   * Whether to clear all the style data (including the element itself), or just
    434   * the descendants' data.
    435   */
    436  enum class IncludeRoot {
    437    Yes,
    438    No,
    439  };
    440 
    441  /**
    442   * Clears the ServoElementData and HasDirtyDescendants from all elements
    443   * in the subtree rooted at aElement.
    444   */
    445  static void ClearServoDataFromSubtree(Element*,
    446                                        IncludeRoot = IncludeRoot::Yes);
    447 
    448  /**
    449   * Clears HasDirtyDescendants and RestyleData from all elements in the
    450   * subtree rooted at aElement.
    451   */
    452  static void ClearRestyleStateFromSubtree(Element* aElement);
    453 
    454  explicit RestyleManager(nsPresContext* aPresContext);
    455 
    456 protected:
    457  /**
    458   * Reparent the descendants of aFrame.  This is used by ReparentComputedStyle
    459   * and shouldn't be called by anyone else.  aProviderChild, if non-null, is a
    460   * child that was the style parent for aFrame and hence shouldn't be
    461   * reparented.
    462   */
    463  void ReparentFrameDescendants(nsIFrame* aFrame, nsIFrame* aProviderChild,
    464                                ServoStyleSet& aStyleSet);
    465 
    466  /**
    467   * Performs post-Servo-traversal processing on this element and its
    468   * descendants.
    469   *
    470   * Returns whether any style did actually change. There may be cases where we
    471   * didn't need to change any style after all, for example, when a content
    472   * attribute changes that happens not to have any effect on the style of that
    473   * element or any descendant or sibling.
    474   */
    475  bool ProcessPostTraversal(Element* aElement, ServoRestyleState& aRestyleState,
    476                            ServoPostTraversalFlags aFlags);
    477 
    478  struct TextPostTraversalState;
    479  bool ProcessPostTraversalForText(nsIContent* aTextNode,
    480                                   TextPostTraversalState& aState,
    481                                   ServoRestyleState& aRestyleState,
    482                                   ServoPostTraversalFlags aFlags);
    483 
    484  ServoStyleSet* StyleSet() const { return PresContext()->StyleSet(); }
    485 
    486  void RestyleWholeContainer(nsINode* aContainer, NodeSelectorFlags);
    487  void RestylePreviousSiblings(nsIContent* aStartingSibling);
    488  void RestyleSiblingsStartingWith(nsIContent* aStartingSibling);
    489 
    490  void RestyleForEmptyChange(Element* aContainer);
    491  void MaybeRestyleForEdgeChildChange(nsINode* aContainer,
    492                                      nsIContent* aChangedChild);
    493 
    494  bool IsDisconnected() const { return !mPresContext; }
    495 
    496  void IncrementRestyleGeneration() {
    497    if (++mRestyleGeneration == 0) {
    498      // Keep mRestyleGeneration from being 0, since that's what
    499      // nsPresContext::GetRestyleGeneration returns when it no
    500      // longer has a RestyleManager.
    501      ++mRestyleGeneration;
    502    }
    503    IncrementUndisplayedRestyleGeneration();
    504  }
    505 
    506  void IncrementUndisplayedRestyleGeneration() {
    507    if (++mUndisplayedRestyleGeneration == 0) {
    508      // Ensure mUndisplayedRestyleGeneration > 0, for the same reason as
    509      // IncrementRestyleGeneration.
    510      ++mUndisplayedRestyleGeneration;
    511    }
    512  }
    513 
    514  nsPresContext* PresContext() const {
    515    MOZ_ASSERT(mPresContext);
    516    return mPresContext;
    517  }
    518 
    519 private:
    520  nsPresContext* mPresContext;  // weak, can be null after Disconnect().
    521  uint64_t mRestyleGeneration;
    522  uint64_t mUndisplayedRestyleGeneration;
    523 
    524  // Used to keep track of frames that have been destroyed during
    525  // ProcessRestyledFrames, so we don't try to touch them again even if
    526  // they're referenced again later in the changelist.
    527  mozilla::UniquePtr<nsTHashSet<const nsIFrame*>> mDestroyedFrames;
    528 
    529  // Containers we've already fully restyled / invalidated.
    530  nsTHashSet<RefPtr<nsINode>> mRestyledAsWholeContainer;
    531 
    532 protected:
    533  // True if we're in the middle of a nsRefreshDriver refresh
    534  bool mInStyleRefresh;
    535 
    536  // The total number of animation flushes by this frame constructor.
    537  // Used to keep the layer and animation manager in sync.
    538  uint64_t mAnimationGeneration;
    539 
    540  OverflowChangedTracker mOverflowChangedTracker;
    541 
    542  AnimationsWithDestroyedFrame* mAnimationsWithDestroyedFrame = nullptr;
    543 
    544  const SnapshotTable& Snapshots() const { return mSnapshots; }
    545  void ClearSnapshots();
    546  ServoElementSnapshot& SnapshotFor(Element&);
    547  void TakeSnapshotForAttributeChange(Element&, int32_t aNameSpaceID,
    548                                      nsAtom* aAttribute);
    549 
    550  void DoProcessPendingRestyles(ServoTraversalFlags aFlags);
    551 
    552  // Function to do the actual (recursive) work of
    553  // ReparentComputedStyleForFirstLine, once we have asserted the invariants
    554  // that only hold on the initial call.
    555  void DoReparentComputedStyleForFirstLine(nsIFrame*, ServoStyleSet&);
    556 
    557  // We use a separate data structure from nsStyleChangeList because we need a
    558  // frame to create nsStyleChangeList entries, and the primary frame may not be
    559  // attached yet.
    560  struct ReentrantChange {
    561    nsCOMPtr<nsIContent> mContent;
    562    nsChangeHint mHint;
    563  };
    564  typedef AutoTArray<ReentrantChange, 10> ReentrantChangeList;
    565 
    566  // Only non-null while processing change hints. See the comment in
    567  // ProcessPendingRestyles.
    568  ReentrantChangeList* mReentrantChanges = nullptr;
    569 
    570  // We use this flag to track if the current restyle contains any non-animation
    571  // update, which triggers a normal restyle, and so there might be any new
    572  // transition created later. Therefore, if this flag is true, we need to
    573  // increase mAnimationGeneration before creating new transitions, so their
    574  // creation sequence will be correct.
    575  bool mHaveNonAnimationRestyles = false;
    576 
    577  // Set to true when posting restyle events triggered by CSS rule changes.
    578  // This flag is cleared once ProcessPendingRestyles has completed.
    579  // When we process a traversal all descendants elements of the document
    580  // triggered by CSS rule changes, we will need to update all elements with
    581  // CSS animations.  We propagate TraversalRestyleBehavior::ForCSSRuleChanges
    582  // to traversal function if this flag is set.
    583  bool mRestyleForCSSRuleChanges = false;
    584 
    585  // A hashtable with the elements that have changed state or attributes, in
    586  // order to calculate restyle hints during the traversal.
    587  SnapshotTable mSnapshots;
    588 };
    589 
    590 }  // namespace mozilla
    591 
    592 #endif