Bug 1188251 part 11 - Add RestyleType::Layer; r=dholbert
authorBrian Birtles <birtles@gmail.com>
Tue, 18 Aug 2015 16:11:55 +0900
changeset 290757 058fb2d079be64c57c129090ac6347123f61d4a9
parent 290756 3e2e93d1bf5baee2b3469098bce0cc8bab49b8e3
child 290758 74f24cabb959ffb201b23d98ff29b23da5a26bf9
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1188251
milestone43.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 1188251 part 11 - Add RestyleType::Layer; r=dholbert We currently have a series of methods that clobber various bits of animation state to force animations on layers to be updated. This aligns closely with the restyle code introduced in this patch series. By re-using RequestRestyle when updating animations on layers, not only should we be able to simplify the code somewhat but, in future, we should also be able to have Animation objects use the same mechanism to update layers during a regular tick. For example, currently we have a bug where when an animation starts after a delay with the same value as the backwards fill then we don't send the animation to the compositor right away (see https://dxr.mozilla.org/mozilla-central/rev/d6ea652c579992daa9041cc9718bb7c6abefbc91/layout/style/test/test_animations_omta.html#287). By adding this Restyle::Layer value we should be able to fix that in future.
dom/animation/Animation.cpp
layout/style/AnimationCommon.cpp
layout/style/AnimationCommon.h
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -371,16 +371,18 @@ Animation::Tick()
     MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(),
                "Orphaned pending animtaions should have an active timeline");
     FinishPendingAt(mTimeline->GetCurrentTime().Value());
   }
 
   UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
 
   // FIXME: Detect the no-change case and don't request a restyle at all
+  // FIXME: Detect changes to IsPlaying() state and request RestyleType::Layer
+  //        so that layers get updated immediately
   AnimationCollection* collection = GetCollection();
   if (collection) {
     collection->RequestRestyle(CanThrottle() ?
       AnimationCollection::RestyleType::Throttled :
       AnimationCollection::RestyleType::Standard);
   }
 }
 
@@ -948,17 +950,17 @@ Animation::FlushStyle() const
   }
 }
 
 void
 Animation::PostUpdate()
 {
   AnimationCollection* collection = GetCollection();
   if (collection) {
-    collection->NotifyAnimationUpdated();
+    collection->RequestRestyle(AnimationCollection::RestyleType::Layer);
   }
 }
 
 void
 Animation::CancelPendingTasks()
 {
   if (mPendingState == PendingState::NotPending) {
     return;
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -295,27 +295,16 @@ CommonAnimationManager::AddStyleUpdatesT
     if (elementToRestyle) {
       nsRestyleHint rshint = collection->IsForTransitions()
         ? eRestyle_CSSTransitions : eRestyle_CSSAnimations;
       aTracker.AddPendingRestyle(elementToRestyle, rshint, nsChangeHint(0));
     }
   }
 }
 
-void
-CommonAnimationManager::NotifyCollectionUpdated(AnimationCollection&
-                                                  aCollection)
-{
-  MaybeStartObservingRefreshDriver();
-  mPresContext->ClearLastStyleUpdateForAllAnimations();
-  mPresContext->RestyleManager()->IncrementAnimationGeneration();
-  aCollection.UpdateAnimationGeneration(mPresContext);
-  aCollection.PostRestyleForAnimation(mPresContext);
-}
-
 /* static */ bool
 CommonAnimationManager::ExtractComputedValueForTransition(
                           nsCSSProperty aProperty,
                           nsStyleContext* aStyleContext,
                           StyleAnimationValue& aComputedValue)
 {
   bool result = StyleAnimationValue::ExtractComputedValue(aProperty,
                                                           aStyleContext,
@@ -796,26 +785,16 @@ AnimationCollection::GetElementToRestyle
     return nullptr;
   }
   if (!pseudoFrame) {
     return nullptr;
   }
   return pseudoFrame->GetContent()->AsElement();
 }
 
-void
-AnimationCollection::NotifyAnimationUpdated()
-{
-  // On the next flush, force us to update the style rule
-  mNeedsRefreshes = true;
-  mStyleRuleRefreshTime = TimeStamp();
-
-  mManager->NotifyCollectionUpdated(*this);
-}
-
 /* static */ void
 AnimationCollection::LogAsyncAnimationFailure(nsCString& aMessage,
                                                      const nsIContent* aContent)
 {
   if (aContent) {
     aMessage.AppendLiteral(" [");
     aMessage.Append(nsAtomCString(aContent->NodeInfo()->NameAtom()));
 
@@ -997,43 +976,58 @@ AnimationCollection::RequestRestyle(Rest
     // Pres context will be null after the manager is disconnected.
     return;
   }
 
   MOZ_ASSERT(mElement->GetCrossShadowCurrentDoc() == presContext->Document(),
              "Element::UnbindFromTree should have destroyed the element "
              "transition/animations object");
 
-  // SetNeedStyleFlush is cheap and required regardless of the restyle type
-  // so we do it unconditionally. Furthermore, if the posted animation restyle
-  // has been postponed due to the element being display:none (i.e.
-  // mHasPendingAnimationRestyle is set) then we should still mark the
-  // document as needing a style flush.
-  presContext->Document()->SetNeedStyleFlush();
+  // Steps for Restyle::Layer:
+
+  if (aRestyleType == RestyleType::Layer) {
+    mStyleRuleRefreshTime = TimeStamp();
+    // FIXME: We should be able to remove these two lines once we move
+    // ticking to animation timelines as part of bug 1151731.
+    mNeedsRefreshes = true;
+    mManager->MaybeStartObservingRefreshDriver();
 
-  // If we are already waiting on an animation restyle then there's nothing
-  // more to do.
+    // Prompt layers to re-sync their animations.
+    presContext->ClearLastStyleUpdateForAllAnimations();
+    presContext->RestyleManager()->IncrementAnimationGeneration();
+    UpdateAnimationGeneration(presContext);
+  }
+
+  // Steps for RestyleType::Standard and above:
+
   if (mHasPendingAnimationRestyle) {
     return;
   }
 
   // Upgrade throttled restyles if other factors prevent
   // throttling (e.g. async animations are not enabled).
   if (aRestyleType == RestyleType::Throttled) {
     TimeStamp now = presContext->RefreshDriver()->MostRecentRefresh();
     if (!CanPerformOnCompositorThread(CanAnimateFlags(0)) ||
         !CanThrottleAnimation(now)) {
       aRestyleType = RestyleType::Standard;
     }
   }
 
-  if (aRestyleType == RestyleType::Standard) {
+  if (aRestyleType >= RestyleType::Standard) {
     mHasPendingAnimationRestyle = true;
     PostRestyleForAnimation(presContext);
+    return;
   }
+
+  // Steps for RestyleType::Throttled:
+
+  MOZ_ASSERT(aRestyleType == RestyleType::Throttled,
+             "Should have already handled all non-throttled restyles");
+  presContext->Document()->SetNeedStyleFlush();
 }
 
 void
 AnimationCollection::UpdateAnimationGeneration(nsPresContext* aPresContext)
 {
   mAnimationGeneration =
     aPresContext->RestyleManager()->GetAnimationGeneration();
 }
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -95,20 +95,16 @@ public:
           aContent->GetProperty(nsGkAtoms::transitionsProperty)) {
         return true;
       }
     } while ((aContent = aContent->GetParent()));
 
     return false;
   }
 
-  // Notify this manager that one of its collections of animations,
-  // has been updated.
-  void NotifyCollectionUpdated(AnimationCollection& aCollection);
-
   enum FlushFlags {
     Can_Throttle,
     Cannot_Throttle
   };
   void FlushAnimations(FlushFlags aFlags);
 
   nsIStyleRule* GetAnimationRule(dom::Element* aElement,
                                  nsCSSPseudoElements::Type aPseudoType);
@@ -287,17 +283,25 @@ struct AnimationCollection : public PRCL
   };
 
   enum class RestyleType {
     // Animation style has changed but the compositor is applying the same
     // change so we might be able to defer updating the main thread until it
     // becomes necessary.
     Throttled,
     // Animation style has changed and needs to be updated on the main thread.
-    Standard
+    Standard,
+    // Animation style has changed and needs to be updated on the main thread
+    // as well as forcing animations on layers to be updated.
+    // This is needed in cases such as when an animation becomes paused or has
+    // its playback rate changed. In such a case, although the computed style
+    // and refresh driver time might not change, we still need to ensure the
+    // corresponding animations on layers are updated to reflect the new
+    // configuration of the animation.
+    Layer
   };
   void RequestRestyle(RestyleType aRestyleType);
 
 private:
   static bool
   CanAnimatePropertyOnCompositor(const dom::Element *aElement,
                                  nsCSSProperty aProperty,
                                  CanAnimateFlags aFlags);
@@ -379,18 +383,16 @@ public:
     dom::Element* element = GetElementToRestyle();
     if (element) {
       nsRestyleHint hint = IsForTransitions() ? eRestyle_CSSTransitions
                                               : eRestyle_CSSAnimations;
       aPresContext->PresShell()->RestyleForAnimation(element, hint);
     }
   }
 
-  void NotifyAnimationUpdated();
-
   static void LogAsyncAnimationFailure(nsCString& aMessage,
                                        const nsIContent* aContent = nullptr);
 
   dom::Element *mElement;
 
   // the atom we use in mElement's prop table (must be a static atom,
   // i.e., in an atom list)
   nsIAtom *mElementProperty;