summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/scroll-animations/scroll-timelines/scroll-timeline-invalidation.html
blob: a26500989ed0c64ca715f94f120b79ee19f45bd7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
<!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;
    will-change: transform;
  }
  .contents {
    height: 1000px;
    width: 100%;
  }
</style>
<div id="log"></div>

<script>
'use strict';

promise_test(async t => {
  const animation = createScrollLinkedAnimation(t);
  const effect_duration = 350;
  animation.effect.updateTiming({ duration: effect_duration });
  const scroller = animation.timeline.source;
  let maxScroll = scroller.scrollHeight - scroller.clientHeight;
  scroller.scrollTop = 0.2 * maxScroll;
  const initial_progress = (scroller.scrollTop / maxScroll) * 100;

  animation.play();
  await animation.ready;

  // Animation current time is at 20% because scroller was scrolled to 20%
  assert_percents_equal(animation.currentTime, 20);
  assert_equals(scroller.scrollTop, 180);
  assert_equals(maxScroll, 900);

  // Shrink scroller content size (from 1000 to 500).
  // scroller.scrollTop maintains the same offset, which means shrinking the
  // content has the effect of skipping the animation forward.
  scroller.firstChild.style.height = "500px";
  maxScroll = scroller.scrollHeight - scroller.clientHeight;

  assert_equals(scroller.scrollTop, 180);
  assert_equals(maxScroll, 400);
  await waitForNextFrame();

  const expected_progress = (scroller.scrollTop / maxScroll) * 100;
  assert_true(expected_progress > initial_progress)
  // @ 45%
  assert_percents_equal(animation.currentTime, expected_progress);
  assert_percents_equal(animation.timeline.currentTime, expected_progress);
  assert_percents_equal(animation.effect.getComputedTiming().localTime, expected_progress);
}, '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.source;
  let maxScroll = scroller.scrollHeight - scroller.clientHeight;
  const scrollOffset = 0.2 * maxScroll
  scroller.scrollTop = scrollOffset;
  const initial_progress = (scroller.scrollTop / maxScroll) * 100;

  animation.play();
  await animation.ready;

  // Animation current time is at 20% because scroller was scrolled to 20%
  // assert_equals(animation.currentTime.value, 20);
  assert_percents_equal(animation.currentTime, 20);
  assert_equals(scroller.scrollTop, scrollOffset);
  assert_equals(maxScroll, 900);

  // Change scroller size.
  scroller.style.height = "500px";
  maxScroll = scroller.scrollHeight - scroller.clientHeight;

  assert_equals(scroller.scrollTop, scrollOffset);
  assert_equals(maxScroll, 500);
  await waitForNextFrame();

  const expected_progress = (scroller.scrollTop / maxScroll) * 100;
  assert_true(expected_progress > initial_progress);
  // @ 45%
  assert_percents_equal(animation.currentTime, expected_progress);
  assert_percents_equal(animation.timeline.currentTime, expected_progress);
  assert_percents_equal(animation.effect.getComputedTiming().localTime,
                        expected_progress);
}, 'Animation current time and effect local time are updated after scroller ' +
   'size changes.');

promise_test(async t => {
  await waitForNextFrame();

  const timeline = createScrollTimeline(t);
  const scroller = timeline.source;
  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
  // Instantiate scroll animation that resizes its scroll timeline scroller.
  const animation = new Animation(
    new KeyframeEffect(
      timeline.source.firstChild,
      [{ height: '1000px', easing: 'steps(2, jump-none)'},
       { height: '2000px' }],
    ), timeline);

  animation.play();
  await animation.ready;

  assert_percents_equal(timeline.currentTime, 0);
  assert_equals(scroller.scrollHeight, 1000);

  await runAndWaitForFrameUpdate(() => {
    scroller.scrollTop = 0.6 * maxScroll;
  });

  // Applying the animation effect alters the height of the scroll content and
  // makes the scroll timeline stale.
  // https://github.com/w3c/csswg-drafts/issues/8694

  // With a single layout, timeline current time would be at 60%, but the
  // timeline would be stale.
  const expected_progress = 60 * maxScroll / (maxScroll + 1000);
  assert_approx_equals(timeline.currentTime.value, expected_progress, 0.1);

}, 'If scroll animation resizes its scroll timeline scroller, ' +
   'layout reruns once per frame.');
</script>