Bug 1367568 part 4: Add mochitest to ensure we don't reflow too much for "overflow" changes on <body>. r?bz draft
authorDaniel Holbert <dholbert@cs.stanford.edu>
Thu, 25 May 2017 18:27:04 -0400
changeset 584723 d295710a73a0b88e933aa92efca92f275cf1e291
parent 584693 0af22013e9ee79a8034b04b0f8564c3f00d5969b
child 630494 1ad0edfd9f15e8e8ea0ffe62a174fe17e5446273
push id60860
push userdholbert@mozilla.com
push dateThu, 25 May 2017 22:27:16 +0000
reviewersbz
bugs1367568
milestone55.0a1
Bug 1367568 part 4: Add mochitest to ensure we don't reflow too much for "overflow" changes on <body>. r?bz MozReview-Commit-ID: KD0nv0ckKu
layout/style/test/mochitest.ini
layout/style/test/test_viewport_scrollbar_causing_reflow.html
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -307,16 +307,17 @@ skip-if = toolkit == 'android' # bug 775
 [test_value_computation.html]
 skip-if = toolkit == 'android'
 [test_value_storage.html]
 [test_variable_serialization_computed.html]
 [test_variable_serialization_specified.html]
 [test_variables.html]
 support-files = support/external-variable-url.css
 [test_video_object_fit.html]
+[test_viewport_scrollbar_causing_reflow.html]
 [test_viewport_units.html]
 [test_visited_image_loading.html]
 skip-if = (toolkit == 'android' || stylo) # TIMED_OUT for android, timeout bug 1328511 for stylo
 [test_visited_image_loading_empty.html]
 skip-if = (toolkit == 'android' || stylo) # TIMED_OUT for android, timeout bug 1328511 for stylo
 [test_visited_lying.html]
 skip-if = (toolkit == 'android' || stylo) # TIMED_OUT for android, timeout bug 1328511 for stylo
 [test_visited_pref.html]
new file mode 100644
--- /dev/null
+++ b/layout/style/test/test_viewport_scrollbar_causing_reflow.html
@@ -0,0 +1,125 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1367568
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1367568</title>
+  <script type="application/javascript" 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: -->
+  <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 type="application/javascript">
+"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");
+
+  // Expected maximum number of frames reflowed for "overflow" changes
+  // (+2 is to allow for reflowing scrollbars themselves):
+  const expectedMax = count + 2;
+
+  // 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>