tor-browser

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

scroll-timeline-multi-pass.tentative.html (3766B)


      1 <!DOCTYPE html>
      2 <title>ScrollTimelines may trigger multiple style/layout passes</title>
      3 <link rel="help" src="https://github.com/w3c/csswg-drafts/issues/5261">
      4 <link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#avoiding-cycles">
      5 <script src="/resources/testharness.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <script src="/web-animations/testcommon.js"></script>
      8 <script src="support/testcommon.js"></script>
      9 <style>
     10  @keyframes expand_width {
     11    from { width: 100px; }
     12    to { width: 100px; }
     13  }
     14  @keyframes expand_height {
     15    from { height: 100px; }
     16    to { height: 100px; }
     17  }
     18  main {
     19    height: 0px;
     20    overflow: hidden;
     21    timeline-scope: --timeline1, --timeline2;
     22  }
     23  .scroller {
     24    height: 100px;
     25    overflow: scroll;
     26  }
     27  .scroller > div {
     28    height: 200px;
     29  }
     30  #element1 {
     31    width: 1px;
     32    animation: expand_width 10s;
     33    animation-timeline: --timeline1;
     34  }
     35  #element2 {
     36    height: 1px;
     37    animation: expand_height 10s;
     38    animation-timeline: --timeline2;
     39  }
     40 </style>
     41 <main id=main>
     42  <div id=element1></div>
     43  <div>
     44    <div id=element2></div>
     45  </div>
     46 </main>
     47 <script>
     48    setup(assert_implements_animation_timeline);
     49 
     50    function insertScroller(timeline_name) {
     51      let scroller = document.createElement('div');
     52      scroller.classList.add('scroller');
     53      scroller.style.scrollTimeline = timeline_name;
     54      scroller.append(document.createElement('div'));
     55      main.insertBefore(scroller, element1);
     56    }
     57 
     58    promise_test(async () => {
     59      await waitForNextFrame();
     60 
     61      let events1 = [];
     62      let events2 = [];
     63 
     64      insertScroller('--timeline1');
     65      // Even though the scroller was just inserted into the DOM, |timeline1|
     66      // remains inactive until the next frame.
     67      //
     68      // https://drafts.csswg.org/scroll-animations-1/#avoiding-cycles
     69      assert_equals(getComputedStyle(element1).width, '1px');
     70      (new ResizeObserver(entries => {
     71        events1.push(entries);
     72        insertScroller('--timeline2');
     73        assert_equals(getComputedStyle(element2).height, '1px');
     74      })).observe(element1);
     75 
     76      (new ResizeObserver(entries => {
     77        events2.push(entries);
     78      })).observe(element2);
     79 
     80      await waitForNextFrame();
     81 
     82      // According to the basic rules of the spec [1], the timeline is
     83      // inactive at the time the resize observer event was delivered, because
     84      // #scroller1 did not have a layout box at the time style recalc for
     85      // #element1 happened.
     86      //
     87      // However, an additional style/layout pass should take place
     88      // (before resize observer deliveries) if we detect new ScrollTimelines
     89      // in this situation, hence we ultimately do expect the animation to
     90      // apply [2].
     91      //
     92      // [1] https://drafts.csswg.org/scroll-animations-1/#avoiding-cycles
     93      // [2] https://github.com/w3c/csswg-drafts/issues/5261
     94      assert_equals(events1.length, 1);
     95      assert_equals(events1[0].length, 1);
     96      assert_equals(events1[0][0].contentBoxSize.length, 1);
     97      assert_equals(events1[0][0].contentBoxSize[0].inlineSize, 100);
     98 
     99      // ScrollTimelines created during the ResizeObserver should remain
    100      // inactive during the frame they're created, so the ResizeObserver
    101      // event should not reflect the animated value.
    102      assert_equals(events2.length, 1);
    103      assert_equals(events2[0].length, 1);
    104      assert_equals(events2[0][0].contentBoxSize.length, 1);
    105      assert_equals(events2[0][0].contentBoxSize[0].blockSize, 1);
    106 
    107      assert_equals(getComputedStyle(element1).width, '100px');
    108 
    109      await waitForNextFrame();
    110      assert_equals(getComputedStyle(element2).height, '100px');
    111    }, 'Multiple style/layout passes occur when necessary');
    112 </script>