Bug 1351535 - Part 5: Add EffectCompositor method to pre-traverse within a specific subtree. r=hiro draft
authorCameron McCormack <cam@mcc.id.au>
Tue, 04 Apr 2017 19:12:54 +0800
changeset 558893 0d25cca9d788bc246b30f84032ab89e643782949
parent 558892 0836d2e91bd0f7bce471154b1c78727e19e4f75f
child 558894 a1b4f206b2df8f4329f1ebc7a61af8666109f694
push id52984
push userbmo:cam@mcc.id.au
push dateSat, 08 Apr 2017 15:03:01 +0000
reviewershiro
bugs1351535
milestone55.0a1
Bug 1351535 - Part 5: Add EffectCompositor method to pre-traverse within a specific subtree. r=hiro It's not great that we traverse up the tree looking for the subtree root for each animating element that is in mElementsToRestyle. An alternative could be to traverse the entire subtree and build a hash set of the elements within it, so that each test in the mElementsToRestyle loop can be done quickly. I suspect that most of the time looking up the tree for each animation will be quicker, but it does have worse worst case behavior. MozReview-Commit-ID: FWoQ7fD9YZC
dom/animation/EffectCompositor.cpp
dom/animation/EffectCompositor.h
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -958,30 +958,56 @@ EffectCompositor::SetPerformanceWarning(
   for (KeyframeEffectReadOnly* effect : *effects) {
     effect->SetPerformanceWarning(aProperty, aWarning);
   }
 }
 
 bool
 EffectCompositor::PreTraverse()
 {
+  return PreTraverseInSubtree(nullptr);
+}
+
+static bool
+IsFlattenedTreeDescendantOf(nsINode* aPossibleDescendant,
+                            nsINode* aPossibleAncestor)
+{
+  do {
+    if (aPossibleDescendant == aPossibleAncestor) {
+      return true;
+    }
+    aPossibleDescendant = aPossibleDescendant->GetFlattenedTreeParentNode();
+  } while (aPossibleDescendant);
+
+  return false;
+}
+
+bool
+EffectCompositor::PreTraverseInSubtree(Element* aRoot)
+{
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mPresContext->RestyleManager()->IsServo());
 
   bool foundElementsNeedingRestyle = false;
   for (auto& elementsToRestyle : mElementsToRestyle) {
     for (auto iter = elementsToRestyle.Iter(); !iter.Done(); iter.Next()) {
       bool postedRestyle = iter.Data();
       // Ignore throttled restyle.
       if (!postedRestyle) {
         continue;
       }
 
       NonOwningAnimationTarget target = iter.Key();
 
+      // Ignore restyles that aren't in the flattened tree subtree rooted at
+      // aRoot.
+      if (aRoot && !IsFlattenedTreeDescendantOf(target.mElement, aRoot)) {
+        continue;
+      }
+
       // We need to post restyle hints even if the target is not in EffectSet to
       // ensure the final restyling for removed animations.
       // We can't call PostRestyleEvent directly here since we are still in the
       // middle of the servo traversal.
       mPresContext->RestyleManager()->AsServo()->
         PostRestyleEventForAnimations(target.mElement, eRestyle_CSSAnimations);
 
       foundElementsNeedingRestyle = true;
--- a/dom/animation/EffectCompositor.h
+++ b/dom/animation/EffectCompositor.h
@@ -244,16 +244,20 @@ public:
   // traversal (e.g. changing member variables) for all elements that we expect
   // to restyle on the next traversal.
   // Returns true if there are elements needing a restyle for animation.
   bool PreTraverse();
 
   // Similar to the above but only for the (pseudo-)element.
   bool PreTraverse(dom::Element* aElement, nsIAtom* aPseudoTagOrNull);
 
+  // Similar to the above but for all elements in the subtree rooted
+  // at aElement.
+  bool PreTraverseInSubtree(dom::Element* aElement);
+
 private:
   ~EffectCompositor() = default;
 
   // Rebuilds the animation rule corresponding to |aCascadeLevel| on the
   // EffectSet associated with the specified (pseudo-)element.
   static void ComposeAnimationRule(dom::Element* aElement,
                                    CSSPseudoElementType aPseudoType,
                                    CascadeLevel aCascadeLevel);