Bug 1355348 - Add SMIL restyles in the stylo pretraverse; r=heycam
authorBrian Birtles <birtles@gmail.com>
Wed, 26 Apr 2017 13:00:11 +0900
changeset 569344 f4de7213d853c01abe9bb2b1da738d4b0b90095d
parent 569343 5881280a872d74f1a24fc212ec524209a5631758
child 569345 a1e5a034eefb49ca4b577c0b44c77a5ca377d2e4
push id56143
push userbmo:jeremychen@mozilla.com
push dateThu, 27 Apr 2017 10:17:21 +0000
reviewersheycam
bugs1355348
milestone55.0a1
Bug 1355348 - Add SMIL restyles in the stylo pretraverse; r=heycam MozReview-Commit-ID: mwjkKr6wsr
dom/smil/nsSMILAnimationController.cpp
dom/smil/nsSMILAnimationController.h
layout/style/ServoStyleSet.cpp
--- a/dom/smil/nsSMILAnimationController.cpp
+++ b/dom/smil/nsSMILAnimationController.cpp
@@ -6,16 +6,18 @@
 
 #include "nsSMILAnimationController.h"
 
 #include <algorithm>
 
 #include "mozilla/AutoRestore.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/SVGAnimationElement.h"
+#include "mozilla/RestyleManagerInlines.h"
+#include "nsContentUtils.h"
 #include "nsCSSProps.h"
 #include "nsIDocument.h"
 #include "nsIPresShell.h"
 #include "nsIPresShellInlines.h"
 #include "nsITimer.h"
 #include "nsSMILCompositor.h"
 #include "nsSMILCSSProperty.h"
 #include "nsSMILTimedElement.h"
@@ -718,16 +720,77 @@ nsSMILAnimationController::AddStyleUpdat
     aTracker.AddPendingRestyle(key.mElement,
                                eRestyle_StyleAttribute_Animations,
                                nsChangeHint(0));
   }
 
   mMightHavePendingStyleUpdates = false;
 }
 
+bool
+nsSMILAnimationController::PreTraverse()
+{
+  return PreTraverseInSubtree(nullptr);
+}
+
+bool
+nsSMILAnimationController::PreTraverseInSubtree(Element* aRoot)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!mMightHavePendingStyleUpdates) {
+    return false;
+  }
+
+  nsIPresShell* shell = mDocument->GetShell();
+  if (!shell) {
+    return false;
+  }
+
+  nsPresContext* context = shell->GetPresContext();
+  if (!context) {
+    return false;
+  }
+  MOZ_ASSERT(context->RestyleManager()->IsServo(),
+             "PreTraverse should only be called for the servo style system");
+
+  bool foundElementsNeedingRestyle = false;
+  for (auto iter = mAnimationElementTable.Iter(); !iter.Done(); iter.Next()) {
+    SVGAnimationElement* animElement = iter.Get()->GetKey();
+
+    nsSMILTargetIdentifier key;
+    if (!GetTargetIdentifierForAnimation(animElement, key)) {
+      // Something's wrong/missing about animation's target; skip this animation
+      continue;
+    }
+
+    // Ignore restyles that aren't in the flattened tree subtree rooted at
+    // aRoot.
+    if (aRoot &&
+        !nsContentUtils::ContentIsFlattenedTreeDescendantOf(key.mElement,
+                                                            aRoot)) {
+      continue;
+    }
+
+    context->RestyleManager()->AsServo()->
+      PostRestyleEventForAnimations(key.mElement,
+                                    eRestyle_StyleAttribute_Animations);
+
+    foundElementsNeedingRestyle = true;
+  }
+
+  // Only clear the mMightHavePendingStyleUpdates flag if we definitely posted
+  // all restyles.
+  if (!aRoot) {
+    mMightHavePendingStyleUpdates = false;
+  }
+
+  return foundElementsNeedingRestyle;
+}
+
 //----------------------------------------------------------------------
 // Add/remove child time containers
 
 nsresult
 nsSMILAnimationController::AddChild(nsSMILTimeContainer& aChild)
 {
   TimeContainerPtrKey* key = mChildContainerTable.PutEntry(&aChild);
   NS_ENSURE_TRUE(key, NS_ERROR_OUT_OF_MEMORY);
--- a/dom/smil/nsSMILAnimationController.h
+++ b/dom/smil/nsSMILAnimationController.h
@@ -20,16 +20,17 @@
 #include "nsRefreshDriver.h"
 
 struct nsSMILTargetIdentifier;
 class nsIDocument;
 
 namespace mozilla {
 class RestyleTracker;
 namespace dom {
+class Element;
 class SVGAnimationElement;
 } // namespace dom
 } // namespace mozilla
 
 //----------------------------------------------------------------------
 // nsSMILAnimationController
 //
 // The animation controller maintains the animation timer and determines the
@@ -108,16 +109,19 @@ public:
   }
 
   void AddStyleUpdatesTo(mozilla::RestyleTracker& aTracker);
   bool MightHavePendingStyleUpdates() const
   {
     return mMightHavePendingStyleUpdates;
   }
 
+  bool PreTraverse();
+  bool PreTraverseInSubtree(mozilla::dom::Element* aRoot);
+
 protected:
   ~nsSMILAnimationController();
 
   // Typedefs
   typedef nsPtrHashKey<nsSMILTimeContainer> TimeContainerPtrKey;
   typedef nsTHashtable<TimeContainerPtrKey> TimeContainerHashtable;
   typedef nsPtrHashKey<mozilla::dom::SVGAnimationElement> AnimationElementPtrKey;
   typedef nsTHashtable<AnimationElementPtrKey> AnimationElementHashtable;
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/dom/KeyframeEffectReadOnly.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCSSRuleProcessor.h"
 #include "nsDeviceContext.h"
 #include "nsHTMLStyleSheet.h"
 #include "nsIDocumentInlines.h"
 #include "nsPrintfCString.h"
+#include "nsSMILAnimationController.h"
 #include "nsStyleContext.h"
 #include "nsStyleSet.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 ServoStyleSet::ServoStyleSet()
   : mPresContext(nullptr)
@@ -258,20 +259,28 @@ ServoStyleSet::PreTraverseSync()
 
 void
 ServoStyleSet::PreTraverse(Element* aRoot)
 {
   PreTraverseSync();
 
   // Process animation stuff that we should avoid doing during the parallel
   // traversal.
+  nsSMILAnimationController* smilController =
+    mPresContext->Document()->GetAnimationController();
   if (aRoot) {
     mPresContext->EffectCompositor()->PreTraverseInSubtree(aRoot);
+    if (smilController) {
+      smilController->PreTraverseInSubtree(aRoot);
+    }
   } else {
     mPresContext->EffectCompositor()->PreTraverse();
+    if (smilController) {
+      smilController->PreTraverse();
+    }
   }
 }
 
 bool
 ServoStyleSet::PrepareAndTraverseSubtree(RawGeckoElementBorrowed aRoot,
                                          TraversalRootBehavior aRootBehavior,
                                          TraversalRestyleBehavior
                                            aRestyleBehavior)
@@ -290,16 +299,21 @@ ServoStyleSet::PrepareAndTraverseSubtree
   bool postTraversalRequired =
     Servo_TraverseSubtree(aRoot, mRawSet.get(), aRootBehavior, aRestyleBehavior);
   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 or transitions' styles.
+  //
+  // We don't need to do this for SMIL since SMIL only updates its animation
+  // values once at the begin of a tick. As a result, even if the previous
+  // traversal caused, for example, the font-size to change, the SMIL style
+  // won't be updated until the next tick anyway.
   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