Bug 951793 - Obey overscroll-behavior for swipe navigation. r=mstange draft
authorBotond Ballo <botond@mozilla.com>
Mon, 23 Oct 2017 18:27:24 -0400
changeset 703292 9fd9b60db5c6e5f01033f6dca934024ce488cedb
parent 703291 43f8d69a8e10f778179e77679cb7581b95d25b87
child 703293 930e5c558a7bef5b1a816a9b8c37b271cc4f155b
push id90783
push userbballo@mozilla.com
push dateFri, 24 Nov 2017 21:22:10 +0000
reviewersmstange
bugs951793
milestone59.0a1
Bug 951793 - Obey overscroll-behavior for swipe navigation. r=mstange MozReview-Commit-ID: i2BuiAfG71
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/AsyncPanZoomController.cpp
gfx/layers/apz/src/AsyncPanZoomController.h
widget/InputData.cpp
widget/InputData.h
widget/cocoa/nsChildView.mm
widget/nsGUIEventIPC.h
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -1193,16 +1193,19 @@ APZCTreeManager::ReceiveInputEvent(Input
             apzc,
             /* aTargetConfirmed = */ hitResult != HitDispatchToContentRegion,
             panInput, aOutInputBlockId);
 
         // Update the out-parameters so they are what the caller expects.
         apzc->GetGuid(aOutTargetGuid);
         panInput.mPanStartPoint = *untransformedStartPoint;
         panInput.mPanDisplacement = *untransformedDisplacement;
+
+        panInput.mOverscrollBehaviorAllowsSwipe =
+            apzc->OverscrollBehaviorAllowsSwipe();
       }
       break;
     } case PINCHGESTURE_INPUT: {  // note: no one currently sends these
       PinchGestureInput& pinchInput = aEvent.AsPinchGestureInput();
       RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(pinchInput.mFocusPoint,
                                                             &hitResult);
       if (apzc) {
         MOZ_ASSERT(hitResult != HitNothing);
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -2875,16 +2875,22 @@ ParentLayerPoint AsyncPanZoomController:
   }
   if (!mY.OverscrollBehaviorAllowsHandoff()) {
     residualVelocity.y = aHandoffVelocity.y;
     aHandoffVelocity.y = 0;
   }
   return residualVelocity;
 }
 
+bool AsyncPanZoomController::OverscrollBehaviorAllowsSwipe() const
+{
+  RecursiveMutexAutoLock lock(mRecursiveMutex);
+  // Swipe navigation is a "non-local" overscroll behavior like handoff.
+  return mX.OverscrollBehaviorAllowsHandoff();
+}
 
 void AsyncPanZoomController::HandleFlingOverscroll(const ParentLayerPoint& aVelocity,
                                                    const RefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
                                                    const RefPtr<const AsyncPanZoomController>& aScrolledApzc) {
   APZCTreeManager* treeManagerLocal = GetApzcTreeManager();
   if (treeManagerLocal) {
     const FlingHandoffState handoffState{aVelocity,
                                          aOverscrollHandoffChain,
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -437,16 +437,18 @@ public:
    * to CSS coordinates relative to the beginning of the scroll track.
    * Only the component in the direction of scrolling is returned.
    */
   CSSCoord ConvertScrollbarPoint(const ParentLayerPoint& aScrollbarPoint,
                                  const ScrollThumbData& aThumbData) const;
 
   void NotifyMozMouseScrollEvent(const nsString& aString) const;
 
+  bool OverscrollBehaviorAllowsSwipe() const;
+
 protected:
   // Protected destructor, to discourage deletion outside of Release():
   virtual ~AsyncPanZoomController();
 
   // Returns the cached current frame time.
   TimeStamp GetFrameTime() const;
 
   /**
--- a/widget/InputData.cpp
+++ b/widget/InputData.cpp
@@ -485,16 +485,17 @@ PanGestureInput::PanGestureInput()
   : InputData(PANGESTURE_INPUT)
   , mLineOrPageDeltaX(0)
   , mLineOrPageDeltaY(0)
   , mUserDeltaMultiplierX(1.0)
   , mUserDeltaMultiplierY(1.0)
   , mHandledByAPZ(false)
   , mFollowedByMomentum(false)
   , mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection(false)
+  , mOverscrollBehaviorAllowsSwipe(false)
 {
 }
 
 PanGestureInput::PanGestureInput(PanGestureType aType, uint32_t aTime,
                                  TimeStamp aTimeStamp,
                                  const ScreenPoint& aPanStartPoint,
                                  const ScreenPoint& aPanDisplacement,
                                  Modifiers aModifiers)
@@ -504,16 +505,17 @@ PanGestureInput::PanGestureInput(PanGest
   , mPanDisplacement(aPanDisplacement)
   , mLineOrPageDeltaX(0)
   , mLineOrPageDeltaY(0)
   , mUserDeltaMultiplierX(1.0)
   , mUserDeltaMultiplierY(1.0)
   , mHandledByAPZ(false)
   , mFollowedByMomentum(false)
   , mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection(false)
+  , mOverscrollBehaviorAllowsSwipe(false)
 {
 }
 
 bool
 PanGestureInput::IsMomentum() const
 {
   switch (mType) {
     case PanGestureInput::PANGESTURE_MOMENTUMSTART:
--- a/widget/InputData.h
+++ b/widget/InputData.h
@@ -380,16 +380,24 @@ public:
 
   // If this is true, and this event started a new input block that couldn't
   // find a scrollable target which is scrollable in the horizontal component
   // of the scroll start direction, then this input block needs to be put on
   // hold until a content response has arrived, even if the block has a
   // confirmed target.
   // This is used by events that can result in a swipe instead of a scroll.
   bool mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection;
+
+  // This is used by APZ to communicate to the macOS widget code whether
+  // the overscroll-behavior of the scroll frame handling this swipe allows
+  // non-local overscroll behaviors in the horizontal direction (such as
+  // swipe navigation).
+  bool mOverscrollBehaviorAllowsSwipe;
+
+  // XXX: If adding any more bools, switch to using bitfields instead.
 };
 
 /**
  * Encapsulation class for pinch events. In general, these will be generated by
  * a gesture listener by looking at SingleTouchData/MultiTouchInput instances and
  * determining whether or not the user was trying to do a gesture.
  */
 class PinchGestureInput : public InputData
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -2918,17 +2918,17 @@ nsChildView::DispatchAPZWheelInputEvent(
         result = mAPZC->ReceiveInputEvent(aEvent, &guid, &inputBlockId);
         if (result == nsEventStatus_eConsumeNoDefault) {
           return;
         }
 
         PanGestureInput& panInput = aEvent.AsPanGestureInput();
 
         event = panInput.ToWidgetWheelEvent(this);
-        if (aCanTriggerSwipe) {
+        if (aCanTriggerSwipe && panInput.mOverscrollBehaviorAllowsSwipe) {
           SwipeInfo swipeInfo = SendMayStartSwipe(panInput);
           event.mCanTriggerSwipe = swipeInfo.wantsSwipe;
           if (swipeInfo.wantsSwipe) {
             if (result == nsEventStatus_eIgnore) {
               // APZ has determined and that scrolling horizontally in the
               // requested direction is impossible, so it didn't do any
               // scrolling for the event.
               // We know now that MayStartSwipe wants a swipe, so we can start
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -1220,33 +1220,35 @@ struct ParamTraits<mozilla::PanGestureIn
     WriteParam(aMsg, aParam.mLocalPanDisplacement);
     WriteParam(aMsg, aParam.mLineOrPageDeltaX);
     WriteParam(aMsg, aParam.mLineOrPageDeltaY);
     WriteParam(aMsg, aParam.mUserDeltaMultiplierX);
     WriteParam(aMsg, aParam.mUserDeltaMultiplierY);
     WriteParam(aMsg, aParam.mHandledByAPZ);
     WriteParam(aMsg, aParam.mFollowedByMomentum);
     WriteParam(aMsg, aParam.mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection);
+    WriteParam(aMsg, aParam.mOverscrollBehaviorAllowsSwipe);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, static_cast<mozilla::InputData*>(aResult)) &&
            ReadParam(aMsg, aIter, &aResult->mType) &&
            ReadParam(aMsg, aIter, &aResult->mPanStartPoint) &&
            ReadParam(aMsg, aIter, &aResult->mPanDisplacement) &&
            ReadParam(aMsg, aIter, &aResult->mLocalPanStartPoint) &&
            ReadParam(aMsg, aIter, &aResult->mLocalPanDisplacement) &&
            ReadParam(aMsg, aIter, &aResult->mLineOrPageDeltaX) &&
            ReadParam(aMsg, aIter, &aResult->mLineOrPageDeltaY) &&
            ReadParam(aMsg, aIter, &aResult->mUserDeltaMultiplierX) &&
            ReadParam(aMsg, aIter, &aResult->mUserDeltaMultiplierY) &&
            ReadParam(aMsg, aIter, &aResult->mHandledByAPZ) &&
            ReadParam(aMsg, aIter, &aResult->mFollowedByMomentum) &&
-           ReadParam(aMsg, aIter, &aResult->mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection);
+           ReadParam(aMsg, aIter, &aResult->mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection) &&
+           ReadParam(aMsg, aIter, &aResult->mOverscrollBehaviorAllowsSwipe);
   }
 };
 
 template<>
 struct ParamTraits<mozilla::PinchGestureInput::PinchGestureType>
   : public ContiguousEnumSerializerInclusive<
              mozilla::PinchGestureInput::PinchGestureType,
              mozilla::PinchGestureInput::PinchGestureType::PINCHGESTURE_START,