Bug 1458711 - Allow pinch-zooming to be triggered by Mac trackpad gestures (behind a pref); r?botond,mstange
Previously, a feature was added to trigger pinch-zooming on desktops using the
mousewheel and a modifier key of the user's choosing (behind a pref).
To make testing easier on Macs, we wanted to trigger pinch-zooming
through Mac trackpad gestures. This patch enables pinch zooming through
trackpad gestures when the prefs apz.allow-zooming and
dom.meta-viewport.enabled are set to true. Currently, tests for this feature
were performed manually.
We will be using this feature only for internal testing. Later on when zooming
on desktops is more well-behaved, we will create automated tests and ship it.
MozReview-Commit-ID: HQ9OsPA1HPM
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -540,16 +540,17 @@ public:
virtual void SetPluginFocused(bool& aFocused) override;
bool IsPluginFocused() { return mPluginFocused; }
virtual LayoutDeviceIntPoint GetClientOffset() override;
void DispatchAPZWheelInputEvent(mozilla::InputData& aEvent, bool aCanTriggerSwipe);
+ nsEventStatus DispatchAPZInputEvent(mozilla::InputData& aEvent);
void SwipeFinished();
protected:
virtual ~nsChildView();
void ReportMoveEvent();
void ReportSizeEvent();
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -2900,16 +2900,27 @@ nsChildView::ReportSwipeStarted(uint64_t
for (size_t i = 1; i < mSwipeEventQueue->queuedEvents.Length(); i++) {
mSwipeTracker->ProcessEvent(mSwipeEventQueue->queuedEvents[i]);
}
}
mSwipeEventQueue = nullptr;
}
}
+nsEventStatus
+nsChildView::DispatchAPZInputEvent(InputData& aEvent)
+{
+ if (mAPZC) {
+ uint64_t inputBlockId = 0;
+ ScrollableLayerGuid guid;
+ return mAPZC->InputBridge()->ReceiveInputEvent(aEvent, &guid, &inputBlockId);
+ }
+ return nsEventStatus_eIgnore;
+}
+
void
nsChildView::DispatchAPZWheelInputEvent(InputData& aEvent, bool aCanTriggerSwipe)
{
if (mSwipeTracker && aEvent.mInputType == PANGESTURE_INPUT) {
// Give the swipe tracker a first pass at the event. If a new pan gesture
// has been started since the beginning of the swipe, the swipe tracker
// will know to ignore the event.
nsEventStatus status = mSwipeTracker->ProcessEvent(aEvent.AsPanGestureInput());
@@ -4174,76 +4185,127 @@ NSEvent* gLastDragMouseDownEvent = nil;
NS_OBJC_END_TRY_ABORT_BLOCK;
}
// Pinch zoom gesture.
- (void)magnifyWithEvent:(NSEvent *)anEvent
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
- if (!anEvent || !mGeckoChild ||
- [self beginOrEndGestureForEventPhase:anEvent]) {
- return;
- }
-
- nsAutoRetainCocoaObject kungFuDeathGrip(self);
-
- float deltaZ = [anEvent deltaZ];
-
- EventMessage msg;
- switch (mGestureState) {
- case eGestureState_StartGesture:
- msg = eMagnifyGestureStart;
- mGestureState = eGestureState_MagnifyGesture;
- break;
-
- case eGestureState_MagnifyGesture:
- msg = eMagnifyGestureUpdate;
- break;
-
- case eGestureState_None:
- case eGestureState_RotateGesture:
- default:
+ if (!mGeckoChild) {
return;
}
- // This sends the pinch gesture value as a fake wheel event that has the
- // control key pressed so that pages can implement custom pinch gesture
- // handling. It may seem strange that this doesn't use a wheel event with
- // the deltaZ property set, but this matches Chrome's behavior as described
- // at https://code.google.com/p/chromium/issues/detail?id=289887
- //
- // The intent of the formula below is to produce numbers similar to Chrome's
- // implementation of this feature. Chrome implements deltaY using the formula
- // "-100 * log(1 + [event magnification])" which is unfortunately incorrect.
- // All deltas for a single pinch gesture should sum to 0 if the start and end
- // of a pinch gesture end up in the same place. This doesn't happen in Chrome
- // because they followed Apple's misleading documentation, which implies that
- // "1 + [event magnification]" is the scale factor. The scale factor is
- // instead "pow(ratio, [event magnification])" so "[event magnification]" is
- // already in log space.
- //
- // The multiplication by the backing scale factor below counteracts the
- // division by the backing scale factor in WheelEvent.
- WidgetWheelEvent geckoWheelEvent(true, EventMessage::eWheel, mGeckoChild);
- [self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoWheelEvent];
- double backingScale = mGeckoChild->BackingScaleFactor();
- geckoWheelEvent.mDeltaY = -100.0 * [anEvent magnification] * backingScale;
- geckoWheelEvent.mModifiers |= MODIFIER_CONTROL;
- mGeckoChild->DispatchWindowEvent(geckoWheelEvent);
-
- // If the fake wheel event wasn't stopped, then send a normal magnify event.
- if (!geckoWheelEvent.mFlags.mDefaultPrevented) {
- WidgetSimpleGestureEvent geckoEvent(true, msg, mGeckoChild);
- geckoEvent.mDelta = deltaZ;
- [self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent];
- mGeckoChild->DispatchWindowEvent(geckoEvent);
-
- // Keep track of the cumulative magnification for the final "magnify" event.
- mCumulativeMagnification += deltaZ;
+ if (gfxPrefs::APZAllowZooming()) {
+ NSPoint locationInWindow = nsCocoaUtils::EventLocationForWindow(anEvent, [self window]);
+ ScreenPoint position = ViewAs<ScreenPixel>(
+ [self convertWindowCoordinatesRoundDown:locationInWindow],
+ PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
+
+ PRIntervalTime eventIntervalTime = PR_IntervalNow();
+ TimeStamp eventTimeStamp = nsCocoaUtils::GetEventTimeStamp([anEvent timestamp]);
+ NSEventPhase eventPhase = [anEvent phase];
+ PinchGestureInput::PinchGestureType pinchGestureType;
+
+ switch (eventPhase) {
+ case NSEventPhaseBegan: {
+ pinchGestureType = PinchGestureInput::PINCHGESTURE_START;
+ break;
+ }
+ case NSEventPhaseChanged: {
+ pinchGestureType = PinchGestureInput::PINCHGESTURE_SCALE;
+ break;
+ }
+ case NSEventPhaseEnded: {
+ pinchGestureType = PinchGestureInput::PINCHGESTURE_END;
+ break;
+ }
+ default: {
+ NS_WARNING("Unexpected phase for pinch gesture event.");
+ return;
+ }
+ }
+
+ PinchGestureInput event{pinchGestureType,
+ eventIntervalTime,
+ eventTimeStamp,
+ position,
+ 100.0,
+ 100.0 * (1.0 - [anEvent magnification]),
+ nsCocoaUtils::ModifiersForEvent(anEvent)};
+
+ if (pinchGestureType == PinchGestureInput::PINCHGESTURE_END) {
+ event.mFocusPoint = PinchGestureInput::BothFingersLifted<ScreenPixel>();
+ }
+
+ mGeckoChild->DispatchAPZInputEvent(event);
+ } else {
+
+ if (!anEvent ||
+ [self beginOrEndGestureForEventPhase:anEvent]) {
+ return;
+ }
+
+ nsAutoRetainCocoaObject kungFuDeathGrip(self);
+
+ float deltaZ = [anEvent deltaZ];
+
+ EventMessage msg;
+ switch (mGestureState) {
+ case eGestureState_StartGesture:
+ msg = eMagnifyGestureStart;
+ mGestureState = eGestureState_MagnifyGesture;
+ break;
+
+ case eGestureState_MagnifyGesture:
+ msg = eMagnifyGestureUpdate;
+ break;
+
+ case eGestureState_None:
+ case eGestureState_RotateGesture:
+ default:
+ return;
+ }
+
+ // This sends the pinch gesture value as a fake wheel event that has the
+ // control key pressed so that pages can implement custom pinch gesture
+ // handling. It may seem strange that this doesn't use a wheel event with
+ // the deltaZ property set, but this matches Chrome's behavior as described
+ // at https://code.google.com/p/chromium/issues/detail?id=289887
+ //
+ // The intent of the formula below is to produce numbers similar to Chrome's
+ // implementation of this feature. Chrome implements deltaY using the formula
+ // "-100 * log(1 + [event magnification])" which is unfortunately incorrect.
+ // All deltas for a single pinch gesture should sum to 0 if the start and end
+ // of a pinch gesture end up in the same place. This doesn't happen in Chrome
+ // because they followed Apple's misleading documentation, which implies that
+ // "1 + [event magnification]" is the scale factor. The scale factor is
+ // instead "pow(ratio, [event magnification])" so "[event magnification]" is
+ // already in log space.
+ //
+ // The multiplication by the backing scale factor below counteracts the
+ // division by the backing scale factor in WheelEvent.
+ WidgetWheelEvent geckoWheelEvent(true, EventMessage::eWheel, mGeckoChild);
+ [self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoWheelEvent];
+ double backingScale = mGeckoChild->BackingScaleFactor();
+ geckoWheelEvent.mDeltaY = -100.0 * [anEvent magnification] * backingScale;
+ geckoWheelEvent.mModifiers |= MODIFIER_CONTROL;
+ mGeckoChild->DispatchWindowEvent(geckoWheelEvent);
+
+ // If the fake wheel event wasn't stopped, then send a normal magnify event.
+ if (!geckoWheelEvent.mFlags.mDefaultPrevented) {
+ WidgetSimpleGestureEvent geckoEvent(true, msg, mGeckoChild);
+ geckoEvent.mDelta = deltaZ;
+ [self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent];
+ mGeckoChild->DispatchWindowEvent(geckoEvent);
+
+ // Keep track of the cumulative magnification for the final "magnify" event.
+ mCumulativeMagnification += deltaZ;
+ }
+
}
NS_OBJC_END_TRY_ABORT_BLOCK;
}
// Smart zoom gesture, i.e. two-finger double tap on trackpads.
- (void)smartMagnifyWithEvent:(NSEvent *)anEvent
{