seamlessly-updating-the-playback-rate-of-an-animation.html (6388B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <title>Seamlessly updating the playback rate of an animation</title> 4 <link rel="help" 5 href="https://drafts.csswg.org/web-animations-1/#seamlessly-updating-the-playback-rate-of-an-animation"> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 <script src="../../testcommon.js"></script> 9 <body> 10 <div id="log"></div> 11 <script> 12 'use strict'; 13 14 promise_test(async t => { 15 const animation = createDiv(t).animate(null, 100 * MS_PER_SEC); 16 await animation.ready; 17 18 animation.currentTime = 50 * MS_PER_SEC; 19 20 animation.updatePlaybackRate(0.5); 21 await animation.ready; 22 // Since the animation is in motion (and we want to test it while it is in 23 // motion!) we can't assert that the current time == 50s but we can check 24 // that the current time is NOT re-calculated by simply substituting in the 25 // new playback rate (i.e. without adjusting the start time). If that were 26 // the case the currentTime would jump to 25s. So we just test the currentTime 27 // hasn't gone backwards. 28 assert_greater_than_equal(animation.currentTime, 50 * MS_PER_SEC, 29 'Reducing the playback rate should not change the current time ' + 30 'of a playing animation'); 31 32 animation.updatePlaybackRate(2); 33 await animation.ready; 34 // Likewise, we test here that the current time does not jump to 100s as it 35 // would if we naively applied a playbackRate of 2 without adjusting the 36 // startTime. 37 assert_less_than(animation.currentTime, 100 * MS_PER_SEC, 38 'Increasing the playback rate should not change the current time ' + 39 'of a playing animation'); 40 }, 'Updating the playback rate maintains the current time'); 41 42 promise_test(async t => { 43 const animation = createDiv(t).animate(null, 100 * MS_PER_SEC); 44 await animation.ready; 45 46 assert_false(animation.pending); 47 animation.updatePlaybackRate(2); 48 assert_true(animation.pending); 49 }, 'Updating the playback rate while running makes the animation pending'); 50 51 promise_test(async t => { 52 const animation = createDiv(t).animate(null, 100 * MS_PER_SEC); 53 animation.currentTime = 50 * MS_PER_SEC; 54 assert_true(animation.pending); 55 56 animation.updatePlaybackRate(0.5); 57 58 // Check that the hold time is updated as expected 59 assert_time_equals_literal(animation.currentTime, 50 * MS_PER_SEC); 60 61 await animation.ready; 62 63 // As above, check that the currentTime is not calculated by simply 64 // substituting in the updated playbackRate without updating the startTime. 65 assert_greater_than_equal(animation.currentTime, 50 * MS_PER_SEC, 66 'Reducing the playback rate should not change the current time ' + 67 'of a play-pending animation'); 68 }, 'Updating the playback rate on a play-pending animation maintains' 69 + ' the current time'); 70 71 promise_test(async t => { 72 const animation = createDiv(t).animate(null, 100 * MS_PER_SEC); 73 animation.currentTime = 50 * MS_PER_SEC; 74 await animation.ready; 75 76 animation.pause(); 77 animation.updatePlaybackRate(0.5); 78 79 assert_greater_than_equal(animation.currentTime, 50 * MS_PER_SEC); 80 }, 'Updating the playback rate on a pause-pending animation maintains' 81 + ' the current time'); 82 83 promise_test(async t => { 84 const animation = createDiv(t).animate(null, 100 * MS_PER_SEC); 85 86 animation.updatePlaybackRate(2); 87 animation.updatePlaybackRate(3); 88 animation.updatePlaybackRate(4); 89 90 assert_equals(animation.playbackRate, 1); 91 await animation.ready; 92 93 assert_equals(animation.playbackRate, 4); 94 }, 'If a pending playback rate is set multiple times, the latest wins'); 95 96 test(t => { 97 const animation = createDiv(t).animate(null, 100 * MS_PER_SEC); 98 animation.cancel(); 99 100 animation.updatePlaybackRate(2); 101 assert_equals(animation.playbackRate, 2); 102 assert_false(animation.pending); 103 }, 'In the idle state, the playback rate is applied immediately'); 104 105 promise_test(async t => { 106 const animation = createDiv(t).animate(null, 100 * MS_PER_SEC); 107 animation.pause(); 108 await animation.ready; 109 110 animation.updatePlaybackRate(2); 111 assert_equals(animation.playbackRate, 2); 112 assert_false(animation.pending); 113 }, 'In the paused state, the playback rate is applied immediately'); 114 115 promise_test(async t => { 116 const animation = createDiv(t).animate(null, 100 * MS_PER_SEC); 117 animation.finish(); 118 assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC); 119 assert_false(animation.pending); 120 121 animation.updatePlaybackRate(2); 122 assert_equals(animation.playbackRate, 2); 123 assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC); 124 assert_false(animation.pending); 125 }, 'Updating the playback rate on a finished animation maintains' 126 + ' the current time'); 127 128 promise_test(async t => { 129 const animation = createDiv(t).animate(null, 100 * MS_PER_SEC); 130 animation.finish(); 131 assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC); 132 assert_false(animation.pending); 133 134 animation.updatePlaybackRate(0); 135 assert_equals(animation.playbackRate, 0); 136 assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC); 137 assert_false(animation.pending); 138 }, 'Updating the playback rate to zero on a finished animation maintains' 139 + ' the current time'); 140 141 promise_test(async t => { 142 const animation = createDiv(t).animate(null, 100 * MS_PER_SEC); 143 await animation.ready; 144 145 // Get the animation in a state where it has an unresolved current time, 146 // a resolved start time (so it is not 'idle') and but no pending play task. 147 animation.timeline = null; 148 animation.startTime = 0; 149 assert_equals(animation.currentTime, null); 150 assert_equals(animation.playState, 'running'); 151 152 // Make the effect end infinite. 153 animation.effect.updateTiming({ endDelay: 1e38 }); 154 155 // Now we want to check that when we go to set a negative playback rate we 156 // don't end up throwing an InvalidStateError (which would happen if we ended 157 // up applying the auto-rewind behavior). 158 animation.updatePlaybackRate(-1); 159 160 // Furthermore, we should apply the playback rate immediately since the 161 // current time is unresolved. 162 assert_equals(animation.playbackRate, -1, 163 'We apply the pending playback rate immediately if the current time is ' + 164 'unresolved'); 165 assert_false(animation.pending); 166 }, 'Updating the negative playback rate with the unresolved current time and' 167 + ' a positive infinite associated effect end should not throw an' 168 + ' exception'); 169 170 </script> 171 </body>