Bug 1458711 - Allow pinch-zooming to be triggered by Mac trackpad gestures (behind a pref); r=botond,mstange
authorTanushree Podder <tpodder@tpodder-uphtdd.local>
Tue, 15 May 2018 16:03:24 -0400
changeset 418712 8adad3e36890e89989afaeccb09c0ca29b2f118a
parent 418711 6c6e3334fbf7085f95a740c36438d213e9dabc01
child 418713 a00ab75aea2b5d6008589c74596a983e2b964e3c
push id34010
push userbtara@mozilla.com
push dateThu, 17 May 2018 22:02:46 +0000
treeherdermozilla-central@fdd6d3850e7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond, mstange
bugs1458711
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
 {