Bug 1374752: Pack together the StyleSet, ChangeList and handled change hints, and use the latter with anonymous boxes while we're at it. r=heycam
authorEmilio Cobos Álvarez <emilio@crisal.io>
Tue, 20 Jun 2017 23:21:27 +0200
changeset 414257 fdde73cf429c62cd1e712afcc196110f8601cb2a
parent 414256 ceb1c35ada75186ba4ed458174a073e1cad8cdeb
child 414258 6f795df6dc6fd1fdc82f6c661ddbaffdefbac958
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1374752
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1374752: Pack together the StyleSet, ChangeList and handled change hints, and use the latter with anonymous boxes while we're at it. r=heycam MozReview-Commit-ID: DiWcUwD9po5
layout/base/ServoRestyleManager.cpp
layout/base/ServoRestyleManager.h
layout/generic/ViewportFrame.cpp
layout/generic/ViewportFrame.h
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsInlineFrame.cpp
layout/generic/nsInlineFrame.h
layout/tables/nsTableFrame.cpp
layout/tables/nsTableFrame.h
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -176,50 +176,43 @@ ServoRestyleManager::ClearRestyleStateFr
  * need to track during the post-traversal.
  *
  * This is currently used to properly compute change hints when the parent
  * element of this node is a display: contents node, and also to avoid computing
  * the style for text children more than once per element.
  */
 struct ServoRestyleManager::TextPostTraversalState
 {
-  nsStyleContext& mParentContext;
-  ServoStyleSet& mStyleSet;
-  RefPtr<nsStyleContext> mStyle;
-  bool mShouldPostHints;
-  bool mShouldComputeHints;
-  nsChangeHint mComputedHint;
-  nsChangeHint mHintsHandled;
-
+public:
   TextPostTraversalState(nsStyleContext& aParentContext,
-                         ServoStyleSet& aStyleSet,
                          bool aDisplayContentsParentStyleChanged,
-                         nsChangeHint aHintsHandled)
+                         ServoRestyleState& aParentRestyleState)
     : mParentContext(aParentContext)
-    , mStyleSet(aStyleSet)
+    , mParentRestyleState(aParentRestyleState)
     , mStyle(nullptr)
     , mShouldPostHints(aDisplayContentsParentStyleChanged)
     , mShouldComputeHints(aDisplayContentsParentStyleChanged)
     , mComputedHint(nsChangeHint_Empty)
-    , mHintsHandled(aHintsHandled)
   {}
 
+  nsStyleChangeList& ChangeList() { return mParentRestyleState.ChangeList(); }
+
   nsStyleContext& ComputeStyle(nsIContent* aTextNode)
   {
     if (!mStyle) {
-      mStyle = mStyleSet.ResolveStyleForText(aTextNode, &mParentContext);
+      mStyle = mParentRestyleState.StyleSet().ResolveStyleForText(
+        aTextNode, &mParentContext);
     }
     MOZ_ASSERT(mStyle);
     return *mStyle;
   }
 
   void ComputeHintIfNeeded(nsIContent* aContent,
                            nsIFrame* aTextFrame,
-                           nsStyleContext& aNewContext,
-                           nsStyleChangeList& aChangeList)
+                           nsStyleContext& aNewContext)
   {
     MOZ_ASSERT(aTextFrame);
     MOZ_ASSERT(aNewContext.GetPseudo() == nsCSSAnonBoxes::mozText);
 
     if (MOZ_LIKELY(!mShouldPostHints)) {
       return;
     }
 
@@ -233,46 +226,53 @@ struct ServoRestyleManager::TextPostTrav
     // we'll cross that bridge when we support those in stylo.
     if (mShouldComputeHints) {
       mShouldComputeHints = false;
       uint32_t equalStructs, samePointerStructs;
       mComputedHint =
         oldContext->CalcStyleDifference(&aNewContext,
                                         &equalStructs,
                                         &samePointerStructs);
-      mComputedHint = NS_RemoveSubsumedHints(mComputedHint, mHintsHandled);
+      mComputedHint = NS_RemoveSubsumedHints(
+        mComputedHint, mParentRestyleState.ChangesHandled());
     }
 
     if (mComputedHint) {
-      aChangeList.AppendChange(aTextFrame, aContent, mComputedHint);
+      mParentRestyleState.ChangeList().AppendChange(
+        aTextFrame, aContent, mComputedHint);
     }
   }
+
+private:
+  nsStyleContext& mParentContext;
+  ServoRestyleState& mParentRestyleState;
+  RefPtr<nsStyleContext> mStyle;
+  bool mShouldPostHints;
+  bool mShouldComputeHints;
+  nsChangeHint mComputedHint;
 };
 
 static void
 UpdateBlockFramePseudoElements(nsBlockFrame* aFrame,
-                               ServoStyleSet& aStyleSet,
-                               nsStyleChangeList& aChangeList)
+                               ServoRestyleState& aRestyleState)
 {
   if (nsBulletFrame* bullet = aFrame->GetBullet()) {
     RefPtr<nsStyleContext> newContext =
-      aStyleSet.ResolvePseudoElementStyle(
-          aFrame->GetContent()->AsElement(),
-          bullet->StyleContext()->GetPseudoType(),
-          aFrame->StyleContext(),
-          /* aPseudoElement = */ nullptr);
+      aRestyleState.StyleSet().ResolvePseudoElementStyle(
+        aFrame->GetContent()->AsElement(),
+        bullet->StyleContext()->GetPseudoType(),
+        aFrame->StyleContext(),
+        /* aPseudoElement = */ nullptr);
 
-    aFrame->UpdateStyleOfOwnedChildFrame(bullet, newContext, aChangeList);
+    aFrame->UpdateStyleOfOwnedChildFrame(bullet, newContext, aRestyleState);
   }
 }
 
 static void
-UpdateBackdropIfNeeded(nsIFrame* aFrame,
-                       ServoStyleSet& aStyleSet,
-                       nsStyleChangeList& aChangeList)
+UpdateBackdropIfNeeded(nsIFrame* aFrame, ServoRestyleState& aRestyleState)
 {
   const nsStyleDisplay* display = aFrame->StyleContext()->StyleDisplay();
   if (display->mTopLayer != NS_STYLE_TOP_LAYER_TOP) {
     return;
   }
 
   // Elements in the top layer are guaranteed to have absolute or fixed
   // position per https://fullscreen.spec.whatwg.org/#new-stacking-layer.
@@ -287,71 +287,66 @@ UpdateBackdropIfNeeded(nsIFrame* aFrame,
   MOZ_ASSERT(backdropPlaceholder->IsPlaceholderFrame());
   nsIFrame* backdropFrame =
     nsPlaceholderFrame::GetRealFrameForPlaceholder(backdropPlaceholder);
   MOZ_ASSERT(backdropFrame->IsBackdropFrame());
   MOZ_ASSERT(backdropFrame->StyleContext()->GetPseudoType() ==
              CSSPseudoElementType::backdrop);
 
   RefPtr<nsStyleContext> newContext =
-    aStyleSet.ResolvePseudoElementStyle(
-        aFrame->GetContent()->AsElement(),
-        CSSPseudoElementType::backdrop,
-        aFrame->StyleContext(),
-        /* aPseudoElement = */ nullptr);
+    aRestyleState.StyleSet().ResolvePseudoElementStyle(
+      aFrame->GetContent()->AsElement(),
+      CSSPseudoElementType::backdrop,
+      aFrame->StyleContext(),
+      /* aPseudoElement = */ nullptr);
 
-  aFrame->UpdateStyleOfOwnedChildFrame(backdropFrame,
-                                       newContext,
-                                       aChangeList);
+  aFrame->UpdateStyleOfOwnedChildFrame(
+    backdropFrame, newContext, aRestyleState);
 }
 
 static void
 UpdateFramePseudoElementStyles(nsIFrame* aFrame,
-                               ServoStyleSet& aStyleSet,
-                               nsStyleChangeList& aChangeList)
+                               ServoRestyleState& aRestyleState)
 {
   if (aFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
     UpdateBlockFramePseudoElements(static_cast<nsBlockFrame*>(aFrame),
-                                   aStyleSet,
-                                   aChangeList);
+                                   aRestyleState);
   }
 
-  UpdateBackdropIfNeeded(aFrame, aStyleSet, aChangeList);
+  UpdateBackdropIfNeeded(aFrame, aRestyleState);
 }
 
 bool
 ServoRestyleManager::ProcessPostTraversal(Element* aElement,
                                           nsStyleContext* aParentContext,
-                                          ServoStyleSet* aStyleSet,
-                                          nsStyleChangeList& aChangeList,
-                                          nsChangeHint aChangesHandled)
+                                          ServoRestyleState& aRestyleState)
 {
   nsIFrame* styleFrame = nsLayoutUtils::GetStyleFrame(aElement);
 
   // Grab the change hint from Servo.
   nsChangeHint changeHint = Servo_TakeChangeHint(aElement);
-  changeHint = NS_RemoveSubsumedHints(changeHint, aChangesHandled);
-  aChangesHandled |= changeHint;
+  changeHint =
+    NS_RemoveSubsumedHints(changeHint, aRestyleState.ChangesHandled());
 
   // Handle lazy frame construction by posting a reconstruct for any lazily-
   // constructed roots.
   if (aElement->HasFlag(NODE_NEEDS_FRAME)) {
     changeHint |= nsChangeHint_ReconstructFrame;
     // The only time the primary frame is non-null is when image maps do hacky
     // SetPrimaryFrame calls.
     MOZ_ASSERT(!styleFrame || styleFrame->IsImageFrame());
     styleFrame = nullptr;
   }
 
   // Although we shouldn't generate non-ReconstructFrame hints for elements with
   // no frames, we can still get them here if they were explicitly posted by
   // PostRestyleEvent, such as a RepaintFrame hint when a :link changes to be
   // :visited.  Skip processing these hints if there is no frame.
   if ((styleFrame || (changeHint & nsChangeHint_ReconstructFrame)) && changeHint) {
-    aChangeList.AppendChange(styleFrame, aElement, changeHint);
+    aRestyleState.ChangeList().AppendChange(styleFrame, aElement, changeHint);
   }
 
   // If our change hint is reconstruct, we delegate to the frame constructor,
   // which consumes the new style and expects the old style to be on the frame.
   //
   // XXXbholley: We should teach the frame constructor how to clear the dirty
   // descendants bit to avoid the traversal here.
   if (changeHint & nsChangeHint_ReconstructFrame) {
@@ -376,45 +371,43 @@ ServoRestyleManager::ProcessPostTraversa
     displayContentsNode =
       PresContext()->FrameConstructor()->GetDisplayContentsNodeFor(aElement);
     if (displayContentsNode) {
       oldStyleContext = displayContentsNode->mStyle;
     }
   }
 
   RefPtr<ServoComputedValues> computedValues =
-    aStyleSet->ResolveServoStyle(aElement);
+    aRestyleState.StyleSet().ResolveServoStyle(aElement);
 
   // Note that we rely in the fact that we don't cascade pseudo-element styles
   // separately right now (that is, if a pseudo style changes, the normal style
   // changes too).
   //
   // Otherwise we should probably encode that information somehow to avoid
   // expensive checks in the common case.
   //
   // Also, we're going to need to check for pseudos of display: contents
   // elements, though that is buggy right now even in non-stylo mode, see
   // bug 1251799.
   const bool recreateContext = oldStyleContext &&
     oldStyleContext->ComputedValues() != computedValues;
 
+  ServoRestyleState childrenRestyleState(aRestyleState, changeHint);
+
   RefPtr<nsStyleContext> newContext = nullptr;
   if (recreateContext) {
     MOZ_ASSERT(styleFrame || displayContentsNode);
 
     auto pseudo = aElement->GetPseudoElementType();
     nsIAtom* pseudoTag = pseudo == CSSPseudoElementType::NotPseudo
       ? nullptr : nsCSSPseudoElements::GetPseudoAtom(pseudo);
 
-    newContext =
-      aStyleSet->GetContext(computedValues.forget(),
-                            aParentContext,
-                            pseudoTag,
-                            pseudo,
-                            aElement);
+    newContext = aRestyleState.StyleSet().GetContext(
+      computedValues.forget(), aParentContext, pseudoTag, pseudo, aElement);
 
     newContext->EnsureSameStructsCached(oldStyleContext);
 
     // XXX This could not always work as expected: there are kinds of content
     // with the first split and the last sharing style, but others not. We
     // should handle those properly.
     // XXXbz I think the UpdateStyleOfOwnedAnonBoxes call below handles _that_
     // right, but not other cases where we happen to have different styles on
@@ -425,99 +418,95 @@ ServoRestyleManager::ProcessPostTraversa
     }
 
     if (MOZ_UNLIKELY(displayContentsNode)) {
       MOZ_ASSERT(!styleFrame);
       displayContentsNode->mStyle = newContext;
     }
 
     if (styleFrame) {
-      styleFrame->UpdateStyleOfOwnedAnonBoxes(*aStyleSet, aChangeList, changeHint);
-      UpdateFramePseudoElementStyles(styleFrame, *aStyleSet, aChangeList);
+      styleFrame->UpdateStyleOfOwnedAnonBoxes(childrenRestyleState);
+      UpdateFramePseudoElementStyles(styleFrame, childrenRestyleState);
     }
 
     if (!aElement->GetParent()) {
       // This is the root.  Update styles on the viewport as needed.
       ViewportFrame* viewport =
         do_QueryFrame(mPresContext->PresShell()->GetRootFrame());
       if (viewport) {
-        viewport->UpdateStyle(*aStyleSet, aChangeList);
+        viewport->UpdateStyle(childrenRestyleState);
       }
     }
 
     // Some changes to animations don't affect the computed style and yet still
     // require the layer to be updated. For example, pausing an animation via
     // the Web Animations API won't affect an element's style but still
     // requires to update the animation on the layer.
     //
     // We can sometimes reach this when the animated style is being removed.
     // Since AddLayerChangesForAnimation checks if |styleFrame| has a transform
     // style or not, we need to call it *after* setting |newContext| to
     // |styleFrame| to ensure the animated transform has been removed first.
-    AddLayerChangesForAnimation(styleFrame, aElement, aChangeList);
+    AddLayerChangesForAnimation(
+      styleFrame, aElement, aRestyleState.ChangeList());
   }
 
   const bool descendantsNeedFrames =
     aElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
   const bool traverseElementChildren =
     aElement->HasDirtyDescendantsForServo() ||
     aElement->HasAnimationOnlyDirtyDescendantsForServo() ||
     descendantsNeedFrames;
   const bool traverseTextChildren = recreateContext || descendantsNeedFrames;
   bool recreatedAnyContext = recreateContext;
   if (traverseElementChildren || traverseTextChildren) {
     nsStyleContext* upToDateContext =
       recreateContext ? newContext : oldStyleContext;
 
     StyleChildrenIterator it(aElement);
-    TextPostTraversalState textState(
-        *upToDateContext,
-        *aStyleSet,
-        displayContentsNode && recreateContext,
-        aChangesHandled);
+    TextPostTraversalState textState(*upToDateContext,
+                                     displayContentsNode && recreateContext,
+                                     childrenRestyleState);
     for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
       if (traverseElementChildren && n->IsElement()) {
-        recreatedAnyContext |=
-          ProcessPostTraversal(n->AsElement(), upToDateContext,
-                               aStyleSet, aChangeList, aChangesHandled);
+        recreatedAnyContext |= ProcessPostTraversal(
+          n->AsElement(), upToDateContext, childrenRestyleState);
       } else if (traverseTextChildren && n->IsNodeOfType(nsINode::eTEXT)) {
-        recreatedAnyContext |=
-          ProcessPostTraversalForText(n, aChangeList, textState);
+        recreatedAnyContext |= ProcessPostTraversalForText(n, textState);
       }
     }
   }
 
   aElement->UnsetHasDirtyDescendantsForServo();
   aElement->UnsetHasAnimationOnlyDirtyDescendantsForServo();
   aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
   return recreatedAnyContext;
 }
 
 bool
 ServoRestyleManager::ProcessPostTraversalForText(
     nsIContent* aTextNode,
-    nsStyleChangeList& aChangeList,
     TextPostTraversalState& aPostTraversalState)
 {
   // Handle lazy frame construction.
   if (aTextNode->HasFlag(NODE_NEEDS_FRAME)) {
-    aChangeList.AppendChange(nullptr, aTextNode, nsChangeHint_ReconstructFrame);
+    aPostTraversalState.ChangeList().AppendChange(
+      nullptr, aTextNode, nsChangeHint_ReconstructFrame);
     return true;
   }
 
   // Handle restyle.
   nsIFrame* primaryFrame = aTextNode->GetPrimaryFrame();
   if (!primaryFrame) {
     return false;
   }
 
   RefPtr<nsStyleContext> oldStyleContext = primaryFrame->StyleContext();
   nsStyleContext& newContext = aPostTraversalState.ComputeStyle(aTextNode);
-  aPostTraversalState.ComputeHintIfNeeded(
-      aTextNode, primaryFrame, newContext, aChangeList);
+  aPostTraversalState.ComputeHintIfNeeded(aTextNode, primaryFrame, newContext);
 
   for (nsIFrame* f = primaryFrame; f;
        f = GetNextContinuationWithSameStyle(f, oldStyleContext)) {
     f->SetStyleContext(&newContext);
   }
 
   return true;
 }
@@ -637,19 +626,18 @@ ServoRestyleManager::DoProcessPendingRes
     }
 
     // Recreate style contexts, and queue up change hints (which also handle
     // lazy frame construction).
     nsStyleChangeList currentChanges(StyleBackendType::Servo);
     DocumentStyleRootIterator iter(doc);
     bool anyStyleChanged = false;
     while (Element* root = iter.GetNextStyleRoot()) {
-      anyStyleChanged |=
-        ProcessPostTraversal(
-            root, nullptr, styleSet, currentChanges, nsChangeHint(0));
+      ServoRestyleState state(*styleSet, currentChanges);
+      anyStyleChanged |= ProcessPostTraversal(root, nullptr, state);
     }
 
     // Process the change hints.
     //
     // Unfortunately, the frame constructor can generate new change hints while
     // processing existing ones. We redirect those into a secondary queue and
     // iterate until there's nothing left.
     ReentrantChangeList newChanges;
--- a/layout/base/ServoRestyleManager.h
+++ b/layout/base/ServoRestyleManager.h
@@ -23,16 +23,46 @@ class nsAttrValue;
 class nsIAtom;
 class nsIContent;
 class nsIFrame;
 class nsStyleChangeList;
 
 namespace mozilla {
 
 /**
+ * A stack class used to pass some common restyle state in a slightly more
+ * comfortable way than a bunch of individual arguments.
+ */
+class ServoRestyleState
+{
+public:
+  ServoRestyleState(ServoStyleSet& aStyleSet, nsStyleChangeList& aChangeList)
+    : mStyleSet(aStyleSet)
+    , mChangeList(aChangeList)
+    , mChangesHandled(nsChangeHint(0))
+  {}
+
+  ServoRestyleState(ServoRestyleState& aParentState,
+                    nsChangeHint aHintForThisFrame)
+    : mStyleSet(aParentState.mStyleSet)
+    , mChangeList(aParentState.mChangeList)
+    , mChangesHandled(aParentState.mChangesHandled | aHintForThisFrame)
+  {}
+
+  nsChangeHint ChangesHandled() const { return mChangesHandled; }
+  nsStyleChangeList& ChangeList() { return mChangeList; }
+  ServoStyleSet& StyleSet() { return mStyleSet; }
+
+private:
+  ServoStyleSet& mStyleSet;
+  nsStyleChangeList& mChangeList;
+  const nsChangeHint mChangesHandled;
+};
+
+/**
  * Restyle manager for a Servo-backed style system.
  */
 class ServoRestyleManager : public RestyleManager
 {
   friend class ServoStyleSet;
 
 public:
   typedef ServoElementSnapshotTable SnapshotTable;
@@ -122,23 +152,20 @@ private:
    *
    * Returns whether any style did actually change. There may be cases where we
    * didn't need to change any style after all, for example, when a content
    * attribute changes that happens not to have any effect on the style of that
    * element or any descendant or sibling.
    */
   bool ProcessPostTraversal(Element* aElement,
                             nsStyleContext* aParentContext,
-                            ServoStyleSet* aStyleSet,
-                            nsStyleChangeList& aChangeList,
-                            nsChangeHint aChangesHandledForDescendants);
+                            ServoRestyleState& aRestyleState);
 
   struct TextPostTraversalState;
   bool ProcessPostTraversalForText(nsIContent* aTextNode,
-                                   nsStyleChangeList& aChangeList,
                                    TextPostTraversalState& aState);
 
   inline ServoStyleSet* StyleSet() const
   {
     MOZ_ASSERT(PresContext()->StyleSet()->IsServo(),
                "ServoRestyleManager should only be used with a Servo-flavored "
                "style backend");
     return PresContext()->StyleSet()->AsServo();
--- a/layout/generic/ViewportFrame.cpp
+++ b/layout/generic/ViewportFrame.cpp
@@ -5,16 +5,17 @@
 
 /*
  * rendering object that is the root of the frame tree, which contains
  * the document's scrollbars and contains fixed-positioned elements
  */
 
 #include "mozilla/ViewportFrame.h"
 
+#include "mozilla/ServoRestyleManager.h"
 #include "nsGkAtoms.h"
 #include "nsIScrollableFrame.h"
 #include "nsSubDocumentFrame.h"
 #include "nsCanvasFrame.h"
 #include "nsAbsoluteContainingBlock.h"
 #include "GeckoProfiler.h"
 #include "nsIMozBrowserFrame.h"
 #include "nsPlaceholderFrame.h"
@@ -411,34 +412,33 @@ ViewportFrame::ComputeCustomOverflow(nsO
   if (rootScrollFrame && !rootScrollFrame->IsIgnoringViewportClipping()) {
     return false;
   }
 
   return nsContainerFrame::ComputeCustomOverflow(aOverflowAreas);
 }
 
 void
-ViewportFrame::UpdateStyle(ServoStyleSet& aStyleSet,
-                           nsStyleChangeList& aChangeList)
+ViewportFrame::UpdateStyle(ServoRestyleState& aRestyleState)
 {
   nsStyleContext* oldContext = StyleContext();
   nsIAtom* pseudo = oldContext->GetPseudo();
   RefPtr<nsStyleContext> newContext =
-    aStyleSet.ResolveInheritingAnonymousBoxStyle(pseudo, nullptr);
+    aRestyleState.StyleSet().ResolveInheritingAnonymousBoxStyle(pseudo, nullptr);
 
   // We're special because we have a null GetContent(), so don't call things
   // like UpdateStyleOfOwnedChildFrame that try to append changes for the
   // content to the change list.  Nor do we computed a changehint, since we have
   // no way to apply it anyway.
   newContext->EnsureSameStructsCached(oldContext);
 
   MOZ_ASSERT(!GetNextContinuation(), "Viewport has continuations?");
   SetStyleContext(newContext);
 
-  UpdateStyleOfOwnedAnonBoxes(aStyleSet, aChangeList, nsChangeHint_Empty);
+  UpdateStyleOfOwnedAnonBoxes(aRestyleState);
 }
 
 void
 ViewportFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
 {
   if (mFrames.NotEmpty()) {
     aResult.AppendElement(mFrames.FirstChild());
   }
--- a/layout/generic/ViewportFrame.h
+++ b/layout/generic/ViewportFrame.h
@@ -13,16 +13,18 @@
 
 #include "mozilla/Attributes.h"
 #include "nsContainerFrame.h"
 
 class nsPresContext;
 
 namespace mozilla {
 
+class ServoRestyleState;
+
 /**
   * ViewportFrame is the parent of a single child - the doc root frame or a scroll frame
   * containing the doc root frame. ViewportFrame stores this child in its primary child
   * list.
   */
 class ViewportFrame : public nsContainerFrame {
 public:
   NS_DECL_QUERYFRAME
@@ -71,17 +73,17 @@ public:
    * @return the rect to use as containing block rect
    */
   nsRect AdjustReflowInputAsContainingBlock(ReflowInput* aReflowInput) const;
 
   /**
    * Update our style (and recursively the styles of any anonymous boxes we
    * might own)
    */
-  void UpdateStyle(ServoStyleSet& aStyleSet, nsStyleChangeList& aChangeList);
+  void UpdateStyle(ServoRestyleState& aStyleSet);
 
   /**
    * Return our single anonymous box child.
    */
   void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -10197,19 +10197,17 @@ nsFrame::BoxMetrics() const
 {
   nsBoxLayoutMetrics* metrics = GetProperty(BoxMetricsProperty());
   NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called");
   return metrics;
 }
 
 void
 nsIFrame::UpdateStyleOfChildAnonBox(nsIFrame* aChildFrame,
-                                    ServoStyleSet& aStyleSet,
-                                    nsStyleChangeList& aChangeList,
-                                    nsChangeHint aHintForThisFrame)
+                                    ServoRestyleState& aRestyleState)
 {
   MOZ_ASSERT(aChildFrame->GetParent() == this,
              "This should only be used for children!");
   MOZ_ASSERT((!GetContent() && IsViewportFrame()) ||
              aChildFrame->GetContent() == GetContent(),
              "What content node is it a frame for?");
   MOZ_ASSERT(!aChildFrame->GetPrevContinuation(),
              "Only first continuations should end up here");
@@ -10218,53 +10216,58 @@ nsIFrame::UpdateStyleOfChildAnonBox(nsIF
   // statically...  But this API is a bit nicer.
   nsIAtom* pseudo = aChildFrame->StyleContext()->GetPseudo();
   MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(pseudo), "Child is not an anon box?");
   MOZ_ASSERT(!nsCSSAnonBoxes::IsNonInheritingAnonBox(pseudo),
              "Why did the caller bother calling us?");
 
   // Anon boxes inherit from their parent; that's us.
   RefPtr<nsStyleContext> newContext =
-    aStyleSet.ResolveInheritingAnonymousBoxStyle(pseudo, StyleContext());
+    aRestyleState.StyleSet().ResolveInheritingAnonymousBoxStyle(pseudo,
+                                                                StyleContext());
 
   nsChangeHint childHint =
-    UpdateStyleOfOwnedChildFrame(aChildFrame, newContext, aChangeList);
+    UpdateStyleOfOwnedChildFrame(aChildFrame, newContext, aRestyleState);
 
   // Now that we've updated the style on aChildFrame, check whether it itself
   // has anon boxes to deal with.
-  aChildFrame->UpdateStyleOfOwnedAnonBoxes(aStyleSet, aChangeList, childHint);
+  ServoRestyleState childrenState(aRestyleState, childHint);
+  aChildFrame->UpdateStyleOfOwnedAnonBoxes(childrenState);
 }
 
 nsChangeHint
 nsIFrame::UpdateStyleOfOwnedChildFrame(nsIFrame* aChildFrame,
                                        nsStyleContext* aNewStyleContext,
-                                       nsStyleChangeList& aChangeList)
+                                       ServoRestyleState& aRestyleState)
 {
   // Figure out whether we have an actual change.  It's important that we do
   // this, for several reasons:
   //
   // 1) Even if all the child's changes are due to properties it inherits from
   //    us, it's possible that no one ever asked us for those style structs and
   //    hence changes to them aren't reflected in aHintForThisFrame at all.
   //
   // 2) Content can change stylesheets that change the styles of pseudos, and
   //    extensions can add/remove stylesheets that change the styles of
   //    anonymous boxes directly.
   uint32_t equalStructs, samePointerStructs; // Not used, actually.
   nsChangeHint childHint = aChildFrame->StyleContext()->CalcStyleDifference(
     aNewStyleContext,
     &equalStructs,
     &samePointerStructs);
+  childHint = NS_RemoveSubsumedHints(childHint, aRestyleState.ChangesHandled());
   if (childHint) {
     if (childHint & nsChangeHint_ReconstructFrame) {
       // If we generate a reconstruct here, remove any non-reconstruct hints we
       // may have already generated for this content.
-      aChangeList.PopChangesForContent(aChildFrame->GetContent());
-    }
-    aChangeList.AppendChange(aChildFrame, aChildFrame->GetContent(), childHint);
+      aRestyleState.ChangeList().PopChangesForContent(
+        aChildFrame->GetContent());
+    }
+    aRestyleState.ChangeList().AppendChange(
+      aChildFrame, aChildFrame->GetContent(), childHint);
   }
 
   for (nsIFrame* kid = aChildFrame; kid; kid = kid->GetNextContinuation()) {
     kid->SetStyleContext(aNewStyleContext);
   }
 
   return childHint;
 }
@@ -10556,49 +10559,44 @@ nsIFrame::UpdateWidgetProperties()
   }
   if (nsCOMPtr<nsIWidget> widget = GetWindowWidget(presContext)) {
     widget->SetWindowOpacity(StyleUIReset()->mWindowOpacity);
     widget->SetWindowTransform(ComputeWidgetTransform());
   }
 }
 
 void
-nsIFrame::DoUpdateStyleOfOwnedAnonBoxes(ServoStyleSet& aStyleSet,
-                                        nsStyleChangeList& aChangeList,
-                                        nsChangeHint aHintForThisFrame)
+nsIFrame::DoUpdateStyleOfOwnedAnonBoxes(ServoRestyleState& aRestyleState)
 {
   // As a special case, we check for {ib}-split block frames here, rather
   // than have an nsInlineFrame::AppendDirectlyOwnedAnonBoxes implementation
   // that returns them.
   //
   // (If we did handle them in AppendDirectlyOwnedAnonBoxes, we would have to
   // return *all* of the in-flow {ib}-split block frames, not just the first
   // one.  For restyling, we really just need the first in flow, and the other
   // user of the AppendOwnedAnonBoxes API, AllChildIterator, doesn't need to
   // know about them at all, since these block frames never create NAC.  So we
   // avoid any unncessary hashtable lookups for the {ib}-split frames by calling
   // UpdateStyleOfOwnedAnonBoxesForIBSplit directly here.)
   if (IsInlineFrame()) {
     if ((GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
-      static_cast<nsInlineFrame*>(this)->
-        UpdateStyleOfOwnedAnonBoxesForIBSplit(aStyleSet, aChangeList,
-                                              aHintForThisFrame);
+      static_cast<nsInlineFrame*>(this)->UpdateStyleOfOwnedAnonBoxesForIBSplit(
+        aRestyleState);
     }
     return;
   }
 
   AutoTArray<OwnedAnonBox,4> frames;
   AppendDirectlyOwnedAnonBoxes(frames);
   for (OwnedAnonBox& box : frames) {
     if (box.mUpdateStyleFn) {
-      box.mUpdateStyleFn(this, box.mAnonBoxFrame,
-                         aStyleSet, aChangeList, aHintForThisFrame);
+      box.mUpdateStyleFn(this, box.mAnonBoxFrame, aRestyleState);
     } else {
-      UpdateStyleOfChildAnonBox(box.mAnonBoxFrame,
-                                aStyleSet, aChangeList, aHintForThisFrame);
+      UpdateStyleOfChildAnonBox(box.mAnonBoxFrame, aRestyleState);
     }
   }
 }
 
 /* virtual */ void
 nsIFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
 {
   MOZ_ASSERT(!(GetStateBits() & NS_FRAME_OWNS_ANON_BOXES));
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -94,17 +94,17 @@ struct nsMargin;
 struct CharacterDataChangeInfo;
 
 namespace mozilla {
 
 enum class CSSPseudoElementType : uint8_t;
 class EventStates;
 struct ReflowInput;
 class ReflowOutput;
-class ServoStyleSet;
+class ServoRestyleState;
 class DisplayItemData;
 class EffectSet;
 
 namespace layers {
 class Layer;
 } // namespace layers
 
 namespace gfx {
@@ -3286,69 +3286,65 @@ public:
    * @return The style context that should be the parent of this frame's
    *         style context.  Null is permitted, and means that this frame's
    *         style context should be the root of the style context tree.
    */
   virtual nsStyleContext* GetParentStyleContext(nsIFrame** aProviderFrame) const = 0;
 
   /**
    * Called by ServoRestyleManager to update the style contexts of anonymous
-   * boxes directly associtated with this frame.  The passed-in ServoStyleSet
-   * can be used to create new style contexts as needed.
+   * boxes directly associtated with this frame.
+   *
+   * The passed-in ServoRestyleState can be used to create new style contexts
+   * as needed, as well as posting changes to the change list.
+   *
+   * It's guaranteed to already have a change in it for this frame and this
+   * frame's content.
    *
    * This function will be called after this frame's style context has already
    * been updated.  This function will only be called on frames which have the
    * NS_FRAME_OWNS_ANON_BOXES bit set.
-   *
-   * The nsStyleChangeList can be used to append additional changes.  It's
-   * guaranteed to already have a change in it for this frame and this frame's
-   * content and a change hint of aHintForThisFrame.
-   */
-  void UpdateStyleOfOwnedAnonBoxes(mozilla::ServoStyleSet& aStyleSet,
-                                   nsStyleChangeList& aChangeList,
-                                   nsChangeHint aHintForThisFrame) {
+   */
+  void UpdateStyleOfOwnedAnonBoxes(mozilla::ServoRestyleState& aRestyleState)
+  {
     if (GetStateBits() & NS_FRAME_OWNS_ANON_BOXES) {
-      DoUpdateStyleOfOwnedAnonBoxes(aStyleSet, aChangeList, aHintForThisFrame);
+      DoUpdateStyleOfOwnedAnonBoxes(aRestyleState);
     }
   }
 
 protected:
   // This does the actual work of UpdateStyleOfOwnedAnonBoxes.  It calls
   // AppendDirectlyOwnedAnonBoxes to find all of the anonymous boxes
   // owned by this frame, and then updates styles on each of them.
-  void DoUpdateStyleOfOwnedAnonBoxes(mozilla::ServoStyleSet& aStyleSet,
-                                     nsStyleChangeList& aChangeList,
-                                     nsChangeHint aHintForThisFrame);
+  void DoUpdateStyleOfOwnedAnonBoxes(mozilla::ServoRestyleState& aRestyleState);
 
   // A helper for DoUpdateStyleOfOwnedAnonBoxes for the specific case
   // of the owned anon box being a child of this frame.
   void UpdateStyleOfChildAnonBox(nsIFrame* aChildFrame,
-                                 mozilla::ServoStyleSet& aStyleSet,
-                                 nsStyleChangeList& aChangeList,
-                                 nsChangeHint aHintForThisFrame);
+                                 mozilla::ServoRestyleState& aRestyleState);
 
 public:
   // A helper both for UpdateStyleOfChildAnonBox, and to update frame-backed
   // pseudo-elements in ServoRestyleManager.
   //
   // This gets a style context that will be the new style context for
   // `aChildFrame`, and takes care of updating it, calling CalcStyleDifference,
   // and adding to the change list as appropriate.
   //
   // Returns the generated change hint for the frame.
   nsChangeHint UpdateStyleOfOwnedChildFrame(
-      nsIFrame* aChildFrame,
-      nsStyleContext* aNewStyleContext,
-      nsStyleChangeList& aChangeList);
+    nsIFrame* aChildFrame,
+    nsStyleContext* aNewStyleContext,
+    mozilla::ServoRestyleState& aRestyleState);
 
   struct OwnedAnonBox
   {
-    typedef void (*UpdateStyleFn)(nsIFrame* aOwningFrame, nsIFrame* aAnonBox,
-                                  mozilla::ServoStyleSet&,
-                                  nsStyleChangeList&, nsChangeHint);
+    typedef void (*UpdateStyleFn)(nsIFrame* aOwningFrame,
+                                  nsIFrame* aAnonBox,
+                                  mozilla::ServoRestyleState& aRestyleState);
 
     explicit OwnedAnonBox(nsIFrame* aAnonBoxFrame,
                           UpdateStyleFn aUpdateStyleFn = nullptr)
       : mAnonBoxFrame(aAnonBoxFrame)
       , mUpdateStyleFn(aUpdateStyleFn)
     {}
 
     nsIFrame* mAnonBoxFrame;
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -1010,19 +1010,17 @@ nsInlineFrame::AccessibleType()
     return a11y::eHyperTextType;
 
   return a11y::eNoType;
 }
 #endif
 
 void
 nsInlineFrame::UpdateStyleOfOwnedAnonBoxesForIBSplit(
-    ServoStyleSet& aStyleSet,
-    nsStyleChangeList& aChangeList,
-    nsChangeHint aHintForThisFrame)
+  ServoRestyleState& aRestyleState)
 {
   MOZ_ASSERT(GetStateBits() & NS_FRAME_OWNS_ANON_BOXES,
              "Why did we get called?");
   MOZ_ASSERT(GetStateBits() & NS_FRAME_PART_OF_IBSPLIT,
              "Why did we have the NS_FRAME_OWNS_ANON_BOXES bit set?");
   // Note: this assert _looks_ expensive, but it's cheap in all the cases when
   // it passes!
   MOZ_ASSERT(nsLayoutUtils::FirstContinuationOrIBSplitSibling(this) == this,
@@ -1032,23 +1030,23 @@ nsInlineFrame::UpdateStyleOfOwnedAnonBox
              "We should be the primary frame for our element");
 
   nsIFrame* blockFrame = GetProperty(nsIFrame::IBSplitSibling());
   MOZ_ASSERT(blockFrame, "Why did we have an IB split?");
 
   // The anonymous block's style inherits from ours, and we already have our new
   // style context.
   RefPtr<nsStyleContext> newContext =
-    aStyleSet.ResolveInheritingAnonymousBoxStyle(
+    aRestyleState.StyleSet().ResolveInheritingAnonymousBoxStyle(
       nsCSSAnonBoxes::mozBlockInsideInlineWrapper, StyleContext());
 
   // We're guaranteed that newContext only differs from the old style context on
   // the block in things they might inherit from us.  And changehint processing
   // guarantees walking the continuation and ib-sibling chains, so our existing
-  // changehint beign in aChangeList is good enough.  So we don't need to touch
+  // changehint being in aChangeList is good enough.  So we don't need to touch
   // aChangeList at all here.
 
   while (blockFrame) {
     MOZ_ASSERT(!blockFrame->GetPrevContinuation(),
                "Must be first continuation");
 
     MOZ_ASSERT(blockFrame->StyleContext()->GetPseudo() ==
                nsCSSAnonBoxes::mozBlockInsideInlineWrapper,
--- a/layout/generic/nsInlineFrame.h
+++ b/layout/generic/nsInlineFrame.h
@@ -112,19 +112,17 @@ public:
     return (GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET)
              ? !!(GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST)
              : (!GetNextInFlow());
   }
 
   // Restyles the block wrappers around our non-inline-outside kids.
   // This will only be called when such wrappers in fact exist.
   void UpdateStyleOfOwnedAnonBoxesForIBSplit(
-      mozilla::ServoStyleSet& aStyleSet,
-      nsStyleChangeList& aChangeList,
-      nsChangeHint aHintForThisFrame);
+    mozilla::ServoRestyleState& aRestyleState);
 
 protected:
   // Additional reflow state used during our reflow methods
   struct InlineReflowInput {
     nsIFrame* mPrevFrame;
     nsInlineFrame* mNextInFlow;
     nsIFrame*      mLineContainer;
     nsLineLayout*  mLineLayout;
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -34,16 +34,17 @@
 #include "nsCSSAnonBoxes.h"
 #include "nsIPresShell.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIScriptError.h"
 #include "nsFrameManager.h"
 #include "nsError.h"
 #include "nsCSSFrameConstructor.h"
+#include "mozilla/ServoRestyleManager.h"
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/StyleSetHandle.h"
 #include "mozilla/StyleSetHandleInlines.h"
 #include "nsDisplayList.h"
 #include "nsIScrollableFrame.h"
 #include "nsCSSProps.h"
 #include "RestyleTracker.h"
 #include "nsStyleChangeList.h"
@@ -8008,43 +8009,43 @@ nsTableFrame::AppendDirectlyOwnedAnonBox
                nsCSSAnonBoxes::tableWrapper,
              "What happened to our parent?");
   aResult.AppendElement(
     OwnedAnonBox(wrapper, &UpdateStyleOfOwnedAnonBoxesForTableWrapper));
 }
 
 /* static */ void
 nsTableFrame::UpdateStyleOfOwnedAnonBoxesForTableWrapper(
-    nsIFrame* aOwningFrame,
-    nsIFrame* aWrapperFrame,
-    ServoStyleSet& aStyleSet,
-    nsStyleChangeList& aChangeList,
-    nsChangeHint aHintForThisFrame)
+  nsIFrame* aOwningFrame,
+  nsIFrame* aWrapperFrame,
+  ServoRestyleState& aRestyleState)
 {
   MOZ_ASSERT(aWrapperFrame->StyleContext()->GetPseudo() ==
                nsCSSAnonBoxes::tableWrapper,
              "What happened to our parent?");
 
   RefPtr<nsStyleContext> newContext =
-    aStyleSet.ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::tableWrapper,
-                                                 aOwningFrame->StyleContext());
+    aRestyleState.StyleSet().ResolveInheritingAnonymousBoxStyle(
+      nsCSSAnonBoxes::tableWrapper, aOwningFrame->StyleContext());
 
   // Figure out whether we have an actual change.  It's important that we do
   // this, even though all the wrapper's changes are due to properties it
   // inherits from us, because it's possible that no one ever asked us for those
   // style structs and hence changes to them aren't reflected in
   // aHintForThisFrame at all.
   uint32_t equalStructs, samePointerStructs; // Not used, actually.
   nsChangeHint wrapperHint = aWrapperFrame->StyleContext()->CalcStyleDifference(
     newContext,
     &equalStructs,
     &samePointerStructs);
+  wrapperHint =
+    NS_RemoveSubsumedHints(wrapperHint, aRestyleState.ChangesHandled());
   if (wrapperHint) {
-    aChangeList.AppendChange(aWrapperFrame, aWrapperFrame->GetContent(),
-                             wrapperHint);
+    aRestyleState.ChangeList().AppendChange(
+      aWrapperFrame, aWrapperFrame->GetContent(), wrapperHint);
   }
 
   for (nsIFrame* cur = aWrapperFrame; cur; cur = cur->GetNextContinuation()) {
     cur->SetStyleContext(newContext);
   }
 
   MOZ_ASSERT(!(aWrapperFrame->GetStateBits() & NS_FRAME_OWNS_ANON_BOXES),
              "Wrapper frame doesn't have any anon boxes of its own!");
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -593,21 +593,19 @@ public:
 
   virtual bool ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) override;
 
   // Return our wrapper frame.
   void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override;
 
 protected:
   static void UpdateStyleOfOwnedAnonBoxesForTableWrapper(
-      nsIFrame* aOwningFrame,
-      nsIFrame* aWrapperFrame,
-      mozilla::ServoStyleSet& aStyleSet,
-      nsStyleChangeList& aChangeList,
-      nsChangeHint aHintForThisFrame);
+    nsIFrame* aOwningFrame,
+    nsIFrame* aWrapperFrame,
+    mozilla::ServoRestyleState& aRestyleState);
 
   /** protected constructor.
     * @see NewFrame
     */
   explicit nsTableFrame(nsStyleContext* aContext, ClassID aID = kClassID);
 
   /** destructor, responsible for mColumnLayoutData */
   virtual ~nsTableFrame();