Bug 1387551 - Handle "general.smoothScroll" with async keyboard scrolling. r=kats
authorRyan Hunt <rhunt@eqrion.net>
Tue, 08 Aug 2017 14:53:04 -0500
changeset 374284 3265cc2501b6d23f2ece3cc27eaa6d87401bc7bc
parent 374283 1bcc26dc569dfe62df8cbef97f1ccd78bb0c8965
child 374285 80ff3f300e05f38f96c385b03d1973a966a2bd35
child 374398 bff4d1e4243f2c1472d9339aa7060be4c819b637
push id32318
push userkwierso@gmail.com
push dateFri, 11 Aug 2017 20:16:01 +0000
treeherdermozilla-central@80ff3f300e05 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1387551
milestone57.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 1387551 - Handle "general.smoothScroll" with async keyboard scrolling. r=kats This commit modifies AsyncPanZoomController to scroll immediately for any keyboard scrolls when the pref, "general.smoothScroll" is disabled. MozReview-Commit-ID: 3lfRMOCC7er
gfx/layers/apz/src/APZUtils.h
gfx/layers/apz/src/AsyncPanZoomController.cpp
gfx/layers/apz/src/AsyncPanZoomController.h
gfx/layers/apz/src/InputBlockState.h
gfx/layers/apz/src/InputQueue.cpp
--- a/gfx/layers/apz/src/APZUtils.h
+++ b/gfx/layers/apz/src/APZUtils.h
@@ -45,17 +45,20 @@ operator|(CancelAnimationFlags a, Cancel
 enum class ScrollSource {
   // scrollTo() or something similar.
   DOM,
 
   // Touch-screen or trackpad with gesture support.
   Touch,
 
   // Mouse wheel.
-  Wheel
+  Wheel,
+
+  // Keyboard
+  Keyboard,
 };
 
 typedef uint32_t TouchBehaviorFlags;
 
 // Epsilon to be used when comparing 'float' coordinate values
 // with FuzzyEqualsAdditive. The rationale is that 'float' has 7 decimal
 // digits of precision, and coordinate values should be no larger than in the
 // ten thousands. Note also that the smallest legitimate difference in page
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -1742,29 +1742,54 @@ AsyncPanZoomController::OnKeyboard(const
   // Report the type of scroll action to telemetry
   ReportKeyboardScrollAction(aEvent.mAction);
 
   // Mark that this APZC has async key scrolled
   mTestHasAsyncKeyScrolled = true;
 
   // Calculate the destination for this keyboard scroll action
   CSSPoint destination = GetKeyboardDestination(aEvent.mAction);
-  nsIScrollableFrame::ScrollUnit scrollUnit = KeyboardScrollAction::GetScrollUnit(aEvent.mAction.mType);
+  bool scrollSnapped = MaybeAdjustDestinationForScrollSnapping(aEvent, destination);
+
+  // If smooth scrolling is disabled, then scroll immediately to the destination
+  if (!gfxPrefs::SmoothScrollEnabled()) {
+    CancelAnimation();
+
+    // CallDispatchScroll interprets the start and end points as the start and
+    // end of a touch scroll so they need to be reversed.
+    ParentLayerPoint startPoint = destination * mFrameMetrics.GetZoom();
+    ParentLayerPoint endPoint = mFrameMetrics.GetScrollOffset() * mFrameMetrics.GetZoom();
+    ParentLayerPoint delta = endPoint - startPoint;
+
+    ScreenPoint distance = ToScreenCoordinates(
+        ParentLayerPoint(fabs(delta.x), fabs(delta.y)), startPoint);
+
+    OverscrollHandoffState handoffState(
+        *mInputQueue->GetCurrentKeyboardBlock()->GetOverscrollHandoffChain(),
+        distance,
+        ScrollSource::Keyboard);
+
+    CallDispatchScroll(startPoint, endPoint, handoffState);
+
+    SetState(NOTHING);
+
+    return nsEventStatus_eConsumeDoDefault;
+  }
 
   // The lock must be held across the entire update operation, so the
   // compositor doesn't end the animation before we get a chance to
   // update it.
   ReentrantMonitorAutoEnter lock(mMonitor);
 
-  if (Maybe<CSSPoint> snapPoint = FindSnapPointNear(destination, scrollUnit)) {
+  if (scrollSnapped) {
     // If we're scroll snapping, use a smooth scroll animation to get
     // the desired physics. Note that SmoothScrollTo() will re-use an
     // existing smooth scroll animation if there is one.
-    APZC_LOG("%p keyboard scrolling to snap point %s\n", this, Stringify(*snapPoint).c_str());
-    SmoothScrollTo(*snapPoint);
+    APZC_LOG("%p keyboard scrolling to snap point %s\n", this, Stringify(destination).c_str());
+    SmoothScrollTo(destination);
     return nsEventStatus_eConsumeDoDefault;
   }
 
   // Use a keyboard scroll animation to scroll, reusing an existing one if it exists
   if (mState != KEYBOARD_SCROLL) {
     CancelAnimation();
     SetState(KEYBOARD_SCROLL);
 
@@ -4359,10 +4384,25 @@ bool AsyncPanZoomController::MaybeAdjust
   if (Maybe<CSSPoint> snapPoint = FindSnapPointNear(destination, unit)) {
     aDelta = (*snapPoint - aStartPosition) * zoom;
     aStartPosition = *snapPoint;
     return true;
   }
   return false;
 }
 
+bool AsyncPanZoomController::MaybeAdjustDestinationForScrollSnapping(
+    const KeyboardInput& aEvent,
+    CSSPoint& aDestination)
+{
+  ReentrantMonitorAutoEnter lock(mMonitor);
+  nsIScrollableFrame::ScrollUnit unit =
+      KeyboardScrollAction::GetScrollUnit(aEvent.mAction.mType);
+
+  if (Maybe<CSSPoint> snapPoint = FindSnapPointNear(aDestination, unit)) {
+    aDestination = *snapPoint;
+    return true;
+  }
+  return false;
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -1314,16 +1314,19 @@ private:
   // snap point). The delta is interpreted as being relative to
   // |aStartPosition|, and if a target snap point is found, |aStartPosition|
   // is also updated, to the value of the snap point.
   // Returns true iff. a target snap point was found.
   bool MaybeAdjustDeltaForScrollSnapping(const ScrollWheelInput& aEvent,
                                          ParentLayerPoint& aDelta,
                                          CSSPoint& aStartPosition);
 
+  bool MaybeAdjustDestinationForScrollSnapping(const KeyboardInput& aEvent,
+                                               CSSPoint& aDestination);
+
   // Snap to a snap position nearby the current scroll position, if appropriate.
   void ScrollSnap();
 
   // Snap to a snap position nearby the destination predicted based on the
   // current velocity, if appropriate.
   void ScrollSnapToDestination();
 
   // Snap to a snap position nearby the provided destination, if appropriate.
--- a/gfx/layers/apz/src/InputBlockState.h
+++ b/gfx/layers/apz/src/InputBlockState.h
@@ -500,14 +500,21 @@ public:
 
   KeyboardBlockState* AsKeyboardBlock() override {
     return this;
   }
 
   bool MustStayActive() override {
     return false;
   }
+
+  /**
+   * @return Whether or not overscrolling is prevented for this keyboard block.
+   */
+  bool AllowScrollHandoff() const {
+    return false;
+  }
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_layers_InputBlockState_h
--- a/gfx/layers/apz/src/InputQueue.cpp
+++ b/gfx/layers/apz/src/InputQueue.cpp
@@ -534,16 +534,19 @@ bool
 InputQueue::AllowScrollHandoff() const
 {
   if (GetCurrentWheelBlock()) {
     return GetCurrentWheelBlock()->AllowScrollHandoff();
   }
   if (GetCurrentPanGestureBlock()) {
     return GetCurrentPanGestureBlock()->AllowScrollHandoff();
   }
+  if (GetCurrentKeyboardBlock()) {
+    return GetCurrentKeyboardBlock()->AllowScrollHandoff();
+  }
   return true;
 }
 
 bool
 InputQueue::IsDragOnScrollbar(bool aHitScrollbar)
 {
   if (!mDragTracker.InDrag()) {
     return false;