summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/web-animations/timing-model/animations/seamlessly-updating-the-playback-rate-of-an-animation.html
blob: dffbeabd599a2c3cab376191f9030b697deecc21 (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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<!doctype html>
<meta charset=utf-8>
<title>Seamlessly updating the playback rate of an animation</title>
<link rel="help"
  href="https://drafts.csswg.org/web-animations-1/#seamlessly-updating-the-playback-rate-of-an-animation">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<body>
<div id="log"></div>
<script>
'use strict';

promise_test(async t => {
  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
  await animation.ready;

  animation.currentTime = 50 * MS_PER_SEC;

  animation.updatePlaybackRate(0.5);
  await animation.ready;
  // Since the animation is in motion (and we want to test it while it is in
  // motion!) we can't assert that the current time == 50s but we can check
  // that the current time is NOT re-calculated by simply substituting in the
  // new playback rate (i.e. without adjusting the start time). If that were
  // the case the currentTime would jump to 25s. So we just test the currentTime
  // hasn't gone backwards.
  assert_greater_than_equal(animation.currentTime, 50 * MS_PER_SEC,
    'Reducing the playback rate should not change the current time ' +
    'of a playing animation');

  animation.updatePlaybackRate(2);
  await animation.ready;
  // Likewise, we test here that the current time does not jump to 100s as it
  // would if we naively applied a playbackRate of 2 without adjusting the
  // startTime.
  assert_less_than(animation.currentTime, 100 * MS_PER_SEC,
    'Increasing the playback rate should not change the current time ' +
    'of a playing animation');
}, 'Updating the playback rate maintains the current time');

promise_test(async t => {
  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
  await animation.ready;

  assert_false(animation.pending);
  animation.updatePlaybackRate(2);
  assert_true(animation.pending);
}, 'Updating the playback rate while running makes the animation pending');

promise_test(async t => {
  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
  animation.currentTime = 50 * MS_PER_SEC;
  assert_true(animation.pending);

  animation.updatePlaybackRate(0.5);

  // Check that the hold time is updated as expected
  assert_time_equals_literal(animation.currentTime, 50 * MS_PER_SEC);

  await animation.ready;

  // As above, check that the currentTime is not calculated by simply
  // substituting in the updated playbackRate without updating the startTime.
  assert_greater_than_equal(animation.currentTime, 50 * MS_PER_SEC,
    'Reducing the playback rate should not change the current time ' +
    'of a play-pending animation');
}, 'Updating the playback rate on a play-pending animation maintains'
   + ' the current time');

promise_test(async t => {
  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
  animation.currentTime = 50 * MS_PER_SEC;
  await animation.ready;

  animation.pause();
  animation.updatePlaybackRate(0.5);

  assert_greater_than_equal(animation.currentTime, 50 * MS_PER_SEC);
}, 'Updating the playback rate on a pause-pending animation maintains'
   + ' the current time');

promise_test(async t => {
  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);

  animation.updatePlaybackRate(2);
  animation.updatePlaybackRate(3);
  animation.updatePlaybackRate(4);

  assert_equals(animation.playbackRate, 1);
  await animation.ready;

  assert_equals(animation.playbackRate, 4);
}, 'If a pending playback rate is set multiple times, the latest wins');

test(t => {
  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
  animation.cancel();

  animation.updatePlaybackRate(2);
  assert_equals(animation.playbackRate, 2);
  assert_false(animation.pending);
}, 'In the idle state, the playback rate is applied immediately');

promise_test(async t => {
  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
  animation.pause();
  await animation.ready;

  animation.updatePlaybackRate(2);
  assert_equals(animation.playbackRate, 2);
  assert_false(animation.pending);
}, 'In the paused state, the playback rate is applied immediately');

promise_test(async t => {
  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
  animation.finish();
  assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC);
  assert_false(animation.pending);

  animation.updatePlaybackRate(2);
  assert_equals(animation.playbackRate, 2);
  assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC);
  assert_false(animation.pending);
}, 'Updating the playback rate on a finished animation maintains'
   + ' the current time');

promise_test(async t => {
  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
  animation.finish();
  assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC);
  assert_false(animation.pending);

  animation.updatePlaybackRate(0);
  assert_equals(animation.playbackRate, 0);
  assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC);
  assert_false(animation.pending);
}, 'Updating the playback rate to zero on a finished animation maintains'
   + ' the current time');

promise_test(async t => {
  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
  await animation.ready;

  // Get the animation in a state where it has an unresolved current time,
  // a resolved start time (so it is not 'idle') and but no pending play task.
  animation.timeline = null;
  animation.startTime = 0;
  assert_equals(animation.currentTime, null);
  assert_equals(animation.playState, 'running');

  // Make the effect end infinite.
  animation.effect.updateTiming({ endDelay: 1e38 });

  // Now we want to check that when we go to set a negative playback rate we
  // don't end up throwing an InvalidStateError (which would happen if we ended
  // up applying the auto-rewind behavior).
  animation.updatePlaybackRate(-1);

  // Furthermore, we should apply the playback rate immediately since the
  // current time is unresolved.
  assert_equals(animation.playbackRate, -1,
    'We apply the pending playback rate immediately if the current time is ' +
    'unresolved');
  assert_false(animation.pending);
}, 'Updating the negative playback rate with the unresolved current time and'
   + ' a positive infinite associated effect end should not throw an'
   + ' exception');

</script>
</body>