Bug 1453568 - Dispatch cancel event when setting null timeline. r?birtles draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Tue, 17 Apr 2018 08:29:30 +0900
changeset 783348 037b431a9285f676cf2c65d4839e122f1bd184aa
parent 783347 822a9c0f680e07227609b9d6824afb1d2547e1ce
push id106674
push userhikezoe@mozilla.com
push dateTue, 17 Apr 2018 01:36:18 +0000
reviewersbirtles
bugs1453568
milestone61.0a1
Bug 1453568 - Dispatch cancel event when setting null timeline. r?birtles MozReview-Commit-ID: 4uKW0TUHpHt
dom/animation/Animation.cpp
testing/web-platform/meta/MANIFEST.json
testing/web-platform/tests/web-animations/interfaces/Animation/oncancel.html
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -226,32 +226,37 @@ Animation::SetTimeline(AnimationTimeline
 // https://drafts.csswg.org/web-animations/#setting-the-timeline
 void
 Animation::SetTimelineNoUpdate(AnimationTimeline* aTimeline)
 {
   if (mTimeline == aTimeline) {
     return;
   }
 
+  AnimationPlayState playState = PlayState();
+
   StickyTimeDuration activeTime = mEffect
                                   ? mEffect->GetComputedTiming().mActiveTime
                                   : StickyTimeDuration();
 
   RefPtr<AnimationTimeline> oldTimeline = mTimeline;
   if (oldTimeline) {
     oldTimeline->RemoveAnimation(this);
   }
 
   mTimeline = aTimeline;
   if (!mStartTime.IsNull()) {
     mHoldTime.SetNull();
   }
 
   if (!aTimeline) {
     MaybeQueueCancelEvent(activeTime);
+    if (playState != AnimationPlayState::Idle) {
+      DispatchPlaybackEvent(NS_LITERAL_STRING("cancel"));
+    }
   }
   UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
 }
 
 // https://drafts.csswg.org/web-animations/#set-the-animation-start-time
 void
 Animation::SetStartTime(const Nullable<TimeDuration>& aNewStartTime)
 {
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -599696,17 +599696,17 @@
    "4e3dd92351d76c5c7d09ddd1ca025520f4c8875d",
    "testharness"
   ],
   "web-animations/interfaces/Animation/idlharness.html": [
    "d61aa2d95ea31809a275183408e822c8c1eec87d",
    "testharness"
   ],
   "web-animations/interfaces/Animation/oncancel.html": [
-   "04d9893cd9968f71971bafd7a9bcbb6e3c955cdd",
+   "b0b133c7c07447fe7786e24bf130acb73378aca1",
    "testharness"
   ],
   "web-animations/interfaces/Animation/onfinish.html": [
    "db82fabeaf2b646647f134634fef30f05e5ec7f8",
    "testharness"
   ],
   "web-animations/interfaces/Animation/pause.html": [
    "f044cc7ac09c38f127e399f7d6f9a0714046aa8e",
--- a/testing/web-platform/tests/web-animations/interfaces/Animation/oncancel.html
+++ b/testing/web-platform/tests/web-animations/interfaces/Animation/oncancel.html
@@ -25,10 +25,50 @@ promise_test(async t => {
 
   assert_equals(event.currentTime, null,
     'event.currentTime should be null');
   assert_equals(event.timelineTime, finishedTimelineTime,
     'event.timelineTime should equal to the animation timeline ' +
     'when finished promise is rejected');
 }, 'oncancel event is fired when animation.cancel() is called.');
 
+promise_test(async t => {
+  const div = createDiv(t);
+  const animation = div.animate({}, 100 * MS_PER_SEC);
+
+  const eventWatcher = new EventWatcher(t, animation, 'cancel');
+  animation.timeline = null;
+
+  const event = await eventWatcher.wait_for('cancel');
+  assert_equals(event.currentTime, null,
+    'event.currentTime should be null');
+  assert_equals(event.timelineTime, null,
+    'event.timelineTime should be null');
+}, 'oncancel event is fired when setting null timeline.');
+
+promise_test(async t => {
+  const div = createDiv(t);
+  const animation = div.animate({}, 100 * MS_PER_SEC);
+
+  const eventWatcher = new EventWatcher(t, animation, 'cancel');
+  animation.cancel();
+
+  const event = await eventWatcher.wait_for('cancel');
+
+  assert_equals(event.currentTime, null,
+    'event.currentTime should be null');
+  assert_not_equals(event.timelineTime, null,
+    'event.timelineTime should not be null');
+
+  assert_equals(animation.playState, 'idle',
+                'animation play state should be idle');
+
+  animation.oncancel = () => {
+    assert_unreached('oncancel event should not be fired');
+  };
+
+  animation.timeline = null;
+
+  await waitForAnimationFrames(2);
+}, 'oncancel event is not fired when setting null timeline after idle state.');
+
 </script>
 </body>