Bug 1356141 - Don't traverse any elements that needed only for animation-only restyles in normal traversal. r?heycam draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Tue, 20 Jun 2017 06:30:48 +0900
changeset 596933 b5586c0a92c6f3d65499b7be123e1f51dd2ca100
parent 596932 a3815f61536ecadbd33636471ea0e3e49dc62a82
child 596934 445e8633edf2dca920aeba703287b7f406d7df34
push id64773
push userhikezoe@mozilla.com
push dateMon, 19 Jun 2017 21:31:47 +0000
reviewersheycam
bugs1356141
milestone56.0a1
Bug 1356141 - Don't traverse any elements that needed only for animation-only restyles in normal traversal. r?heycam Before this patch, we were setting the dirty descendants bit in animation-only restyles and it triggered unnecessary traversal for elements that does not need the traversal (i.e no need selector matching). MozReview-Commit-ID: 6pmF3ojVzgb
dom/base/Element.h
layout/base/ServoRestyleManager.cpp
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -482,16 +482,26 @@ public:
 
   void UnsetHasDirtyDescendantsForServo() {
     MOZ_ASSERT(IsStyledByServo());
     UnsetFlags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
   }
 
   inline void NoteDirtyDescendantsForServo();
 
+  bool HasAnimationOnlyDirtyDescendantsForServo() const {
+    MOZ_ASSERT(IsStyledByServo());
+    return HasFlag(ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO);
+  }
+
+  void UnsetHasAnimationOnlyDirtyDescendantsForServo() {
+    MOZ_ASSERT(IsStyledByServo());
+    UnsetFlags(ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO);
+  }
+
 #ifdef DEBUG
   inline bool DirtyDescendantsBitIsPropagatedForServo();
 #endif
 
   bool HasServoData() const {
     return !!mServoData.Get();
   }
 
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -129,45 +129,48 @@ ServoRestyleManager::PostRebuildAllStyle
   // if we do, we need to re-selector-match them here.
 }
 
 /* static */ void
 ServoRestyleManager::ClearServoDataFromSubtree(Element* aElement)
 {
   if (!aElement->HasServoData()) {
     MOZ_ASSERT(!aElement->HasDirtyDescendantsForServo());
+    MOZ_ASSERT(!aElement->HasAnimationOnlyDirtyDescendantsForServo());
     return;
   }
 
   StyleChildrenIterator it(aElement);
   for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
     if (n->IsElement()) {
       ClearServoDataFromSubtree(n->AsElement());
     }
   }
 
   aElement->ClearServoData();
   aElement->UnsetHasDirtyDescendantsForServo();
+  aElement->UnsetHasAnimationOnlyDirtyDescendantsForServo();
 }
 
-
 /* static */ void
 ServoRestyleManager::ClearRestyleStateFromSubtree(Element* aElement)
 {
-  if (aElement->HasDirtyDescendantsForServo()) {
+  if (aElement->HasDirtyDescendantsForServo() ||
+      aElement->HasAnimationOnlyDirtyDescendantsForServo()) {
     StyleChildrenIterator it(aElement);
     for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
       if (n->IsElement()) {
         ClearRestyleStateFromSubtree(n->AsElement());
       }
     }
   }
 
   Unused << Servo_TakeChangeHint(aElement);
   aElement->UnsetHasDirtyDescendantsForServo();
+  aElement->UnsetHasAnimationOnlyDirtyDescendantsForServo();
   aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
 }
 
 /**
  * This struct takes care of encapsulating some common state that text nodes may
  * need to track during the post-traversal.
  *
  * This is currently used to properly compute change hints when the parent
@@ -439,17 +442,19 @@ ServoRestyleManager::ProcessPostTraversa
     // 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);
   }
 
   const bool descendantsNeedFrames =
     aElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
   const bool traverseElementChildren =
-    aElement->HasDirtyDescendantsForServo() || descendantsNeedFrames;
+    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(
@@ -465,16 +470,17 @@ ServoRestyleManager::ProcessPostTraversa
       } else if (traverseTextChildren && n->IsNodeOfType(nsINode::eTEXT)) {
         recreatedAnyContext |=
           ProcessPostTraversalForText(n, aChangeList, textState);
       }
     }
   }
 
   aElement->UnsetHasDirtyDescendantsForServo();
+  aElement->UnsetHasAnimationOnlyDirtyDescendantsForServo();
   aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
   return recreatedAnyContext;
 }
 
 bool
 ServoRestyleManager::ProcessPostTraversalForText(
     nsIContent* aTextNode,
     nsStyleChangeList& aChangeList,