Bug 1351535 - Part 6: Add ServoStyleSet::StyleSubtreeForReconstruct. r=bholley draft
authorCameron McCormack <cam@mcc.id.au>
Tue, 04 Apr 2017 19:34:30 +0800
changeset 558894 a1b4f206b2df8f4329f1ebc7a61af8666109f694
parent 558893 0d25cca9d788bc246b30f84032ab89e643782949
child 558895 95853ed25a56d063ef8b5d5ea5f1364b2463e6bc
push id52984
push userbmo:cam@mcc.id.au
push dateSat, 08 Apr 2017 15:03:01 +0000
reviewersbholley
bugs1351535
milestone55.0a1
Bug 1351535 - Part 6: Add ServoStyleSet::StyleSubtreeForReconstruct. r=bholley MozReview-Commit-ID: CovU36o4lAV
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -209,23 +209,27 @@ ServoStyleSet::PreTraverseSync()
   ResolveMappedAttrDeclarationBlocks();
 
   // This is lazily computed and pseudo matching needs to access
   // it so force computation early.
   mPresContext->Document()->GetDocumentState();
 }
 
 void
-ServoStyleSet::PreTraverse()
+ServoStyleSet::PreTraverse(Element* aRoot)
 {
   PreTraverseSync();
 
   // Process animation stuff that we should avoid doing during the parallel
   // traversal.
-  mPresContext->EffectCompositor()->PreTraverse();
+  if (aRoot) {
+    mPresContext->EffectCompositor()->PreTraverseInSubtree(aRoot);
+  } else {
+    mPresContext->EffectCompositor()->PreTraverse();
+  }
 }
 
 bool
 ServoStyleSet::PrepareAndTraverseSubtree(RawGeckoElementBorrowed aRoot,
                                          TraversalRootBehavior aRootBehavior,
                                          TraversalRestyleBehavior
                                            aRestyleBehavior)
 {
@@ -233,37 +237,44 @@ ServoStyleSet::PrepareAndTraverseSubtree
   // calling into the (potentially-parallel) Servo traversal, where a cache hit
   // is necessary to avoid a data race when updating the cache.
   mozilla::Unused << aRoot->OwnerDoc()->GetRootElement();
 
   MOZ_ASSERT(!sInServoTraversal);
   sInServoTraversal = true;
 
   bool isInitial = !aRoot->HasServoData();
+  bool forReconstruct =
+    aRestyleBehavior == TraversalRestyleBehavior::ForReconstruct;
   bool postTraversalRequired =
     Servo_TraverseSubtree(aRoot, mRawSet.get(), aRootBehavior, aRestyleBehavior);
-  MOZ_ASSERT_IF(isInitial, !postTraversalRequired);
+  MOZ_ASSERT_IF(isInitial || forReconstruct, !postTraversalRequired);
+
+  auto root = const_cast<Element*>(aRoot);
 
   // If there are still animation restyles needed, trigger a second traversal to
   // update CSS animations' styles.
-  if (mPresContext->EffectCompositor()->PreTraverse()) {
+  EffectCompositor* compositor = mPresContext->EffectCompositor();
+  if (forReconstruct ? compositor->PreTraverseInSubtree(root)
+                     : compositor->PreTraverse()) {
     if (Servo_TraverseSubtree(aRoot, mRawSet.get(),
                               aRootBehavior, aRestyleBehavior)) {
+      MOZ_ASSERT(!forReconstruct);
       if (isInitial) {
         // We're doing initial styling, and the additional animation
         // traversal changed the styles that were set by the first traversal.
         // This would normally require a post-traversal to update the style
         // contexts, and the DOM now has dirty descendant bits and RestyleData
         // in expectation of that post-traversal. But since this is actually
         // the initial styling, there are no style contexts to update and no
         // frames to apply the change hints to, so we don't need to do that
         // post-traversal. Instead, just drop this state and tell the caller
         // that no post-traversal is required.
         MOZ_ASSERT(!postTraversalRequired);
-        ServoRestyleManager::ClearRestyleStateFromSubtree(const_cast<Element*>(aRoot));
+        ServoRestyleManager::ClearRestyleStateFromSubtree(root);
       } else {
         postTraversalRequired = true;
       }
     }
   }
 
   sInServoTraversal = false;
   return postTraversalRequired;
@@ -742,16 +753,28 @@ ServoStyleSet::StyleNewChildren(Element*
   PrepareAndTraverseSubtree(aParent,
                             TraversalRootBehavior::UnstyledChildrenOnly,
                             TraversalRestyleBehavior::Normal);
   // We can't assert that Servo_TraverseSubtree returns false, since aParent
   // or some of its other children might have pending restyles.
 }
 
 void
+ServoStyleSet::StyleSubtreeForReconstruct(Element* aRoot)
+{
+  PreTraverse(aRoot);
+
+  DebugOnly<bool> postTraversalRequired =
+    PrepareAndTraverseSubtree(aRoot,
+                              TraversalRootBehavior::Normal,
+                              TraversalRestyleBehavior::ForReconstruct);
+  MOZ_ASSERT(!postTraversalRequired);
+}
+
+void
 ServoStyleSet::NoteStyleSheetsChanged()
 {
   Servo_StyleSet_NoteStyleSheetsChanged(mRawSet.get());
 }
 
 #ifdef DEBUG
 void
 ServoStyleSet::AssertTreeIsClean()
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -232,16 +232,26 @@ public:
    * Like the above, but skips the root node, and only styles unstyled children.
    * When potentially appending multiple children, it's preferable to call
    * StyleNewChildren on the node rather than making multiple calls to
    * StyleNewSubtree on each child, since it allows for more parallelism.
    */
   void StyleNewChildren(dom::Element* aParent);
 
   /**
+   * Like StyleNewSubtree, but in response to a request to reconstruct frames
+   * for the given subtree, and so works on elements that already have
+   * styles.  This will leave the subtree in a state just like after an initial
+   * styling, i.e. with new styles, no change hints, and with the dirty
+   * descendants bits cleared.  No comparison of old and new styles is done,
+   * so no change hints will be processed.
+   */
+  void StyleSubtreeForReconstruct(dom::Element* aRoot);
+
+  /**
    * Records that the contents of style sheets have changed since the last
    * restyle.  Calling this will ensure that the Stylist rebuilds its
    * selector maps.
    */
   void NoteStyleSheetsChanged();
 
 #ifdef DEBUG
   void AssertTreeIsClean();
@@ -309,18 +319,21 @@ private:
    * Clear our cached mNonInheritingStyleContexts.  We do this when we want to
    * make sure those style contexts won't live too long (e.g. when rebuilding
    * all style data or when shutting down the style set).
    */
   void ClearNonInheritingStyleContexts();
 
   /**
    * Perform processes that we should do before traversing.
+   *
+   * When aRoot is null, the entire document is pre-traversed.  Otherwise,
+   * only the subtree rooted at aRoot is pre-traversed.
    */
-  void PreTraverse();
+  void PreTraverse(dom::Element* aRoot = nullptr);
   // Subset of the pre-traverse steps that involve syncing up data
   void PreTraverseSync();
 
   already_AddRefed<ServoComputedValues> ResolveStyleLazily(dom::Element* aElement,
                                                            nsIAtom* aPseudoTag);
 
   nsPresContext* mPresContext;
   UniquePtr<RawServoStyleSet> mRawSet;