Automatic update from web-platform-tests Snapshot post-layout for all but scroll-timelines 'Run snapshot post-layout state steps' was introduced in the CSSOM View spec[1] to formalize when state for scroll-state() queries, anchor position effects based on scrolling, and scroll-timeline progress is updated. There is a pull request[2] to tell when to invoke snapshotting from the HTML event loop. This CL aligns snapshotting with that CL for all snapshotting except for scroll-timelines. scroll-timeline-multi-pass.tentative.html is updated to align with the one-snapshot-per-resizeObserver-loop-iteration in the HTML spec PR. The difference between scroll-timelines and other snapshotting is that the scroll-timelines are still snapshotted before the first style/layout update in the resizeObserver loop. The reason we keep the pre-layout snapshotting of scroll-timelines for now is that timleines are only progressed before the first style/layout update, which means the post-layout snapshotting will always cause scroll-timelines to be a frame late (with the exception of the first frame) unless we start allowing scroll-timelines to progress in the resizeObserver loop. [1] https://drafts.csswg.org/cssom-view/#run-snapshot-post-layout-state-steps [2] https://github.com/whatwg/html/pull/11613 Bug: 384523570 Change-Id: Iabb35fd06e5a2b9a95a09a25d27d7baad545653f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7673480 Reviewed-by: Robert Flack <flackr@chromium.org> Commit-Queue: Rune Lillesveen <futhark@chromium.org> Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org> Cr-Commit-Position: refs/heads/main@{#1601971} -- Capture uncaught error causing harness flakiness -- wpt-commits: 7427991d737d3a1704194ad8673ccc57d1ac78f4, a7f2794f9d1382ede06e2cf284b2eca5d9e07944 wpt-pr: 58613
118 lines
4.0 KiB
HTML
118 lines
4.0 KiB
HTML
<!DOCTYPE html>
|
|
<title>ScrollTimelines may trigger multiple style/layout passes</title>
|
|
<link rel="help" src="https://github.com/w3c/csswg-drafts/issues/5261">
|
|
<link rel="help" src="https://github.com/whatwg/html/pull/11613">
|
|
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#avoiding-cycles">
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="/web-animations/testcommon.js"></script>
|
|
<script src="support/testcommon.js"></script>
|
|
<style>
|
|
@keyframes expand_width {
|
|
from { width: 100px; }
|
|
to { width: 100px; }
|
|
}
|
|
@keyframes expand_height {
|
|
from { height: 100px; }
|
|
to { height: 100px; }
|
|
}
|
|
main {
|
|
height: 0px;
|
|
overflow: hidden;
|
|
timeline-scope: --timeline1, --timeline2;
|
|
}
|
|
.scroller {
|
|
height: 100px;
|
|
overflow: scroll;
|
|
}
|
|
.scroller > div {
|
|
height: 200px;
|
|
}
|
|
#element1 {
|
|
width: 1px;
|
|
animation: expand_width 10s;
|
|
animation-timeline: --timeline1;
|
|
}
|
|
#element2 {
|
|
height: 1px;
|
|
animation: expand_height 10s;
|
|
animation-timeline: --timeline2;
|
|
}
|
|
</style>
|
|
<main id=main>
|
|
<div id=element1></div>
|
|
<div>
|
|
<div id=element2></div>
|
|
</div>
|
|
</main>
|
|
<script>
|
|
setup(assert_implements_animation_timeline);
|
|
|
|
function insertScroller(timeline_name) {
|
|
let scroller = document.createElement('div');
|
|
scroller.classList.add('scroller');
|
|
scroller.style.scrollTimeline = timeline_name;
|
|
scroller.append(document.createElement('div'));
|
|
main.insertBefore(scroller, element1);
|
|
}
|
|
|
|
promise_test(async (t) => {
|
|
await waitForNextFrame();
|
|
|
|
let events1 = [];
|
|
let events2 = [];
|
|
|
|
insertScroller('--timeline1');
|
|
// Even though the scroller was just inserted into the DOM, |timeline1|
|
|
// remains inactive until the next frame.
|
|
//
|
|
// https://drafts.csswg.org/scroll-animations-1/#avoiding-cycles
|
|
assert_equals(getComputedStyle(element1).width, '1px');
|
|
(new ResizeObserver(entries => t.step_func(() => {
|
|
events1.push(entries);
|
|
insertScroller('--timeline2');
|
|
assert_equals(getComputedStyle(element2).height, '1px');
|
|
}))).observe(element1);
|
|
|
|
(new ResizeObserver(entries => {
|
|
events2.push(entries);
|
|
})).observe(element2);
|
|
|
|
await waitForNextFrame();
|
|
|
|
// According to the basic rules of the spec [1], the timeline is
|
|
// inactive at the time the resize observer event was delivered, because
|
|
// #scroller1 did not have a layout box at the time style recalc for
|
|
// #element1 happened.
|
|
//
|
|
// However, an additional style/layout pass should take place
|
|
// (before resize observer deliveries) if we detect new ScrollTimelines
|
|
// in this situation, hence we ultimately do expect the animation to
|
|
// apply [2].
|
|
//
|
|
// [1] https://drafts.csswg.org/scroll-animations-1/#avoiding-cycles
|
|
// [2] https://github.com/w3c/csswg-drafts/issues/5261
|
|
assert_equals(events1.length, 1);
|
|
assert_equals(events1[0].length, 1);
|
|
assert_equals(events1[0][0].contentBoxSize.length, 1);
|
|
assert_equals(events1[0][0].contentBoxSize[0].inlineSize, 100);
|
|
|
|
// The HTML PR[3] that uses the 'run snapshot post-layout state steps',
|
|
// would try to create new scroll-timelines for each iteration of the
|
|
// resize observer loop, so the ResizeObserver event should reflect the
|
|
// animated value for the second observation.
|
|
//
|
|
// [3] https://github.com/whatwg/html/pull/11613/
|
|
assert_equals(events2.length, 2);
|
|
assert_equals(events2[0].length, 1);
|
|
assert_equals(events2[0][0].contentBoxSize.length, 1);
|
|
assert_equals(events2[0][0].contentBoxSize[0].blockSize, 1);
|
|
assert_equals(events2[1].length, 1);
|
|
assert_equals(events2[1][0].contentBoxSize.length, 1);
|
|
assert_equals(events2[1][0].contentBoxSize[0].blockSize, 100);
|
|
|
|
assert_equals(getComputedStyle(element1).width, '100px');
|
|
assert_equals(getComputedStyle(element2).height, '100px');
|
|
}, 'Multiple style/layout passes occur when necessary');
|
|
</script>
|