diff options
Diffstat (limited to 'testing/web-platform/tests/scroll-animations/scroll-timelines/setting-timeline.tentative.html')
-rw-r--r-- | testing/web-platform/tests/scroll-animations/scroll-timelines/setting-timeline.tentative.html | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/testing/web-platform/tests/scroll-animations/scroll-timelines/setting-timeline.tentative.html b/testing/web-platform/tests/scroll-animations/scroll-timelines/setting-timeline.tentative.html new file mode 100644 index 0000000000..34d9af2bff --- /dev/null +++ b/testing/web-platform/tests/scroll-animations/scroll-timelines/setting-timeline.tentative.html @@ -0,0 +1,394 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Setting the timeline of scroll animation</title> +<link rel="help" + href="https://drafts.csswg.org/web-animations-1/#setting-the-timeline"> +<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 { + /* The height is set to align scrolling in pixels with logical time in ms */ + height: 1200px; + width: 100%; + } + @keyframes anim { + from { opacity: 0; } + to { opacity: 1; } + } + .anim { + animation: anim 1s paused linear; + } +</style> +<body> +<script> +'use strict'; + +function createAnimation(t) { + const elem = createDiv(t); + const animation = elem.animate({ opacity: [1, 0] }, 1000); + return animation; +} + +function createPausedCssAnimation(t) { + const elem = createDiv(t); + elem.classList.add('anim'); + return elem.getAnimations()[0]; +} + +function updateScrollPosition(timeline, offset) { + const scroller = timeline.source; + assert_true(!!scroller, 'source is resolved'); + scroller.scrollTop = offset; + // Wait for new animation frame which allows the timeline to compute new + // current time. + return waitForNextFrame(); +} + +function assert_timeline_current_time(animation, timeline_current_time) { + if (animation.currentTime instanceof CSSUnitValue){ + assert_percents_equal(animation.timeline.currentTime, timeline_current_time, + `Timeline's currentTime aligns with the scroll ` + + `position even when paused`); + } + else { + assert_times_equal(animation.timeline.currentTime, timeline_current_time, + `Timeline's currentTime aligns with the scroll ` + + `position even when paused`); + } +} + +function assert_scroll_synced_times(animation, timeline_current_time, + animation_current_time) { + assert_timeline_current_time(animation, timeline_current_time); + if (animation.currentTime instanceof CSSUnitValue){ + assert_percents_equal(animation.currentTime, animation_current_time, + `Animation's currentTime aligns with the scroll position`); + } + else { + assert_times_equal(animation.currentTime, animation_current_time, + `Animation's currentTime aligns with the scroll position`); + } +} + +function assert_paused_times(animation, timeline_current_time, + animation_current_time) { + assert_timeline_current_time(animation, timeline_current_time); + if (animation.currentTime instanceof CSSUnitValue){ + assert_percents_equal(animation.currentTime, animation_current_time, + `Animation's currentTime is fixed while paused`); + } + else { + assert_times_equal(animation.currentTime, animation_current_time, + `Animation's currentTime is fixed while paused`); + } +} + +promise_test(async t => { + const scrollTimeline = createScrollTimeline(t); + await updateScrollPosition(scrollTimeline, 100); + + const animation = createAnimation(t); + animation.timeline = scrollTimeline; + assert_true(animation.pending); + await animation.ready; + + assert_equals(animation.playState, 'running'); + assert_scroll_synced_times(animation, 10, 10); +}, 'Setting a scroll timeline on a play-pending animation synchronizes ' + + 'currentTime of the animation with the scroll position.'); + +promise_test(async t => { + const scrollTimeline = createScrollTimeline(t); + await updateScrollPosition(scrollTimeline, 100); + + const animation = createAnimation(t); + animation.pause(); + animation.timeline = scrollTimeline; + assert_true(animation.pending); + await animation.ready; + + assert_equals(animation.playState, 'paused'); + assert_paused_times(animation, 10, 0); + + await updateScrollPosition(animation.timeline, 200); + + assert_equals(animation.playState, 'paused'); + assert_paused_times(animation, 20, 0); + + animation.play(); + await animation.ready; + + assert_scroll_synced_times(animation, 20, 20); +}, 'Setting a scroll timeline on a pause-pending animation fixes the ' + + 'currentTime of the animation based on the scroll position once resumed'); + +promise_test(async t => { + const scrollTimeline = createScrollTimeline(t); + await updateScrollPosition(scrollTimeline, 100); + + const animation = createAnimation(t); + animation.reverse(); + animation.timeline = scrollTimeline; + await animation.ready; + + assert_equals(animation.playState, 'running'); + assert_scroll_synced_times(animation, 10, 90); +}, 'Setting a scroll timeline on a reversed play-pending animation ' + + 'synchronizes the currentTime of the animation with the scroll ' + + 'position.'); + +promise_test(async t => { + const scrollTimeline = createScrollTimeline(t); + await updateScrollPosition(scrollTimeline, 100); + + const animation = createAnimation(t); + await animation.ready; + + animation.timeline = scrollTimeline; + assert_false(animation.pending); + assert_equals(animation.playState, 'running'); + assert_scroll_synced_times(animation, 10, 10); +}, 'Setting a scroll timeline on a running animation synchronizes the ' + + 'currentTime of the animation with the scroll position.'); + +promise_test(async t => { + const scrollTimeline = createScrollTimeline(t); + await updateScrollPosition(scrollTimeline, 100); + + const animation = createAnimation(t); + animation.pause(); + await animation.ready; + + animation.timeline = scrollTimeline; + assert_false(animation.pending); + assert_equals(animation.playState, 'paused'); + assert_paused_times(animation, 10, 0); + + animation.play(); + await animation.ready; + + assert_scroll_synced_times(animation, 10, 10); +}, 'Setting a scroll timeline on a paused animation fixes the currentTime of ' + + 'the animation based on the scroll position when resumed'); + +promise_test(async t => { + const scrollTimeline = createScrollTimeline(t); + await updateScrollPosition(scrollTimeline, 100); + + const animation = createAnimation(t); + animation.reverse(); + animation.pause(); + await animation.ready; + + animation.timeline = scrollTimeline; + assert_false(animation.pending); + assert_equals(animation.playState, 'paused'); + assert_paused_times(animation, 10, 100); + + animation.play(); + await animation.ready; + + assert_scroll_synced_times(animation, 10, 90); +}, 'Setting a scroll timeline on a reversed paused animation ' + + 'fixes the currentTime of the animation based on the scroll ' + + 'position when resumed'); + +promise_test(async t => { + const animation = createAnimation(t); + const scrollTimeline = createScrollTimeline(t); + animation.timeline = scrollTimeline; + await animation.ready; + await updateScrollPosition(scrollTimeline, 100); + + animation.timeline = document.timeline; + assert_times_equal(animation.currentTime, 100); +}, 'Transitioning from a scroll timeline to a document timeline on a running ' + + 'animation preserves currentTime'); + +promise_test(async t => { + const animation = createAnimation(t); + const scrollTimeline = createScrollTimeline(t); + animation.timeline = scrollTimeline; + await animation.ready; + await updateScrollPosition(scrollTimeline, 100); + + animation.pause(); + animation.timeline = document.timeline; + + await animation.ready; + assert_times_equal(animation.currentTime, 100); +}, 'Transitioning from a scroll timeline to a document timeline on a ' + + 'pause-pending animation preserves currentTime'); + +promise_test(async t => { + const animation = createAnimation(t); + const scrollTimeline = createScrollTimeline(t); + animation.timeline = scrollTimeline; + await animation.ready; + + animation.reverse(); + animation.pause(); + await updateScrollPosition(scrollTimeline, 100); + assert_scroll_synced_times(animation, 10, 90); + + await animation.ready; + + animation.timeline = document.timeline; + assert_false(animation.pending); + assert_equals(animation.playState, 'paused'); + assert_times_equal(animation.currentTime, 900); +}, 'Transition from a scroll timeline to a document timeline on a reversed ' + + 'paused animation maintains correct currentTime'); + +promise_test(async t => { + const animation = createAnimation(t); + const scrollTimeline = createScrollTimeline(t); + animation.timeline = scrollTimeline; + await animation.ready; + await updateScrollPosition(scrollTimeline, 100); + + const progress = animation.currentTime.value / 100; + const duration = animation.effect.getTiming().duration; + animation.timeline = null; + + const expectedCurrentTime = progress * duration; + assert_times_equal(animation.currentTime, expectedCurrentTime); +}, 'Transitioning from a scroll timeline to a null timeline on a running ' + + 'animation preserves current progress.'); + +promise_test(async t => { + const keyframeEfect = new KeyframeEffect(createDiv(t), + { opacity: [0, 1] }, + 1000); + const animation = new Animation(keyframeEfect, null); + animation.startTime = 0; + assert_equals(animation.playState, 'running'); + + const scrollTimeline = createScrollTimeline(t); + await updateScrollPosition(scrollTimeline, 100); + + animation.timeline = scrollTimeline; + assert_equals(animation.playState, 'running'); + assert_percents_equal(animation.currentTime, 10); +}, 'Switching from a null timeline to a scroll timeline on an animation with ' + + 'a resolved start time preserved the play state'); + +promise_test(async t => { + const firstScrollTimeline = createScrollTimeline(t); + await updateScrollPosition(firstScrollTimeline, 100); + + const secondScrollTimeline = createScrollTimeline(t); + await updateScrollPosition(secondScrollTimeline, 200); + + const animation = createAnimation(t); + animation.timeline = firstScrollTimeline; + await animation.ready; + assert_percents_equal(animation.currentTime, 10); + + animation.timeline = secondScrollTimeline; + assert_percents_equal(animation.currentTime, 20); +}, 'Switching from one scroll timeline to another updates currentTime'); + +promise_test(async t => { + const scrollTimeline = createScrollTimeline(t); + await updateScrollPosition(scrollTimeline, 100); + + const animation = createPausedCssAnimation(t); + animation.timeline = scrollTimeline; + await animation.ready; + assert_equals(animation.playState, 'paused'); + assert_percents_equal(animation.currentTime, 0); + + const target = animation.effect.target; + target.style.animationPlayState = 'running'; + await animation.ready; + + assert_percents_equal(animation.currentTime, 10); +}, 'Switching from a document timeline to a scroll timeline updates ' + + 'currentTime when unpaused via CSS.'); + +promise_test(async t => { + const scrollTimeline = createScrollTimeline(t); + await updateScrollPosition(scrollTimeline, 100); + + const animation = createAnimation(t); + animation.pause(); + animation.timeline = scrollTimeline; + await animation.ready; + assert_percents_equal(animation.currentTime, 0); + + animation.currentTime = CSSNumericValue.parse("50%"); + + animation.play(); + await animation.ready; + assert_percents_equal(animation.currentTime, 50); +}, 'Switching from a document timeline to a scroll timeline and updating ' + + 'currentTime preserves the new value when unpaused.'); + +promise_test(async t => { + const scrollTimeline = createScrollTimeline(t); + await updateScrollPosition(scrollTimeline, 100); + + const animation = createAnimation(t); + animation.pause(); + animation.timeline = scrollTimeline; + await animation.ready; + assert_percents_equal(animation.currentTime, 0); + assert_equals(animation.playState, 'paused'); + + // Set a start time that will ensure that current time is in the active + // region in order not to trigger a seek when play is called. + animation.startTime = CSSNumericValue.parse("-10%"); + assert_equals(animation.playState, 'running'); + + animation.play(); + await animation.ready; + assert_percents_equal(animation.startTime, -10); +}, 'Switching from a document timeline to a scroll timeline and updating ' + + 'startTime preserves the new value when play is called.'); + +promise_test(async t => { + const elem = createDiv(t); + const animation = elem.animate(null, Infinity); + await animation.ready; + + animation.timeline = new ScrollTimeline(); + let timing = animation.effect.getComputedTiming(); + assert_percents_equal(timing.endTime, 100); + assert_percents_equal(timing.activeDuration, 100); + assert_percents_equal(timing.duration, 100); + + animation.effect.updateTiming({ iterations: 2 }); + timing = animation.effect.getComputedTiming(); + assert_percents_equal(timing.endTime, 100); + assert_percents_equal(timing.activeDuration, 100); + assert_percents_equal(timing.duration, 50); + + // Blink implementation does not permit setting an infinite number of + // iterations on a scroll-linked animation. Workaround by temporarily + // switching back to a document timeline. + animation.timeline = document.timeline; + animation.effect.updateTiming({ iterations: Infinity }); + animation.timeline = new ScrollTimeline(); + timing = animation.effect.getComputedTiming(); + // Having an infinite number of iterations with a finite timeline results in + // each iteration having zero duration. + assert_percents_equal(timing.duration, 0); + // If either the iteration duration or iteration count is zero, the active + // duration is always zero. + assert_percents_equal(timing.activeDuration, 0); + assert_percents_equal(timing.endTime, 0); + +}, 'Switching from a document timeline to a scroll timeline on an infinite ' + + 'duration animation.') + +</script> +</body> |