summaryrefslogtreecommitdiffstats
path: root/layout/generic/test/test_flex_interrupt.html
blob: dfe4208f93eb248c95f804b5764d3652732c5c92 (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
<!doctype html>
<title>Test for bug 1579929</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<style>
  .container {
    display: flex;
    flex-direction: column;
    overflow-y: scroll;
  }
  #outer {
    width: 500px;
    height: 300px;
  }
</style>
<div class="container" id="outer">
  <div class="item" id="firstItem" style="width: 50px">
    <!--popuplated by script-->
  </div>
  <div class="container">
    <div class="container">
      <div class="container">
        <div class="container">
          <div class="container">
            <div class="item">Item</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
<script>
SimpleTest.waitForExplicitFinish();

// Globals/constants:

const gUtils = SpecialPowers.DOMWindowUtils;

// This needs to match/exceed nsPresContext::sInterruptChecksToSkip in order
// for us to actually be able to trigger the mHasPendingInterrupt=true codepath
// in this test.  Each of these "dummy" blocks will trigger a call to
// nsPresContext::CheckForInterrupt, and after 200, we'll actually trigger an
// interrupt.
const gInterruptCheckThreshold = 200;

// Expected to match the inline style="width:..." for #firstItem (we slowly
// increment it to trigger reflows):
let gFirstItemWidthPX = 50;

function main() {
  const outer = document.getElementById("outer");
  const firstItem = document.getElementById("firstItem");

  // Insert a bunch of elements to be sure we actually get interrupted.
  // (See description of gInterruptCheckThreshold above)
  for (let i = 0; i < gInterruptCheckThreshold; i++) {
    let dummyBlock = document.createElement("div");
    dummyBlock.innerText = "dummy";
    firstItem.appendChild(dummyBlock);
  }

  // Flush any pending relayout:
  outer.offsetHeight;

  // Take control of the refresh driver
  gUtils.advanceTimeAndRefresh(0);

  // Force reflow and store the "cost" (in num-frames-reflowed)
  const costOfNormalReflow = forceReflow();

  // Sanity-check: do that again and remeasure cost, to be sure it's stable:
  const costOfNormalReflow2 = forceReflow();
  is(costOfNormalReflow, costOfNormalReflow2,
     "Our forceReflow function is expected to reliably trigger " +
     "the same set of frames to be reflowed. If this fails, there's a " +
     "bug in the test, or non-determinism in layout code.");

  // Now, we force the next reflow to get interrupted, and then measure the
  // cost under those conditions:
  gUtils.forceReflowInterrupt();
  const costOfInterruptedReflow = forceReflow();

  // Hopefully the interrupted one was less expensive...
  ok(costOfInterruptedReflow <= costOfNormalReflow,
     "num frames reflowed in interrupted reflow (" +
     costOfInterruptedReflow +
     ") shouldn't exceed the num frames reflowed in normal reflow (" +
     costOfNormalReflow + ")");

  gUtils.restoreNormalRefresh();
  SimpleTest.finish();
}

// This function dirties firstItem's width, forces a reflow, and
// returns the number of frames that were reflowed as a result.
function forceReflow() {
  gFirstItemWidthPX++;
  firstItem.style.width = gFirstItemWidthPX + "px";

  const origFramesReflowed = gUtils.framesReflowed;
  gUtils.advanceTimeAndRefresh(0);
  return gUtils.framesReflowed - origFramesReflowed;
}

main();
</script>