Bug 1519007 - Do not allow APZ to move the layout viewport outside the scrollable rect. r=kats a=pascalc
authorBotond Ballo <botond@mozilla.com>
Fri, 29 Mar 2019 22:00:36 +0000
changeset 526070 b71adadd3a3c9a7cd176c186b71d0c0d53850b16
parent 526069 7f959873589075d1edf179e25664ea2cdd9bfc73
child 526071 0d43ca71665f2f956269ab5b7d6bd00175a7fb11
push id2032
push userffxbld-merge
push dateMon, 13 May 2019 09:36:57 +0000
treeherdermozilla-release@455c1065dcbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats, pascalc
bugs1519007
milestone67.0
Bug 1519007 - Do not allow APZ to move the layout viewport outside the scrollable rect. r=kats a=pascalc Differential Revision: https://phabricator.services.mozilla.com/D24826
gfx/layers/FrameMetrics.cpp
gfx/layers/FrameMetrics.h
gfx/layers/apz/src/AsyncPanZoomController.cpp
--- a/gfx/layers/FrameMetrics.cpp
+++ b/gfx/layers/FrameMetrics.cpp
@@ -13,22 +13,23 @@ namespace layers {
 
 const ScrollableLayerGuid::ViewID ScrollableLayerGuid::NULL_SCROLL_ID = 0;
 
 void FrameMetrics::RecalculateLayoutViewportOffset() {
   if (!mIsRootContent) {
     return;
   }
   KeepLayoutViewportEnclosingVisualViewport(GetVisualViewport(),
-                                            mLayoutViewport);
+                                            mScrollableRect, mLayoutViewport);
 }
 
 /* static */
 void FrameMetrics::KeepLayoutViewportEnclosingVisualViewport(
-    const CSSRect& aVisualViewport, CSSRect& aLayoutViewport) {
+    const CSSRect& aVisualViewport, const CSSRect& aScrollableRect,
+    CSSRect& aLayoutViewport) {
   // If the visual viewport is contained within the layout viewport, we don't
   // need to make any adjustments, so we can exit early.
   //
   // Additionally, if the composition bounds changes (due to an orientation
   // change, window resize, etc.), it may take a few frames for aLayoutViewport
   // to update and during that time, the visual viewport may be larger than the
   // layout viewport. In such situations, we take an early exit if the visual
   // viewport contains the layout viewport.
@@ -72,16 +73,20 @@ void FrameMetrics::KeepLayoutViewportEnc
     }
     if (aVisualViewport.Y() < aLayoutViewport.Y()) {
       aLayoutViewport.MoveToY(aVisualViewport.Y());
     } else if (aLayoutViewport.YMost() < aVisualViewport.YMost()) {
       aLayoutViewport.MoveByY(aVisualViewport.YMost() -
                               aLayoutViewport.YMost());
     }
   }
+
+  // Regardless of any adjustment above, the layout viewport is not allowed
+  // to go outside the scrollable rect.
+  aLayoutViewport = aLayoutViewport.MoveInsideAndClamp(aScrollableRect);
 }
 
 void ScrollMetadata::SetUsesContainerScrolling(bool aValue) {
   mUsesContainerScrolling = aValue;
 }
 
 static OverscrollBehavior ToOverscrollBehavior(
     StyleOverscrollBehavior aBehavior) {
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -506,18 +506,22 @@ struct FrameMetrics {
   void RecalculateLayoutViewportOffset();
 
   // Helper function for RecalculateViewportOffset(). Exposed so that
   // APZC can perform the operation on other copies of the layout
   // and visual viewport rects (e.g. the "effective" ones used to implement
   // the frame delay).
   // Modifies |aLayoutViewport| to continue enclosing |aVisualViewport|
   // if possible.
+  // The layout viewport needs to remain clamped to the scrollable rect,
+  // and we pass in the scrollable rect so this function can maintain that
+  // constraint.
   static void KeepLayoutViewportEnclosingVisualViewport(
-      const CSSRect& aVisualViewport, CSSRect& aLayoutViewport);
+      const CSSRect& aVisualViewport, const CSSRect& aScrollableRect,
+      CSSRect& aLayoutViewport);
 
  private:
   // A ID assigned to each scrollable frame, unique within each LayersId..
   ViewID mScrollId;
 
   // The pres-shell resolution that has been induced on the document containing
   // this scroll frame as a result of zooming this scroll frame (whether via
   // user action, or choosing an initial zoom level on page load). This can
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -3496,17 +3496,17 @@ void AsyncPanZoomController::AdjustScrol
   // For a similar reason, apply the shift to mCompositedLayoutViewport.
   // mCompositedLayoutViewport also needs to immediately pick up any new
   // size from Metrics().GetViewport() to make sure it reflects any height
   // change due to dynamic toolbar movement.
   mCompositedLayoutViewport.SizeTo(Metrics().GetLayoutViewport().Size());
   FrameMetrics::KeepLayoutViewportEnclosingVisualViewport(
       CSSRect(mCompositedScrollOffset,
               Metrics().CalculateCompositedSizeInCssPixels()),
-      mCompositedLayoutViewport);
+      Metrics().GetScrollableRect(), mCompositedLayoutViewport);
   RequestContentRepaint();
   UpdateSharedCompositorFrameMetrics();
 }
 
 void AsyncPanZoomController::SetScrollOffset(const CSSPoint& aOffset) {
   Metrics().SetScrollOffset(aOffset);
   Metrics().RecalculateLayoutViewportOffset();
 }