Bug 1519553 - Add test that we don't round subpixel scroll anchoring adjustments. r=dholbert
authorRyan Hunt <rhunt@eqrion.net>
Thu, 07 Feb 2019 20:40:32 -0600
changeset 459662 31252f85aa36b976c83946f9bdf5b6ca715860ae
parent 459661 e7698adc8e9038b76896fe20dcd740a5093720b1
child 459663 b4ab57f9c0cb57f93a6ec6fd8a5bf45d54ebfffa
push id35564
push userccoroiu@mozilla.com
push dateSat, 16 Feb 2019 09:37:16 +0000
treeherdermozilla-central@7ab4a0c9980f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1519553
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1519553 - Add test that we don't round subpixel scroll anchoring adjustments. r=dholbert This test might be overkill, but I was tired when writing it and couldn't think of a better way. It feels like there should be, though. Differential Revision: https://phabricator.services.mozilla.com/D19108
testing/web-platform/tests/css/css-scroll-anchoring/device-pixel-adjustment.html
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-anchoring/device-pixel-adjustment.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-scroll-anchoring-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+
+body {
+    height: 200vh;
+}
+#anchor {
+    width: 100px;
+    height: 100px;
+    background-color: blue;
+}
+
+</style>
+<div id="expander"></div>
+<div id="anchor"></div>
+<script>
+
+// This tests that scroll anchor adjustments can happen by quantities smaller
+// than a device pixel.
+//
+// Unfortunately, we can't test this by simply reading 'scrollTop', because
+// 'scrollTop' may be rounded to the nearest CSS pixel. So, to test that
+// subpixel adjustments can in fact happen, we repeatedly trigger a scroll
+// adjustment in a way that would produce a different final .scrollTop value,
+// depending on whether or not we rounded each adjustment as we apply it.
+
+test(() => {
+    let scroller = document.scrollingElement;
+    let expander = document.querySelector("#expander");
+    let anchor = document.querySelector("#anchor");
+    const initialTop = 10;
+
+    // Scroll 10px to activate scroll anchoring
+    scroller.scrollTop = initialTop;
+
+    // Helper to insert a div with specified height before the anchor node
+    function addChild(height) {
+        let child = document.createElement("div");
+        child.style.height = `${height}px`;
+        anchor.before(child);
+    }
+
+    // Calculate what fraction of a CSS pixel corresponds to one device pixel
+    let devicePixel = 1.0 / window.devicePixelRatio;
+    assert_true(devicePixel <= 1.0, "there should be more device pixels than CSS pixels");
+
+    // The 0.5 is an arbitrary scale when creating the subpixel delta
+    let delta = 0.5 * devicePixel;
+
+    // To help us check for for premature rounding of adjustments, we'll
+    // trigger "count" subpixel adjustments of size "delta", where "count" is
+    // the first positive integer such that:
+    //   round(count * delta) != count * round(delta)
+    // As round(X) and count are integers, this happens when:
+    //   count * delta = count * round(delta) +/- 1
+    // Solving for count:
+    //   count = 1 / abs(delta - round(delta))
+    // Note that we don't need to worry about the denominator being zero, as:
+    //   0 < devicePixel <= 1
+    // And so halving devicePixel should never yield a whole number.
+    let count = 1 / Math.abs(delta - Math.round(delta));
+
+    for (let i = 0; i < count; i++) {
+        addChild(delta);
+        // Trigger an anchor adjustment by forcing a layout flush
+        scroller.scrollTop;
+    }
+
+    let destination = Math.round(initialTop + delta * count);
+    assert_equals(scroller.scrollTop, destination,
+        `adjusting by ${delta}px, ${count} times, should be the same as adjusting by ${delta * count}px, once.`);
+}, "Test that scroll anchor adjustments can happen by a sub device-pixel amount.");
+
+</script>