Bug 1266833 - When the scroll position is clamped during a frame reconstruction, send a scroll offset update to APZ. r=tnikkel a=lizzard
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 02 May 2016 15:44:29 -0400
changeset 334898 3dd73104e8562b63b4832051b0a195d70a7da0b0
parent 334897 5aad362431f0fda920b5236c15e67c3e07b8aba0
child 334899 0b5925bf7d52ce1c785c8bf343c33eb5126e3609
push id1146
push userCallek@gmail.com
push dateMon, 25 Jul 2016 16:35:44 +0000
treeherdermozilla-release@a55778f9cd5a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel, lizzard
bugs1266833
milestone48.0a2
Bug 1266833 - When the scroll position is clamped during a frame reconstruction, send a scroll offset update to APZ. r=tnikkel a=lizzard MozReview-Commit-ID: 2UBM4AWWIVI
gfx/layers/apz/test/reftest/frame-reconstruction-scroll-clamping-ref.html
gfx/layers/apz/test/reftest/frame-reconstruction-scroll-clamping.html
gfx/layers/apz/test/reftest/reftest.list
layout/generic/nsGfxScrollFrame.cpp
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/reftest/frame-reconstruction-scroll-clamping-ref.html
@@ -0,0 +1,27 @@
+<html>
+<script>
+    function run() {
+        document.body.classList.toggle('noscroll');
+        document.getElementById('spacer').style.height = '100%';
+        // Scroll to the very end, including any fractional pixels
+        document.body.scrollTop = document.body.scrollTopMax + 1;
+    }
+</script>
+<style>
+    html, body {
+        margin: 0;
+        padding: 0;
+        background-color: green;
+    }
+
+    .noscroll {
+        overflow: hidden;
+        height: 100%;
+    }
+</style>
+<body onload="run()">
+ <div id="spacer" style="height: 5000px">
+  This is the top of the page.
+ </div>
+ This is the bottom of the page.
+</body>
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/reftest/frame-reconstruction-scroll-clamping.html
@@ -0,0 +1,53 @@
+<html class="reftest-wait">
+<!--
+For bug 1266833; syncing the scroll offset to APZ properly when the scroll
+position is clamped to a smaller value during a frame reconstruction.
+-->
+<script>
+    function run() {
+        document.body.scrollTop = document.body.scrollTopMax;
+
+        // Let the scroll position propagate to APZ before we do the frame
+        // reconstruction. Ideally we would wait for flushApzRepaints here but
+        // we don't have access to DOMWindowUtils in a reftest, so we just wait
+        // 100ms to approximate it. With bug 1266833 fixed, this test should
+        // never fail regardless of what this timeout value is.
+        setTimeout(frameReconstruction, 100);
+    }
+
+    function frameReconstruction() {
+        document.body.classList.toggle('noscroll');
+        document.documentElement.classList.toggle('reconstruct-body');
+        document.getElementById('spacer').style.height = '100%';
+        document.documentElement.classList.remove('reftest-wait');
+    }
+</script>
+<style>
+    html, body {
+        margin: 0;
+        padding: 0;
+        background-color: green;
+    }
+
+    .noscroll {
+        overflow: hidden;
+        height: 100%;
+    }
+
+    /* Toggling this on and off triggers a frame reconstruction on the <body> */
+    html.reconstruct-body::before {
+        top: 0;
+        content: '';
+        display: block;
+        height: 2px;
+        position: absolute;
+        width: 100%;
+        z-index: 99;
+    }
+</style>
+<body onload="setTimeout(run, 0)">
+ <div id="spacer" style="height: 5000px">
+  This is the top of the page.
+ </div>
+ This is the bottom of the page.
+</body>
--- a/gfx/layers/apz/test/reftest/reftest.list
+++ b/gfx/layers/apz/test/reftest/reftest.list
@@ -10,8 +10,10 @@ skip-if(!asyncPan) fuzzy-if(Android,8,10
 # Different async zoom levels. Since the scrollthumb gets async-scaled in the
 # compositor, the border-radius ends of the scrollthumb are going to be a little
 # off, hence the fuzzy-if clauses.
 skip-if(!asyncZoom) fuzzy-if(B2G,98,82) == async-scrollbar-zoom-1.html async-scrollbar-zoom-1-ref.html
 skip-if(!asyncZoom) fuzzy-if(B2G,94,146) == async-scrollbar-zoom-2.html async-scrollbar-zoom-2-ref.html
 
 # Meta-viewport tag support
 skip-if(!asyncZoom) == initial-scale-1.html initial-scale-1-ref.html
+
+skip-if(!asyncPan) == frame-reconstruction-scroll-clamping.html frame-reconstruction-scroll-clamping-ref.html
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2169,16 +2169,21 @@ ScrollFrameHelper::ScrollToWithOrigin(ns
   if (aSnap == nsIScrollableFrame::ENABLE_SNAP) {
     GetSnapPointForDestination(nsIScrollableFrame::DEVICE_PIXELS,
                                mDestination,
                                aScrollPosition);
   }
 
   nsRect scrollRange = GetScrollRangeForClamping();
   mDestination = scrollRange.ClampPoint(aScrollPosition);
+  if (mDestination != aScrollPosition && aOrigin == nsGkAtoms::restore) {
+    // If we're doing a restore but the scroll position is clamped, promote
+    // the origin from one that APZ can clobber to one that it can't clobber.
+    aOrigin = nsGkAtoms::other;
+  }
 
   nsRect range = aRange ? *aRange : nsRect(aScrollPosition, nsSize(0, 0));
 
   if (aMode != nsIScrollableFrame::SMOOTH_MSD) {
     // If we get a non-smooth-scroll, reset the cached APZ scroll destination,
     // so that we know to process the next smooth-scroll destined for APZ.
     mApzSmoothScrollDestination = Nothing();
   }