tor-browser

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

finish-animation.html (14059B)


      1 <!DOCTYPE html>
      2 <meta charset=utf-8>
      3 <title>Finishing an animation</title>
      4 <link rel="help"
      5  href="https://drafts.csswg.org/web-animations/#finishing-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: 200px;
     14  width: 100px;
     15  will-change: transform;
     16 }
     17 
     18 .contents {
     19  height: 1000px;
     20  width: 100%;
     21 }
     22 </style>
     23 <body>
     24 <div id="log"></div>
     25 <script>
     26 'use strict';
     27 
     28 promise_test(async t => {
     29  const animation = createScrollLinkedAnimation(t);
     30  animation.play();
     31  animation.playbackRate = 0;
     32 
     33  assert_throws_dom('InvalidStateError', () => {
     34    animation.finish();
     35  });
     36 }, 'Finishing an animation with a zero playback rate throws');
     37 
     38 promise_test(async t => {
     39  const animation = createScrollLinkedAnimation(t);
     40  animation.play();
     41  animation.finish();
     42 
     43  assert_percents_equal(animation.currentTime, 100,
     44    'After finishing, the currentTime should be set to the end of the'
     45    + ' active duration');
     46 }, 'Finishing an animation seeks to the end time');
     47 
     48 promise_test(async t => {
     49  const animation = createScrollLinkedAnimation(t);
     50  animation.play();
     51  // 1% past effect end
     52  animation.currentTime = CSSNumericValue.parse("101%");
     53  animation.finish();
     54 
     55  assert_percents_equal(animation.currentTime, 100,
     56    'After finishing, the currentTime should be set back to the end of the'
     57    + ' active duration');
     58 }, 'Finishing an animation with a current time past the effect end jumps'
     59  + ' back to the end');
     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  animation.play();
     66  scroller.scrollTop = maxScroll;
     67  await animation.finished;
     68 
     69  animation.playbackRate = -1;
     70  animation.finish();
     71 
     72  assert_percents_equal(animation.currentTime, 0,
     73                        'After finishing a reversed animation the ' +
     74                        'currentTime should be set to zero');
     75 }, 'Finishing a reversed animation jumps to zero time');
     76 
     77 promise_test(async t => {
     78  const animation = createScrollLinkedAnimation(t);
     79  animation.play();
     80  animation.currentTime = CSSNumericValue.parse("100%");
     81  await animation.finished;
     82 
     83  animation.playbackRate = -1;
     84  animation.currentTime = CSSNumericValue.parse("-1000%");
     85  animation.finish();
     86 
     87  assert_percents_equal(animation.currentTime, 0,
     88                        'After finishing a reversed animation the ' +
     89                        'currentTime should be set back to zero');
     90 }, 'Finishing a reversed animation with a current time less than zero'
     91  + ' makes it jump back to zero');
     92 
     93 promise_test(async t => {
     94  const animation = createScrollLinkedAnimation(t);
     95  animation.play();
     96  animation.playbackRate = 0.5;
     97  animation.finish();
     98 
     99  assert_false(animation.pending);
    100  assert_equals(animation.playState, 'finished',
    101                'The play state of a play-pending animation should become ' +
    102                '"finished"');
    103  assert_percents_equal(animation.startTime,
    104                        animation.timeline.currentTime.value - 100 / 0.5,
    105                        'The start time of a play-pending animation should ' +
    106                        'be set');
    107 }, 'Finishing an animation while play-pending resolves the pending'
    108  + ' task immediately');
    109 
    110 promise_test(async t => {
    111  const animation = createScrollLinkedAnimation(t);
    112  const scroller = animation.timeline.source;
    113  await runAndWaitForFrameUpdate(() => {
    114    // Make the scroll timeline inactive.
    115    scroller.style.overflow = 'visible';
    116  });
    117  animation.play();
    118  animation.finish();
    119 
    120  await animation.finished;
    121 
    122  assert_true(animation.pending);
    123  assert_equals(animation.playState, 'finished',
    124                'The play state of a play-pending animation should become ' +
    125                '"finished"');
    126  assert_percents_equal(animation.currentTime, 100,
    127                        'The current time of a play-pending animation should ' +
    128                        'be set to the end of the active duration');
    129  assert_equals(animation.startTime, null,
    130                'The start time of a finished play-pending animation should ' +
    131                'be unresolved');
    132 }, 'Finishing an animation attached to inactive timeline while play-pending '
    133  + 'doesn\'t resolves the pending task');
    134 
    135 promise_test(async t => {
    136  const animation = createScrollLinkedAnimation(t);
    137  animation.play();
    138  let resolvedFinished = false;
    139  animation.finished.then(() => {
    140    resolvedFinished = true;
    141  });
    142 
    143  await animation.ready;
    144 
    145  animation.finish();
    146  await Promise.resolve();
    147 
    148  assert_true(resolvedFinished, 'finished promise should be resolved');
    149 }, 'Finishing an animation resolves the finished promise synchronously');
    150 
    151 promise_test(async t => {
    152  const animation = createScrollLinkedAnimation(t);
    153  animation.play();
    154  const promise = animation.ready;
    155  let readyResolved = false;
    156 
    157  animation.finish();
    158  animation.ready.then(() => { readyResolved = true; });
    159 
    160  const promiseResult = await animation.finished;
    161  await animation.ready;
    162 
    163  assert_equals(promiseResult, animation);
    164  assert_equals(animation.ready, promise);
    165  assert_true(readyResolved);
    166 }, 'A pending ready promise is resolved and not replaced when the animation'
    167  + ' is finished');
    168 
    169 promise_test(async t => {
    170  const animation = createScrollLinkedAnimation(t);
    171  animation.play();
    172  animation.effect.target.remove();
    173 
    174  const eventWatcher = new EventWatcher(t, animation, 'finish');
    175 
    176  await animation.ready;
    177  animation.finish();
    178 
    179  await eventWatcher.wait_for('finish');
    180  assert_equals(animation.effect.target.parentNode, null,
    181    'finish event should be fired for the animation on an orphaned element');
    182 }, 'Finishing an animation fires finish event on orphaned element');
    183 
    184 promise_test(async t => {
    185  const animation = createScrollLinkedAnimation(t);
    186  animation.play();
    187  await animation.ready;
    188 
    189  const originalFinishPromise = animation.finished;
    190 
    191  animation.cancel();
    192  assert_equals(animation.startTime, null);
    193  assert_equals(animation.currentTime, null);
    194 
    195  const resolvedFinishPromise = animation.finished;
    196  assert_not_equals(originalFinishPromise, resolvedFinishPromise,
    197              'Canceling an animation should create a new finished promise');
    198 
    199  animation.finish();
    200  assert_equals(animation.playState, 'finished',
    201                'The play state of a canceled animation should become ' +
    202                '"finished"');
    203  assert_percents_equal(animation.startTime,
    204                        animation.timeline.currentTime.value - 100,
    205                        'The start time of a finished animation should be set');
    206  assert_percents_equal(animation.currentTime, 100,
    207                        'Hold time should be set to end boundary of the ' +
    208                        'animation');
    209 
    210 }, 'Finishing a canceled animation sets the current and start times');
    211 
    212 promise_test(async t => {
    213  const animation = createScrollLinkedAnimation(t);
    214  const scroller = animation.timeline.source;
    215  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
    216  // Wait for new animation frame which allows the timeline to compute new
    217  // current time.
    218  await runAndWaitForFrameUpdate(() => {
    219    scroller.scrollTop = 0.25 * maxScroll;
    220  });
    221 
    222  const eventWatcher = new EventWatcher(t, animation, 'finish');
    223  animation.finish();
    224  await animation.finished;
    225  const finishEvent = await eventWatcher.wait_for('finish');
    226  assert_equals(animation.playState, 'finished',
    227    'Animation is finished.');
    228  assert_percents_equal(animation.currentTime, 100,
    229    'The current time is the end of the active duration in finished state.');
    230  assert_percents_equal(animation.startTime, -75,
    231    'The start time is calculated to match the current time.');
    232  assert_percents_equal(finishEvent.currentTime, 100,
    233    'event.currentTime is the animation current time.');
    234  assert_percents_equal(finishEvent.timelineTime, 25,
    235    'event.timelineTime is timeline.currentTime');
    236 }, 'Finishing idle animation produces correct state and fires finish event.');
    237 
    238 promise_test(async t => {
    239  const animation = createScrollLinkedAnimation(t);
    240  const scroller = animation.timeline.source;
    241  // Make the scroll timeline inactive.
    242  scroller.style.overflow = 'visible';
    243  await waitForNextFrame();
    244  assert_equals(animation.timeline.currentTime, null,
    245                'Sanity check the timeline is inactive.');
    246  animation.finish();
    247  assert_equals(animation.playState, 'paused', 'Animation is paused.');
    248 }, 'Finishing idle animation attached to inactive timeline pauses the ' +
    249    'animation.');
    250 
    251 promise_test(async t => {
    252  const animation = createScrollLinkedAnimation(t);
    253  const scroller = animation.timeline.source;
    254  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
    255  scroller.scrollTop = 0.25 * maxScroll;
    256  animation.play();
    257  await animation.ready;
    258 
    259  const eventWatcher = new EventWatcher(t, animation, 'finish');
    260  animation.finish();
    261  await animation.finished;
    262  const finishEvent = await eventWatcher.wait_for('finish');
    263  assert_equals(animation.playState, 'finished',
    264    'Animation is finished.');
    265  assert_percents_equal(animation.currentTime, 100,
    266    'The current time is the end of active duration in finished state.');
    267  assert_percents_equal(animation.startTime, -75,
    268    'The start time is calculated to match animation current time.');
    269  assert_percents_equal(finishEvent.currentTime, 100,
    270    'event.currentTime is the animation current time.');
    271  assert_percents_equal(finishEvent.timelineTime, 25,
    272    'event.timelineTime is timeline.currentTime');
    273 }, 'Finishing running animation produces correct state and fires finish event.');
    274 
    275 promise_test(async t => {
    276  const animation = createScrollLinkedAnimation(t);
    277  const scroller = animation.timeline.source;
    278  animation.play();
    279  await animation.ready;
    280 
    281  await runAndWaitForFrameUpdate(() => {
    282    // Make the scroll timeline inactive.
    283    scroller.style.overflow = 'visible';
    284  });
    285  assert_equals(animation.timeline.currentTime, null,
    286                'Sanity check the timeline is inactive.');
    287  assert_equals(animation.playState, 'running',
    288                'Sanity check the animation is running.');
    289 
    290  animation.finish();
    291  assert_equals(animation.playState, 'paused', 'Animation is paused.');
    292 }, 'Finishing running animation attached to inactive timeline pauses the ' +
    293    'animation.');
    294 
    295 promise_test(async t => {
    296  const animation = createScrollLinkedAnimation(t);
    297  animation.pause();
    298  await animation.ready;
    299 
    300  animation.finish();
    301 
    302  assert_equals(animation.playState, 'finished',
    303                'The play state of a paused animation should become ' +
    304                '"finished"');
    305  assert_percents_equal(animation.startTime,
    306                    animation.timeline.currentTime.value - 100,
    307                    'The start time of a paused animation should be set');
    308 }, 'Finishing a paused animation resolves the start time');
    309 
    310 promise_test(async t => {
    311  const animation = createScrollLinkedAnimation(t);
    312  animation.play();
    313  // Update playbackRate so we can test that the calculated startTime
    314  // respects it
    315  animation.playbackRate = 2;
    316  animation.pause();
    317  // While animation is still pause-pending call finish()
    318  animation.finish();
    319 
    320  assert_false(animation.pending);
    321  assert_equals(animation.playState, 'finished',
    322                'The play state of a pause-pending animation should become ' +
    323                '"finished"');
    324  assert_percents_equal(animation.startTime,
    325                        animation.timeline.currentTime.value - 100 / 2,
    326                        'The start time of a pause-pending animation should ' +
    327                        'be set');
    328 }, 'Finishing a pause-pending animation resolves the pending task'
    329  + ' immediately and update the start time');
    330 
    331 promise_test(async t => {
    332  const animation = createScrollLinkedAnimation(t);
    333  animation.play();
    334  animation.playbackRate = -2;
    335  animation.pause();
    336  animation.finish();
    337 
    338  assert_false(animation.pending);
    339  assert_equals(animation.playState, 'finished',
    340                'The play state of a pause-pending animation should become ' +
    341                '"finished"');
    342  assert_percents_equal(animation.startTime,
    343                        animation.timeline.currentTime,
    344                        'The start time of a pause-pending animation should ' +
    345                        'be set');
    346 }, 'Finishing a pause-pending animation with negative playback rate'
    347  + ' resolves the pending task immediately');
    348 
    349 promise_test(async t => {
    350  const animation = createScrollLinkedAnimation(t);
    351  animation.play();
    352  await animation.ready;
    353 
    354  animation.pause();
    355  animation.play();
    356  // We are now in the unusual situation of being play-pending whilst having
    357  // a resolved start time. Check that finish() still triggers a transition
    358  // to the finished state immediately.
    359  animation.finish();
    360 
    361  assert_equals(animation.playState, 'finished',
    362                'After aborting a pause then finishing an animation its play ' +
    363                'state should become "finished" immediately');
    364 }, 'Finishing an animation during an aborted pause makes it finished'
    365  + ' immediately');
    366 
    367 promise_test(async t => {
    368  const animation = createScrollLinkedAnimation(t);
    369  animation.play();
    370  await animation.ready;
    371 
    372  animation.updatePlaybackRate(2);
    373  assert_true(animation.pending);
    374 
    375  animation.finish();
    376  assert_false(animation.pending);
    377  assert_equals(animation.playbackRate, 2);
    378  assert_percents_equal(animation.currentTime, 100);
    379 }, 'A pending playback rate should be applied immediately when an animation'
    380  + ' is finished');
    381 
    382 promise_test(async t => {
    383  const animation = createScrollLinkedAnimation(t);
    384  animation.play();
    385  await animation.ready;
    386 
    387  animation.updatePlaybackRate(0);
    388 
    389  assert_throws_dom('InvalidStateError', () => {
    390    animation.finish();
    391  });
    392 }, 'An exception should be thrown if the effective playback rate is zero');
    393 </script>
    394 </body>