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 17:53:29 -0400
changeset 584694 56939d4e6cd8ca018c3d0eec5b64776e136b4229
parent 584693 0af22013e9ee79a8034b04b0f8564c3f00d5969b
child 630478 e978d099fd203ac3d64c7f2fb728bdc9779f68d6
push id60842
push userdholbert@mozilla.com
push dateThu, 25 May 2017 21:53:59 +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: Je7d3btwHYP
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
@@ -308,16 +308,17 @@ skip-if = toolkit == 'android' # bug 775
 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_units.html]
+[test_viewport_scrollbar_causing_reflow.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]
 skip-if = (toolkit == 'android' || stylo) # TIMED_OUT for android, timeout bug 1328511 for stylo
new file mode 100644
--- /dev/null
+++ b/layout/style/test/test_viewport_scrollbar_causing_reflow.html
@@ -0,0 +1,121 @@
+<!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:100px">
+    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 don't cause excessive 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 + ")";
+
+  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>