mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-22 18:32:00 +00:00
Bug 1180865 - Implement pinch locking in APZC. r=botond
Mechanism for restricting pinch zooming when gesture is a two finger pan. If the pinch span is below a given threshold and the scroll distance above a given threshold then the zoom level is maintained to allow for smooth panning with two fingers. MozReview-Commit-ID: 62Fv0WeplOo --HG-- extra : rebase_source : 71d7da4c4b4cc3a5adde13ad1a7c1fbf49856c35
This commit is contained in:
parent
04cbca1e20
commit
d00bc034b2
@ -366,6 +366,23 @@ typedef GenericFlingAnimation FlingAnimation;
|
||||
* the main thread doesn't actually need to do a repaint. This pref allows the
|
||||
* main thread to skip doing those repaints in cases where it doesn't need to.
|
||||
*
|
||||
* \li\b apz.pinch_lock.mode
|
||||
* The preferred pinch locking style. See PinchLockMode for possible values.
|
||||
*
|
||||
* \li\b apz.pinch_lock.scroll_lock_threshold
|
||||
* Pinch locking is triggered if the user scrolls more than this distance
|
||||
* and pinches less than apz.pinch_lock.span_lock_threshold.\n
|
||||
* Units: (real-world, i.e. screen) inches
|
||||
*
|
||||
* \li\b apz.pinch_lock.span_breakout_threshold
|
||||
* Distance in inches the user must pinch before lock can be broken.\n
|
||||
* Units: (real-world, i.e. screen) inches measured between two touch points
|
||||
*
|
||||
* \li\b apz.pinch_lock.span_lock_threshold
|
||||
* Pinch locking is triggered if the user pinches less than this distance
|
||||
* and scrolls more than apz.pinch_lock.scroll_lock_threshold.\n
|
||||
* Units: (real-world, i.e. screen) inches measured between two touch points
|
||||
*
|
||||
* \li\b apz.popups.enabled
|
||||
* Determines whether APZ is used for XUL popup widgets with remote content.
|
||||
* Ideally, this should always be true, but it is currently not well tested, and
|
||||
@ -759,6 +776,7 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
|
||||
mX(this),
|
||||
mY(this),
|
||||
mPanDirRestricted(false),
|
||||
mPinchLocked(false),
|
||||
mZoomConstraints(false, false,
|
||||
mFrameMetrics.GetDevPixelsPerCSSPixel() * kViewportMinScale / ParentLayerToScreenScale(1),
|
||||
mFrameMetrics.GetDevPixelsPerCSSPixel() * kViewportMaxScale / ParentLayerToScreenScale(1)),
|
||||
@ -864,6 +882,11 @@ AsyncPanZoomController::GetSecondTapTolerance()
|
||||
return static_cast<AxisLockMode>(gfxPrefs::APZAxisLockMode());
|
||||
}
|
||||
|
||||
/* static */AsyncPanZoomController::PinchLockMode AsyncPanZoomController::GetPinchLockMode()
|
||||
{
|
||||
return static_cast<PinchLockMode>(gfxPrefs::APZPinchLockMode());
|
||||
}
|
||||
|
||||
bool
|
||||
AsyncPanZoomController::ArePointerEventsConsumable(TouchBlockState* aBlock, uint32_t aTouchPoints) {
|
||||
if (aTouchPoints == 0) {
|
||||
@ -1328,6 +1351,7 @@ nsEventStatus AsyncPanZoomController::OnTouchCancel(const MultiTouchInput& aEven
|
||||
nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEvent) {
|
||||
APZC_LOG("%p got a scale-begin in state %d\n", this, mState);
|
||||
|
||||
mPinchLocked = false;
|
||||
mPinchPaintTimerSet = false;
|
||||
// Note that there may not be a touch block at this point, if we received the
|
||||
// PinchGestureEvent directly from widget code without any touch events.
|
||||
@ -1369,9 +1393,26 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
ParentLayerCoord spanDistance = fabsf(aEvent.mPreviousSpan - aEvent.mCurrentSpan);
|
||||
ParentLayerPoint focusPoint, focusChange;
|
||||
{
|
||||
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
||||
|
||||
focusPoint = aEvent.mLocalFocusPoint - mFrameMetrics.GetCompositionBounds().TopLeft();
|
||||
focusChange = mLastZoomFocus - focusPoint;
|
||||
mLastZoomFocus = focusPoint;
|
||||
}
|
||||
|
||||
HandlePinchLocking(
|
||||
ToScreenCoordinates(ParentLayerPoint(0, spanDistance), focusPoint).Length(),
|
||||
ToScreenCoordinates(focusChange, focusPoint));
|
||||
bool allowZoom = mZoomConstraints.mAllowZoom && !mPinchLocked;
|
||||
|
||||
// If zooming is not allowed, this is a two-finger pan.
|
||||
// Tracking panning distance and velocity.
|
||||
if (!mZoomConstraints.mAllowZoom) {
|
||||
// UpdateWithTouchAtDevicePoint() acquires the tree lock, so
|
||||
// it cannot be called while the mRecursiveMutex lock is held.
|
||||
if (!allowZoom) {
|
||||
mX.UpdateWithTouchAtDevicePoint(aEvent.mLocalFocusPoint.x, 0, aEvent.mTime);
|
||||
mY.UpdateWithTouchAtDevicePoint(aEvent.mLocalFocusPoint.y, 0, aEvent.mTime);
|
||||
}
|
||||
@ -1397,11 +1438,8 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
||||
|
||||
CSSToParentLayerScale userZoom = mFrameMetrics.GetZoom().ToScaleFactor();
|
||||
ParentLayerPoint focusPoint = aEvent.mLocalFocusPoint - mFrameMetrics.GetCompositionBounds().TopLeft();
|
||||
CSSPoint cssFocusPoint = focusPoint / mFrameMetrics.GetZoom();
|
||||
|
||||
ParentLayerPoint focusChange = mLastZoomFocus - focusPoint;
|
||||
mLastZoomFocus = focusPoint;
|
||||
// If displacing by the change in focus point will take us off page bounds,
|
||||
// then reduce the displacement such that it doesn't.
|
||||
focusChange.x -= mX.DisplacementWillOverscrollAmount(focusChange.x);
|
||||
@ -1439,12 +1477,9 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||
realMaxZoom = realMinZoom;
|
||||
}
|
||||
|
||||
bool doScale = (spanRatio > 1.0 && userZoom < realMaxZoom) ||
|
||||
(spanRatio < 1.0 && userZoom > realMinZoom);
|
||||
|
||||
if (!mZoomConstraints.mAllowZoom) {
|
||||
doScale = false;
|
||||
}
|
||||
bool doScale = allowZoom && (
|
||||
(spanRatio > 1.0 && userZoom < realMaxZoom) ||
|
||||
(spanRatio < 1.0 && userZoom > realMinZoom));
|
||||
|
||||
if (doScale) {
|
||||
spanRatio = clamped(spanRatio,
|
||||
@ -2601,6 +2636,24 @@ void AsyncPanZoomController::HandlePanningUpdate(const ScreenPoint& aPanDistance
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::HandlePinchLocking(ScreenCoord spanDistance, ScreenPoint focusChange) {
|
||||
if (mPinchLocked) {
|
||||
if (GetPinchLockMode() == PINCH_STICKY) {
|
||||
ScreenCoord spanBreakoutThreshold = gfxPrefs::APZPinchLockSpanBreakoutThreshold() * APZCTreeManager::GetDPI();
|
||||
mPinchLocked = !(spanDistance > spanBreakoutThreshold);
|
||||
}
|
||||
} else {
|
||||
if (GetPinchLockMode() != PINCH_FREE) {
|
||||
ScreenCoord spanLockThreshold = gfxPrefs::APZPinchLockSpanLockThreshold() * APZCTreeManager::GetDPI();
|
||||
ScreenCoord scrollLockThreshold = gfxPrefs::APZPinchLockScrollLockThreshold() * APZCTreeManager::GetDPI();
|
||||
|
||||
if (spanDistance < spanLockThreshold && focusChange.Length() > scrollLockThreshold) {
|
||||
mPinchLocked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
AsyncPanZoomController::StartPanning(const ParentLayerPoint& aStartPoint) {
|
||||
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
||||
|
@ -655,6 +655,11 @@ protected:
|
||||
*/
|
||||
void HandlePanningUpdate(const ScreenPoint& aDelta);
|
||||
|
||||
/**
|
||||
* Set and update the pinch lock
|
||||
*/
|
||||
void HandlePinchLocking(ScreenCoord spanDistance, ScreenPoint focusChange);
|
||||
|
||||
/**
|
||||
* Sets up anything needed for panning. This takes us out of the "TOUCHING"
|
||||
* state and starts actually panning us.
|
||||
@ -724,6 +729,14 @@ protected:
|
||||
|
||||
static AxisLockMode GetAxisLockMode();
|
||||
|
||||
enum PinchLockMode {
|
||||
PINCH_FREE, /* No locking at all */
|
||||
PINCH_STANDARD, /* Default pinch locking mode that remains locked until pinch gesture ends*/
|
||||
PINCH_STICKY, /* Allow lock to be broken, with hysteresis */
|
||||
};
|
||||
|
||||
static PinchLockMode GetPinchLockMode();
|
||||
|
||||
// Helper function for OnSingleTapUp(), OnSingleTapConfirmed(), and
|
||||
// OnLongPressUp().
|
||||
nsEventStatus GenerateSingleTap(GeckoContentController::TapType aType,
|
||||
@ -800,6 +813,10 @@ private:
|
||||
// the touch-action CSS property.
|
||||
bool mPanDirRestricted;
|
||||
|
||||
// This flag is set to true when we are in a pinch-locked state. ie: user
|
||||
// is performing a two-finger pan rather than a pinch gesture
|
||||
bool mPinchLocked;
|
||||
|
||||
// Most up-to-date constraints on zooming. These should always be reasonable
|
||||
// values; for example, allowing a min zoom of 0.0 can cause very bad things
|
||||
// to happen.
|
||||
|
@ -333,6 +333,10 @@ private:
|
||||
DECL_GFX_PREF(Live, "apz.overscroll.stop_distance_threshold", APZOverscrollStopDistanceThreshold, float, 5.0f);
|
||||
DECL_GFX_PREF(Live, "apz.paint_skipping.enabled", APZPaintSkipping, bool, true);
|
||||
DECL_GFX_PREF(Live, "apz.peek_messages.enabled", APZPeekMessages, bool, true);
|
||||
DECL_GFX_PREF(Live, "apz.pinch_lock.mode", APZPinchLockMode, int32_t, 1);
|
||||
DECL_GFX_PREF(Live, "apz.pinch_lock.scroll_lock_threshold", APZPinchLockScrollLockThreshold, float, 1.0f / 32.0f);
|
||||
DECL_GFX_PREF(Live, "apz.pinch_lock.span_breakout_threshold", APZPinchLockSpanBreakoutThreshold, float, 1.0f / 32.0f);
|
||||
DECL_GFX_PREF(Live, "apz.pinch_lock.span_lock_threshold", APZPinchLockSpanLockThreshold, float, 1.0f / 32.0f);
|
||||
DECL_GFX_PREF(Live, "apz.popups.enabled", APZPopupsEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "apz.printtree", APZPrintTree, bool, false);
|
||||
DECL_GFX_PREF(Live, "apz.record_checkerboarding", APZRecordCheckerboarding, bool, false);
|
||||
|
@ -710,6 +710,10 @@ pref("apz.overscroll.stretch_factor", "0.35");
|
||||
pref("apz.paint_skipping.enabled", true);
|
||||
// Fetch displayport updates early from the message queue
|
||||
pref("apz.peek_messages.enabled", true);
|
||||
pref("apz.pinch_lock.mode", 1);
|
||||
pref("apz.pinch_lock.scoll_lock_threshold", "0.03125"); // 1/32 inches
|
||||
pref("apz.pinch_lock.span_breakout_threshold", "0.03125"); // 1/32 inches
|
||||
pref("apz.pinch_lock.span_lock_threshold", "0.03125"); // 1/32 inches
|
||||
pref("apz.popups.enabled", false);
|
||||
|
||||
// Whether to print the APZC tree for debugging
|
||||
|
Loading…
x
Reference in New Issue
Block a user