Bug 1171966 - Update SMIL animation styles only when there are pending changes; r=dholbert
authorBrian Birtles <birtles@gmail.com>
Fri, 31 Jul 2015 13:14:46 +0900
changeset 288894 6efdf94d0b97bb3130ebc869c066c13071f4a36c
parent 288893 fb2a27db76bc5a570c482cb900fa439402c74a9d
child 288895 525bb2034be22ff987ddc87cfeff8407ea2689e5
push id934
push userraliiev@mozilla.com
push dateMon, 26 Oct 2015 12:58:05 +0000
treeherdermozilla-release@05704e35c1d0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1171966, 960465
milestone42.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 1171966 - Update SMIL animation styles only when there are pending changes; r=dholbert Bug 960465 (specifically part 6, changeset 7d16f2fd8329) changed the way we process animation-only style changes. This caused us to update SMIL animations more often than is needed. This patch adjusts this behavior to update the style from SMIL animations less frequently by tracking when animated values have been composited without adding the corresponding changes to a restyle tracker.
dom/smil/nsSMILAnimationController.cpp
dom/smil/nsSMILAnimationController.h
layout/base/RestyleManager.cpp
--- a/dom/smil/nsSMILAnimationController.cpp
+++ b/dom/smil/nsSMILAnimationController.cpp
@@ -27,16 +27,17 @@ using namespace mozilla::dom;
 // ctors, dtors, factory methods
 
 nsSMILAnimationController::nsSMILAnimationController(nsIDocument* aDoc)
   : mAvgTimeBetweenSamples(0),
     mResampleNeeded(false),
     mDeferredStartSampling(false),
     mRunningSample(false),
     mRegisteredWithRefreshDriver(false),
+    mMightHavePendingStyleUpdates(false),
     mDocument(aDoc)
 {
   MOZ_ASSERT(aDoc, "need a non-null document");
 
   nsRefreshDriver* refreshDriver = GetRefreshDriver();
   if (refreshDriver) {
     mStartTime = refreshDriver->MostRecentRefresh();
   } else {
@@ -434,16 +435,17 @@ nsSMILAnimationController::DoSample(bool
   // when the inherited value is *also* being animated, we really should be
   // traversing our animated nodes in an ancestors-first order (bug 501183)
   for (auto iter = currentCompositorTable->Iter(); !iter.Done(); iter.Next()) {
     iter.Get()->ComposeAttribute();
   }
 
   // Update last compositor table
   mLastCompositorTable = currentCompositorTable.forget();
+  mMightHavePendingStyleUpdates = true;
 
   NS_ASSERTION(!mResampleNeeded, "Resample dirty flag set during sample!");
 }
 
 void
 nsSMILAnimationController::RewindElements()
 {
   bool rewindNeeded = false;
@@ -699,16 +701,19 @@ nsSMILAnimationController::GetTargetIden
   aResult.mIsCSS = isCSS;
 
   return true;
 }
 
 void
 nsSMILAnimationController::AddStyleUpdatesTo(RestyleTracker& aTracker)
 {
+  MOZ_ASSERT(mMightHavePendingStyleUpdates,
+             "Should only add style updates when we think we might have some");
+
   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;
     }
@@ -716,16 +721,18 @@ nsSMILAnimationController::AddStyleUpdat
     // mIsCSS true means that the rules are the ones returned from
     // Element::GetSMILOverrideStyleRule (via nsSMILCSSProperty objects),
     // and mIsCSS false means the rules are nsSMILMappedAttribute objects
     // returned from nsSVGElement::GetAnimatedContentStyleRule.
     nsRestyleHint rshint = key.mIsCSS ? eRestyle_StyleAttribute_Animations
                                       : eRestyle_SVGAttrAnimations;
     aTracker.AddPendingRestyle(key.mElement, rshint, nsChangeHint(0));
   }
+
+  mMightHavePendingStyleUpdates = false;
 }
 
 //----------------------------------------------------------------------
 // Add/remove child time containers
 
 nsresult
 nsSMILAnimationController::AddChild(nsSMILTimeContainer& aChild)
 {
--- a/dom/smil/nsSMILAnimationController.h
+++ b/dom/smil/nsSMILAnimationController.h
@@ -69,20 +69,18 @@ public:
   // Methods for resampling all animations
   // (A resample performs the same operations as a sample but doesn't advance
   // the current time and doesn't check if the container is paused)
   // This will flush pending style changes for the document.
   void Resample() { DoSample(false); }
 
   void SetResampleNeeded()
   {
-    if (!mRunningSample) {
-      if (!mResampleNeeded) {
-        FlagDocumentNeedsFlush();
-      }
+    if (!mRunningSample && !mResampleNeeded) {
+      FlagDocumentNeedsFlush();
       mResampleNeeded = true;
     }
   }
 
   // This will flush pending style changes for the document.
   void FlushResampleRequests()
   {
     if (!mResampleNeeded)
@@ -99,20 +97,26 @@ public:
   void Traverse(nsCycleCollectionTraversalCallback* aCallback);
   void Unlink();
 
   // Methods for relaying the availability of the refresh driver
   void NotifyRefreshDriverCreated(nsRefreshDriver* aRefreshDriver);
   void NotifyRefreshDriverDestroying(nsRefreshDriver* aRefreshDriver);
 
   // Helper to check if we have any animation elements at all
-  bool HasRegisteredAnimations()
-  { return mAnimationElementTable.Count() != 0; }
+  bool HasRegisteredAnimations() const
+  {
+    return mAnimationElementTable.Count() != 0;
+  }
 
   void AddStyleUpdatesTo(mozilla::RestyleTracker& aTracker);
+  bool MightHavePendingStyleUpdates() const
+  {
+    return mMightHavePendingStyleUpdates;
+  }
 
 protected:
   ~nsSMILAnimationController();
 
   // Typedefs
   typedef nsPtrHashKey<nsSMILTimeContainer> TimeContainerPtrKey;
   typedef nsTHashtable<TimeContainerPtrKey> TimeContainerHashtable;
   typedef nsPtrHashKey<mozilla::dom::SVGAnimationElement> AnimationElementPtrKey;
@@ -181,16 +185,19 @@ protected:
   // record the time, set the following flag, and then wait until we have an
   // animation element. Then we'll reset this flag and actually start sampling.
   bool                       mDeferredStartSampling;
   bool                       mRunningSample;
 
   // Are we registered with our document's refresh driver?
   bool                       mRegisteredWithRefreshDriver;
 
+  // Have we updated animated values without adding them to the restyle tracker?
+  bool                       mMightHavePendingStyleUpdates;
+
   // Store raw ptr to mDocument.  It owns the controller, so controller
   // shouldn't outlive it
   nsIDocument* mDocument;
 
   // Contains compositors used in our last sample.  We keep this around
   // so we can detect when an element/attribute used to be animated,
   // but isn't anymore for some reason. (e.g. if its <animate> element is
   // removed or retargeted)
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -1769,28 +1769,23 @@ RestyleManager::EndProcessingRestyles()
 
 void
 RestyleManager::UpdateOnlyAnimationStyles()
 {
   TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();
   bool doCSS = mLastUpdateForThrottledAnimations != now;
   mLastUpdateForThrottledAnimations = now;
 
-  bool doSMIL = false;
   nsIDocument* document = mPresContext->Document();
-  nsSMILAnimationController* animationController = nullptr;
-  if (document->HasAnimationController()) {
-    animationController = document->GetAnimationController();
-    // FIXME:  Ideally, we only want to do this if animation timelines
-    // have advanced.  However, different SMIL animations could be
-    // getting their time from different outermost SVG elements, so
-    // finding all of them might be a pain.  So this could be optimized
-    // to set doSMIL to true in fewer cases.
-    doSMIL = true;
-  }
+  nsSMILAnimationController* animationController =
+    document->HasAnimationController() ?
+    document->GetAnimationController() :
+    nullptr;
+  bool doSMIL = animationController &&
+                animationController->MightHavePendingStyleUpdates();
 
   if (!doCSS && !doSMIL) {
     return;
   }
 
   nsTransitionManager* transitionManager = mPresContext->TransitionManager();
   nsAnimationManager* animationManager = mPresContext->AnimationManager();