Bug 1495647 - Use the effective playback rate when calculating the playState; r=hiro
authorBrian Birtles <birtles@gmail.com>
Wed, 03 Oct 2018 06:13:52 +0000
changeset 495082 eb6c2a002b78687405182d04b16dc441135c4108
parent 495081 15130d3c1c010f4b0b8fe7731936862dad65df85
child 495083 9ae3e805de4742bf7143f2d90ecd83672c93cdd8
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershiro
bugs1495647
milestone64.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 1495647 - Use the effective playback rate when calculating the playState; r=hiro This corresponds to the following change to the Web Animations spec: https://github.com/w3c/csswg-drafts/pull/3191/commits/abdebabf7f4af1a77376eadffdf8bc0ff46fc551 Depends on D7573 Differential Revision: https://phabricator.services.mozilla.com/D7574
dom/animation/Animation.cpp
testing/web-platform/tests/web-animations/timing-model/animations/play-states.html
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -369,27 +369,31 @@ Animation::SetPlaybackRate(double aPlayb
 // https://drafts.csswg.org/web-animations/#seamlessly-update-the-playback-rate
 void
 Animation::UpdatePlaybackRate(double aPlaybackRate)
 {
   if (mPendingPlaybackRate && mPendingPlaybackRate.value() == aPlaybackRate) {
     return;
   }
 
+  // Calculate the play state using the existing playback rate since below we
+  // want to know if the animation is _currently_ finished or not, not whether
+  // it _will_ be finished.
+  AnimationPlayState playState = PlayState();
+
   mPendingPlaybackRate = Some(aPlaybackRate);
 
   // If we already have a pending task, there is nothing more to do since the
   // playback rate will be applied then.
   if (Pending()) {
     return;
   }
 
   AutoMutationBatchForAnimation mb(*this);
 
-  AnimationPlayState playState = PlayState();
   if (playState == AnimationPlayState::Idle ||
       playState == AnimationPlayState::Paused) {
     // We are either idle or paused. In either case we can apply the pending
     // playback rate immediately.
     ApplyPendingPlaybackRate();
 
     // We don't need to update timing or post an update here because:
     //
@@ -452,19 +456,20 @@ Animation::PlayState() const
     return AnimationPlayState::Idle;
   }
 
   if (mPendingState == PendingState::PausePending ||
       (mStartTime.IsNull() && !Pending())) {
     return AnimationPlayState::Paused;
   }
 
+  double playbackRate = CurrentOrPendingPlaybackRate();
   if (!currentTime.IsNull() &&
-      ((mPlaybackRate > 0.0 && currentTime.Value() >= EffectEnd()) ||
-       (mPlaybackRate < 0.0 && currentTime.Value() <= TimeDuration())))  {
+      ((playbackRate > 0.0 && currentTime.Value() >= EffectEnd()) ||
+       (playbackRate < 0.0 && currentTime.Value() <= TimeDuration())))  {
     return AnimationPlayState::Finished;
   }
 
   return AnimationPlayState::Running;
 }
 
 Promise*
 Animation::GetReady(ErrorResult& aRv)
--- a/testing/web-platform/tests/web-animations/timing-model/animations/play-states.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animations/play-states.html
@@ -145,10 +145,41 @@ test(t => {
   const animation = createDiv(t).animate({}, 100 * MS_PER_SEC);
   assert_equals(animation.startTime, null,
                 'Sanity check: start time should be unresolved');
 
   assert_equals(animation.playState, 'running');
 }, 'reports \'running\' when playback rate > 0 and'
    + ' current time < target effect end and there is a pending play task');
 
+test(t => {
+  const animation = createDiv(t).animate({}, 100 * MS_PER_SEC);
+  assert_equals(animation.playState, 'running');
+  assert_true(animation.pending);
+}, 'reports \'running\' for a play-pending animation');
+
+test(t => {
+  const animation = createDiv(t).animate({}, 100 * MS_PER_SEC);
+  animation.pause();
+  assert_equals(animation.playState, 'paused');
+  assert_true(animation.pending);
+}, 'reports \'paused\' for a pause-pending animation');
+
+test(t => {
+  const animation = createDiv(t).animate({}, 0);
+  assert_equals(animation.playState, 'finished');
+  assert_true(animation.pending);
+}, 'reports \'finished\' for a finished-pending animation');
+
+test(t => {
+  const animation = createDiv(t).animate({}, 100 * MS_PER_SEC);
+  // Set up the pending playback rate
+  animation.updatePlaybackRate(-1);
+  // Call play again so that we seek to the end while remaining play-pending
+  animation.play();
+  // For a pending animation, the play state should always report what the
+  // play state _will_ be once we finish pending.
+  assert_equals(animation.playState, 'running');
+  assert_true(animation.pending);
+}, 'reports the play state based on the pending playback rate');
+
 </script>
 </body>