play-animation.html (9381B)
1 <!DOCTYPE html> 2 <meta charset=utf-8> 3 <title>Playing an animation</title> 4 <link rel="help" 5 href="https://drafts.csswg.org/web-animations/#playing-an-animation-section"> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 <script src="/web-animations/testcommon.js"></script> 9 <script src="testcommon.js"></script> 10 <style> 11 .scroller { 12 overflow: auto; 13 height: 100px; 14 width: 100px; 15 will-change: transform; 16 } 17 18 .contents { 19 height: 1000px; 20 width: 100%; 21 } 22 </style> 23 <body> 24 <script> 25 'use strict'; 26 27 promise_test(async t => { 28 const animation = createScrollLinkedAnimation(t); 29 animation.play(); 30 assert_equals(animation.startTime, null); 31 await animation.ready; 32 assert_percents_equal(animation.startTime, 0); 33 34 animation.cancel(); 35 const scroller = animation.timeline.source; 36 const maxScroll = scroller.scrollHeight - scroller.clientHeight; 37 scroller.scrollTop = maxScroll / 2; 38 animation.play(); 39 await animation.ready; 40 assert_percents_equal(animation.currentTime, 50); 41 42 }, 'Playing an animations aligns the start time with the start of the active ' + 43 'range'); 44 45 promise_test(async t => { 46 const animation = createScrollLinkedAnimation(t); 47 animation.playbackRate = -1; 48 animation.play(); 49 await animation.ready; 50 assert_percents_equal(animation.startTime, 100); 51 }, 'Playing an animations with a negative playback rate aligns the start ' + 52 'time with the end of the active range'); 53 54 promise_test(async t => { 55 const animation = createScrollLinkedAnimation(t); 56 animation.play(); 57 animation.startTime = CSSNumericValue.parse("10%"); 58 await animation.ready; 59 assert_percents_equal(animation.startTime, 10); 60 }, 'Start time set while play pending is preserved.'); 61 62 promise_test(async t => { 63 const animation = createScrollLinkedAnimation(t); 64 animation.play(); 65 animation.currentTime = CSSNumericValue.parse("10%"); 66 await animation.ready; 67 assert_percents_equal(animation.currentTime, 10); 68 }, 'Current time set while play pending is preserved.'); 69 70 promise_test(async t => { 71 const animation = createScrollLinkedAnimation(t); 72 animation.play(); 73 await animation.ready; 74 animation.currentTime = CSSNumericValue.parse("10%"); 75 assert_percents_equal(animation.currentTime, 10); 76 animation.play(); 77 await animation.ready; 78 assert_percents_equal(animation.currentTime, 0); 79 }, 'Playing a running animation resets a sticky start time'); 80 81 promise_test(async t => { 82 const animation = createScrollLinkedAnimation(t); 83 animation.play(); 84 animation.finish(); 85 assert_percents_equal(animation.currentTime, 100); 86 animation.play(); 87 await animation.ready; 88 assert_percents_equal(animation.currentTime, 0); 89 }, 'Playing a finished animation restarts the animation aligned at the start'); 90 91 promise_test(async t => { 92 const animation = createScrollLinkedAnimation(t); 93 animation.play(); 94 animation.playbackRate = -1; 95 animation.currentTime = CSSNumericValue.parse("0%"); 96 assert_percents_equal(animation.currentTime, 0); 97 animation.play(); 98 await animation.ready; 99 100 assert_percents_equal(animation.currentTime, 100); 101 }, 'Playing a finished and reversed animation restarts the animation aligned ' + 102 'at the end'); 103 104 promise_test(async t => { 105 const animation = createScrollLinkedAnimation(t); 106 animation.play(); 107 animation.finish(); 108 await animation.finished; 109 110 // Start time is now sticky since modified by an explicit API call. 111 // All current time calculations will be based on the new start time 112 // while running. 113 assert_percents_equal(animation.startTime, -100, 114 'start time when finished'); 115 assert_percents_equal(animation.currentTime, 100, 116 'current time when finished'); 117 118 const scroller = animation.timeline.source; 119 const maxScroll = scroller.scrollHeight - scroller.clientHeight; 120 scroller.scrollTop = maxScroll / 2; 121 await waitForNextFrame(); 122 assert_percents_equal(animation.startTime, -100, 123 'start time after scrolling a finished animation'); 124 // Clamped at effect end time. 125 assert_percents_equal(animation.currentTime, 100, 126 'current time after scrolling a finished animation'); 127 128 // Initiate a pause then abort it 129 animation.pause(); 130 animation.play(); 131 132 // Wait to return to running state 133 await animation.ready; 134 135 assert_percents_equal(animation.startTime, 0, 136 'After aborting a pause when finished, the start time should no ' + 137 'longer be sticky'); 138 assert_percents_equal(animation.currentTime, 50, 139 'After aborting a pause when finished, the current time should realign ' + 140 'with the scroll position'); 141 }, 'Playing a pause-pending but previously finished animation realigns' 142 + ' with the scroll position'); 143 144 promise_test(async t => { 145 const animation = createScrollLinkedAnimation(t); 146 animation.play(); 147 animation.finish(); 148 await animation.ready; 149 150 animation.play(); 151 assert_equals(animation.startTime, null); 152 await animation.ready; 153 assert_percents_equal(animation.startTime, 0, 'start time is zero'); 154 }, 'Playing a finished animation clears the start time'); 155 156 promise_test(async t => { 157 const animation = createScrollLinkedAnimation(t); 158 animation.play(); 159 animation.cancel(); 160 const promise = animation.ready; 161 animation.play(); 162 assert_not_equals(animation.ready, promise); 163 }, 'The ready promise should be replaced if the animation is not already' 164 + ' pending'); 165 166 promise_test(async t => { 167 const animation = createScrollLinkedAnimation(t); 168 animation.play(); 169 const promise = animation.ready; 170 const promiseResult = await promise; 171 assert_equals(promiseResult, animation); 172 assert_equals(animation.ready, promise); 173 }, 'A pending ready promise should be resolved and not replaced when the' 174 + ' animation enters the running state'); 175 176 promise_test(async t => { 177 const animation = createScrollLinkedAnimation(t); 178 animation.play(); 179 animation.currentTime = CSSNumericValue.parse("50%"); 180 await animation.ready; 181 182 assert_percents_equal(animation.currentTime, 50); 183 184 animation.pause(); 185 await animation.ready; 186 187 assert_percents_equal(animation.currentTime, 50); 188 189 animation.play(); 190 await animation.ready; 191 192 assert_percents_equal(animation.startTime, 0); 193 }, 'Resuming an animation from paused realigns with scroll position.'); 194 195 promise_test(async t => { 196 const animation = createScrollLinkedAnimation(t); 197 animation.play(); 198 await animation.ready; 199 200 // Go to pause-pending state 201 animation.pause(); 202 assert_true(animation.pending, 'Animation is pending'); 203 const pauseReadyPromise = animation.ready; 204 205 // Now play again immediately (abort the pause) 206 animation.play(); 207 assert_true(animation.pending, 'Animation is still pending'); 208 assert_equals(animation.ready, pauseReadyPromise, 209 'The pause Promise is re-used when playing while waiting to pause'); 210 211 // Sanity check: Animation proceeds to running state 212 await animation.ready; 213 assert_true(!animation.pending && animation.playState === 'running', 214 'Animation is running after aborting a pause'); 215 }, 'If a pause operation is interrupted, the ready promise is reused'); 216 217 promise_test(async t => { 218 // Seek animation beyond target end 219 const animation = createScrollLinkedAnimation(t); 220 animation.play(); 221 animation.currentTime = CSSNumericValue.parse("-100%"); 222 await animation.ready; 223 assert_percents_equal(animation.currentTime, -100); 224 225 // Set pending playback rate to the opposite direction 226 animation.updatePlaybackRate(-1); 227 assert_true(animation.pending); 228 // Note: Updating the playback rate calls play without rewind. For a 229 // scroll-timeline, this will immediately apply the playback rate. 230 // TODO: Determine if we should defer applying the new playback rate. 231 assert_equals(animation.playbackRate, 1); 232 233 // When we play, we should align to the target end, NOT to zero (which 234 // is where we would seek to if we used the playbackRate of 1. 235 animation.play(); 236 await animation.ready; 237 assert_percents_equal(animation.startTime, 100); 238 assert_percents_equal(animation.currentTime, 100); 239 }, 'A pending playback rate is used when determining timeline range alignment'); 240 241 promise_test(async t => { 242 const animation = createScrollLinkedAnimation(t); 243 animation.play(); 244 animation.cancel(); 245 assert_equals(animation.startTime, null, 246 'Start time should be unresolved'); 247 248 animation.play(); 249 assert_true(animation.pending, 'Animation should be play-pending'); 250 251 await animation.ready; 252 253 assert_false(animation.pending, 'animation should no longer be pending'); 254 assert_percents_equal(animation.startTime, 0, 255 'The start time of the playing animation should be zero'); 256 }, 'Playing a canceled animation sets the start time'); 257 258 promise_test(async t => { 259 const animation = createScrollLinkedAnimation(t); 260 animation.play(); 261 animation.playbackRate = -1; 262 animation.cancel(); 263 assert_equals(animation.startTime, null, 'Start time should be unresolved'); 264 265 animation.play(); 266 assert_true(animation.pending, 'Animation should be play-pending'); 267 268 await animation.ready; 269 270 assert_false(animation.pending, 'Animation should no longer be pending'); 271 assert_percents_equal(animation.startTime, 100, 272 'The start time of the playing animation should be set'); 273 }, 'Playing a canceled animation backwards sets the start time'); 274 275 </script> 276 </body>