gecko-dev/testing/web-platform/tests/scroll-animations/scroll-timeline-invalidation.html
Olga Gerchikov 91c2e3234c 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
2020-04-06 12:44:14 +00:00

105 lines
3.6 KiB
HTML

<!DOCTYPE html>
<meta charset="utf-8">
<title>ScrollTimeline invalidation</title>
<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>
<script src="testcommon.js"></script>
<style>
.scroller {
overflow: auto;
height: 100px;
width: 100px;
}
.contents {
height: 1000px;
width: 100%;
}
</style>
<div id="log"></div>
<script>
'use strict';
promise_test(async t => {
const animation = createScrollLinkedAnimation(t);
animation.effect.updateTiming({ duration: 350 });
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;
// Change scroller content size.
scroller.firstChild.style.height = "500px";
await animation.finished;
const newTime = animation.effect.getTiming().duration;
assert_times_equal(animation.currentTime, newTime,
'Animation current time is updated after scroller invalidation.');
assert_times_equal(
animation.effect.getComputedTiming().localTime, newTime,
'Effect local time is updated after scroller invalidation.');
}, 'Animation current time and effect local time are updated after scroller ' +
'content size changes.');
promise_test(async t => {
const animation = createScrollLinkedAnimation(t);
animation.effect.updateTiming({ duration: 350 });
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;
// Change scroller size.
scroller.style.height = "500px";
await animation.finished;
const newTime = animation.effect.getTiming().duration;
assert_times_equal(animation.currentTime, newTime,
'Animation current time is updated after scroller invalidation.');
assert_times_equal(
animation.effect.getComputedTiming().localTime, newTime,
'Effect local time is updated after scroller invalidation.');
}, 'Animation current time and effect local time are updated after scroller ' +
'size changes.');
promise_test(async t => {
const timeline = createScrollTimeline(t);
const scroller = timeline.scrollSource;
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
// Instantiate scroll animation that resizes its scroll timeline scroller.
const animation = new Animation(
new KeyframeEffect(
timeline.scrollSource.firstChild,
[{ height: '1000px' }, { height: '2000px' }],
{ duration: 1000, }
), timeline);
animation.play();
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 animation frame.');
await waitForNextFrame();
assert_times_equal(timeline.currentTime, 163.636,
'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>