Bug 1839315: part 4) Link from `SheetLoadData::mWasAlternate` to spec. r=emilio DONTBUILD
[gecko.git] / layout / style / test / test_flexbox_reflow_counts.html
bloba8f4913f7d8d7e43f8d00bb06da0f97761a0d573
1 <!DOCTYPE HTML>
2 <html>
3 <!--
4 https://bugzilla.mozilla.org/show_bug.cgi?id=1142686
5 -->
6 <head>
7 <meta charset="utf-8">
8 <title>Test for Bug 1142686</title>
9 <script src="/tests/SimpleTest/SimpleTest.js"></script>
10 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
11 <style>
12 .flex {
13 display: flex;
15 #outerFlex {
16 border: 1px solid black;
18 </style>
19 </head>
20 <body>
21 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1142686">Mozilla Bug 1142686</a>
22 <div id="display">
23 <div id="content">
24 <div class="flex" id="outerFlex">
25 <div class="flex" id="midFlex">
26 <div id="innerBlock">
27 </div>
28 </div>
29 </div>
30 </div>
31 </div>
32 <pre id="test">
33 <script type="application/javascript">
34 "use strict";
36 /** Test for Bug 1142686 **/
38 /**
39 * This test checks how many reflows are required, when we make a change inside
40 * a set of two nested flex containers, with various styles applied to
41 * the containers & innermost child. Some flex layout operations require two
42 * passes (which can cause exponential blowup). This test is intended to verify
43 * that certain configurations do *not* require two-pass layout, by comparing
44 * the reflow-count for a more-complex scenario against a less-complex scenario.
46 * We have two nested flex containers around an initially-empty block. For each
47 * measurement, we put some text in the block, and we see how many frame-reflow
48 * operations occur as a result.
51 const gUtils = SpecialPowers.getDOMWindowUtils(window);
53 // The elements:
54 const gOuterFlex = document.getElementById("outerFlex");
55 const gMidFlex = document.getElementById("midFlex");
56 const gInnerBlock = document.getElementById("innerBlock");
58 // This cleanup helper-function removes all children from 'parent'
59 // except for 'childToPreserve' (if specified)
60 function removeChildrenExcept(parent, childToPreserve)
62 if (childToPreserve && childToPreserve.parentNode != parent) {
63 // This is just a sanity/integrity-check -- if this fails, it's probably a
64 // bug in this test rather than in the code. I'm not checking this via
65 // e.g. "is(childToPreserve.parentNode, parent)", because this *should*
66 // always pass, and each "pass" is not interesting here since it's a
67 // sanity-check. It's only interesting/noteworthy if it fails. So, to
68 // avoid bloating this test's passed-subtest-count & output, we only bother
69 // reporting on this in the case where something's wrong.
70 ok(false, "bug in test; 'childToPreserve' should be child of 'parent'");
73 // For simplicity, we just remove *all children* and then reappend
74 // childToPreserve as the sole child.
75 while (parent.firstChild) {
76 parent.removeChild(parent.firstChild);
78 if (childToPreserve) {
79 parent.appendChild(childToPreserve);
83 // Appends 'childCount' new children to 'parent'
84 function addNChildren(parent, childCount)
86 for (let i = 0; i < childCount; i++) {
87 let newChild = document.createElement("div");
88 // Give the new child some text so it's got a nonzero content-size:
89 newChild.append("a");
90 parent.appendChild(newChild);
94 // Undoes whatever styling customizations and DOM insertions that a given
95 // testcase has done, to prepare for running the next testcase.
96 function cleanup()
98 gOuterFlex.style = gMidFlex.style = gInnerBlock.style = "";
99 removeChildrenExcept(gInnerBlock);
100 removeChildrenExcept(gMidFlex, gInnerBlock);
101 removeChildrenExcept(gOuterFlex, gMidFlex);
104 // Each testcase here has a label (used in test output), a function to set up
105 // the testcase, and (optionally) a function to set up the reference case.
106 let gTestcases = [
108 label : "border on flex items",
109 addTestStyle : function() {
110 gMidFlex.style.border = gInnerBlock.style.border = "3px solid black";
114 label : "padding on flex items",
115 addTestStyle : function() {
116 gMidFlex.style.padding = gInnerBlock.style.padding = "5px";
120 label : "margin on flex items",
121 addTestStyle : function() {
122 gMidFlex.style.margin = gInnerBlock.style.margin = "2px";
126 // When we make a change in one flex item, the number of reflows should not
127 // scale with its number of siblings (as long as those siblings' sizes
128 // aren't impacted by the change):
129 label : "additional flex items in outer flex container",
131 // Compare 5 bonus flex items vs. 1 bonus flex item:
132 addTestStyle : function() {
133 addNChildren(gOuterFlex, 5);
135 addReferenceStyle : function() {
136 addNChildren(gOuterFlex, 1);
140 // (As above, but now the bonus flex items are one step deeper in the tree,
141 // on the nested flex container rather than the outer one)
142 label : "additional flex items in nested flex container",
143 addTestStyle : function() {
144 addNChildren(gMidFlex, 5);
146 addReferenceStyle : function() {
147 addNChildren(gMidFlex, 1);
152 // Flush layout & return the global frame-reflow-count
153 function getReflowCount()
155 let unusedVal = gOuterFlex.offsetHeight; // flush layout
156 return gUtils.framesReflowed;
159 // This function adds some text inside of gInnerBlock, and returns the number
160 // of frames that need to be reflowed as a result.
161 function makeTweakAndCountReflows()
163 let beforeCount = getReflowCount();
164 gInnerBlock.appendChild(document.createTextNode("hello"));
165 let afterCount = getReflowCount();
167 let numReflows = afterCount - beforeCount;
168 if (numReflows <= 0) {
169 ok(false, "something's wrong -- we should've reflowed *something*");
171 return numReflows;
174 // Given a testcase (from gTestcases), this function verifies that the
175 // testcase scenario requires the same number of reflows as the reference
176 // scenario.
177 function runOneTest(aTestcase)
179 aTestcase.addTestStyle();
180 let numTestcaseReflows = makeTweakAndCountReflows();
181 cleanup();
183 if (aTestcase.addReferenceStyle) {
184 aTestcase.addReferenceStyle();
186 let numReferenceReflows = makeTweakAndCountReflows();
187 cleanup();
189 is(numTestcaseReflows, numReferenceReflows,
190 "Testcase & reference case should require same number of reflows" +
191 " (testcase label: '" + aTestcase.label + "')");
194 gTestcases.forEach(runOneTest);
196 </script>
197 </pre>
198 </body>
199 </html>