tor-browser

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

getAnimations.html (12692B)


      1 <!DOCTYPE html>
      2 <meta charset=utf-8>
      3 <title>Animatable.getAnimations</title>
      4 <link rel="help" href="https://drafts.csswg.org/web-animations/#dom-animatable-getanimations">
      5 <script src="/resources/testharness.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <script src="../../testcommon.js"></script>
      8 <body>
      9 <script>
     10 'use strict';
     11 
     12 test(t => {
     13  const div = createDiv(t);
     14  assert_array_equals(div.getAnimations(), []);
     15 }, 'Returns an empty array for an element with no animations');
     16 
     17 test(t => {
     18  const div = createDiv(t);
     19  const animationA = div.animate(null, 100 * MS_PER_SEC);
     20  const animationB = div.animate(null, 100 * MS_PER_SEC);
     21  assert_array_equals(div.getAnimations(), [animationA, animationB]);
     22 }, 'Returns both animations for an element with two animations');
     23 
     24 test(t => {
     25  const divA = createDiv(t);
     26  const divB = createDiv(t);
     27  const animationA = divA.animate(null, 100 * MS_PER_SEC);
     28  const animationB = divB.animate(null, 100 * MS_PER_SEC);
     29  assert_array_equals(divA.getAnimations(), [animationA], 'divA');
     30  assert_array_equals(divB.getAnimations(), [animationB], 'divB');
     31 }, 'Returns only the animations specific to each sibling element');
     32 
     33 test(t => {
     34  const divParent = createDiv(t);
     35  const divChild = createDiv(t);
     36  divParent.appendChild(divChild);
     37  const animationParent = divParent.animate(null, 100 * MS_PER_SEC);
     38  const animationChild = divChild.animate(null, 100 * MS_PER_SEC);
     39  assert_array_equals(divParent.getAnimations(), [animationParent],
     40                      'divParent');
     41  assert_array_equals(divChild.getAnimations(), [animationChild], 'divChild');
     42 }, 'Returns only the animations specific to each parent/child element');
     43 
     44 test(t => {
     45  const divParent = createDiv(t);
     46  const divChild = createDiv(t);
     47  divParent.appendChild(divChild);
     48  const divGrandChildA = createDiv(t);
     49  const divGrandChildB = createDiv(t);
     50  divChild.appendChild(divGrandChildA);
     51  divChild.appendChild(divGrandChildB);
     52 
     53  // Trigger the animations in a somewhat random order
     54  const animGrandChildB = divGrandChildB.animate(null, 100 * MS_PER_SEC);
     55  const animChild = divChild.animate(null, 100 * MS_PER_SEC);
     56  const animGrandChildA = divGrandChildA.animate(null, 100 * MS_PER_SEC);
     57 
     58  assert_array_equals(
     59    divParent.getAnimations({ subtree: true }),
     60    [animGrandChildB, animChild, animGrandChildA],
     61    'Returns expected animations from parent'
     62  );
     63  assert_array_equals(
     64    divChild.getAnimations({ subtree: true }),
     65    [animGrandChildB, animChild, animGrandChildA],
     66    'Returns expected animations from child'
     67  );
     68  assert_array_equals(
     69    divGrandChildA.getAnimations({ subtree: true }),
     70    [animGrandChildA],
     71    'Returns expected animations from grandchild A'
     72  );
     73 }, 'Returns animations on descendants when subtree: true is specified');
     74 
     75 test(t => {
     76  createStyle(t, {
     77    '@keyframes anim': '',
     78    [`.pseudo::before`]: 'animation: anim 100s; ' + "content: '';",
     79  });
     80  const div = createDiv(t);
     81  div.classList.add('pseudo');
     82 
     83  assert_equals(
     84    div.getAnimations().length,
     85    0,
     86    'Returns no animations when subtree is false'
     87  );
     88  assert_equals(
     89    div.getAnimations({ subtree: true }).length,
     90    1,
     91    'Returns one animation when subtree is true'
     92  );
     93 }, 'Returns animations on pseudo-elements when subtree: true is specified');
     94 
     95 test(t => {
     96  const host = createDiv(t);
     97  const shadow = host.attachShadow({ mode: 'open' });
     98 
     99  const elem = createDiv(t);
    100  shadow.appendChild(elem);
    101 
    102  const elemChild = createDiv(t);
    103  elem.appendChild(elemChild);
    104 
    105  elemChild.animate(null, 100 * MS_PER_SEC);
    106 
    107  assert_equals(
    108    host.getAnimations({ subtree: true }).length,
    109    0,
    110    'Returns no animations with subtree:true when called on the host'
    111  );
    112  assert_equals(
    113    elem.getAnimations({ subtree: true }).length,
    114    1,
    115    'Returns one animation when called on a parent in the shadow tree'
    116  );
    117 }, 'Does NOT cross shadow-tree boundaries when subtree: true is specified');
    118 
    119 test(t => {
    120  const foreignElement
    121    = document.createElementNS('http://example.org/test', 'test');
    122  document.body.appendChild(foreignElement);
    123  t.add_cleanup(() => {
    124    foreignElement.remove();
    125  });
    126 
    127  const animation = foreignElement.animate(null, 100 * MS_PER_SEC);
    128  assert_array_equals(foreignElement.getAnimations(), [animation]);
    129 }, 'Returns animations for a foreign element');
    130 
    131 test(t => {
    132  const div = createDiv(t);
    133  const animation = div.animate(null, 100 * MS_PER_SEC);
    134  animation.finish();
    135  assert_array_equals(div.getAnimations(), []);
    136 }, 'Does not return finished animations that do not fill forwards');
    137 
    138 test(t => {
    139  const div = createDiv(t);
    140  const animation = div.animate(null, {
    141    duration: 100 * MS_PER_SEC,
    142    fill: 'forwards',
    143  });
    144  animation.finish();
    145  assert_array_equals(div.getAnimations(), [animation]);
    146 }, 'Returns finished animations that fill forwards');
    147 
    148 test(t => {
    149  const div = createDiv(t);
    150  const animation = div.animate(null, {
    151    duration: 100 * MS_PER_SEC,
    152    delay: 100 * MS_PER_SEC,
    153  });
    154  assert_array_equals(div.getAnimations(), [animation]);
    155 }, 'Returns animations yet to reach their active phase');
    156 
    157 test(t => {
    158  const div = createDiv(t);
    159  const animation = div.animate(null, 100 * MS_PER_SEC);
    160  animation.playbackRate = -1;
    161  assert_array_equals(div.getAnimations(), []);
    162 }, 'Does not return reversed finished animations that do not fill backwards');
    163 
    164 test(t => {
    165  const div = createDiv(t);
    166  const animation = div.animate(null, {
    167    duration: 100 * MS_PER_SEC,
    168    fill: 'backwards',
    169  });
    170  animation.playbackRate = -1;
    171  assert_array_equals(div.getAnimations(), [animation]);
    172 }, 'Returns reversed finished animations that fill backwards');
    173 
    174 test(t => {
    175  const div = createDiv(t);
    176  const animation = div.animate(null, 100 * MS_PER_SEC);
    177  animation.playbackRate = -1;
    178  animation.currentTime = 200 * MS_PER_SEC;
    179  assert_array_equals(div.getAnimations(), [animation]);
    180 }, 'Returns reversed animations yet to reach their active phase');
    181 
    182 test(t => {
    183  const div = createDiv(t);
    184  const animation = div.animate(null, {
    185    duration: 100 * MS_PER_SEC,
    186    delay: 100 * MS_PER_SEC,
    187  });
    188  animation.playbackRate = 0;
    189  assert_array_equals(div.getAnimations(), []);
    190 }, 'Does not return animations with zero playback rate in before phase');
    191 
    192 test(t => {
    193  const div = createDiv(t);
    194  const animation = div.animate(null, 100 * MS_PER_SEC);
    195  animation.finish();
    196  animation.playbackRate = 0;
    197  animation.currentTime = 200 * MS_PER_SEC;
    198  assert_array_equals(div.getAnimations(), []);
    199 }, 'Does not return animations with zero playback rate in after phase');
    200 
    201 test(t => {
    202  const div = createDiv(t);
    203  const effect = new KeyframeEffect(div, {}, 225);
    204  const animation = new Animation(effect, new DocumentTimeline());
    205  animation.reverse();
    206  animation.pause();
    207  animation.playbackRate = -1;;
    208  animation.updatePlaybackRate(1);
    209  assert_array_equals(div.getAnimations(), []);
    210 }, 'Does not return an animation that has recently been made not current by setting the playback rate');
    211 
    212 test(t => {
    213  const div = createDiv(t);
    214  const animation = div.animate(null, 100 * MS_PER_SEC);
    215 
    216  animation.finish();
    217  assert_array_equals(div.getAnimations(), [],
    218                      'Animation should not be returned when it is finished');
    219 
    220  animation.effect.updateTiming({
    221    duration: animation.effect.getTiming().duration + 100 * MS_PER_SEC,
    222  });
    223  assert_array_equals(div.getAnimations(), [animation],
    224                      'Animation should be returned after extending the'
    225                      + ' duration');
    226 
    227  animation.effect.updateTiming({ duration: 0 });
    228  assert_array_equals(div.getAnimations(), [],
    229                      'Animation should not be returned after setting the'
    230                      + ' duration to zero');
    231 }, 'Returns animations based on dynamic changes to individual'
    232   + ' animations\' duration');
    233 
    234 test(t => {
    235  const div = createDiv(t);
    236  const animation = div.animate(null, 100 * MS_PER_SEC);
    237 
    238  animation.effect.updateTiming({ endDelay: -200 * MS_PER_SEC });
    239  assert_array_equals(div.getAnimations(), [],
    240                      'Animation should not be returned after setting a'
    241                      + ' negative end delay such that the end time is less'
    242                      + ' than the current time');
    243 
    244  animation.effect.updateTiming({ endDelay: 100 * MS_PER_SEC });
    245  assert_array_equals(div.getAnimations(), [animation],
    246                      'Animation should be returned after setting a positive'
    247                      + ' end delay such that the end time is more than the'
    248                      + ' current time');
    249 }, 'Returns animations based on dynamic changes to individual'
    250   + ' animations\' end delay');
    251 
    252 test(t => {
    253  const div = createDiv(t);
    254  const animation = div.animate(null, 100 * MS_PER_SEC);
    255 
    256  animation.finish();
    257  assert_array_equals(div.getAnimations(), [],
    258                      'Animation should not be returned when it is finished');
    259 
    260  animation.effect.updateTiming({ iterations: 10 });
    261  assert_array_equals(div.getAnimations(), [animation],
    262                      'Animation should be returned after inreasing the'
    263                      + ' number of iterations');
    264 
    265  animation.effect.updateTiming({ iterations: 0 });
    266  assert_array_equals(div.getAnimations(), [],
    267                      'Animations should not be returned after setting the'
    268                      + ' iteration count to zero');
    269 
    270  animation.effect.updateTiming({ iterations: Infinity });
    271  assert_array_equals(div.getAnimations(), [animation],
    272                      'Animation should be returned after inreasing the'
    273                      + ' number of iterations to infinity');
    274 }, 'Returns animations based on dynamic changes to individual'
    275   + ' animations\' iteration count');
    276 
    277 test(t => {
    278  const div = createDiv(t);
    279  const animation = div.animate(null,
    280                                { duration: 100 * MS_PER_SEC,
    281                                  delay: 50 * MS_PER_SEC,
    282                                  endDelay: -50 * MS_PER_SEC });
    283 
    284  assert_array_equals(div.getAnimations(), [animation],
    285                      'Animation should be returned at during delay phase');
    286 
    287  animation.currentTime = 50 * MS_PER_SEC;
    288  assert_array_equals(div.getAnimations(), [animation],
    289                      'Animation should be returned after seeking to the start'
    290                      + ' of the active interval');
    291 
    292  animation.currentTime = 100 * MS_PER_SEC;
    293  assert_array_equals(div.getAnimations(), [],
    294                      'Animation should not be returned after seeking to the'
    295                      + ' clipped end of the active interval');
    296 }, 'Returns animations based on dynamic changes to individual'
    297   + ' animations\' current time');
    298 
    299 promise_test(async t => {
    300  const div = createDiv(t);
    301 
    302  const animA = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
    303  const animB = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
    304  await animA.finished;
    305  // It is not guaranteed that the mircrotask PerformCheckpoint() happens before
    306  // the animation finish promised got resolved, because the microtask
    307  // checkpoint could also be triggered from other source such as the event_loop
    308  // Thus we wait for one animation frame to make sure the finished animation is
    309  // properly removed.
    310  await waitForNextFrame(1);
    311  assert_array_equals(div.getAnimations(), [animB]);
    312 }, 'Does not return an animation that has been removed');
    313 
    314 promise_test(async t => {
    315  const div = createDiv(t);
    316 
    317  const animA = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
    318  const animB = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
    319  await animA.finished;
    320 
    321  animA.persist();
    322 
    323  assert_array_equals(div.getAnimations(), [animA, animB]);
    324 }, 'Returns an animation that has been persisted');
    325 
    326 promise_test(async t => {
    327  const div = createDiv(t);
    328  const watcher = EventWatcher(t, div, 'transitionrun');
    329 
    330  // Create a covering animation to prevent transitions from firing after
    331  // calling getAnimations().
    332  const coveringAnimation = new Animation(
    333    new KeyframeEffect(div, { opacity: [0, 1] }, 100 * MS_PER_SEC)
    334  );
    335 
    336  // Setup transition start point.
    337  div.style.transition = 'opacity 100s';
    338  getComputedStyle(div).opacity;
    339 
    340  // Update specified style but don't flush style.
    341  div.style.opacity = '0.5';
    342 
    343  // Fetch animations
    344  div.getAnimations();
    345 
    346  // Play the covering animation to ensure that only the call to
    347  // getAnimations() has a chance to trigger transitions.
    348  coveringAnimation.play();
    349 
    350  // If getAnimations() flushed style, we should get a transitionrun event.
    351  await watcher.wait_for('transitionrun');
    352 }, 'Triggers a style change event');
    353 
    354 </script>
    355 </body>