Bug 1453568 - Dispatch cancel event when setting null timeline. r?birtles
MozReview-Commit-ID: 4uKW0TUHpHt
--- 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>