Bug 960465 patch 5 - Make SMIL animations participate in the animation-only style flush. r=birtles
authorL. David Baron <dbaron@dbaron.org>
Tue, 17 Feb 2015 11:15:02 +1300
changeset 258155 0288ff191edf0ae7be2a2036920d4e777c49174b
parent 258154 b36e2a0e902f4d7004220490778751442a7e9238
child 258156 7d16f2fd83297da151207217a88fae96777d437e
push id721
push userjlund@mozilla.com
push dateTue, 21 Apr 2015 23:03:33 +0000
treeherdermozilla-release@d27c9211ebb3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbirtles
bugs960465
milestone38.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 960465 patch 5 - Make SMIL animations participate in the animation-only style flush. r=birtles This is needed to prevent these reftests from failing: layout/reftests/svg/smil/smil-transitions-interaction-1a.svg layout/reftests/svg/smil/smil-transitions-interaction-1b.svg layout/reftests/svg/smil/smil-transitions-interaction-2a.svg layout/reftests/svg/smil/smil-transitions-interaction-2b.svg layout/reftests/svg/smil/smil-transitions-interaction-4a.svg layout/reftests/svg/smil/smil-transitions-interaction-4b.svg The mIsCSS path fixes the a tests, and the !mIsCSS path fixes the b tests. This is because this patch series changes the way in which transitions interact with other types of animations to depend on those animations being flushed in the animation-only style flush. (The relevant call is added in patch 6, though we don't really depend on it until patch 17.)
dom/smil/moz.build
dom/smil/nsSMILAnimationController.cpp
dom/smil/nsSMILAnimationController.h
layout/base/RestyleManager.cpp
--- a/dom/smil/moz.build
+++ b/dom/smil/moz.build
@@ -62,12 +62,13 @@ UNIFIED_SOURCES += [
     'TimeEvent.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 LOCAL_INCLUDES += [
     '/dom/base',
     '/dom/svg',
+    '/layout/base',
     '/layout/style',
 ]
 
 FINAL_LIBRARY = 'xul'
--- a/dom/smil/nsSMILAnimationController.cpp
+++ b/dom/smil/nsSMILAnimationController.cpp
@@ -9,16 +9,17 @@
 #include "nsCSSProps.h"
 #include "nsITimer.h"
 #include "mozilla/dom/Element.h"
 #include "nsIDocument.h"
 #include "mozilla/dom/SVGAnimationElement.h"
 #include "nsSMILTimedElement.h"
 #include <algorithm>
 #include "mozilla/AutoRestore.h"
+#include "RestyleTracker.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 // nsSMILAnimationController implementation
 
 //----------------------------------------------------------------------
@@ -809,16 +810,46 @@ nsSMILAnimationController::GetTargetIden
   aResult.mElement = targetElem;
   aResult.mAttributeName = attributeName;
   aResult.mAttributeNamespaceID = attributeNamespaceID;
   aResult.mIsCSS = isCSS;
 
   return true;
 }
 
+/*static*/ PLDHashOperator
+nsSMILAnimationController::AddStyleUpdate(AnimationElementPtrKey* aKey,
+                                          void* aData)
+{
+  SVGAnimationElement* animElement = aKey->GetKey();
+  RestyleTracker* restyleTracker = static_cast<RestyleTracker*>(aData);
+
+  nsSMILTargetIdentifier key;
+  if (!GetTargetIdentifierForAnimation(animElement, key)) {
+    // Something's wrong/missing about animation's target; skip this animation
+    return PL_DHASH_NEXT;
+  }
+
+  // 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
+                                    : eRestyle_SVGAttrAnimations;
+  restyleTracker->AddPendingRestyle(key.mElement, rshint, nsChangeHint(0));
+
+  return PL_DHASH_NEXT;
+}
+
+void
+nsSMILAnimationController::AddStyleUpdatesTo(RestyleTracker& aTracker)
+{
+  mAnimationElementTable.EnumerateEntries(AddStyleUpdate, &aTracker);
+}
+
 //----------------------------------------------------------------------
 // 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
@@ -17,16 +17,17 @@
 #include "nsSMILCompositorTable.h"
 #include "nsSMILMilestone.h"
 #include "nsRefreshDriver.h"
 
 struct nsSMILTargetIdentifier;
 class nsIDocument;
 
 namespace mozilla {
+class RestyleTracker;
 namespace dom {
 class SVGAnimationElement;
 }
 }
 
 //----------------------------------------------------------------------
 // nsSMILAnimationController
 //
@@ -100,16 +101,18 @@ public:
   // 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; }
 
+  void AddStyleUpdatesTo(mozilla::RestyleTracker& aTracker);
+
 protected:
   ~nsSMILAnimationController();
 
   // Typedefs
   typedef nsPtrHashKey<nsSMILTimeContainer> TimeContainerPtrKey;
   typedef nsTHashtable<TimeContainerPtrKey> TimeContainerHashtable;
   typedef nsPtrHashKey<mozilla::dom::SVGAnimationElement> AnimationElementPtrKey;
   typedef nsTHashtable<AnimationElementPtrKey> AnimationElementHashtable;
@@ -170,16 +173,19 @@ protected:
       AnimationElementPtrKey* aKey, void* aData);
   static void SampleTimedElement(mozilla::dom::SVGAnimationElement* aElement,
                                  TimeContainerHashtable* aActiveContainers);
   static void AddAnimationToCompositorTable(
     mozilla::dom::SVGAnimationElement* aElement, nsSMILCompositorTable* aCompositorTable);
   static bool GetTargetIdentifierForAnimation(
       mozilla::dom::SVGAnimationElement* aAnimElem, nsSMILTargetIdentifier& aResult);
 
+  static PLDHashOperator
+    AddStyleUpdate(AnimationElementPtrKey* aKey, void* aData);
+
   // Methods for adding/removing time containers
   virtual nsresult AddChild(nsSMILTimeContainer& aChild) MOZ_OVERRIDE;
   virtual void     RemoveChild(nsSMILTimeContainer& aChild) MOZ_OVERRIDE;
 
   void FlagDocumentNeedsFlush();
 
   // Members
   nsAutoRefCnt mRefCnt;
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -35,16 +35,17 @@
 #include "StickyScrollContainer.h"
 #include "nsIRootBox.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsContentUtils.h"
 #include "nsIFrameInlines.h"
 #include "ActiveLayerTracker.h"
 #include "nsDisplayList.h"
 #include "RestyleTrackerInlines.h"
+#include "nsSMILAnimationController.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 namespace mozilla {
 
 using namespace layers;
@@ -1739,36 +1740,57 @@ RestyleManager::EndProcessingRestyles()
   mPresContext->PresShell()->VerifyStyleTree();
 #endif
 }
 
 void
 RestyleManager::UpdateOnlyAnimationStyles()
 {
   TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();
-  if (mLastUpdateForThrottledAnimations == now) {
+  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;
+  }
+
+  if (!doCSS && !doSMIL) {
     return;
   }
-  mLastUpdateForThrottledAnimations = now;
 
   nsTransitionManager* transitionManager = mPresContext->TransitionManager();
   nsAnimationManager* animationManager = mPresContext->AnimationManager();
 
   transitionManager->SetInAnimationOnlyStyleUpdate(true);
 
   RestyleTracker tracker(ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE |
                          ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT);
   tracker.Init(this);
 
-  // FIXME:  We should have the transition manager and animation manager
-  // add only the elements for which animations are currently throttled
-  // (i.e., animating on the compositor with main-thread style updates
-  // suppressed).
-  transitionManager->AddStyleUpdatesTo(tracker);
-  animationManager->AddStyleUpdatesTo(tracker);
+  if (doCSS) {
+    // FIXME:  We should have the transition manager and animation manager
+    // add only the elements for which animations are currently throttled
+    // (i.e., animating on the compositor with main-thread style updates
+    // suppressed).
+    transitionManager->AddStyleUpdatesTo(tracker);
+    animationManager->AddStyleUpdatesTo(tracker);
+  }
+
+  if (doSMIL) {
+    animationController->AddStyleUpdatesTo(tracker);
+  }
 
   ProcessRestyles(tracker);
 
   transitionManager->SetInAnimationOnlyStyleUpdate(false);
 }
 
 void
 RestyleManager::PostRestyleEventCommon(Element* aElement,