summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/scroll-animations/css/scroll-timeline-multi-pass.tentative.html
blob: 403316ead0fed5072111d50b0673d57a95c99cf0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
<!DOCTYPE html>
<title>ScrollTimelines may trigger multiple style/layout passes</title>
<link rel="help" src="https://github.com/w3c/csswg-drafts/issues/5261">
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#avoiding-cycles">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<script src="support/testcommon.js"></script>
<style>
  @keyframes expand_width {
    from { width: 100px; }
    to { width: 100px; }
  }
  @keyframes expand_height {
    from { height: 100px; }
    to { height: 100px; }
  }
  main {
    height: 0px;
    overflow: hidden;
    timeline-scope: --timeline1, --timeline2;
  }
  .scroller {
    height: 100px;
    overflow: scroll;
  }
  .scroller > div {
    height: 200px;
  }
  #element1 {
    width: 1px;
    animation: expand_width 10s;
    animation-timeline: --timeline1;
  }
  #element2 {
    height: 1px;
    animation: expand_height 10s;
    animation-timeline: --timeline2;
  }
</style>
<main id=main>
  <div id=element1></div>
  <div>
    <div id=element2></div>
  </div>
</main>
<script>
    setup(assert_implements_animation_timeline);

    function insertScroller(timeline_name) {
      let scroller = document.createElement('div');
      scroller.classList.add('scroller');
      scroller.style.scrollTimeline = timeline_name;
      scroller.append(document.createElement('div'));
      main.insertBefore(scroller, element1);
    }

    promise_test(async () => {
      await waitForNextFrame();

      let events1 = [];
      let events2 = [];

      insertScroller('--timeline1');
      // Even though the scroller was just inserted into the DOM, |timeline1|
      // remains inactive until the next frame.
      //
      // https://drafts.csswg.org/scroll-animations-1/#avoiding-cycles
      assert_equals(getComputedStyle(element1).width, '1px');
      (new ResizeObserver(entries => {
        events1.push(entries);
        insertScroller('--timeline2');
        assert_equals(getComputedStyle(element2).height, '1px');
      })).observe(element1);

      (new ResizeObserver(entries => {
        events2.push(entries);
      })).observe(element2);

      await waitForNextFrame();

      // According to the basic rules of the spec [1], the timeline is
      // inactive at the time the resize observer event was delivered, because
      // #scroller1 did not have a layout box at the time style recalc for
      // #element1 happened.
      //
      // However, an additional style/layout pass should take place
      // (before resize observer deliveries) if we detect new ScrollTimelines
      // in this situation, hence we ultimately do expect the animation to
      // apply [2].
      //
      // [1] https://drafts.csswg.org/scroll-animations-1/#avoiding-cycles
      // [2] https://github.com/w3c/csswg-drafts/issues/5261
      assert_equals(events1.length, 1);
      assert_equals(events1[0].length, 1);
      assert_equals(events1[0][0].contentBoxSize.length, 1);
      assert_equals(events1[0][0].contentBoxSize[0].inlineSize, 100);

      // ScrollTimelines created during the ResizeObserver should remain
      // inactive during the frame they're created, so the ResizeObserver
      // event should not reflect the animated value.
      assert_equals(events2.length, 1);
      assert_equals(events2[0].length, 1);
      assert_equals(events2[0][0].contentBoxSize.length, 1);
      assert_equals(events2[0][0].contentBoxSize[0].blockSize, 1);

      assert_equals(getComputedStyle(element1).width, '100px');
      assert_equals(getComputedStyle(element2).height, '100px');
    }, 'Multiple style/layout passes occur when necessary');
</script>