Bug 1458711 - Allow pinch-zooming to be triggered by Mac trackpad gestures (behind a pref); r?botond,mstange draft
authorTanushree Podder <tpodder@tpodder-uphtdd.local>
Tue, 15 May 2018 16:03:24 -0400
changeset 795952 23b053b561915cf2e5ea67f0ad9b4b2b5b7145ef
parent 794191 4303d49c53931385892231969e40048f096b4d4c
push id110132
push userbmo:tpodder@mozilla.com
push dateWed, 16 May 2018 21:05:05 +0000
reviewersbotond, mstange
bugs1458711
milestone62.0a1
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
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
--- 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
 {