Bug 1626422 [wpt PR 22581] - Snapshot scroll timeline state once per animation frame., a=testonly

Automatic update from web-platform-tests
Snapshot scroll timeline state once per animation frame.

This change simplifies previous scroll timeline snapshotting model
implemented in
https://chromium-review.googlesource.com/c/chromium/src/+/2005629.

In previous model snapshotting is allowed any time scroll timeline is
invalidated outside of document lifecycle update, e.g. in user scripts.
Such invalidations may cause scroll animations to be stale after layout
run, which is against existing invariant that requires clean layout
state after document update.

This change allows snapshotting just once per animation frame. Scripts
that cause scroll timeline invalidation need to wait for next animation
frame to read updated scroll timeline current time.

Changes made:
- Snapshot scroll timeline phase and time once per animation frame at
  top of frame.
- On scroll timeline invalidation request a new frame where new state
  is snapshotted.
- Updated tests that read scroll timeline current time after scroller
  invalidation to wait for next frame.

Bug: 944449
Change-Id: I9b2f15f8f6456ef1c01ff7bedf72545ed7618b96
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2129232
Commit-Queue: Majid Valipour <majidvp@chromium.org>
Reviewed-by: Robert Flack <flackr@chromium.org>
Reviewed-by: Majid Valipour <majidvp@chromium.org>
Cr-Commit-Position: refs/heads/master@{#755797}

--

wpt-commits: 167fc7a89f441e9548454d54f260a6d19cf973b6
wpt-pr: 22581
This commit is contained in:
Olga Gerchikov 2020-04-03 10:11:00 +00:00 committed by moz-wptsync-bot
parent 6353a0330e
commit 91c2e3234c
9 changed files with 201 additions and 32 deletions

View File

@ -95,8 +95,10 @@ function setupAndRegisterTests() {
'timeline is inactive.');
// Make the timeline active.
scroller.style.display = ""
scroller.scrollTop;
scroller.style.display = "";
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_times_equal(animation.currentTime, 200,
'Current time must be initialized.');
@ -114,7 +116,7 @@ function setupAndRegisterTests() {
// Make the timeline inactive again.
scroller.style.display = "none"
scroller.scrollTop;
await waitForNextFrame();
assert_times_equal(animation.currentTime, 200,
'Current time must be the previous current time.');
@ -122,7 +124,6 @@ function setupAndRegisterTests() {
'Initial start time must be unresolved.');
scrollerRef.scrollTop = 0.6 * maxScroll;
scrollerRef.scrollTop;
// Wait until local times are synced back to the main thread.
await waitForAnimationFrameWithCondition(_ => {
return animationRef.effect.getComputedTiming().localTime == 600;

View File

@ -4,6 +4,7 @@
<link rel="help" href="https://wicg.github.io/scroll-animations/#current-time-algorithm">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<style>
html {
@ -16,7 +17,7 @@ html {
</style>
<script>
test(function() {
promise_test(async t => {
const scroller = document.scrollingElement;
// Set the timeRange(s) such that currentTime maps directly to the value
// scrolled. This makes it easier to assert on the currentTime in the test.
@ -35,6 +36,9 @@ test(function() {
// Now do some scrolling and make sure that the ScrollTimelines update.
scroller.scrollTop = 50;
scroller.scrollLeft = 75;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
// As noted above, the timeRange(s) are mapped such that currentTime should be
// the scroll offset.

View File

@ -12,7 +12,7 @@
<script>
'use strict';
test(function() {
promise_test(async t => {
const scrollerOverrides = new Map([['direction', 'rtl']]);
const scroller = setupScrollTimelineTest(scrollerOverrides);
@ -52,6 +52,9 @@ test(function() {
// block/vertical direction should be unaffected.
scroller.scrollTop = 50;
scroller.scrollLeft = 75 - scrollerSize;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_equals(blockScrollTimeline.currentTime, 50, 'Scrolled block timeline');
assert_equals(
@ -64,7 +67,7 @@ test(function() {
verticalScrollTimeline.currentTime, 50, 'Scrolled vertical timeline');
}, 'currentTime handles direction: rtl correctly');
test(function() {
promise_test(async t => {
const scrollerOverrides = new Map([['writing-mode', 'vertical-rl']]);
const scroller = setupScrollTimelineTest(scrollerOverrides);
@ -106,6 +109,9 @@ test(function() {
// vertical is normal.
scroller.scrollTop = 50;
scroller.scrollLeft = 75 - scrollerSize;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_equals(
blockScrollTimeline.currentTime, scrollerSize - 75,
@ -119,7 +125,7 @@ test(function() {
verticalScrollTimeline.currentTime, 50, 'Scrolled vertical timeline');
}, 'currentTime handles writing-mode: vertical-rl correctly');
test(function() {
promise_test(async t => {
const scrollerOverrides = new Map([['writing-mode', 'vertical-lr']]);
const scroller = setupScrollTimelineTest(scrollerOverrides);
@ -159,6 +165,9 @@ test(function() {
// not affect horizontal/vertical.
scroller.scrollTop = 50;
scroller.scrollLeft = 75;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_equals(blockScrollTimeline.currentTime, 75, 'Scrolled block timeline');
assert_equals(
@ -169,7 +178,7 @@ test(function() {
verticalScrollTimeline.currentTime, 50, 'Scrolled vertical timeline');
}, 'currentTime handles writing-mode: vertical-lr correctly');
test(function() {
promise_test(async t => {
const scrollerOverrides = new Map([['direction', 'rtl']]);
const scroller = setupScrollTimelineTest(scrollerOverrides);
// Set the timeRange such that currentTime maps directly to the value
@ -214,14 +223,19 @@ test(function() {
// Check the length-based ScrollTimeline.
scroller.scrollLeft = 0;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_equals(
lengthScrollTimeline.currentTime, 0,
'Length-based timeline before the startScrollOffset point');
scroller.scrollLeft = -20;
await waitForNextFrame();
assert_equals(
lengthScrollTimeline.currentTime, 0,
'Length-based timeline at the startScrollOffset point');
scroller.scrollLeft = -50;
await waitForNextFrame();
assert_times_equal(
lengthScrollTimeline.currentTime,
calculateCurrentTime(50, 20, scrollerSize, scrollerSize),
@ -229,14 +243,17 @@ test(function() {
// Check the percentage-based ScrollTimeline.
scroller.scrollLeft = -(0.19 * scrollerSize);
await waitForNextFrame();
assert_equals(
percentageScrollTimeline.currentTime, 0,
'Percentage-based timeline before the startScrollOffset point');
scroller.scrollLeft = -(0.20 * scrollerSize);
await waitForNextFrame();
assert_equals(
percentageScrollTimeline.currentTime, 0,
'Percentage-based timeline at the startScrollOffset point');
scroller.scrollLeft = -(0.4 * scrollerSize);
await waitForNextFrame();
assert_times_equal(
percentageScrollTimeline.currentTime,
calculateCurrentTime(
@ -245,14 +262,17 @@ test(function() {
// Check the calc-based ScrollTimeline.
scroller.scrollLeft = -(0.2 * scrollerSize - 10);
await waitForNextFrame();
assert_equals(
calcScrollTimeline.currentTime, 0,
'Calc-based timeline before the startScrollOffset point');
scroller.scrollLeft = -(0.2 * scrollerSize - 5);
await waitForNextFrame();
assert_equals(
calcScrollTimeline.currentTime, 0,
'Calc-based timeline at the startScrollOffset point');
scroller.scrollLeft = -(0.2 * scrollerSize);
await waitForNextFrame();
assert_times_equal(
calcScrollTimeline.currentTime,
calculateCurrentTime(
@ -261,7 +281,7 @@ test(function() {
'Calc-based timeline after the startScrollOffset point');
}, 'currentTime handles startScrollOffset with direction: rtl correctly');
test(function() {
promise_test(async t => {
const scrollerOverrides = new Map([['direction', 'rtl']]);
const scroller = setupScrollTimelineTest(scrollerOverrides);
// Set the timeRange such that currentTime maps directly to the value
@ -295,14 +315,19 @@ test(function() {
// Check the length-based ScrollTimeline.
scroller.scrollLeft = -scrollerSize;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_equals(
lengthScrollTimeline.currentTime, lengthScrollTimeline.timeRange,
'Length-based timeline after the endScrollOffset point');
scroller.scrollLeft = 20 - scrollerSize;
await waitForNextFrame();
assert_equals(
lengthScrollTimeline.currentTime, lengthScrollTimeline.timeRange,
'Length-based timeline at the endScrollOffset point');
scroller.scrollLeft = 50 - scrollerSize;
await waitForNextFrame();
assert_times_equal(
lengthScrollTimeline.currentTime,
calculateCurrentTime(
@ -311,14 +336,17 @@ test(function() {
// Check the percentage-based ScrollTimeline.
scroller.scrollLeft = 0.19 * scrollerSize - scrollerSize;
await waitForNextFrame();
assert_equals(
percentageScrollTimeline.currentTime, percentageScrollTimeline.timeRange,
'Percentage-based timeline after the endScrollOffset point');
scroller.scrollLeft = 0.20 * scrollerSize - scrollerSize;
await waitForNextFrame();
assert_equals(
percentageScrollTimeline.currentTime, percentageScrollTimeline.timeRange,
'Percentage-based timeline at the endScrollOffset point');
scroller.scrollLeft = 0.4 * scrollerSize - scrollerSize;
await waitForNextFrame();
assert_times_equal(
percentageScrollTimeline.currentTime,
calculateCurrentTime(
@ -327,14 +355,17 @@ test(function() {
// Check the calc-based ScrollTimeline. 80% + 5px
scroller.scrollLeft = -0.8 * scrollerSize - 10;
await waitForNextFrame();
assert_equals(
calcScrollTimeline.currentTime, calcScrollTimeline.timeRange,
'Calc-based timeline after the endScrollOffset point');
scroller.scrollLeft = -0.8 * scrollerSize - 5;
await waitForNextFrame();
assert_equals(
calcScrollTimeline.currentTime, calcScrollTimeline.timeRange,
'Calc-based timeline at the endScrollOffset point');
scroller.scrollLeft = -0.8 * scrollerSize;
await waitForNextFrame();
assert_times_equal(
calcScrollTimeline.currentTime,
calculateCurrentTime(
@ -342,7 +373,7 @@ test(function() {
'Calc-based timeline before the endScrollOffset point');
}, 'currentTime handles endScrollOffset with direction: rtl correctly');
test(function() {
promise_test(async t => {
const scrollerOverrides = new Map([['direction', 'rtl']]);
const scroller = setupScrollTimelineTest(scrollerOverrides);
// Set the timeRange such that currentTime maps directly to the value
@ -385,6 +416,9 @@ test(function() {
scroller.scrollLeft = 0;
let expectedCurrentTime = calculateCurrentTime(
scroller.scrollLeft, 0, scrollerSize, scrollerSize);
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_times_equal(
inclusiveAutoScrollTimeline.currentTime, expectedCurrentTime,

View File

@ -12,7 +12,7 @@
<script>
'use strict';
test(function() {
promise_test(async t => {
const scroller = setupScrollTimelineTest();
// Set the timeRange such that currentTime maps directly to the value
// scrolled. The contents and scroller are square, so it suffices to compute
@ -48,6 +48,9 @@ test(function() {
// Do some scrolling and make sure that the ScrollTimelines update.
scroller.scrollTop = 50;
scroller.scrollLeft = 75;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
// As noted above timeRange is mapped such that currentTime should be the
// scroll offset.
@ -60,7 +63,7 @@ test(function() {
verticalScrollTimeline.currentTime, 50, 'Scrolled vertical timeline');
}, 'currentTime calculates the correct time based on scrolled amount');
test(function() {
promise_test(async t => {
// It is difficult to calculate the scroll offset which results in an exact
// currentTime. Scrolling is calculated in integers which allows for the
// possibility of rounding, and scrollbar widths differ between platforms
@ -76,11 +79,14 @@ test(function() {
// calculate where the 50% scroll mark would be.
const halfwayY = (scroller.scrollHeight - scroller.clientHeight) / 2;
scroller.scrollTop = halfwayY;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_approx_equals(scrollTimeline.currentTime, 50, 0.5);
}, 'currentTime adjusts correctly for the timeRange');
test(function() {
promise_test(async t => {
const scroller = setupScrollTimelineTest();
// Set the timeRange such that currentTime maps directly to the value
// scrolled. The contents and scroller are square, so it suffices to compute
@ -129,6 +135,9 @@ test(function() {
// Check the length-based ScrollTimeline.
scroller.scrollTop = 19;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_equals(
lengthScrollTimeline.currentTime, 0,
'Length-based timeline current time before the startScrollOffset'
@ -137,6 +146,7 @@ test(function() {
lengthScrollTimeline.phase, "before",
'Length-based timeline phase before the startScrollOffset point');
scroller.scrollTop = 20;
await waitForNextFrame();
assert_equals(
lengthScrollTimeline.currentTime, 0,
'Length-based timeline current time at the startScrollOffset point');
@ -144,6 +154,7 @@ test(function() {
lengthScrollTimeline.phase, "active",
'Length-based timeline phase at the startScrollOffset point');
scroller.scrollTop = 50;
await waitForNextFrame();
assert_times_equal(
lengthScrollTimeline.currentTime,
calculateCurrentTime(50, 20, scrollerSize, scrollerSize),
@ -154,6 +165,7 @@ test(function() {
// Check the percentage-based ScrollTimeline.
scroller.scrollTop = 0.19 * scrollerSize;
await waitForNextFrame();
assert_equals(
percentageScrollTimeline.currentTime, 0,
'Percentage-based timeline current time before the startScrollOffset'
@ -162,6 +174,7 @@ test(function() {
percentageScrollTimeline.phase, "before",
'Percentage-based timeline phase before the startScrollOffset point');
scroller.scrollTop = 0.20 * scrollerSize;
await waitForNextFrame();
assert_equals(
percentageScrollTimeline.currentTime, 0,
'Percentage-based timeline current time at the startScrollOffset point');
@ -169,6 +182,7 @@ test(function() {
percentageScrollTimeline.phase, "active",
'Percentage-based timeline phase at the startScrollOffset point');
scroller.scrollTop = 0.50 * scrollerSize;
await waitForNextFrame();
assert_times_equal(
percentageScrollTimeline.currentTime,
calculateCurrentTime(
@ -181,6 +195,7 @@ test(function() {
// Check the calc-based ScrollTimeline.
scroller.scrollTop = 0.2 * scrollerSize - 10;
await waitForNextFrame();
assert_equals(
calcScrollTimeline.currentTime, 0,
'Calc-based timeline current time before the startScrollOffset point');
@ -188,6 +203,7 @@ test(function() {
calcScrollTimeline.phase, "before",
'Calc-based timeline phase at the startScrollOffset point');
scroller.scrollTop = 0.2 * scrollerSize - 5;
await waitForNextFrame();
assert_equals(
calcScrollTimeline.currentTime, 0,
'Calc-based timeline current time at the startScrollOffset point');
@ -195,6 +211,7 @@ test(function() {
calcScrollTimeline.phase, "active",
'Calc-based timeline phase at the startScrollOffset point');
scroller.scrollTop = 0.2 * scrollerSize;
await waitForNextFrame();
assert_times_equal(
calcScrollTimeline.currentTime,
calculateCurrentTime(
@ -206,7 +223,7 @@ test(function() {
'Calc-based timeline phase at the startScrollOffset point');
}, 'currentTime handles startScrollOffset correctly');
test(function() {
promise_test(async t => {
const scroller = setupScrollTimelineTest();
// Set the timeRange such that currentTime maps directly to the value
// scrolled. The contents and scroller are square, so it suffices to compute
@ -234,6 +251,9 @@ test(function() {
// Check the length-based ScrollTimeline.
scroller.scrollTop = scrollerSize;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_equals(
lengthScrollTimeline.currentTime, lengthScrollTimeline.timeRange,
'Length-based timeline current time after the endScrollOffset point');
@ -241,6 +261,7 @@ test(function() {
lengthScrollTimeline.phase, "after",
'Length-based timeline phase after the endScrollOffset point');
scroller.scrollTop = scrollerSize - 20;
await waitForNextFrame();
assert_equals(
lengthScrollTimeline.currentTime, lengthScrollTimeline.timeRange,
'Length-based timeline current time at the endScrollOffset point');
@ -248,6 +269,7 @@ test(function() {
lengthScrollTimeline.phase, "after",
'Length-based timeline phase at the endScrollOffset point');
scroller.scrollTop = scrollerSize - 50;
await waitForNextFrame();
assert_times_equal(
lengthScrollTimeline.currentTime,
calculateCurrentTime(
@ -259,6 +281,7 @@ test(function() {
// Check the percentage-based ScrollTimeline.
scroller.scrollTop = 0.81 * scrollerSize;
await waitForNextFrame();
assert_equals(
percentageScrollTimeline.currentTime, percentageScrollTimeline.timeRange,
'Percentage-based timeline current time after the endScrollOffset point');
@ -266,6 +289,7 @@ test(function() {
percentageScrollTimeline.phase, "after",
'Percentage-based timeline phase after the endScrollOffset point');
scroller.scrollTop = 0.80 * scrollerSize;
await waitForNextFrame();
assert_equals(
percentageScrollTimeline.currentTime, percentageScrollTimeline.timeRange,
'Percentage-based timeline current time at the endScrollOffset point');
@ -273,6 +297,7 @@ test(function() {
percentageScrollTimeline.phase, "after",
'Percentage-based timeline phase at the endScrollOffset point');
scroller.scrollTop = 0.50 * scrollerSize;
await waitForNextFrame();
assert_times_equal(
percentageScrollTimeline.currentTime,
calculateCurrentTime(
@ -284,6 +309,7 @@ test(function() {
// Check the calc-based ScrollTimeline.
scroller.scrollTop = 0.8 * scrollerSize + 6;
await waitForNextFrame();
assert_equals(
calcScrollTimeline.currentTime, calcScrollTimeline.timeRange,
'Calc-based timeline current time after the endScrollOffset point');
@ -291,6 +317,7 @@ test(function() {
calcScrollTimeline.phase, "after",
'Calc-based timeline phase after the endScrollOffset point');
scroller.scrollTop = 0.8 * scrollerSize + 5;
await waitForNextFrame();
assert_equals(
calcScrollTimeline.currentTime, calcScrollTimeline.timeRange,
'Calc-based timeline current time at the endScrollOffset point');
@ -298,6 +325,7 @@ test(function() {
calcScrollTimeline.phase, "after",
'Calc-based timeline phase at the endScrollOffset point');
scroller.scrollTop = 0.5 * scrollerSize;
await waitForNextFrame();
assert_times_equal(
calcScrollTimeline.currentTime,
calculateCurrentTime(
@ -308,7 +336,7 @@ test(function() {
'Calc-based timeline phase before the endScrollOffset point');
}, 'currentTime handles endScrollOffset correctly');
test(function() {
promise_test(async t => {
const scroller = setupScrollTimelineTest();
// Set the timeRange such that currentTime maps directly to the value
// scrolled. The contents and scroller are square, so it suffices to compute
@ -324,12 +352,15 @@ test(function() {
});
scroller.scrollTop = 150;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_times_equal(
scrollTimeline.currentTime,
calculateCurrentTime(150, 20, scrollerSize - 50, scrollerSize));
}, 'currentTime handles startScrollOffset and endScrollOffset together correctly');
test(function() {
promise_test(async t => {
const scroller = setupScrollTimelineTest();
// Set the timeRange such that currentTime maps directly to the value
// scrolled. The contents and scroller are square, so it suffices to compute
@ -345,10 +376,13 @@ test(function() {
});
scroller.scrollTop = 150;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_equals(scrollTimeline.currentTime, scrollTimeline.timeRange);
}, 'currentTime handles startScrollOffset == endScrollOffset correctly');
test(function() {
promise_test(async t => {
const scroller = setupScrollTimelineTest();
// Set the timeRange such that currentTime maps directly to the value
// scrolled. The contents and scroller are square, so it suffices to compute
@ -364,8 +398,12 @@ test(function() {
});
scroller.scrollTop = 40;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_equals(scrollTimeline.currentTime, 0);
scroller.scrollTop = 60;
await waitForNextFrame();
assert_equals(scrollTimeline.currentTime, scrollTimeline.timeRange);
}, 'currentTime handles startScrollOffset > endScrollOffset correctly');
</script>

View File

@ -47,6 +47,9 @@
// Now do some scrolling and make sure that the Animation current time is
// correct.
scroller.scrollTop = 0.2 * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_equals(animation.currentTime, animation.timeline.currentTime,
"The current time corresponds to the scroll position of the scroller.");
assert_times_equal(
@ -62,6 +65,9 @@ promise_test(async t => {
const timeRange = animation.timeline.timeRange;
// Advance the scroller.
scroller.scrollTop = 0.2 * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
// Verify initial start and current times in Idle state.
assert_equals(animation.currentTime, null,
@ -93,6 +99,9 @@ promise_test(async t => {
const timeRange = timeline.timeRange;
// Advance the scroller.
scroller.scrollTop = 0.2 * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
// Verify initial start and current times in Idle state.
assert_equals(animation1.currentTime, null,

View File

@ -28,6 +28,9 @@ promise_test(async t => {
const scroller = animation.timeline.scrollSource;
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = 0.2 * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
animation.play();
await animation.ready;
@ -52,6 +55,9 @@ promise_test(async t => {
const scroller = animation.timeline.scrollSource;
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = 0.2 * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
animation.play();
await animation.ready;
@ -85,14 +91,15 @@ promise_test(async t => {
await animation.ready;
await waitForNextFrame();
scroller.scrollTop = 0.2 * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_times_equal(timeline.currentTime, 200,
'Timeline current time is updated after scroller update.');
'Timeline current time is updated after animation frame.');
await waitForNextFrame();
assert_times_equal(timeline.currentTime, 163.636,
'Timeline current time is updated after animation frame and ' +
'Timeline current time is updated after two animation frames and ' +
'reflects single layout run.');
}, 'If scroll animation resizes its scroll timeline scroller, ' +
'layout runs only once to reflect the initial update.');
</script>

View File

@ -57,12 +57,15 @@
for (const test_case_key in test_cases){
const test_case = test_cases[test_case_key];
test(t => {
promise_test(async t => {
const timeline = createScrollTimelineWithOffsets(t, "20%", "80%");
const scroller = timeline.scrollSource;
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = test_case.scroll_percent * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_equals(
timeline.phase,
@ -107,12 +110,15 @@
for (const test_case_key in test_cases_start_offset_greater_than_end_offset){
const test_case =
test_cases_start_offset_greater_than_end_offset[test_case_key];
test(t => {
promise_test(async t => {
const timeline = createScrollTimelineWithOffsets(t, "80%", "20%");
const scroller = timeline.scrollSource;
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = test_case.scroll_percent * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_equals(
timeline.phase,
@ -147,12 +153,15 @@
for (const test_case_key in test_cases_start_offset_equal_to_end_offset){
const test_case =
test_cases_start_offset_equal_to_end_offset[test_case_key];
test(t => {
promise_test(async t => {
const timeline = createScrollTimelineWithOffsets(t, "50%", "50%");
const scroller = timeline.scrollSource;
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = test_case.scroll_percent * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_equals(
timeline.phase,
@ -163,7 +172,7 @@
" offset is " + test_case.name);
}
test(t => {
promise_test(async t => {
const timeline = createScrollTimeline(t);
const scroller = timeline.scrollSource;
// Timeline should be inactive since layout hasn't updated yet
@ -171,13 +180,14 @@
// Accessing scroller.scrollHeight forces the scroller to update
scroller.scrollHeight;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_equals(timeline.phase, "active");
// Setting the scroller to display none should make the timeline inactive
scroller.style.display = "none"
// Force another layout
scroller.scrollHeight;
await waitForNextFrame();
assert_equals(timeline.phase, "inactive");
}, 'Scroll timeline starts inactive, can transition to active, and then' +

View File

@ -26,6 +26,9 @@
const scroller = animation.timeline.scrollSource;
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;
@ -35,11 +38,14 @@
});
}, 'Setting animation current time to null throws TypeError.');
test(t => {
promise_test(async t => {
const animation = createScrollLinkedAnimation(t);
const scroller = animation.timeline.scrollSource;
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 = 333;
@ -55,6 +61,9 @@
const scroller = animation.timeline.scrollSource;
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;
@ -73,6 +82,9 @@
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
const range = animation.timeline.timeRange;
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;
@ -95,6 +107,9 @@
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
const range = animation.timeline.timeRange;
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;
@ -108,11 +123,14 @@
);
}, 'Set animation current time to a negative value.');
test(t => {
promise_test(async t => {
const animation = createScrollLinkedAnimation(t);
const scroller = animation.timeline.scrollSource;
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 = 300;
@ -127,6 +145,9 @@
const scroller = animation.timeline.scrollSource;
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;
@ -158,6 +179,9 @@
const scroller = animation.timeline.scrollSource;
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;
@ -181,6 +205,9 @@
" 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_times_equal(
animation.startTime,

View File

@ -25,6 +25,9 @@
const scroller = animation.timeline.scrollSource;
// this forces a layout which results in an active timeline
scroller.scrollTop = 0;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
animation.playbackRate = 0.5;
animation.play();
@ -39,6 +42,9 @@
const scroller = animation.timeline.scrollSource;
// this forces a layout which results in an active timeline
scroller.scrollTop = 0;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
animation.play();
animation.playbackRate = 0.5;
@ -54,6 +60,9 @@
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
const timeRange = animation.timeline.timeRange;
scroller.scrollTop = 0.2 * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
animation.playbackRate = 0.5;
animation.play();
@ -71,6 +80,9 @@
const playbackRate = 2;
scroller.scrollTop = 0.2 * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
animation.play();
await animation.ready;
@ -92,6 +104,9 @@
animation.play();
await animation.ready;
scroller.scrollTop = 0.2 * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_times_equal(animation.currentTime, 0.2 * timeRange * 2,
'The current time should increase two times faster than timeline time.');
@ -108,6 +123,9 @@
animation.playbackRate = 2;
scroller.scrollTop = 0.25 * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_times_equal(
animation.currentTime,
@ -117,11 +135,14 @@
}, 'The playback rate affects the rate of progress of the current time' +
' when scrolling');
test(t => {
promise_test(async t => {
const animation = createScrollLinkedAnimation(t);
const scroller = animation.timeline.scrollSource;
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.playbackRate = 2;
@ -149,6 +170,9 @@
const scroller = animation.timeline.scrollSource;
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;
@ -181,6 +205,9 @@
const range = animation.timeline.timeRange;
animation.playbackRate = -1;
scroller.scrollTop = 0.3 * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
animation.play();
await animation.ready;
@ -194,6 +221,9 @@
const scroller = animation.timeline.scrollSource;
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = 0.5 * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
animation.play();
await animation.ready;
@ -204,6 +234,7 @@
animation.playbackRate = -1;
scroller.scrollTop = 0.8 * maxScroll;
await waitForNextFrame();
// -300 = 500 - 800
let timelineDiff = startingTimelineTime - animation.timeline.currentTime;
// 200 = 500 + (-300)
@ -211,6 +242,7 @@
assert_times_equal(animation.currentTime, expected);
scroller.scrollTop = 0.2 * maxScroll;
await waitForNextFrame();
// 300 = 500 - 200
timelineDiff = startingTimelineTime - animation.timeline.currentTime;
// 800 = 500 + 300
@ -226,6 +258,9 @@
const range = animation.timeline.timeRange;
animation.playbackRate = 0;
scroller.scrollTop = 0.3 * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
animation.play();
await animation.ready;
@ -238,12 +273,16 @@
const scroller = animation.timeline.scrollSource;
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = 0.2 * maxScroll;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
animation.play();
await animation.ready;
assert_times_equal(animation.currentTime, 200);
animation.playbackRate = 0;
scroller.scrollTop = 0.5 * maxScroll;
await waitForNextFrame();
// Ensure that current time does not change.
assert_time_equals_literal(animation.timeline.currentTime, 500);