blob: ca66aa654e66ed418f201ff65dd08b561f6a98dd [file] [log] [blame] [edit]
<!DOCTYPE html>
<meta charset="utf-8">
<title>ScrollTimeline current time algorithm - interaction with writing modes</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>
<body></body>
<script>
'use strict';
promise_test(async t => {
const scrollerOverrides = new Map([['direction', 'rtl']]);
const scroller = setupScrollTimelineTest(scrollerOverrides);
const verticalScrollRange = scroller.scrollHeight - scroller.clientHeight;
const horizontalScrollRange = scroller.scrollWidth - scroller.clientWidth;
const blockScrollTimeline = new ScrollTimeline(
{source: scroller, orientation: 'block'});
const inlineScrollTimeline = new ScrollTimeline(
{source: scroller, orientation: 'inline'});
const horizontalScrollTimeline = new ScrollTimeline(
{source: scroller, orientation: 'horizontal'});
const verticalScrollTimeline = new ScrollTimeline(
{source: scroller, orientation: 'vertical'});
// Unscrolled, all timelines should read a current time of 0 even though the
// X-axis will have started at the right hand side for rtl.
assert_percents_equal(blockScrollTimeline.currentTime, 0,
'Unscrolled block timeline');
assert_percents_equal(inlineScrollTimeline.currentTime, 0,
'Unscrolled inline timeline');
assert_percents_equal(horizontalScrollTimeline.currentTime, 0,
'Unscrolled horizontal timeline');
assert_percents_equal(verticalScrollTimeline.currentTime, 0,
'Unscrolled vertical timeline');
// The offset in the inline/horizontal direction should be inverted. The
// block/vertical direction should be unaffected.
scroller.scrollTop = 0.1 * verticalScrollRange;
scroller.scrollLeft = -0.8 * horizontalScrollRange;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_percents_equal(blockScrollTimeline.currentTime, 10,
'Scrolled block timeline');
assert_percents_equal(inlineScrollTimeline.currentTime, 80,
'Scrolled inline timeline');
assert_percents_equal(horizontalScrollTimeline.currentTime, 80,
'Scrolled horizontal timeline');
assert_percents_equal(verticalScrollTimeline.currentTime, 10,
'Scrolled vertical timeline');
}, 'currentTime handles direction: rtl correctly');
promise_test(async t => {
const scrollerOverrides = new Map([['writing-mode', 'vertical-rl']]);
const scroller = setupScrollTimelineTest(scrollerOverrides);
const verticalScrollRange = scroller.scrollHeight - scroller.clientHeight;
const horizontalScrollRange = scroller.scrollWidth - scroller.clientWidth;
const blockScrollTimeline = new ScrollTimeline(
{source: scroller, orientation: 'block'});
const inlineScrollTimeline = new ScrollTimeline(
{source: scroller, orientation: 'inline'});
const horizontalScrollTimeline = new ScrollTimeline(
{source: scroller, orientation: 'horizontal'});
const verticalScrollTimeline = new ScrollTimeline(
{source: scroller, orientation: 'vertical'});
// Unscrolled, all timelines should read a current time of 0 even though the
// X-axis will have started at the right hand side for vertical-rl.
assert_percents_equal(blockScrollTimeline.currentTime, 0,
'Unscrolled block timeline');
assert_percents_equal(inlineScrollTimeline.currentTime, 0,
'Unscrolled inline timeline');
assert_percents_equal(horizontalScrollTimeline.currentTime, 0,
'Unscrolled horizontal timeline');
assert_percents_equal(verticalScrollTimeline.currentTime, 0,
'Unscrolled vertical timeline');
// For vertical-rl, the X-axis starts on the right-hand-side and is the block
// axis. The Y-axis is normal but is the inline axis. For the
// horizontal/vertical cases, horizontal starts on the right-hand-side and
// vertical is normal.
scroller.scrollTop = 0.1 * verticalScrollRange;
scroller.scrollLeft = -0.8 * horizontalScrollRange;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_percents_equal(blockScrollTimeline.currentTime, 80,
'Scrolled block timeline');
assert_percents_equal(inlineScrollTimeline.currentTime, 10,
'Scrolled inline timeline');
assert_percents_equal(horizontalScrollTimeline.currentTime, 80,
'Scrolled horizontal timeline');
assert_percents_equal(verticalScrollTimeline.currentTime, 10,
'Scrolled vertical timeline');
}, 'currentTime handles writing-mode: vertical-rl correctly');
promise_test(async t => {
const scrollerOverrides = new Map([['writing-mode', 'vertical-lr']]);
const scroller = setupScrollTimelineTest(scrollerOverrides);
const verticalScrollRange = scroller.scrollHeight - scroller.clientHeight;
const horizontalScrollRange = scroller.scrollWidth - scroller.clientWidth;
const blockScrollTimeline = new ScrollTimeline(
{source: scroller, orientation: 'block'});
const inlineScrollTimeline = new ScrollTimeline(
{source: scroller, orientation: 'inline'});
const horizontalScrollTimeline = new ScrollTimeline(
{source: scroller, orientation: 'horizontal'});
const verticalScrollTimeline = new ScrollTimeline(
{source: scroller, orientation: 'vertical'});
// Unscrolled, all timelines should read a current time of 0.
assert_percents_equal(blockScrollTimeline.currentTime, 0,
'Unscrolled block timeline');
assert_percents_equal(inlineScrollTimeline.currentTime, 0,
'Unscrolled inline timeline');
assert_percents_equal(horizontalScrollTimeline.currentTime, 0,
'Unscrolled horizontal timeline');
assert_percents_equal(verticalScrollTimeline.currentTime, 0,
'Unscrolled vertical timeline');
// For vertical-lr, both axes start at their 'normal' positions but the X-axis
// is the block direction and the Y-axis is the inline direction. This does
// not affect horizontal/vertical.
scroller.scrollTop = 0.1 * verticalScrollRange;
scroller.scrollLeft = 0.2 * horizontalScrollRange;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_percents_equal(blockScrollTimeline.currentTime, 20,
'Scrolled block timeline');
assert_percents_equal(inlineScrollTimeline.currentTime, 10,
'Scrolled inline timeline');
assert_percents_equal(horizontalScrollTimeline.currentTime, 20,
'Scrolled horizontal timeline');
assert_percents_equal(verticalScrollTimeline.currentTime, 10,
'Scrolled vertical timeline');
}, 'currentTime handles writing-mode: vertical-lr correctly');
promise_test(async t => {
const scrollerOverrides = new Map([['direction', 'rtl']]);
const scroller = setupScrollTimelineTest(scrollerOverrides);
const horizontalScrollRange = scroller.scrollWidth - scroller.clientWidth;
const lengthScrollTimeline = new ScrollTimeline({
source: scroller,
orientation: 'horizontal',
scrollOffsets: [CSS.px(20), 'auto']
});
const percentageScrollTimeline = new ScrollTimeline({
source: scroller,
orientation: 'horizontal',
scrollOffsets: [CSS.percent(20), 'auto']
});
const calcScrollTimeline = new ScrollTimeline({
source: scroller,
orientation: 'horizontal',
scrollOffsets: [CSS.percent(20).sub(CSS.px(5)), 'auto']
});
// Unscrolled, all timelines should read a current time of 0, since
// the current offset (0) will be less than the startScrollOffset.
assert_percents_equal(lengthScrollTimeline.currentTime, 0,
'Unscrolled length-based timeline');
assert_percents_equal(percentageScrollTimeline.currentTime, 0,
'Unscrolled percentage-based timeline');
assert_percents_equal(calcScrollTimeline.currentTime, 0,
'Unscrolled calc-based timeline');
// With direction rtl offsets are inverted, such that scrollLeft == 0
// is the 'zero' point for currentTime. However the
// startScrollOffset is an absolute distance along the offset, so doesn't
// need adjusting.
// 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_percents_equal(lengthScrollTimeline.currentTime, 0,
'Length-based timeline before the startScrollOffset point');
scroller.scrollLeft = -20;
await waitForNextFrame();
assert_percents_equal(lengthScrollTimeline.currentTime, 0,
'Length-based timeline at the startScrollOffset point');
scroller.scrollLeft = -50;
await waitForNextFrame();
assert_percents_equal(
lengthScrollTimeline.currentTime,
calculateCurrentTime(50, 20, horizontalScrollRange),
'Length-based timeline after the startScrollOffset point');
// Check the percentage-based ScrollTimeline.
scroller.scrollLeft = -(0.19 * horizontalScrollRange);
await waitForNextFrame();
assert_percents_equal(percentageScrollTimeline.currentTime, 0,
'Percentage-based timeline before the startScrollOffset point');
scroller.scrollLeft = -(0.20 * horizontalScrollRange);
await waitForNextFrame();
assert_percents_equal(percentageScrollTimeline.currentTime, 0,
'Percentage-based timeline at the startScrollOffset point');
scroller.scrollLeft = -(0.4 * horizontalScrollRange);
await waitForNextFrame();
assert_percents_equal(
percentageScrollTimeline.currentTime,
calculateCurrentTime(
0.4 * horizontalScrollRange, 0.2 * horizontalScrollRange,
horizontalScrollRange),
'Percentage-based timeline after the startScrollOffset point');
// Check the calc-based ScrollTimeline.
scroller.scrollLeft = -(0.2 * horizontalScrollRange - 10);
await waitForNextFrame();
assert_percents_equal(calcScrollTimeline.currentTime, 0,
'Calc-based timeline before the startScrollOffset point');
scroller.scrollLeft = -(0.2 * horizontalScrollRange - 5);
await waitForNextFrame();
assert_percents_equal(calcScrollTimeline.currentTime, 0,
'Calc-based timeline at the startScrollOffset point');
scroller.scrollLeft = -(0.2 * horizontalScrollRange);
await waitForNextFrame();
assert_percents_equal(
calcScrollTimeline.currentTime,
calculateCurrentTime(
0.2 * horizontalScrollRange, 0.2 * horizontalScrollRange - 5,
horizontalScrollRange),
'Calc-based timeline after the startScrollOffset point');
}, 'currentTime handles startScrollOffset with direction: rtl correctly');
promise_test(async t => {
const scrollerOverrides = new Map([['direction', 'rtl']]);
const scroller = setupScrollTimelineTest(scrollerOverrides);
const horizontalScrollRange = scroller.scrollWidth - scroller.clientWidth;
const lengthScrollTimeline = new ScrollTimeline({
source: scroller,
orientation: 'horizontal',
scrollOffsets: [CSS.px(horizontalScrollRange - 20)]
});
const percentageScrollTimeline = new ScrollTimeline({
source: scroller,
orientation: 'horizontal',
scrollOffsets: [CSS.percent(80)]
});
const calcScrollTimeline = new ScrollTimeline({
source: scroller,
orientation: 'horizontal',
scrollOffsets: [CSS.percent(80).add(CSS.px(5))]
});
// With direction rtl offsets are inverted, such that scrollLeft == 0
// is the 'zero' point for currentTime. However the
// endScrollOffset is an absolute distance along the offset, so doesn't need
// adjusting.
// Check the length-based ScrollTimeline.
scroller.scrollLeft = -horizontalScrollRange;
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_percents_equal(lengthScrollTimeline.currentTime, 100,
'Length-based timeline after the endScrollOffset point');
scroller.scrollLeft = 20 - horizontalScrollRange;
await waitForNextFrame();
assert_percents_equal(lengthScrollTimeline.currentTime, 100,
'Length-based timeline at the endScrollOffset point');
scroller.scrollLeft = 50 - horizontalScrollRange;
await waitForNextFrame();
assert_percents_equal(
lengthScrollTimeline.currentTime,
calculateCurrentTime(
horizontalScrollRange - 50, 0, horizontalScrollRange - 20),
'Length-based timeline before the endScrollOffset point');
// Check the percentage-based ScrollTimeline.
scroller.scrollLeft = 0.19 * horizontalScrollRange - horizontalScrollRange;
await waitForNextFrame();
assert_percents_equal(percentageScrollTimeline.currentTime, 100,
'Percentage-based timeline after the endScrollOffset point');
scroller.scrollLeft = 0.20 * horizontalScrollRange - horizontalScrollRange;
await waitForNextFrame();
assert_percents_equal(percentageScrollTimeline.currentTime, 100,
'Percentage-based timeline at the endScrollOffset point');
scroller.scrollLeft = 0.4 * horizontalScrollRange - horizontalScrollRange;
await waitForNextFrame();
assert_percents_equal(
percentageScrollTimeline.currentTime,
calculateCurrentTime(
0.6 * horizontalScrollRange, 0, 0.8 * horizontalScrollRange),
'Percentage-based timeline before the endScrollOffset point');
// Check the calc-based ScrollTimeline. 80% + 5px
scroller.scrollLeft = -0.8 * horizontalScrollRange - 10;
await waitForNextFrame();
assert_percents_equal(calcScrollTimeline.currentTime, 100,
'Calc-based timeline after the endScrollOffset point');
scroller.scrollLeft = -0.8 * horizontalScrollRange - 5;
await waitForNextFrame();
assert_percents_equal(calcScrollTimeline.currentTime, 100,
'Calc-based timeline at the endScrollOffset point');
scroller.scrollLeft = -0.8 * horizontalScrollRange;
await waitForNextFrame();
assert_percents_equal(
calcScrollTimeline.currentTime,
calculateCurrentTime(
0.8 * horizontalScrollRange, 0, 0.8 * horizontalScrollRange + 5),
'Calc-based timeline before the endScrollOffset point');
}, 'currentTime handles endScrollOffset with direction: rtl correctly');
promise_test(async t => {
const scrollerOverrides = new Map([['direction', 'rtl']]);
const scroller = setupScrollTimelineTest(scrollerOverrides);
const horizontalScrollRange = scroller.scrollWidth - scroller.clientWidth;
// When the endScrollOffset is equal to the maximum scroll offset (and there
// are no fill modes), the endScrollOffset is treated as inclusive.
const inclusiveAutoScrollTimeline = new ScrollTimeline({
source: scroller,
orientation: 'inline',
});
const inclusiveLengthScrollTimeline = new ScrollTimeline({
source: scroller,
orientation: 'inline',
scrollOffsets: [CSS.px(horizontalScrollRange)]
});
const inclusivePercentageScrollTimeline = new ScrollTimeline({
source: scroller,
orientation: 'inline',
scrollOffsets: [CSS.percent(100)]
});
const inclusiveCalcScrollTimeline = new ScrollTimeline({
source: scroller,
orientation: 'inline',
scrollOffsets: [CSS.percent(80).sub(CSS.px(0.2 * horizontalScrollRange))]
});
// With direction rtl offsets are inverted, such that scrollLeft ==
// horizontalScrollRange is the 'zero' point for currentTime. However the
// endScrollOffset is an absolute distance along the offset, so doesn't need
// adjusting.
scroller.scrollLeft = 0;
let expectedCurrentTime = calculateCurrentTime(
scroller.scrollLeft, 0, horizontalScrollRange);
// Wait for new animation frame which allows the timeline to compute new
// current time.
await waitForNextFrame();
assert_percents_equal(
inclusiveAutoScrollTimeline.currentTime, expectedCurrentTime,
'Inclusive auto timeline at the endScrollOffset point');
assert_percents_equal(
inclusiveLengthScrollTimeline.currentTime, expectedCurrentTime,
'Inclusive length-based timeline at the endScrollOffset point');
assert_percents_equal(
inclusivePercentageScrollTimeline.currentTime, expectedCurrentTime,
'Inclusive percentage-based timeline at the endScrollOffset point');
assert_percents_equal(
inclusiveCalcScrollTimeline.currentTime, expectedCurrentTime,
'Inclusive calc-based timeline at the endScrollOffset point');
}, 'currentTime handles endScrollOffset (inclusive case) with direction: rtl' +
' correctly');
</script>