summaryrefslogtreecommitdiffstats
path: root/layout/style/test/test_viewport_scrollbar_causing_reflow.html
blob: ced14f352a67822d30a5e083965393607dfa9f50 (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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1367568
-->
<head>
  <meta charset="utf-8">
  <title>Test for Bug 1367568</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug 1367568</a>
<div id="content">
  <!-- Some fixed-width divs that we shouldn't have to reflow when the viewport
       changes. More than 5 so that our leeway for scrollbar parts doesn't
       accidentally cause the test to pass -->
  <div style="width: 100px">fixed-width <div>(child)</div></div>
  <div style="width: 100px">fixed-width <div>(child)</div></div>
  <div style="width: 100px">fixed-width <div>(child)</div></div>
  <div style="width: 100px">fixed-width <div>(child)</div></div>
  <div style="width: 100px">fixed-width <div>(child)</div></div>
  <div style="width: 100px">fixed-width <div>(child)</div></div>
  <div style="position: absolute; width: 150px">
    abs-fixed-width
    <div>(child)</div>
  </div>
</div>
<pre id="test">
<script>
"use strict";

/** Test for Bug 1367568 **/

/**
 * This test verifies that "overflow" changes on the <body> don't cause
 * an unnecessarily large amount of reflow.
 */

// Vars used in setStyleAndMeasure that we really only have to look up once:
const gUtils = SpecialPowers.getDOMWindowUtils(window);

function setStyleAndMeasure(initialStyle, finalStyle) {
  is(document.body.style.length, 0,
     "Bug in test - body should start with empty style");
  let unusedVal = document.body.offsetHeight; // flush layout
  let constructCount = gUtils.framesConstructed;

  document.body.style = initialStyle;
  unusedVal = document.body.offsetHeight; // flush layout
  let reflowCountBeforeTweak = gUtils.framesReflowed;

  document.body.style = finalStyle;
  unusedVal = document.body.offsetHeight; // flush layout
  let reflowCountAfterTweak = gUtils.framesReflowed;

  // Clean up:
  document.body.style = "";

  is(gUtils.framesConstructed, constructCount,
     "Style tweak shouldn't have triggered frame construction");

  // ...and return the delta:
  return reflowCountAfterTweak - reflowCountBeforeTweak;
}

function main() {
  // First, we sanity-check that our measurement make sense -- if we leave
  // styles unchanged, we should measure no frames being reflowed:
  let count = setStyleAndMeasure("width: 50px; height: 80px",
                                 "width: 50px; height: 80px");
  is(count, 0,
     "Shouldn't reflow anything when we leave 'width' & 'height' unchanged");

  // Now: see how many frames are reflowed when the "width" & "height" change.
  // We'll use this as the reference when measuring reflow counts for various
  // changes to "overflow" below.
  count = setStyleAndMeasure("width: 50px; height: 80px",
                             "width: 90px; height: 60px");
  ok(count > 0,
     "Should reflow some frames when 'width' & 'height' change");

  const scrollbarsHaveButtons = navigator.platform.includes("Win");
  // This is to allow for reflowing scrollbar parts themselves.
  const scrollbarReflows = scrollbarsHaveButtons ? 5 : 2;
  // Expected maximum number of frames reflowed for "overflow" changes
  const expectedMax = count + scrollbarReflows;

  // Shared ending for messages in all ok() checks below:
  const messageSuffix =
    " shouldn't be greater than count for tweaking width/height on body (" +
    expectedMax + ")";

  // OK, here is where the relevant tests actually begin!!
  // See how many frames we reflow for various tweaks to "overflow" on
  // the body -- we expect the count to be no larger than |expectedMax|.
  count = setStyleAndMeasure("", "overflow: scroll");
  ok(count <= expectedMax,
     "Reflow count when setting 'overflow: scroll' on body (" + count + ")" +
     messageSuffix);

  count = setStyleAndMeasure("", "overflow: hidden");
  ok(count <= expectedMax,
     "Reflow count when setting 'overflow: hidden' on body (" + count + ")" +
     messageSuffix);

  // Test removal of "overflow: scroll":
  count = setStyleAndMeasure("overflow: scroll", "");
  ok(count <= expectedMax,
     "Reflow count when removing 'overflow: scroll' from body (" + count + ")" +
     messageSuffix);

  count = setStyleAndMeasure("overflow: hidden", "");
  ok(count <= expectedMax,
     "Reflow count when removing 'overflow: hidden' from body (" + count + ")" +
     messageSuffix);

  // Test change between two non-'visible' overflow values:
  count = setStyleAndMeasure("overflow: scroll", "overflow: hidden");
  ok(count <= expectedMax,
     "Reflow count when changing 'overflow' on body (" + count + ")" +
     messageSuffix);
}

main();

</script>
</pre>
</body>
</html>