blob: e4e536ad7f543abcc8cf866d162f382948b2d31e [file] [log] [blame]
<!DOCTYPE html>
<meta charset=utf-8>
<title>Verify applied effect output for all fill modes in all timeline states: before start, at start, in range, at end, after end while using various effect delay values</title>
<meta name="timeout" content="long">
<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: hidden;
height: 200px;
width: 200px;
}
.contents {
/* Make scroll range 1000 to simplify the math and avoid rounding errors */
height: 1200px;
width: 100%;
}
</style>
<div id="log"></div>
<script>
'use strict';
test(t => {
const effect = new KeyframeEffect(createDiv(t), { opacity: [0.3, 0.7] });
const animation = new Animation(effect, createScrollTimeline(t));
assert_equals(effect.getTiming().fill, "auto");
assert_equals(effect.getComputedTiming().fill, "none");
}, "Scroll based animation effect fill mode should return 'auto' for" +
" getTiming() and should return 'none' for getComputedTiming().")
// Test cases are included where effect delay causes the effect iteration to
// overlap with the timeline start time and also the timeline end time.
// Timeline
// BEFORE +-----------------+ AFTER
// time: 0 timeline.duration
// 1) +-----------------+
// 2) +------------+
// 3) +---------------------+
// 4) +---------------------+
// 5) +-------------+
// 6) +---------+
// 7) +-----------------+
// 8) +-----------------+
// 9) +-------------------------+
// Note: effects are scaled to fill the timeline so that the start of the
// effect is after the start offset of the timeline, and that the end of the
// effect is at the beginning of the end offset of the timeline.
/* All interesting transitions:
before timeline start
at timeline start
in timeline range
at timeline end
after timeline end
test_case data structure:
fill_mode: {
scroll_percentage: ["state description", expected applied effect value]
}
*/
const test_cases = {
"none": {
0.10: ["before timeline start", 1],
0.25: ["at timeline start", 0.3],
0.50: ["in timeline range", 0.5],
0.75: ["at timeline end", 1],
0.90: ["after timeline end", 1]
},
"backwards": {
0.10: ["before timeline start", 0.3],
0.25: ["at timeline start", 0.3],
0.50: ["in timeline range", 0.5],
0.75: ["at timeline end", 1],
0.90: ["after timeline end", 1]
},
/*
There is an asymmetry between these 2 mirrored scenarios:
1. fillmode: forwards + "at timeline end"
2. fillmode: backwards + "at timeline start"
In scenario 1, effect is not applied
In scenario 2, effect is applied
The difference is accounted for by the equality at the end versus strict
inequality at the start when computing the timeline phase.
This is currently in line with spec expectations but is an issue that
should be addressed.
*/
"forwards": {
0.10: ["before timeline start", 1],
0.25: ["at timeline start", 0.3],
0.50: ["in timeline range", 0.5],
0.75: ["at timeline end", 0.7],
0.90: ["after timeline end", 0.7]
},
"both": {
0.10: ["before timeline start", 0.3],
0.25: ["at timeline start", 0.3],
0.50: ["in timeline range", 0.5],
0.75: ["at timeline end", 0.7],
0.90: ["after timeline end", 0.7]
},
// "auto" behaves differently for different effect delay values. These
// cases are handled in scroll-animation-effect-phases.tentative.html
"auto": {
0.10: ["before timeline start", 1],
0.25: ["at timeline start", 0.3],
0.50: ["in timeline range", 0.5],
0.75: ["at timeline end", 1],
0.90: ["after timeline end", 1]
}
}
for (const fill_mode in test_cases) {
const scroll_percents = test_cases[fill_mode]
for (const scroll_percentage in scroll_percents) {
const expectation = scroll_percents[scroll_percentage];
const [test_name, expected_value] = expectation;
const description =
`Applied effect value ${test_name} with fill: ${fill_mode}`
promise_test(
create_scroll_timeline_fill_test(
fill_mode, scroll_percentage, expected_value),
description);
}
}
function create_scroll_timeline_fill_test(
fill_mode, scroll_percentage, expected){
return async t => {
const target = createDiv(t);
const timeline =
createScrollTimelineWithOffsets(t, CSS.percent(25), CSS.percent(75));
const effect = new KeyframeEffect(
target,
{
opacity: [0.3, 0.7]
},
{
fill: fill_mode
}
);
const animation = new Animation(effect, timeline);
const scroller = timeline.source;
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
animation.play();
await animation.ready;
scroller.scrollTop = scroll_percentage * maxScroll;
// Wait for new animation frame which allows the timeline to compute
// new current time.
await waitForNextFrame();
assert_equals(
parseFloat(window.getComputedStyle(target).opacity),
expected,
"animation effect applied property value");
}
}
</script>