tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

reversing-an-animation.html (9519B)


      1 <!DOCTYPE html>
      2 <meta charset=utf-8>
      3 <title>Reversing an animation</title>
      4 <link rel="help"
      5      href="https://drafts.csswg.org/web-animations/#reversing-an-animation-section">
      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 div = createDiv(t);
     16  const animation = div.animate({}, { duration: 100 * MS_PER_SEC,
     17                                      iterations: Infinity });
     18 
     19  await animation.ready;
     20  // Wait a frame because if currentTime is still 0 when we call
     21  // reverse(), it will throw (per spec).
     22  await waitForAnimationFrames(1);
     23 
     24  assert_greater_than_equal(animation.currentTime, 0,
     25    'currentTime expected to be greater than 0, one frame after starting');
     26  animation.currentTime = 50 * MS_PER_SEC;
     27  const previousPlaybackRate = animation.playbackRate;
     28  animation.reverse();
     29  assert_equals(animation.playbackRate, previousPlaybackRate,
     30                'Playback rate should not have changed');
     31  await animation.ready;
     32 
     33  assert_equals(animation.playbackRate, -previousPlaybackRate,
     34                'Playback rate should be inverted');
     35 }, 'Reversing an animation inverts the playback rate');
     36 
     37 promise_test(async t => {
     38  const div = createDiv(t);
     39  const animation = div.animate({}, { duration: 100 * MS_PER_SEC,
     40                                      iterations: Infinity });
     41  animation.currentTime = 50 * MS_PER_SEC;
     42  animation.pause();
     43 
     44  await animation.ready;
     45 
     46  animation.reverse();
     47  await animation.ready;
     48 
     49  assert_equals(animation.playState, 'running',
     50    'Animation.playState should be "running" after reverse()');
     51 }, 'Reversing an animation plays a pausing animation');
     52 
     53 test(t => {
     54  const div = createDiv(t);
     55  const animation = div.animate({}, 100 * MS_PER_SEC);
     56  animation.currentTime = 50 * MS_PER_SEC;
     57  animation.reverse();
     58 
     59  assert_equals(animation.currentTime, 50 * MS_PER_SEC,
     60    'The current time should not change it is in the middle of ' +
     61    'the animation duration');
     62 }, 'Reversing an animation maintains the same current time');
     63 
     64 test(t => {
     65  const div = createDiv(t);
     66  const animation = div.animate({}, { duration: 200 * MS_PER_SEC,
     67                                      delay: -100 * MS_PER_SEC });
     68  assert_true(animation.pending,
     69              'The animation is pending before we call reverse');
     70 
     71  animation.reverse();
     72 
     73  assert_true(animation.pending,
     74              'The animation is still pending after calling reverse');
     75 }, 'Reversing an animation does not cause it to leave the pending state');
     76 
     77 promise_test(async t => {
     78  const div = createDiv(t);
     79  const animation = div.animate({}, { duration: 200 * MS_PER_SEC,
     80                                      delay: -100 * MS_PER_SEC });
     81  let readyResolved = false;
     82  animation.ready.then(() => { readyResolved = true; });
     83 
     84  animation.reverse();
     85 
     86  await Promise.resolve();
     87  assert_false(readyResolved,
     88               'ready promise should not have been resolved yet');
     89 }, 'Reversing an animation does not cause it to resolve the ready promise');
     90 
     91 test(t => {
     92  const div = createDiv(t);
     93  const animation = div.animate({}, 100 * MS_PER_SEC);
     94  animation.currentTime = 200 * MS_PER_SEC;
     95  animation.reverse();
     96 
     97  assert_equals(animation.currentTime, 100 * MS_PER_SEC,
     98    'reverse() should start playing from the animation effect end ' +
     99    'if the playbackRate > 0 and the currentTime > effect end');
    100 }, 'Reversing an animation when playbackRate > 0 and currentTime > ' +
    101   'effect end should make it play from the end');
    102 
    103 test(t => {
    104  const div = createDiv(t);
    105  const animation = div.animate({}, 100 * MS_PER_SEC);
    106 
    107  animation.currentTime = -200 * MS_PER_SEC;
    108  animation.reverse();
    109 
    110  assert_equals(animation.currentTime, 100 * MS_PER_SEC,
    111    'reverse() should start playing from the animation effect end ' +
    112    'if the playbackRate > 0 and the currentTime < 0');
    113 }, 'Reversing an animation when playbackRate > 0 and currentTime < 0 ' +
    114   'should make it play from the end');
    115 
    116 test(t => {
    117  const div = createDiv(t);
    118  const animation = div.animate({}, 100 * MS_PER_SEC);
    119  animation.playbackRate = -1;
    120  animation.currentTime = -200 * MS_PER_SEC;
    121  animation.reverse();
    122 
    123  assert_equals(animation.currentTime, 0,
    124    'reverse() should start playing from the start of animation time ' +
    125    'if the playbackRate < 0 and the currentTime < 0');
    126 }, 'Reversing an animation when playbackRate < 0 and currentTime < 0 ' +
    127   'should make it play from the start');
    128 
    129 test(t => {
    130  const div = createDiv(t);
    131  const animation = div.animate({}, 100 * MS_PER_SEC);
    132  animation.playbackRate = -1;
    133  animation.currentTime = 200 * MS_PER_SEC;
    134  animation.reverse();
    135 
    136  assert_equals(animation.currentTime, 0,
    137    'reverse() should start playing from the start of animation time ' +
    138    'if the playbackRate < 0 and the currentTime > effect end');
    139 }, 'Reversing an animation when playbackRate < 0 and currentTime > effect ' +
    140   'end should make it play from the start');
    141 
    142 test(t => {
    143  const div = createDiv(t);
    144  const animation = div.animate({}, { duration: 100 * MS_PER_SEC,
    145                                      iterations: Infinity });
    146  animation.currentTime = -200 * MS_PER_SEC;
    147 
    148  assert_throws_dom('InvalidStateError',
    149    () => { animation.reverse(); },
    150    'reverse() should throw InvalidStateError ' +
    151    'if the playbackRate > 0 and the currentTime < 0 ' +
    152    'and the target effect is positive infinity');
    153 }, 'Reversing an animation when playbackRate > 0 and currentTime < 0 ' +
    154   'and the target effect end is positive infinity should throw an exception');
    155 
    156 promise_test(async t => {
    157  const animation = createDiv(t).animate({}, { duration: 100 * MS_PER_SEC,
    158                                               iterations: Infinity });
    159  animation.currentTime = -200 * MS_PER_SEC;
    160 
    161  try { animation.reverse(); } catch(e) { }
    162 
    163  assert_equals(animation.playbackRate, 1, 'playbackRate is unchanged');
    164 
    165  await animation.ready;
    166  assert_equals(animation.playbackRate, 1, 'playbackRate remains unchanged');
    167 }, 'When reversing throws an exception, the playback rate remains unchanged');
    168 
    169 test(t => {
    170  const div = createDiv(t);
    171  const animation = div.animate({}, { duration: 100 * MS_PER_SEC,
    172                                      iterations: Infinity });
    173  animation.currentTime = -200 * MS_PER_SEC;
    174  animation.playbackRate = 0;
    175 
    176  try {
    177    animation.reverse();
    178  } catch (e) {
    179    assert_unreached(`Unexpected exception when calling reverse(): ${e}`);
    180  }
    181 }, 'Reversing animation when playbackRate = 0 and currentTime < 0 ' +
    182   'and the target effect end is positive infinity should NOT throw an ' +
    183   'exception');
    184 
    185 test(t => {
    186  const div = createDiv(t);
    187  const animation = div.animate({}, { duration: 100 * MS_PER_SEC,
    188                                      iterations: Infinity });
    189  animation.playbackRate = -1;
    190  animation.currentTime = -200 * MS_PER_SEC;
    191  animation.reverse();
    192 
    193  assert_equals(animation.currentTime, 0,
    194    'reverse() should start playing from the start of animation time ' +
    195    'if the playbackRate < 0 and the currentTime < 0 ' +
    196    'and the target effect is positive infinity');
    197 }, 'Reversing an animation when playbackRate < 0 and currentTime < 0 ' +
    198   'and the target effect end is positive infinity should make it play ' +
    199   'from the start');
    200 
    201 promise_test(async t => {
    202  const div = createDiv(t);
    203  const animation = div.animate({}, 100 * MS_PER_SEC);
    204  animation.playbackRate = 0;
    205  animation.currentTime = 50 * MS_PER_SEC;
    206  animation.reverse();
    207 
    208  await animation.ready;
    209  assert_equals(animation.playbackRate, 0,
    210    'reverse() should preserve playbackRate if the playbackRate == 0');
    211  assert_equals(animation.currentTime, 50 * MS_PER_SEC,
    212    'reverse() should not affect the currentTime if the playbackRate == 0');
    213 }, 'Reversing when when playbackRate == 0 should preserve the current ' +
    214   'time and playback rate');
    215 
    216 test(t => {
    217  const div = createDiv(t);
    218  const animation =
    219    new Animation(new KeyframeEffect(div, null, 100 * MS_PER_SEC));
    220  assert_equals(animation.currentTime, null);
    221 
    222  animation.reverse();
    223 
    224  assert_equals(animation.currentTime, 100 * MS_PER_SEC,
    225    'animation.currentTime should be at its effect end');
    226 }, 'Reversing an idle animation from starts playing the animation');
    227 
    228 test(t => {
    229  const div = createDiv(t);
    230  const animation =
    231    new Animation(new KeyframeEffect(div, null, 100 * MS_PER_SEC), null);
    232 
    233  assert_throws_dom('InvalidStateError', () => { animation.reverse(); });
    234 }, 'Reversing an animation without an active timeline throws an ' +
    235   'InvalidStateError');
    236 
    237 promise_test(async t => {
    238  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
    239  await animation.ready;
    240 
    241  animation.updatePlaybackRate(2);
    242  animation.reverse();
    243 
    244  await animation.ready;
    245  assert_equals(animation.playbackRate, -2);
    246 }, 'Reversing should use the negative pending playback rate');
    247 
    248 promise_test(async t => {
    249  const animation = createDiv(t).animate(null, {
    250    duration: 100 * MS_PER_SEC,
    251    iterations: Infinity,
    252  });
    253  animation.currentTime = -200 * MS_PER_SEC;
    254  await animation.ready;
    255 
    256  animation.updatePlaybackRate(2);
    257  assert_throws_dom('InvalidStateError', () => { animation.reverse(); });
    258  assert_equals(animation.playbackRate, 1);
    259 
    260  await animation.ready;
    261  assert_equals(animation.playbackRate, 2);
    262 }, 'When reversing fails, it should restore any previous pending playback'
    263   + ' rate');
    264 
    265 </script>
    266 </body>