| <!DOCTYPE html> |
| <meta charset=utf-8> |
| <title>Test play state changes for animations with a negative playback rate</title> |
| <link rel="help" href="https://drafts.csswg.org/web-animations/#play-state"> |
| <script src="../../external/wpt/web-animations/testcommon.js"></script> |
| <script src="../../resources/testharness.js"></script> |
| <script src="../../resources/testharnessreport.js"></script> |
| |
| <script> |
| var duration = 100000; |
| |
| function assert_unresolved(value) { |
| assert_equals(value, null); |
| } |
| |
| function idleAnimation() { |
| var animation = document.documentElement.animate([], duration); |
| animation.reverse(); |
| animation.cancel(); |
| return animation; |
| } |
| |
| function runningAnimation() { |
| var animation = idleAnimation(); |
| animation.play(); |
| animation.startTime = document.timeline.currentTime + duration / 2; |
| return animation; |
| } |
| |
| function pendingAnimation() { |
| var animation = idleAnimation(); |
| animation.play(); |
| return animation; |
| } |
| |
| function pausedAnimation() { |
| var animation = idleAnimation(); |
| animation.pause(); |
| animation.currentTime = duration; |
| return animation; |
| } |
| |
| function finishedAnimation() { |
| var animation = idleAnimation(); |
| animation.play(); |
| animation.finish(); |
| return animation; |
| } |
| |
| test(function() { |
| var animation = idleAnimation(); |
| assert_unresolved(animation.startTime); |
| assert_unresolved(animation.currentTime); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'idle'); |
| }, "Play state is idle after cancelling a reversed animation"); |
| |
| test(function() { |
| var animation = pendingAnimation(); |
| assert_unresolved(animation.startTime); |
| assert_equals(animation.currentTime, duration); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Play state is running after playing a canceled reversed animation"); |
| |
| test(function() { |
| var animation = runningAnimation(); |
| assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); |
| assert_times_equal(animation.currentTime, duration / 2); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Play state is running after playing and setting start time of a canceled reversed animation"); |
| |
| test(function() { |
| var animation = pausedAnimation(); |
| assert_unresolved(animation.startTime); |
| assert_equals(animation.currentTime, duration); |
| // Setting the current time of a pause-pending animation applies a synchronous update. |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| }, "Play state is paused after pausing and setting current time of a canceled reversed animation"); |
| |
| test(function() { |
| var animation = finishedAnimation(); |
| assert_times_equal( |
| animation.startTime, |
| document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); |
| assert_equals(animation.currentTime, 0); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'finished'); |
| }, "Play state is finished after playing and finishing a cancelled reversed animation"); |
| |
| test(function() { |
| var animation = idleAnimation(); |
| animation.play(); |
| assert_unresolved(animation.startTime); |
| assert_equals(animation.currentTime, duration); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling play() on an idle animation"); |
| |
| test(function() { |
| var animation = idleAnimation(); |
| animation.pause(); |
| assert_unresolved(animation.startTime); |
| assert_equals(animation.currentTime, duration); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| }, "Calling pause() on an idle animation"); |
| |
| test(function() { |
| var animation = idleAnimation(); |
| animation.cancel(); |
| assert_unresolved(animation.startTime); |
| assert_unresolved(animation.currentTime); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'idle'); |
| }, "Calling cancel() on an idle animation"); |
| |
| test(function() { |
| var animation = idleAnimation(); |
| animation.finish(); |
| assert_times_equal( |
| animation.startTime, |
| document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); |
| assert_equals(animation.currentTime, 0); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'finished'); |
| }, "Calling finish() on an idle animation"); |
| |
| test(function() { |
| var animation = idleAnimation(); |
| animation.reverse(); |
| assert_unresolved(animation.startTime); |
| assert_equals(animation.currentTime, 0); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling reverse() on an idle animation"); |
| |
| test(function() { |
| var animation = idleAnimation(); |
| animation.currentTime = 1000; |
| assert_unresolved(animation.startTime); |
| assert_equals(animation.currentTime, 1000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| }, "Setting currentTime on an idle animation"); |
| |
| test(function() { |
| var animation = idleAnimation(); |
| animation.startTime = document.timeline.currentTime + 1000; |
| assert_times_equal(animation.startTime, document.timeline.currentTime + 1000); |
| assert_times_equal(animation.currentTime, 1000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting startTime on an idle animation"); |
| |
| test(function() { |
| var animation = pendingAnimation(); |
| animation.play(); |
| assert_unresolved(animation.startTime); |
| assert_equals(animation.currentTime, duration); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling play() on a pending animation"); |
| |
| test(function() { |
| var animation = pendingAnimation(); |
| animation.pause(); |
| assert_unresolved(animation.startTime); |
| assert_equals(animation.currentTime, duration); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| }, "Calling pause() on a pending animation"); |
| |
| test(function() { |
| var animation = pendingAnimation(); |
| animation.cancel(); |
| assert_unresolved(animation.startTime); |
| assert_unresolved(animation.currentTime); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'idle'); |
| }, "Calling cancel() on a pending animation"); |
| |
| test(function() { |
| var animation = pendingAnimation(); |
| animation.finish(); |
| assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); |
| assert_equals(animation.currentTime, 0); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'finished'); |
| }, "Calling finish() on a pending animation"); |
| |
| test(function() { |
| var animation = pendingAnimation(); |
| animation.reverse(); |
| assert_unresolved(animation.startTime); |
| assert_equals(animation.currentTime, 0); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling reverse() on a pending animation"); |
| |
| test(function() { |
| var animation = pendingAnimation(); |
| animation.currentTime = 1000; |
| assert_unresolved(animation.startTime); |
| assert_equals(animation.currentTime, 1000); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting currentTime on a pending animation"); |
| |
| test(function() { |
| var animation = pendingAnimation(); |
| animation.startTime = document.timeline.currentTime + 1000; |
| assert_times_equal(animation.startTime, document.timeline.currentTime + 1000); |
| assert_times_equal(animation.currentTime, 1000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting startTime on a pending animation"); |
| |
| test(function() { |
| var animation = runningAnimation(); |
| var startTime = animation.startTime; |
| var currentTime = animation.currentTime; |
| animation.play(); |
| assert_equals(animation.startTime, startTime); |
| assert_equals(animation.currentTime, currentTime); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling play() on a running animation"); |
| |
| async_test(function(t) { |
| var animation = runningAnimation(); |
| animation.pause(); |
| assert_true(animation.pending); |
| assert_times_equal(animation.currentTime, duration / 2); |
| assert_equals(animation.playState, 'paused'); |
| animation.ready.then(t.step_func_done(() => { |
| assert_equals(animation.startTime, null); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| })); |
| }, "Calling pause() on a running animation"); |
| |
| test(function() { |
| var animation = runningAnimation(); |
| animation.cancel(); |
| assert_unresolved(animation.startTime); |
| assert_unresolved(animation.currentTime); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'idle'); |
| }, "Calling cancel() on a running animation"); |
| |
| test(function() { |
| var animation = runningAnimation(); |
| animation.finish(); |
| assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); |
| assert_equals(animation.currentTime, 0); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'finished'); |
| }, "Calling finish() on a running animation"); |
| |
| async_test(function(t) { |
| var animation = runningAnimation(); |
| assert_equals(animation.playbackRate, -1); |
| animation.reverse(); |
| assert_true(animation.pending); |
| assert_times_equal(animation.currentTime, duration / 2); |
| assert_equals(animation.playbackRate, -1); |
| assert_equals(animation.playState, 'running'); |
| animation.ready.then(t.step_func_done(() => { |
| assert_false(animation.pending); |
| // TODO(crbug.com/960944): Add check to ensure that current time remains |
| // unchanged once remaining timing glitches are resolved. |
| assert_not_equals(animation.startTime, null); |
| assert_equals(animation.playbackRate, 1); |
| assert_equals(animation.playState, 'running'); |
| })); |
| }, "Calling reverse() on a running animation"); |
| |
| test(function() { |
| var animation = runningAnimation(); |
| animation.currentTime = 1000; |
| assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); |
| assert_times_equal(animation.currentTime, 1000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting currentTime on a running animation"); |
| |
| test(function() { |
| var animation = runningAnimation(); |
| animation.startTime = document.timeline.currentTime + 1000; |
| assert_times_equal(animation.startTime, document.timeline.currentTime + 1000); |
| assert_times_equal(animation.currentTime, 1000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting startTime on a running animation"); |
| |
| test(function() { |
| var animation = pausedAnimation(); |
| animation.play(); |
| assert_unresolved(animation.startTime); |
| assert_equals(animation.currentTime, duration); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling play() on a paused animation"); |
| |
| test(function() { |
| var animation = pausedAnimation(); |
| // Calling pause on an animation that is already paused or pause-pending is |
| // a no-op. |
| animation.pause(); |
| assert_unresolved(animation.startTime); |
| assert_equals(animation.currentTime, duration); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| }, "Calling pause() on a paused animation"); |
| |
| test(function() { |
| var animation = pausedAnimation(); |
| animation.cancel(); |
| assert_unresolved(animation.startTime); |
| assert_unresolved(animation.currentTime); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'idle'); |
| }, "Calling cancel() on a paused animation"); |
| |
| test(function() { |
| var animation = pausedAnimation(); |
| animation.finish(); |
| assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); |
| assert_equals(animation.currentTime, 0); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'finished'); |
| }, "Calling finish() on a paused animation"); |
| |
| test(function() { |
| var animation = pausedAnimation(); |
| animation.reverse(); |
| assert_unresolved(animation.startTime); |
| assert_equals(animation.currentTime, 0); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling reverse() on a paused animation"); |
| |
| test(function() { |
| var animation = pausedAnimation(); |
| // Setting the current time on a paused or pause-pending animation gets |
| // resolved synchronously. |
| animation.currentTime = 1000; |
| assert_unresolved(animation.startTime); |
| assert_times_equal(animation.currentTime, 1000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| }, "Setting currentTime on a paused animation"); |
| |
| test(function() { |
| var animation = pausedAnimation(); |
| animation.startTime = document.timeline.currentTime + 1000; |
| assert_times_equal(animation.startTime, document.timeline.currentTime + 1000); |
| assert_times_equal(animation.currentTime, 1000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting startTime on a paused animation"); |
| |
| test(function() { |
| var animation = finishedAnimation(); |
| animation.play(); |
| assert_unresolved(animation.startTime); |
| assert_equals(animation.currentTime, duration); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling play() on a finished animation"); |
| |
| async_test(function(t) { |
| var animation = finishedAnimation(); |
| animation.pause(); |
| assert_equals(animation.currentTime, 0); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| animation.ready.then(t.step_func_done(() => { |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 0); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| })); |
| }, "Calling pause() on a finished animation"); |
| |
| test(function() { |
| var animation = finishedAnimation(); |
| animation.cancel(); |
| assert_unresolved(animation.startTime); |
| assert_unresolved(animation.currentTime); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'idle'); |
| }, "Calling cancel() on a finished animation"); |
| |
| test(function() { |
| var animation = finishedAnimation(); |
| animation.finish(); |
| assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); |
| assert_equals(animation.currentTime, 0); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'finished'); |
| }, "Calling finish() on a finished animation"); |
| |
| async_test(function(t) { |
| var animation = finishedAnimation(); |
| animation.reverse(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 0); |
| assert_equals(animation.playbackRate, -1); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| animation.ready.then(t.step_func_done(() => { |
| assert_false(animation.pending); |
| assert_not_equals(animation.startTime, null); |
| assert_greater_than_equal(animation.currentTime, 0); |
| assert_equals(animation.playbackRate, 1); |
| assert_equals(animation.playState, 'running'); |
| })); |
| |
| }, "Calling reverse() on a finished animation"); |
| |
| test(function() { |
| var animation = finishedAnimation(); |
| animation.currentTime = 1000; |
| assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); |
| assert_times_equal(animation.currentTime, 1000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting currentTime on a finished animation"); |
| </script> |