tor-browser

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

inactive-timeline.https.html (5164B)


      1 <!DOCTYPE html>
      2 <meta charset=utf-8>
      3 <title>Correctness of worklet animation state when timeline becomes newly
      4         active or inactive.</title>
      5 <link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
      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="common.js"></script>
     10 <style>
     11  .scroller {
     12    overflow: auto;
     13    height: 100px;
     14    width: 100px;
     15  }
     16  .contents {
     17    height: 1000px;
     18    width: 100%;
     19  }
     20 </style>
     21 <body>
     22 <div id="log"></div>
     23 <script>
     24 'use strict';
     25 
     26 function createScroller(test) {
     27  var scroller = createDiv(test);
     28  scroller.innerHTML = "<div class='contents'></div>";
     29  scroller.classList.add('scroller');
     30  return scroller;
     31 }
     32 
     33 function createScrollLinkedWorkletAnimation(test) {
     34  const timeline = new ScrollTimeline({
     35    scrollSource: createScroller(test),
     36  });
     37  const DURATION = 1000; // ms
     38  const KEYFRAMES = { transform: ['translateY(100px)', 'translateY(200px)'] };
     39  return new WorkletAnimation('passthrough', new KeyframeEffect(createDiv(test),
     40        KEYFRAMES, DURATION), timeline);
     41 }
     42 
     43 setup(setupAndRegisterTests, {explicit_done: true});
     44 
     45 function setupAndRegisterTests() {
     46  registerPassthroughAnimator().then(() => {
     47 
     48    promise_test(async t => {
     49      const animation = createScrollLinkedWorkletAnimation(t);
     50      const scroller = animation.timeline.scrollSource;
     51      const target = animation.effect.target;
     52 
     53      // There is no direct way to control when local times of composited
     54      // animations are synced to the main thread. This test uses another
     55      // composited worklet animation with an always active timeline as an
     56      // indicator of when the sync is ready. The sync is done when animation
     57      // effect's output has changed as a result of advancing the timeline.
     58      const animationRef = createScrollLinkedWorkletAnimation(t);
     59      const scrollerRef = animationRef.timeline.scrollSource;
     60      const targetRef = animationRef.effect.target;
     61 
     62      const maxScroll = scroller.scrollHeight - scroller.clientHeight;
     63      scroller.scrollTop = 0.2 * maxScroll;
     64 
     65      // Make the timeline inactive.
     66      scroller.style.display = "none"
     67      // Force relayout.
     68      scroller.scrollTop;
     69 
     70      animation.play();
     71      animationRef.play();
     72      assert_equals(animation.currentTime, null,
     73        'Initial current time must be unresolved in idle state.');
     74      assert_equals(animation.startTime, null,
     75        'Initial start time must be unresolved in idle state.');
     76      waitForAnimationFrameWithCondition(_=> {
     77        return animation.playState == "running"
     78      });
     79      assert_equals(animation.currentTime, null,
     80        'Initial current time must be unresolved in playing state.');
     81      assert_equals(animation.startTime, null,
     82        'Initial start time must be unresolved in playing state.');
     83 
     84      scrollerRef.scrollTop = 0.2 * maxScroll;
     85 
     86      // Wait until local times are synced back to the main thread.
     87      await waitForAnimationFrameWithCondition(_ => {
     88        return animationRef.effect.getComputedTiming().localTime == 200;
     89      });
     90 
     91      assert_equals(animation.effect.getComputedTiming().localTime, null,
     92        'The underlying effect local time must be undefined while the ' +
     93        'timeline is inactive.');
     94 
     95      // Make the timeline active.
     96      scroller.style.display = "";
     97      // Wait for new animation frame  which allows the timeline to compute new
     98      // current time.
     99      await waitForNextFrame();
    100 
    101      assert_times_equal(animation.currentTime, 200,
    102        'Current time must be initialized.');
    103      assert_times_equal(animation.startTime, 0,
    104        'Start time must be initialized.');
    105 
    106      scrollerRef.scrollTop = 0.4 * maxScroll;
    107      // Wait until local times are synced back to the main thread.
    108      await waitForAnimationFrameWithCondition(_ => {
    109        return animationRef.effect.getComputedTiming().localTime == 400;
    110      });
    111      assert_times_equal(animation.effect.getComputedTiming().localTime, 200,
    112        'When the timeline becomes newly active, the underlying effect\'s ' +
    113        'timing should be properly updated.');
    114 
    115      // Make the timeline inactive again.
    116      scroller.style.display = "none"
    117      await waitForNextFrame();
    118 
    119      assert_times_equal(animation.currentTime, 200,
    120        'Current time must be the previous current time.');
    121      assert_equals(animation.startTime, null,
    122        'Initial start time must be unresolved.');
    123 
    124      scrollerRef.scrollTop = 0.6 * maxScroll;
    125      // Wait until local times are synced back to the main thread.
    126      await waitForAnimationFrameWithCondition(_ => {
    127        return animationRef.effect.getComputedTiming().localTime == 600;
    128      });
    129 
    130      assert_times_equal(animation.effect.getComputedTiming().localTime, 200,
    131        'When the timeline becomes newly inactive, the underlying effect\'s ' +
    132        'timing should stay unchanged.');
    133    }, 'When timeline time becomes inactive previous current time must be ' +
    134       'the current time and start time unresolved');
    135    done();
    136  });
    137 }
    138 </script>
    139 </body>