mirror of
https://github.com/servo/servo.git
synced 2025-10-18 09:19:16 +01:00
187 lines
5.7 KiB
HTML
187 lines
5.7 KiB
HTML
<!DOCTYPE html>
|
|
<title>@scroll-timeline source invalidation</title>
|
|
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-at-rule">
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="/web-animations/testcommon.js"></script>
|
|
<style>
|
|
#scrollers {
|
|
overflow: hidden;
|
|
height: 0;
|
|
}
|
|
.scroller {
|
|
overflow: scroll;
|
|
width: 100px;
|
|
height: 100px;
|
|
}
|
|
.contents {
|
|
height: 200px;
|
|
}
|
|
@keyframes expand {
|
|
from { width: 100px; }
|
|
to { width: 200px; }
|
|
}
|
|
@scroll-timeline timeline {
|
|
source: selector(#scroller);
|
|
time-range: 1e10s;
|
|
start: 0px;
|
|
end: 100px;
|
|
}
|
|
#element {
|
|
width: 0px;
|
|
height: 20px;
|
|
animation: expand 1e10s linear;
|
|
animation-timeline: timeline;
|
|
}
|
|
/* Ensure stable expectations if feature is not supported */
|
|
@supports not (animation-timeline:foo) {
|
|
#element { animation-play-state: paused; }
|
|
}
|
|
</style>
|
|
<div id=scrollers></div>
|
|
<div id=element></div>
|
|
<script>
|
|
|
|
function createScroller() {
|
|
let scroller = document.createElement('div');
|
|
let contents = document.createElement('div');
|
|
scroller.classList.add('scroller');
|
|
contents.classList.add('contents');
|
|
scroller.append(contents);
|
|
return scroller;
|
|
}
|
|
|
|
function wrapInDiv(element) {
|
|
let div = document.createElement('div');
|
|
div.append(element);
|
|
return div;
|
|
}
|
|
|
|
function scrollerAt(n) {
|
|
return document.querySelectorAll('.scroller')[n];
|
|
}
|
|
|
|
// Resets #scrollers to a state where it has three .scroller children with
|
|
// scrollTop offsets 10, 20 and 30.
|
|
function cleanup() {
|
|
while (scrollers.firstChild)
|
|
scrollers.firstChild.remove();
|
|
|
|
for (let i = 0; i < 3; i++)
|
|
scrollers.append(createScroller());
|
|
|
|
scrollerAt(0).scrollTop = 10;
|
|
scrollerAt(1).scrollTop = 20;
|
|
scrollerAt(2).scrollTop = 30;
|
|
}
|
|
|
|
// Do an initial "cleanup" to set up the first test.
|
|
cleanup();
|
|
|
|
function invalidation_test(func, description) {
|
|
promise_test(async (t) => {
|
|
t.add_cleanup(cleanup);
|
|
await func();
|
|
}, description);
|
|
}
|
|
|
|
invalidation_test(() => {
|
|
assert_equals(getComputedStyle(element).width, '0px');
|
|
}, 'Nonexistent source');
|
|
|
|
invalidation_test(() => {
|
|
assert_equals(getComputedStyle(element).width, '0px');
|
|
scrollerAt(0).setAttribute('id', 'scroller');
|
|
assert_equals(getComputedStyle(element).width, '110px');
|
|
scrollerAt(1).setAttribute('id', 'scroller'); // No effect
|
|
assert_equals(getComputedStyle(element).width, '110px');
|
|
scrollerAt(2).setAttribute('id', 'scroller'); // No effect
|
|
assert_equals(getComputedStyle(element).width, '110px');
|
|
}, 'Setting id attribute');
|
|
|
|
invalidation_test(() => {
|
|
assert_equals(getComputedStyle(element).width, '0px');
|
|
scrollerAt(0).setAttribute('id', 'scroller');
|
|
assert_equals(getComputedStyle(element).width, '110px');
|
|
scrollerAt(0).removeAttribute('id');
|
|
assert_equals(getComputedStyle(element).width, '0px');
|
|
}, 'Removing id attribute');
|
|
|
|
invalidation_test(() => {
|
|
assert_equals(getComputedStyle(element).width, '0px');
|
|
scrollerAt(2).setAttribute('id', 'scroller');
|
|
assert_equals(getComputedStyle(element).width, '130px');
|
|
scrollerAt(1).setAttribute('id', 'scroller');
|
|
assert_equals(getComputedStyle(element).width, '120px');
|
|
scrollerAt(0).setAttribute('id', 'scroller');
|
|
assert_equals(getComputedStyle(element).width, '110px');
|
|
}, 'Setting id attribute earlier in the tree');
|
|
|
|
invalidation_test(async () => {
|
|
assert_equals(getComputedStyle(element).width, '0px');
|
|
|
|
// Appending a new element with id 'scroller' already set before
|
|
// insertion into the tree.
|
|
let scroller = createScroller();
|
|
scroller.setAttribute('id', 'scroller');
|
|
scrollers.append(scroller);
|
|
|
|
// Make sure |scroller| has a layout box.
|
|
//
|
|
// https://drafts.csswg.org/scroll-animations-1/#avoiding-cycles
|
|
//
|
|
// TODO: Depending on the outcome of Issue 5261, the call to offsetTop
|
|
// might be unnecessary.
|
|
// https://github.com/w3c/csswg-drafts/issues/5261
|
|
scroller.offsetTop;
|
|
await waitForNextFrame();
|
|
|
|
assert_equals(getComputedStyle(element).width, '100px');
|
|
}, 'Appending a new element');
|
|
|
|
invalidation_test(async () => {
|
|
assert_equals(getComputedStyle(element).width, '0px');
|
|
|
|
let scroller = createScroller();
|
|
scroller.setAttribute('id', 'scroller');
|
|
scrollers.append(wrapInDiv(wrapInDiv(scroller)));
|
|
await waitForNextFrame();
|
|
|
|
assert_equals(getComputedStyle(element).width, '100px');
|
|
}, 'Inserting a subtree with #scroller descendant');
|
|
|
|
invalidation_test(() => {
|
|
assert_equals(getComputedStyle(element).width, '0px');
|
|
|
|
scrollerAt(0).setAttribute('id', 'scroller');
|
|
scrollerAt(1).setAttribute('id', 'scroller');
|
|
scrollerAt(2).setAttribute('id', 'scroller');
|
|
assert_equals(getComputedStyle(element).width, '110px');
|
|
|
|
scrollerAt(0).remove();
|
|
assert_equals(getComputedStyle(element).width, '120px');
|
|
|
|
scrollerAt(0).remove();
|
|
assert_equals(getComputedStyle(element).width, '130px');
|
|
|
|
scrollerAt(0).remove();
|
|
assert_equals(getComputedStyle(element).width, '0px');
|
|
}, 'Removing source element');
|
|
|
|
invalidation_test(async () => {
|
|
assert_equals(getComputedStyle(element).width, '0px');
|
|
|
|
// Create a chain: #scrollers -> div -> div -> #scroller
|
|
let scroller = createScroller();
|
|
let div = wrapInDiv(wrapInDiv(scroller));
|
|
scrollers.append(div);
|
|
scroller.setAttribute('id', 'scroller');
|
|
scroller.scrollTop = 50;
|
|
await waitForNextFrame();
|
|
assert_equals(getComputedStyle(element).width, '150px');
|
|
|
|
div.remove();
|
|
assert_equals(getComputedStyle(element).width, '0px');
|
|
}, 'Removing ancestor of source element');
|
|
|
|
</script>
|