tor-browser

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

content-visibility-animation-in-auto-subtree.html (8685B)


      1 <!DOCTYPE html>
      2 <meta charset=utf8>
      3 <title>Test getComputedStyle on a CSS animation in a content visibility subtree using content-visibility: auto</title>
      4 <link rel="help" href="https://drafts.csswg.org/css-contain-2/">
      5 <script src="/web-animations/testcommon.js"></script>
      6 <script src="/resources/testharness.js"></script>
      7 <script src="/resources/testharnessreport.js"></script>
      8 <style>
      9 #container {
     10  content-visibility: auto;
     11 }
     12 @keyframes fade {
     13  from { opacity: 1; }
     14  to { opacity: 0;  }
     15 }
     16 #target {
     17  background: green;
     18  height: 100px;
     19  width: 100px;
     20 }
     21 .animate {
     22  animation: fade 1s linear 2 alternate;
     23 }
     24 .transition {
     25  transition: opacity 1s linear;
     26 }
     27 </style>
     28 <body>
     29  <div id="spacer"></div>
     30  <div id="container"></div>
     31 </body>
     32 <script>
     33 "use strict";
     34 
     35 function reset() {
     36  const container = document.getElementById('container');
     37  const target = document.getElementById('target');
     38  container.style = '';
     39  container.removeChild(target);
     40 }
     41 
     42 function createAnimatingElement(test, name) {
     43  const container = document.getElementById('container');
     44  const target = document.createElement('div');
     45  container.appendChild(target);
     46  target.id = 'target';
     47  target.className = name;
     48  test.add_cleanup(() => {
     49    reset();
     50  });
     51  return target;
     52 }
     53 
     54 promise_test(async t => {
     55  const container = document.getElementById('container');
     56  const target = createAnimatingElement(t, 'animate');
     57  let animationIterationEvent = false;
     58  const animation = target.getAnimations()[0];
     59  await animation.ready;
     60  await waitForAnimationFrames(1);
     61  document.getElementById("spacer").style.height = "300vh";
     62  await waitForAnimationFrames(1);
     63  target.addEventListener('animationiteration', () => {
     64    animationIterationEvent = true;
     65  });
     66  animation.currentTime = 1500;
     67  assert_approx_equals(
     68      parseFloat(getComputedStyle(target).opacity), 0.5, 1e-6,
     69      'Computed style is updated even when the animation is running in a ' +
     70      'content visibility subtree');
     71  await waitForAnimationFrames(2);
     72  assert_false(animationIterationEvent,
     73               'Animation events do not fire while the animation is ' +
     74               'running in a content visibility subtree');
     75  document.getElementById("spacer").style.height = "0vh";
     76  await waitForAnimationFrames(2);
     77  assert_true(animationIterationEvent,
     78              'The animationiteration event fires once the animation is ' +
     79              'no longer content visibility');
     80 }, 'Animation events do not fire for a CSS animation running in a content ' +
     81   'visibility subtree');
     82 
     83 promise_test(async t => {
     84  const container = document.getElementById('container');
     85  const target = createAnimatingElement(t, 'animate');
     86  const animation = target.getAnimations()[0];
     87  await animation.ready;
     88  let finishedWhileDisplayLocked = false;
     89  animation.finished.then(() => {
     90    finishedWhileDisplayLocked =
     91        getComputedStyle(target).height == '0px';
     92  });
     93  await waitForAnimationFrames(1);
     94  document.getElementById("spacer").style.height = "300vh";
     95  // Advance to just shy of the effect end.
     96  animation.currentTime = 1999;
     97  assert_approx_equals(
     98      parseFloat(getComputedStyle(target).opacity), 0.999, 1e-6,
     99                'Computed style is updated even when the animation is ' +
    100                'running in a content visibility subtree');
    101  // Advancing frames should not resolve the finished promise.
    102  await waitForAnimationFrames(3);
    103  document.getElementById("spacer").style.height = "0vh";
    104  // Now we can resolve the finished promise.
    105  await animation.finished;
    106  assert_equals(finishedWhileDisplayLocked, false);
    107 }, 'The finished promise does not resolve due to the normal passage of time  ' +
    108   'for a CSS animation in a content visibility subtree');
    109 
    110 promise_test(async t => {
    111  const container = document.getElementById('container');
    112  await waitForAnimationFrames(1);
    113  const target = createAnimatingElement(t, 'transition');
    114  await waitForAnimationFrames(1);
    115  target.style.opacity = 0;
    116  const animation = target.getAnimations()[0];
    117  await animation.ready;
    118  let finishedWhileDisplayLocked = false;
    119  animation.finished.then(() => {
    120    finishedWhileDisplayLocked =
    121        getComputedStyle(target).height == '0px';
    122  });
    123  await waitForAnimationFrames(1);
    124  document.getElementById("spacer").style.height = "300vh";
    125  // Advance to just shy of the effect end.
    126  animation.currentTime = 999;
    127  assert_approx_equals(
    128      parseFloat(getComputedStyle(target).opacity), 0.001, 1e-6,
    129                'Computed style is updated even when the animation is ' +
    130                'running in a content visibility subtree');
    131  // Advancing frames should not resolve the finished promise.
    132  await waitForAnimationFrames(3);
    133  document.getElementById("spacer").style.height = "0vh";
    134  // Now we can resolve the finished promise.
    135  await animation.finished;
    136  assert_equals(finishedWhileDisplayLocked, false);
    137 }, 'The finished promise does not resolve due to the normal passage of time  ' +
    138   'for a CSS transition in a content visibility subtree');
    139 
    140 promise_test(async t => {
    141  const container = document.getElementById('container');
    142  const target = createAnimatingElement(t, 'animate');
    143  const animation = target.getAnimations()[0];
    144  target.className = '';
    145  document.getElementById("spacer").style.height = "300vh";
    146  assert_equals(target.getAnimations().length, 0);
    147 
    148  // Though originally a CSS animation, it is no longer associated with
    149  // CSS rules and no longer has an owning element. It now behaves like a
    150  // programmatic web animation. Animation playback events (but not CSS
    151  // animation events) should be dispatched and promises resolved despite
    152  // being in a content visibility subtree.
    153 
    154  let cssAnimationEndEvent = false;
    155  target.addEventListener('animationend', () => {
    156    cssAnimationEndEvent = true;
    157  });
    158 
    159  let animationFinishEvent = false;
    160  animation.addEventListener('finish', () => {
    161    animationFinishEvent = true;
    162  });
    163 
    164  let animationFinished = false;
    165  animation.finished.then(() => {
    166    animationFinished = true;
    167  });
    168 
    169  animation.play();
    170  assert_equals(target.getAnimations().length, 1);
    171 
    172  animation.currentTime = 1999;
    173  await animation.ready;
    174  await waitForAnimationFrames(2);
    175 
    176  assert_true(animationFinishEvent,
    177              'Animation event not blocked on content visibility subtree if ' +
    178              'no owning element');
    179  assert_true(animationFinished,
    180              'Finished promise not blocked on content visibility subtree if ' +
    181              'no owning element');
    182  assert_false(cssAnimationEndEvent,
    183              'CSS animation events should not be dispatched if there is no ' +
    184              'owning element');
    185 }, 'Events and promises are handled normally for animations without an ' +
    186   'owning element');
    187 
    188 promise_test(async t => {
    189  // The animation is hidden when it is created.
    190  document.getElementById("spacer").style.height = "300vh";
    191  const container = document.getElementById('container');
    192  const target = createAnimatingElement(t, 'animate');
    193  const animation = target.getAnimations()[0];
    194  await waitForAnimationFrames(2);
    195  // Make this animation no longer associated with its owning element.
    196  target.className = '';
    197  assert_equals(target.getAnimations().length, 0);
    198 
    199  // Though originally a CSS animation, it is no longer associated with
    200  // CSS rules and no longer has an owning element. It now behaves like a
    201  // programmatic web animation. Animation playback events (but not CSS
    202  // animation events) should be dispatched and promises resolved despite
    203  // being in a content visibility subtree.
    204 
    205  let cssAnimationEndEvent = false;
    206  target.addEventListener('animationend', () => {
    207    cssAnimationEndEvent = true;
    208  });
    209 
    210  let animationFinishEvent = false;
    211  animation.addEventListener('finish', () => {
    212    animationFinishEvent = true;
    213  });
    214 
    215  let animationFinished = false;
    216  animation.finished.then(() => {
    217    animationFinished = true;
    218  });
    219 
    220  animation.play();
    221  assert_equals(target.getAnimations().length, 1);
    222 
    223  animation.currentTime = 1999;
    224  await animation.ready;
    225  await waitForAnimationFrames(2);
    226 
    227  assert_true(animationFinishEvent,
    228              'Animation event not blocked on content visibility subtree if ' +
    229              'no owning element');
    230  assert_true(animationFinished,
    231              'Finished promise not blocked on content visibility subtree if ' +
    232              'no owning element');
    233  assert_false(cssAnimationEndEvent,
    234              'CSS animation events should not be dispatched if there is no ' +
    235              'owning element');
    236 }, 'CSS animations without an owning element should handle events and promises ' +
    237              'normally, even c-v value does change');
    238 
    239 </script>