| <!DOCTYPE html> | |
| <meta charset=utf-8> | |
| <title>Setting the current time of an animation</title> | |
| <link rel="help" href="https://drafts.csswg.org/web-animations-1/#setting-the-current-time-of-an-animation"> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.js"></script> | |
| <script src="/web-animations/testcommon.js"></script> | |
| <script src="testcommon.js"></script> | |
| <style> | |
| .scroller { | |
| overflow: auto; | |
| height: 200px; | |
| width: 100px; | |
| will-change: transform; | |
| } | |
| .contents { | |
| height: 1000px; | |
| width: 100%; | |
| } | |
| </style> | |
| <body> | |
| <div id="log"></div> | |
| <script> | |
| 'use strict'; | |
| promise_test(async t => { | |
| const animation = createScrollLinkedAnimation(t); | |
| const scroller = animation.timeline.source; | |
| const maxScroll = scroller.scrollHeight - scroller.clientHeight; | |
| scroller.scrollTop = 0.25 * maxScroll; | |
| // Wait for new animation frame which allows the timeline to compute new | |
| // current time. | |
| await waitForNextFrame(); | |
| animation.play(); | |
| await animation.ready; | |
| assert_throws_js(TypeError, () => { | |
| animation.currentTime = null; | |
| }); | |
| }, 'Setting animation current time to null throws TypeError.'); | |
| promise_test(async t => { | |
| const animation = createScrollLinkedAnimation(t); | |
| assert_throws_dom('NotSupportedError', () => { | |
| animation.currentTime = CSSNumericValue.parse("300"); | |
| }); | |
| assert_throws_dom('NotSupportedError', () => { | |
| animation.currentTime = CSSNumericValue.parse("300ms"); | |
| }); | |
| assert_throws_dom('NotSupportedError', () => { | |
| animation.currentTime = CSSNumericValue.parse("0.3s"); | |
| }); | |
| }, 'Setting the current time to an absolute time value throws exception'); | |
| promise_test(async t => { | |
| const animation = createScrollLinkedAnimation(t); | |
| const scroller = animation.timeline.source; | |
| const maxScroll = scroller.scrollHeight - scroller.clientHeight; | |
| scroller.scrollTop = 0.25 * maxScroll; | |
| // Wait for new animation frame which allows the timeline to compute new | |
| // current time. | |
| await waitForNextFrame(); | |
| animation.currentTime = CSSNumericValue.parse("33.3%"); | |
| assert_percents_equal(animation.currentTime, 33.3, | |
| "Animation current time should be equal to the set value." | |
| ); | |
| }, 'Set animation current time to a valid value without playing.'); | |
| promise_test(async t => { | |
| const animation = createScrollLinkedAnimation(t); | |
| const scroller = animation.timeline.source; | |
| const maxScroll = scroller.scrollHeight - scroller.clientHeight; | |
| scroller.scrollTop = 0.25 * maxScroll; | |
| // Wait for new animation frame which allows the timeline to compute new | |
| // current time. | |
| await waitForNextFrame(); | |
| animation.play(); | |
| await animation.ready; | |
| animation.currentTime = CSSNumericValue.parse("33.3%"); | |
| assert_percents_equal(animation.currentTime, 33.3, | |
| "Animation current time should be equal to the set value." | |
| ); | |
| }, 'Set animation current time to a valid value while playing.'); | |
| promise_test(async t => { | |
| const animation = createScrollLinkedAnimation(t); | |
| const scroller = animation.timeline.source; | |
| const maxScroll = scroller.scrollHeight - scroller.clientHeight; | |
| scroller.scrollTop = 0.25 * maxScroll; | |
| // Wait for new animation frame which allows the timeline to compute new | |
| // current time. | |
| await waitForNextFrame(); | |
| animation.play(); | |
| await animation.ready; | |
| animation.currentTime = CSSNumericValue.parse("200%"); | |
| assert_equals(animation.playState, "finished"); | |
| assert_percents_equal(animation.currentTime, 200, | |
| "Animation current time should be equal to the set value." | |
| ); | |
| }, 'Set animation current time to a value beyond effect end.'); | |
| promise_test(async t => { | |
| const animation = createScrollLinkedAnimation(t); | |
| const scroller = animation.timeline.source; | |
| const maxScroll = scroller.scrollHeight - scroller.clientHeight; | |
| scroller.scrollTop = 0.25 * maxScroll; | |
| // Wait for new animation frame which allows the timeline to compute new | |
| // current time. | |
| await waitForNextFrame(); | |
| animation.play(); | |
| await animation.ready; | |
| animation.currentTime = CSSNumericValue.parse("-10%"); | |
| assert_equals(animation.playState, "running"); | |
| assert_percents_equal(animation.currentTime, -10, | |
| "Animation current time should be equal to the set value." | |
| ); | |
| }, 'Set animation current time to a negative value.'); | |
| promise_test(async t => { | |
| const animation = createScrollLinkedAnimation(t); | |
| const scroller = animation.timeline.source; | |
| const maxScroll = scroller.scrollHeight - scroller.clientHeight; | |
| scroller.scrollTop = 0.25 * maxScroll; | |
| // Wait for new animation frame which allows the timeline to compute new | |
| // current time. | |
| await waitForNextFrame(); | |
| animation.play(); | |
| animation.currentTime = CSSNumericValue.parse("30%"); | |
| assert_equals(animation.playState, "running"); | |
| assert_true(animation.pending); | |
| assert_percents_equal(animation.currentTime, 30); | |
| }, "Setting current time while play pending overrides the current time"); | |
| promise_test(async t => { | |
| const animation = createScrollLinkedAnimation(t); | |
| const scroller = animation.timeline.source; | |
| const maxScroll = scroller.scrollHeight - scroller.clientHeight; | |
| scroller.scrollTop = 0.25 * maxScroll; | |
| // Wait for new animation frame which allows the timeline to compute new | |
| // current time. | |
| await waitForNextFrame(); | |
| animation.play(); | |
| await animation.ready; | |
| animation.currentTime = CSSNumericValue.parse("33.3%"); | |
| assert_percents_equal(animation.currentTime, 33.3, | |
| "Animation current time should be equal to the set value." | |
| ); | |
| // Cancel the animation and play it again, check that current time has reset | |
| // to scroll offset based current time. | |
| animation.cancel(); | |
| animation.play(); | |
| await animation.ready; | |
| assert_percents_equal(animation.currentTime, animation.timeline.currentTime, | |
| "Animation current time should return to a value matching its" + | |
| " timeline current time after animation is cancelled and played again." | |
| ); | |
| }, 'Setting animation.currentTime then restarting the animation should' + | |
| ' reset the current time.'); | |
| promise_test(async t => { | |
| const animation = createScrollLinkedAnimation(t); | |
| const scroller = animation.timeline.source; | |
| const maxScroll = scroller.scrollHeight - scroller.clientHeight; | |
| scroller.scrollTop = 0.25 * maxScroll; | |
| // Wait for new animation frame which allows the timeline to compute new | |
| // current time. | |
| await waitForNextFrame(); | |
| animation.play(); | |
| await animation.ready; | |
| const originalCurrentTime = animation.currentTime.value; | |
| // Set the current time to something other than where the scroll offset. | |
| animation.currentTime = CSSNumericValue.parse("50%"); | |
| // Setting current time is internally setting the start time to | |
| // scrollTimeline.currentTime - newAnimationCurrentTime. | |
| // Which results in current time of (timeline.currentTime - start_time). | |
| // This behavior puts the animation in a strange "out of sync" state between | |
| // the scroller and the animation effect, this is currently expected | |
| // behavior. | |
| const expectedStartTime = originalCurrentTime - animation.currentTime.value; | |
| assert_percents_equal(animation.startTime, expectedStartTime, | |
| "Animation current time should be updated when setting the current time" + | |
| " to a time within the range of the animation."); | |
| scroller.scrollTop = 0.7 * maxScroll; | |
| // Wait for new animation frame which allows the timeline to compute new | |
| // current time. | |
| await waitForNextFrame(); | |
| assert_percents_equal(animation.startTime, expectedStartTime, | |
| "Animation start time should remain unchanged when the scroller changes" + | |
| " position." | |
| ); | |
| assert_percents_equal(animation.currentTime, | |
| animation.timeline.currentTime.value - animation.startTime.value, | |
| "Animation current time should return to a value equal to" + | |
| " (timeline.currentTime - animation.startTime) after timeline scroll" + | |
| " source has been scrolled." | |
| ); | |
| }, 'Set Animation current time then scroll.'); | |
| promise_test(async t => { | |
| const animation = createScrollLinkedAnimation(t); | |
| const scroller = animation.timeline.source; | |
| // Wait for new animation frame which allows the timeline to compute new | |
| // current time. | |
| await waitForNextFrame(); | |
| animation.play(); | |
| await animation.ready; | |
| // Make the timeline inactive. | |
| scroller.style.overflow = 'visible'; | |
| scroller.scrollTop; | |
| await waitForNextFrame(); | |
| assert_equals(animation.currentTime, null, | |
| 'Current time is unresolved when the timeline is inactive.'); | |
| animation.currentTime = CSSNumericValue.parse("30%"); | |
| assert_percents_equal(animation.currentTime, 30, | |
| 'Animation current time should be equal to the set value.'); | |
| assert_equals(animation.playState, 'paused', | |
| 'Animation play state is \'paused\' when current time is set and ' + | |
| 'timeline is inactive.'); | |
| }, 'Animation current time and play state are correct when current time is ' + | |
| 'set while the timeline is inactive.'); | |
| promise_test(async t => { | |
| const animation = createScrollLinkedAnimation(t); | |
| const scroller = animation.timeline.source; | |
| // Wait for new animation frame which allows the timeline to compute new | |
| // current time. | |
| await waitForNextFrame(); | |
| animation.play(); | |
| await animation.ready; | |
| // Make the timeline inactive. | |
| scroller.style.overflow = 'visible'; | |
| scroller.scrollTop; | |
| await waitForNextFrame(); | |
| assert_equals(animation.timeline.currentTime, null, | |
| 'Current time is unresolved when the timeline is inactive.'); | |
| animation.currentTime = CSSNumericValue.parse("30%"); | |
| assert_percents_equal(animation.currentTime, 30, | |
| 'Animation current time should be equal to the set value.'); | |
| assert_equals(animation.playState, 'paused', | |
| 'Animation play state is \'paused\' when current time is set and ' + | |
| 'timeline is inactive.'); | |
| // Make the timeline active. | |
| scroller.style.overflow = 'auto'; | |
| scroller.scrollTop; | |
| await waitForNextFrame(); | |
| assert_percents_equal(animation.timeline.currentTime, 0, | |
| 'Current time is resolved when the timeline is active.'); | |
| assert_percents_equal(animation.currentTime, 30, | |
| 'Animation current time holds the set value.'); | |
| assert_equals(animation.playState, 'paused', | |
| 'Animation holds \'paused\' state.'); | |
| }, 'Animation current time set while the timeline is inactive holds when the ' + | |
| 'timeline becomes active again.'); | |
| </script> | |
| </body> |