tor-browser

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

test_restyles_in_smil_animation.html (4909B)


      1 <!doctype html>
      2 <head>
      3 <meta charset=utf-8>
      4 <title>Tests restyles in smil animation</title>
      5 <script src="/tests/SimpleTest/SimpleTest.js"></script>
      6 <script src="/tests/SimpleTest/paint_listener.js"></script>
      7 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
      8 </head>
      9 <body>
     10 
     11 <div id="target-div">
     12  <svg>
     13    <rect id="svg-rect" width="100%" height="100%" fill="lime"/>
     14  </svg>
     15 </div>
     16 
     17 <script>
     18 "use strict";
     19 
     20 // Waits for |frameCount| requestAnimationFrame callbacks.
     21 // Returns the number of frame actually waited.
     22 function waitForAnimationFrames(frameCount) {
     23  return new Promise(function(resolve, reject) {
     24    let previousTime = document.timeline.currentTime;
     25    let framesWaited = 0;
     26    function handleFrame() {
     27      // SMIL uses a time resolution of 1ms but our software-based vsync timer
     28      // sometimes produces ticks with an interval of less than 1ms. In such
     29      // cases we will skip restyling for SMIL animations since the SMIL time
     30      // will not change.
     31      //
     32      // In the following we attempt to detect such situations and wait an
     33      // additional frame when we detect it. However, the detection is not
     34      // completely accurate since it uses the timeline time which is based on
     35      // the navigation start time whereas the SMIL start time is based on the
     36      // refresh driver time.
     37      //
     38      // To account for this inaccuracy the Promise returned by this method
     39      // resolves with the number of frames waited with the additional frames.
     40      // This can be used by the call site to add a suitable tolerance to the
     41      // number of restylings it expects to happen. For example, if a call site
     42      // is anticipating each animation frame to cause restyling, then the
     43      // number of restylings, x, it should expect is frameCount <= x <=
     44      // framesWaited.
     45      const difference = document.timeline.currentTime - previousTime;
     46      framesWaited++;
     47      if (difference >= 1.0 && --frameCount <= 0) {
     48        resolve(framesWaited);
     49        return;
     50      }
     51 
     52      previousTime = document.timeline.currentTime;
     53      window.requestAnimationFrame(handleFrame); // wait another frame
     54    }
     55    window.requestAnimationFrame(handleFrame);
     56  });
     57 }
     58 
     59 // Returns an object consisting of observed styling count and the number of
     60 // frames actually waited because we detected a possibly overflapping SMIL
     61 // time.
     62 function observeStyling(frameCount) {
     63  let priorAnimationTriggeredRestyles = SpecialPowers.DOMWindowUtils.animationTriggeredRestyles;
     64 
     65  return new Promise(function(resolve) {
     66    return waitForAnimationFrames(frameCount).then(framesWaited => {
     67      const restyleCount = SpecialPowers.DOMWindowUtils.animationTriggeredRestyles - priorAnimationTriggeredRestyles;
     68      resolve({
     69        stylingCount: restyleCount,
     70        framesWaited: framesWaited,
     71      });
     72    });
     73  });
     74 }
     75 
     76 function ensureElementRemoval(aElement) {
     77  return new Promise(function(resolve) {
     78    aElement.remove();
     79    waitForAllPaintsFlushed(resolve);
     80  });
     81 }
     82 
     83 function waitForPaintFlushed() {
     84  return new Promise(function(resolve) {
     85    waitForAllPaintsFlushed(resolve);
     86  });
     87 }
     88 
     89 SimpleTest.waitForExplicitFinish();
     90 
     91 add_task(async function smil_is_in_display_none_subtree() {
     92  await waitForPaintFlushed();
     93 
     94  var animate =
     95    document.createElementNS("http://www.w3.org/2000/svg", "animate");
     96  animate.setAttribute("attributeType", "XML");
     97  animate.setAttribute("attributeName", "fill");
     98  animate.setAttribute("values", "red;lime");
     99  animate.setAttribute("dur", "1s");
    100  animate.setAttribute("repeatCount", "indefinite");
    101  document.getElementById("svg-rect").appendChild(animate);
    102 
    103  await waitForAnimationFrames(2);
    104 
    105  let result = await observeStyling(5);
    106  // FIXME: Bug 866411: SMIL animations sometimes skip restyles when the target
    107  // element is newly associated with an nsIFrame.
    108  ok(result.stylingCount >= 4 &&
    109     result.stylingCount <= result.framesWaited,
    110     `should restyle in most frames (got ${result.stylingCount} restyles ` +
    111     `over ${result.framesWaited} frames, expected 4~${result.framesWaited})`);
    112 
    113  var div = document.getElementById("target-div");
    114 
    115  div.style.display = "none";
    116  getComputedStyle(div).display;
    117  await waitForPaintFlushed();
    118 
    119  result = await observeStyling(5);
    120  is(result.stylingCount, 0, "should never restyle if display:none");
    121 
    122  div.style.display = "";
    123  getComputedStyle(div).display;
    124  await waitForAnimationFrames(2);
    125 
    126  result = await observeStyling(5);
    127  // FIXME: Bug 866411: SMIL animations sometimes skip restyles when the target
    128  // element is newly associated with an nsIFrame.
    129  ok(result.stylingCount >= 4 &&
    130     result.stylingCount <= result.framesWaited,
    131     `should restyle again (got ${result.stylingCount} restyles over ` +
    132     `${result.framesWaited} frames, expected 4~${result.framesWaited})`);
    133 
    134  await ensureElementRemoval(animate);
    135 });
    136 </script>
    137 </body>