--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -1816,18 +1816,18 @@ nsEventStatus AsyncPanZoomController::On } } } } return nsEventStatus_eConsumeNoDefault; } nsEventStatus AsyncPanZoomController::HandleEndOfPan() { - MOZ_ASSERT(GetCurrentTouchBlock()); - GetCurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints(); + MOZ_ASSERT(GetCurrentTouchBlock() || GetCurrentPanGestureBlock()); + GetCurrentInputBlock()->GetOverscrollHandoffChain()->FlushRepaints(); ParentLayerPoint flingVelocity = GetVelocityVector(); // Clear our velocities; if DispatchFling() gives the fling to us, // the fling velocity gets *added* to our existing velocity in // AcceptFling(). mX.SetVelocity(0); mY.SetVelocity(0); // Clear our state so that we don't stay in the PANNING state @@ -1839,29 +1839,29 @@ nsEventStatus AsyncPanZoomController::Ha APZC_LOG("%p starting a fling animation if %f >= %f

", this, flingVelocity.Length().value, gfxPrefs::APZFlingMinVelocityThreshold()); if (flingVelocity.Length() < gfxPrefs::APZFlingMinVelocityThreshold()) { // Relieve overscroll now if needed, since we will not transition to a fling // animation and then an overscroll animation, and relieve it then. - GetCurrentTouchBlock() + GetCurrentInputBlock() ->GetOverscrollHandoffChain() ->SnapBackOverscrolledApzc(this); return nsEventStatus_eConsumeNoDefault; } // Make a local copy of the tree manager pointer and check that it's not // null before calling DispatchFling(). This is necessary because Destroy(), // which nulls out mTreeManager, could be called concurrently. if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) { const FlingHandoffState handoffState{ - flingVelocity, GetCurrentTouchBlock()->GetOverscrollHandoffChain(), - false /* not handoff */, GetCurrentTouchBlock()->GetScrolledApzc()}; + flingVelocity, GetCurrentInputBlock()->GetOverscrollHandoffChain(), + false /* not handoff */, GetCurrentInputBlock()->GetScrolledApzc()}; treeManagerLocal->DispatchFling(this, handoffState); } return nsEventStatus_eConsumeNoDefault; } bool AsyncPanZoomController::ConvertToGecko(const ScreenIntPoint& aPoint, LayoutDevicePoint* aOut) { if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) { @@ -2550,35 +2550,64 @@ nsEventStatus AsyncPanZoomController::On // Note that there is a multiplier that applies onto the "physical" pan // displacement (how much the user's fingers moved) that produces the // "logical" pan displacement (how much the page should move). For some of the // code below it makes more sense to use the physical displacement rather than // the logical displacement, and vice-versa. ScreenPoint physicalPanDisplacement = aEvent.mPanDisplacement; ParentLayerPoint logicalPanDisplacement = aEvent.UserMultipliedLocalPanDisplacement(); + if (aEvent.mDeltaType == PanGestureInput::PANDELTA_PAGE) { + // Pan events with page units are used by Gtk, so this replicates Gtk: + // https://gitlab.gnome.org/GNOME/gtk/blob/c734c7e9188b56f56c3a504abee05fa40c5475ac/gtk/gtkrange.c#L3065-3073 + CSSSize pageScrollSize; + CSSToParentLayerScale2D zoom; + { + // Grab the lock to access the frame metrics. + RecursiveMutexAutoLock lock(mRecursiveMutex); + pageScrollSize = mScrollMetadata.GetPageScrollAmount() / + Metrics().GetDevPixelsPerCSSPixel(); + zoom = Metrics().GetZoom(); + } + // scrollUnit* is in units of "ParentLayer pixels per page proportion"... + auto scrollUnitWidth = std::min(std::pow(pageScrollSize.width, 2.0 / 3.0), + pageScrollSize.width / 2.0) * + zoom.xScale; + auto scrollUnitHeight = std::min(std::pow(pageScrollSize.height, 2.0 / 3.0), + pageScrollSize.height / 2.0) * + zoom.yScale; + // ... and pan displacements are in units of "page proportion count" + // here, so the products of them and scrollUnit* are in ParentLayer pixels + ParentLayerPoint physicalPanDisplacementPL( + physicalPanDisplacement.x * scrollUnitWidth, + physicalPanDisplacement.y * scrollUnitHeight); + physicalPanDisplacement = ToScreenCoordinates(physicalPanDisplacementPL, + aEvent.mLocalPanStartPoint); + logicalPanDisplacement.x *= scrollUnitWidth; + logicalPanDisplacement.y *= scrollUnitHeight; + } MOZ_ASSERT(GetCurrentPanGestureBlock()); AdjustDeltaForAllowedScrollDirections( logicalPanDisplacement, GetCurrentPanGestureBlock()->GetAllowedScrollDirections()); // We need to update the axis velocity in order to get a useful display port // size and position. We need to do so even if this is a momentum pan (i.e. // aFingersOnTouchpad == false); in that case the "with touch" part is not // really appropriate, so we may want to rethink this at some point. // Note that we have to make all simulated positions relative to // Axis::GetPos(), because the current position is an invented position, and // because resetting the position to the mouse position (e.g. // aEvent.mLocalStartPoint) would mess up velocity calculation. (This is // the only caller of UpdateWithTouchAtDevicePoint() for pan events, so // there is no risk of other calls resetting the position.) - mX.UpdateWithTouchAtDevicePoint(mX.GetPos() + logicalPanDisplacement.x, + mX.UpdateWithTouchAtDevicePoint(mX.GetPos() - logicalPanDisplacement.x, aEvent.mTime); - mY.UpdateWithTouchAtDevicePoint(mY.GetPos() + logicalPanDisplacement.y, + mY.UpdateWithTouchAtDevicePoint(mY.GetPos() - logicalPanDisplacement.y, aEvent.mTime); HandlePanningUpdate(physicalPanDisplacement); ScreenPoint panDistance(fabs(physicalPanDisplacement.x), fabs(physicalPanDisplacement.y)); OverscrollHandoffState handoffState( *GetCurrentPanGestureBlock()->GetOverscrollHandoffChain(), panDistance, @@ -2603,16 +2632,22 @@ nsEventStatus AsyncPanZoomController::On APZC_LOG("%p got a pan-end in state %d

", this, mState); // Call into OnPan in order to process any delta included in this event. OnPan(aEvent, true); mX.EndTouch(aEvent.mTime); mY.EndTouch(aEvent.mTime); + // Use HandleEndOfPan for fling on platforms that don't + // emit momentum events (Gtk). + if (aEvent.mSimulateMomentum) { + return HandleEndOfPan(); + } + // Drop any velocity on axes where we don't have room to scroll anyways // (in this APZC, or an APZC further in the handoff chain). // This ensures that we don't enlarge the display port unnecessarily. MOZ_ASSERT(GetCurrentPanGestureBlock()); RefPtr<const OverscrollHandoffChain> overscrollHandoffChain = GetCurrentPanGestureBlock()->GetOverscrollHandoffChain(); if (!overscrollHandoffChain->CanScrollInDirection( this, ScrollDirection::eHorizontal)) {