setting-playback-rate.html (11399B)
1 <!DOCTYPE html> 2 <meta charset=utf-8> 3 <title>Setting the playback rate of an animation that is using a ScrollTimeline</title> 4 <link rel="help" href="https://drafts.csswg.org/web-animations/#setting-the-playback-rate-of-an-animation"> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="/web-animations/testcommon.js"></script> 8 <script src="testcommon.js"></script> 9 <style> 10 .scroller { 11 overflow: auto; 12 height: 100px; 13 width: 100px; 14 will-change: transform; 15 } 16 .contents { 17 height: 1000px; 18 width: 100%; 19 } 20 </style> 21 <body> 22 <script> 23 'use strict'; 24 25 promise_test(async t => { 26 const animation = createScrollLinkedAnimation(t); 27 const scroller = animation.timeline.source; 28 // this forces a layout which results in an active timeline 29 scroller.scrollTop = 0; 30 // Wait for new animation frame which allows the timeline to compute new 31 // current time. 32 await waitForNextFrame(); 33 34 animation.playbackRate = 0.5; 35 animation.play(); 36 await animation.ready; 37 38 assert_percents_equal(animation.currentTime, 0, 39 'Zero current time is not affected by playbackRate change.'); 40 }, 'Zero current time is not affected by playbackRate set while the ' + 41 'animation is in idle state.'); 42 43 promise_test(async t => { 44 const animation = createScrollLinkedAnimation(t); 45 const scroller = animation.timeline.source; 46 // this forces a layout which results in an active timeline 47 scroller.scrollTop = 0; 48 // Wait for new animation frame which allows the timeline to compute new 49 // current time. 50 await waitForNextFrame(); 51 52 animation.play(); 53 await animation.ready; 54 animation.playbackRate = 0.5; 55 56 assert_percents_equal(animation.currentTime, 0, 57 'Zero current time is not affected by playbackRate change.'); 58 }, 'Zero current time is not affected by playbackRate set while the ' + 59 'animation is in play-pending state.'); 60 61 promise_test(async t => { 62 const animation = createScrollLinkedAnimation(t); 63 const scroller = animation.timeline.source; 64 const maxScroll = scroller.scrollHeight - scroller.clientHeight; 65 scroller.scrollTop = 0.2 * maxScroll; 66 // Wait for new animation frame which allows the timeline to compute new 67 // current time. 68 await waitForNextFrame(); 69 70 animation.playbackRate = 0.5; 71 animation.play(); 72 await animation.ready; 73 assert_percents_equal(animation.currentTime, 10, 74 'Initial current time is scaled by playbackRate change.'); 75 }, 'Initial current time is scaled by playbackRate set while ' + 76 'scroll-linked animation is in running state.'); 77 78 promise_test(async t => { 79 const animation = createScrollLinkedAnimation(t); 80 const scroller = animation.timeline.source; 81 const maxScroll = scroller.scrollHeight - scroller.clientHeight; 82 const playbackRate = 2; 83 84 scroller.scrollTop = 0.2 * maxScroll; 85 // Wait for new animation frame which allows the timeline to compute new 86 // current time. 87 await waitForNextFrame(); 88 89 animation.play(); 90 await animation.ready; 91 // Set playback rate while the animation is playing. 92 animation.playbackRate = playbackRate; 93 assert_percents_equal(animation.currentTime, 40, 94 'The current time is scaled by the playback rate.'); 95 }, 'The current time is scaled by playbackRate set while the ' + 96 'scroll-linked animation is in play state.'); 97 98 promise_test(async t => { 99 const animation = createScrollLinkedAnimation(t); 100 const scroller = animation.timeline.source; 101 const maxScroll = scroller.scrollHeight - scroller.clientHeight; 102 103 // Set playback rate while the animation is in 'idle' state. 104 animation.playbackRate = 2; 105 animation.play(); 106 await animation.ready; 107 108 // Wait for new animation frame which allows the timeline to compute new 109 // current time. 110 await runAndWaitForFrameUpdate(() => { 111 scroller.scrollTop = 0.2 * maxScroll; 112 }); 113 114 assert_percents_equal(animation.currentTime, 40, 115 'The current time should increase two times faster ' + 116 'than timeline time.'); 117 }, 'The playback rate set before scroll-linked animation started playing ' + 118 'affects the rate of progress of the current time'); 119 120 promise_test(async t => { 121 const animation = createScrollLinkedAnimation(t); 122 const scroller = animation.timeline.source; 123 const maxScroll = scroller.scrollHeight - scroller.clientHeight; 124 animation.play(); 125 126 await animation.ready; 127 128 animation.playbackRate = 2; 129 scroller.scrollTop = 0.25 * maxScroll; 130 // Wait for new animation frame which allows the timeline to compute new 131 // current time. 132 await waitForNextFrame(); 133 134 assert_percents_equal( 135 animation.currentTime, 136 animation.timeline.currentTime.value * animation.playbackRate, 137 'The current time should increase two times faster than timeline time'); 138 }, 'The playback rate affects the rate of progress of the current time' + 139 ' when scrolling'); 140 141 promise_test(async t => { 142 const animation = createScrollLinkedAnimation(t); 143 animation.play(); 144 // Setting the current time while play-pending sets the hold time and not 145 // the start time. currentTime is unaffected by playback rate until no 146 // longer pending. 147 animation.currentTime = CSSNumericValue.parse("25%"); 148 animation.playbackRate = 2; 149 150 assert_equals(animation.playState, "running"); 151 assert_true(animation.pending); 152 assert_percents_equal(animation.currentTime, 25); 153 await animation.ready; 154 assert_percents_equal(animation.currentTime, 25); 155 }, 'Setting the playback rate while play-pending does not scale current ' + 156 'time.'); 157 158 promise_test(async t => { 159 const animation = createScrollLinkedAnimation(t); 160 const scroller = animation.timeline.source; 161 const maxScroll = scroller.scrollHeight - scroller.clientHeight; 162 scroller.scrollTop = 0.25 * maxScroll; 163 animation.play(); 164 await animation.ready; 165 animation.playbackRate = 2; 166 167 assert_percents_equal(animation.currentTime, 50); 168 }, 'Setting the playback rate while playing scales current time.'); 169 170 promise_test(async t => { 171 const animation = createScrollLinkedAnimation(t); 172 173 animation.play(); 174 animation.currentTime = CSSNumericValue.parse("25%"); 175 await animation.ready; 176 animation.playbackRate = 2; 177 178 assert_percents_equal(animation.currentTime, 50); 179 }, 'Setting the playback rate while playing scales the set current time.'); 180 181 promise_test(async t => { 182 const animation = createScrollLinkedAnimation(t); 183 const scroller = animation.timeline.source; 184 const maxScroll = scroller.scrollHeight - scroller.clientHeight; 185 animation.playbackRate = -1; 186 scroller.scrollTop = 0.3 * maxScroll; 187 // Wait for new animation frame which allows the timeline to compute new 188 // current time. 189 await waitForNextFrame(); 190 animation.play(); 191 192 await animation.ready; 193 const expectedCurrentTime = 100 - animation.timeline.currentTime.value; 194 assert_percents_equal(animation.currentTime, expectedCurrentTime); 195 }, 'Negative initial playback rate should correctly modify initial current' + 196 ' time.'); 197 198 promise_test(async t => { 199 const animation = createScrollLinkedAnimation(t); 200 const scroller = animation.timeline.source; 201 const maxScroll = scroller.scrollHeight - scroller.clientHeight; 202 scroller.scrollTop = 0.5 * maxScroll; 203 animation.play(); 204 205 await animation.ready; 206 const startingTimelineTime = animation.timeline.currentTime; 207 const startingCurrentTime = animation.currentTime; 208 assert_percents_equal(startingCurrentTime, 50); 209 assert_percents_equal(startingTimelineTime, 50); 210 211 animation.playbackRate = -1; 212 213 await runAndWaitForFrameUpdate(() => { 214 scroller.scrollTop = 0.8 * maxScroll; 215 }); 216 // -300 = 500 - 800 217 218 // let timelineDiff = 219 // startingTimelineTime.value - animation.timeline.currentTime.value; 220 // // 200 = 500 + (-300) 221 // let expected = startingCurrentTime.value + timelineDiff; 222 assert_percents_equal(animation.timeline.currentTime, 80); 223 assert_percents_equal(animation.currentTime, 20); 224 225 await runAndWaitForFrameUpdate(() => { 226 scroller.scrollTop = 0.2 * maxScroll; 227 }); 228 // // 300 = 500 - 200 229 // timelineDiff = 230 // startingTimelineTime.value - animation.timeline.currentTime.value; 231 // // 800 = 500 + 300 232 // expected = startingCurrentTime.value + timelineDiff; 233 assert_percents_equal(animation.timeline.currentTime, 20); 234 assert_percents_equal(animation.currentTime, 80); 235 }, 'Reversing the playback rate while playing correctly impacts current' + 236 ' time during future scrolls'); 237 238 promise_test(async t => { 239 const animation = createScrollLinkedAnimation(t); 240 const scroller = animation.timeline.source; 241 const maxScroll = scroller.scrollHeight - scroller.clientHeight; 242 animation.playbackRate = 0; 243 scroller.scrollTop = 0.3 * maxScroll; 244 // Wait for new animation frame which allows the timeline to compute new 245 // current time. 246 await waitForNextFrame(); 247 animation.play(); 248 249 await animation.ready; 250 assert_percents_equal(animation.currentTime, 0); 251 }, 'Zero initial playback rate should correctly modify initial current' + 252 ' time.'); 253 254 promise_test(async t => { 255 const animation = createScrollLinkedAnimation(t); 256 const scroller = animation.timeline.source; 257 const maxScroll = scroller.scrollHeight - scroller.clientHeight; 258 scroller.scrollTop = 0.2 * maxScroll; 259 // Wait for new animation frame which allows the timeline to compute new 260 // current time. 261 await waitForNextFrame(); 262 animation.play(); 263 264 await animation.ready; 265 assert_percents_equal(animation.currentTime, 20); 266 await runAndWaitForFrameUpdate(() => { 267 animation.playbackRate = 0; 268 scroller.scrollTop = 0.5 * maxScroll; 269 }); 270 271 // Ensure that current time does not change. 272 assert_percents_equal(animation.timeline.currentTime, 50); 273 assert_percents_equal(animation.currentTime, 0); 274 }, 'Setting a zero playback rate while running preserves the start time'); 275 276 277 promise_test(async t => { 278 const animation = createScrollLinkedAnimation(t); 279 const scroller = animation.timeline.source; 280 const maxScroll = scroller.scrollHeight - scroller.clientHeight; 281 scroller.scrollTop = 0.2 * maxScroll; 282 // Wait for new animation frame which allows the timeline to compute new 283 // current time. 284 await waitForNextFrame(); 285 animation.play(); 286 287 await animation.ready; 288 assert_percents_equal(animation.timeline.currentTime, 20); 289 assert_percents_equal(animation.currentTime, 20); 290 animation.startTime = animation.currentTime; 291 // timeline current time [0%, 100%] --> animation current time [-20%, 80%]. 292 assert_percents_equal(animation.currentTime, 0); 293 294 animation.playbackRate = -1; 295 // timeline current time [0%, 100%] --> animation current time [80%, -20%]. 296 // timeline @ 20% --> animation current time @ (20% - 80%) * (-1) = 60%. 297 assert_percents_equal(animation.timeline.currentTime, 20); 298 assert_percents_equal(animation.currentTime, 60); 299 }, 'Reversing an animation with non-boundary aligned start time ' + 300 'symmetrically adjusts the start time'); 301 302 </script> 303 </body>