Bug 1351535 - Part 6: Add ServoStyleSet::StyleSubtreeForReconstruct. r=bholley
authorCameron McCormack <cam@mcc.id.au>
Tue, 04 Apr 2017 19:34:30 +0800
changeset 352020 3ce1babe4c79569db6038ba8c644e342e91dfe7f
parent 352019 cf6904042b25b92aaffe12206c1aeced91f9b466
child 352021 fbbbbb072f1a4dfc9a8a9ee4f86beb8643536159
push id40356
push usercmccormack@mozilla.com
push dateSun, 09 Apr 2017 06:42:27 +0000
treeherderautoland@fbbbbb072f1a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1351535
milestone55.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 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;