Bug 1070745 part 8 - Use play/pause from nsAnimationManager; r=dholbert
authorBrian Birtles <birtles@gmail.com>
Mon, 20 Oct 2014 13:55:44 +0900
changeset 211171 33635f1b4005efe3e0a507557b8af922e408e1ae
parent 211170 8d9236ef0f6be2d9111beb226b92d64858c42ab3
child 211172 8e104207af9d99dab949103534239bd8b2d34d92
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersdholbert
bugs1070745
milestone36.0a1
Bug 1070745 part 8 - Use play/pause from nsAnimationManager; r=dholbert This patch uses the PlayFromStyle/PauseFromStyle methods on CSSAnimationPlayer to perform play/pause control. (This allows us to encapsulate mHoldTime and mPaused. We will encapsulate mStartTime etc. in subsequent bugs. The override behavior of play()/pause() with regard to animation-play-state is: * pause()/play() override the current animation-play-state * pause() causes the player to remain paused until play() is called regardless of changes to animation-play-state (* Calling play() will override the animation-play-state but won't "stick". i.e. subsequently setting animation-play-state: paused will pause the animation.) These different permutations are tested in the next patch in this series. This interaction will probably become more complicated once we introduce finishing behavior (since we might not want animations to restart when setting animation-play-state: running).
dom/animation/AnimationPlayer.h
layout/style/nsAnimationManager.cpp
--- a/dom/animation/AnimationPlayer.h
+++ b/dom/animation/AnimationPlayer.h
@@ -29,19 +29,19 @@ namespace dom {
 
 class AnimationPlayer : public nsWrapperCache
 {
 protected:
   virtual ~AnimationPlayer() { }
 
 public:
   explicit AnimationPlayer(AnimationTimeline* aTimeline)
-    : mIsPaused(false)
-    , mIsRunningOnCompositor(false)
+    : mIsRunningOnCompositor(false)
     , mTimeline(aTimeline)
+    , mIsPaused(false)
   {
   }
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AnimationPlayer)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AnimationPlayer)
 
   AnimationTimeline* GetParentObject() const { return mTimeline; }
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
@@ -88,26 +88,27 @@ public:
   }
 
   // Return the duration since the start time of the player, taking into
   // account the pause state.  May be negative or null.
   Nullable<TimeDuration> GetCurrentTimeDuration() const;
 
   // The beginning of the delay period.
   Nullable<TimeDuration> mStartTime; // Timeline timescale
-  Nullable<TimeDuration> mHoldTime;  // Player timescale
-  bool mIsPaused;
   bool mIsRunningOnCompositor;
 
   nsRefPtr<AnimationTimeline> mTimeline;
   nsRefPtr<Animation> mSource;
 
 protected:
   void FlushStyle() const;
   void MaybePostRestyle() const;
+
+  Nullable<TimeDuration> mHoldTime;  // Player timescale
+  bool mIsPaused;
 };
 
 } // namespace dom
 
 class CSSAnimationPlayer MOZ_FINAL : public dom::AnimationPlayer
 {
 public:
  explicit CSSAnimationPlayer(dom::AnimationTimeline* aTimeline)
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -21,16 +21,17 @@
 #include "nsIFrame.h"
 #include "nsIDocument.h"
 #include <math.h>
 
 using namespace mozilla;
 using namespace mozilla::css;
 using mozilla::dom::Animation;
 using mozilla::dom::AnimationPlayer;
+using mozilla::CSSAnimationPlayer;
 
 void
 nsAnimationManager::UpdateStyleAndEvents(AnimationPlayerCollection*
                                            aCollection,
                                          TimeStamp aRefreshTime,
                                          EnsureStyleRuleFlags aFlags)
 {
   aCollection->EnsureStyleRuleFor(aRefreshTime, aFlags);
@@ -270,31 +271,32 @@ nsAnimationManager::CheckAnimationRule(n
       // spec says to do, but WebKit seems to honor at least some of
       // them.  See
       // http://lists.w3.org/Archives/Public/www-style/2011Apr/0079.html
       // In order to honor what the spec said, we'd copy more data over
       // (or potentially optimize BuildAnimations to avoid rebuilding it
       // in the first place).
       if (!collection->mPlayers.IsEmpty()) {
 
-        Nullable<TimeDuration> now = timeline->GetCurrentTimeDuration();
-
         for (size_t newIdx = newPlayers.Length(); newIdx-- != 0;) {
           AnimationPlayer* newPlayer = newPlayers[newIdx];
 
           // Find the matching animation with this name in the old list
           // of animations.  We iterate through both lists in a backwards
           // direction which means that if there are more animations in
           // the new list of animations with a given name than in the old
           // list, it will be the animations towards the of the beginning of
           // the list that do not match and are treated as new animations.
-          nsRefPtr<AnimationPlayer> oldPlayer;
+          nsRefPtr<CSSAnimationPlayer> oldPlayer;
           size_t oldIdx = collection->mPlayers.Length();
           while (oldIdx-- != 0) {
-            AnimationPlayer* a = collection->mPlayers[oldIdx];
+            CSSAnimationPlayer* a =
+              collection->mPlayers[oldIdx]->AsCSSAnimationPlayer();
+            MOZ_ASSERT(a, "All players in the CSS Animation collection should"
+                          " be CSSAnimationPlayer objects");
             if (a->Name() == newPlayer->Name()) {
               oldPlayer = a;
               break;
             }
           }
           if (!oldPlayer) {
             continue;
           }
@@ -307,29 +309,28 @@ nsAnimationManager::CheckAnimationRule(n
             oldAnim->Timing() = newAnim->Timing();
             oldAnim->Properties() = newAnim->Properties();
           }
 
           // Reset compositor state so animation will be re-synchronized.
           oldPlayer->mIsRunningOnCompositor = false;
 
           // Handle changes in play state.
-          if (!oldPlayer->IsPaused() && newPlayer->IsPaused()) {
-            // Start pause at current time.
-            oldPlayer->mHoldTime = oldPlayer->GetCurrentTimeDuration();
-          } else if (oldPlayer->IsPaused() && !newPlayer->IsPaused()) {
-            if (now.IsNull()) {
-              oldPlayer->mStartTime.SetNull();
-            } else {
-              oldPlayer->mStartTime.SetValue(now.Value() -
-                                               oldPlayer->mHoldTime.Value());
-            }
-            oldPlayer->mHoldTime.SetNull();
+          // CSSAnimationPlayer takes care of override behavior so that,
+          // for example, if the author has called pause(), that will
+          // override the animation-play-state.
+          // (We should check newPlayer->IsStylePaused() but that requires
+          //  downcasting to CSSAnimationPlayer and we happen to know that
+          //  newPlayer will only ever be paused by calling PauseFromStyle
+          //  making IsPaused synonymous in this case.)
+          if (!oldPlayer->IsStylePaused() && newPlayer->IsPaused()) {
+            oldPlayer->PauseFromStyle();
+          } else if (oldPlayer->IsStylePaused() && !newPlayer->IsPaused()) {
+            oldPlayer->PlayFromStyle();
           }
-          oldPlayer->mIsPaused = newPlayer->mIsPaused;
 
           // Replace new animation with the (updated) old one and remove the
           // old one from the array so we don't try to match it any more.
           //
           // Although we're doing this while iterating this is safe because
           // we're not changing the length of newPlayers and we've finished
           // iterating over the list of old iterations.
           newPlayer = nullptr;
@@ -437,37 +438,35 @@ nsAnimationManager::BuildAnimations(nsSt
       src.GetName().IsEmpty()
       ? nullptr
       : mPresContext->StyleSet()->KeyframesRuleForName(mPresContext,
                                                        src.GetName());
     if (!rule) {
       continue;
     }
 
-    nsRefPtr<AnimationPlayer> dest =
-      *aPlayers.AppendElement(new AnimationPlayer(aTimeline));
+    nsRefPtr<CSSAnimationPlayer> dest = new CSSAnimationPlayer(aTimeline);
+    aPlayers.AppendElement(dest);
 
     AnimationTiming timing;
     timing.mIterationDuration =
       TimeDuration::FromMilliseconds(src.GetDuration());
     timing.mDelay = TimeDuration::FromMilliseconds(src.GetDelay());
     timing.mIterationCount = src.GetIterationCount();
     timing.mDirection = src.GetDirection();
     timing.mFillMode = src.GetFillMode();
 
     nsRefPtr<Animation> destAnim =
       new Animation(mPresContext->Document(), aTarget,
                     aStyleContext->GetPseudoType(), timing, src.GetName());
     dest->SetSource(destAnim);
 
     dest->mStartTime = now;
-    dest->mIsPaused =
-      src.GetPlayState() == NS_STYLE_ANIMATION_PLAY_STATE_PAUSED;
-    if (dest->IsPaused()) {
-      dest->mHoldTime.SetValue(TimeDuration(0));
+    if (src.GetPlayState() == NS_STYLE_ANIMATION_PLAY_STATE_PAUSED) {
+      dest->PauseFromStyle();
     }
 
     // While current drafts of css3-animations say that later keyframes
     // with the same key entirely replace earlier ones (no cascading),
     // this is a bad idea and contradictory to the rest of CSS.  So
     // we're going to keep all the keyframes for each key and then do
     // the replacement on a per-property basis rather than a per-rule
     // basis, just like everything else in CSS.