Bug 1458063 - Introduce a new wheel action for pinch-zooming. r=kats draft
authorBotond Ballo <botond@mozilla.com>
Wed, 02 May 2018 16:51:27 -0400
changeset 790828 02d3efe180fb1cd6d49ca9b8a49e4051e6e05cac
parent 790827 7d2d5498464c1460c1192976b84d28170b3cd98c
push id108607
push userbballo@mozilla.com
push dateWed, 02 May 2018 21:54:50 +0000
reviewerskats
bugs1458063
milestone61.0a1
Bug 1458063 - Introduce a new wheel action for pinch-zooming. r=kats MozReview-Commit-ID: 7DWNvQc2pBE
browser/app/profile/firefox.js
dom/events/EventStateManager.cpp
dom/events/EventStateManager.h
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/APZCTreeManager.h
gfx/layers/apz/src/APZUtils.h
modules/libpref/init/all.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -621,18 +621,19 @@ pref("browser.gesture.twist.left", "cmd_
 pref("browser.gesture.twist.end", "cmd_gestureRotateEnd");
 pref("browser.gesture.tap", "cmd_fullZoomReset");
 
 pref("browser.snapshots.limit", 0);
 
 // 0: Nothing happens
 // 1: Scrolling contents
 // 2: Go back or go forward, in your history
-// 3: Zoom in or out.
+// 3: Zoom in or out (reflowing zoom).
 // 4: Treat vertical wheel as horizontal scroll
+// 5: Zoom in or out (pinch zoom).
 #ifdef XP_MACOSX
 // On macOS, if the wheel has one axis only, shift+wheel comes through as a
 // horizontal scroll event. Thus, we can't assign anything other than normal
 // scrolling to shift+wheel.
 pref("mousewheel.with_shift.action", 1);
 pref("mousewheel.with_alt.action", 2);
 // On MacOS X, control+wheel is typically handled by system and we don't
 // receive the event.  So, command key which is the main modifier key for
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -6252,16 +6252,18 @@ EventStateManager::APZWheelActionFor(con
     return Nothing();
   }
   WheelPrefs::Action action =
     WheelPrefs::GetInstance()->ComputeActionFor(aEvent);
   switch (action) {
   case WheelPrefs::ACTION_SCROLL:
   case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL:
     return Some(layers::APZWheelAction::Scroll);
+  case WheelPrefs::ACTION_PINCH_ZOOM:
+    return Some(layers::APZWheelAction::PinchZoom);
   default:
     return Nothing();
   }
 }
 
 // static
 WheelDeltaAdjustmentStrategy
 EventStateManager::GetWheelDeltaAdjustmentStrategy(
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -582,17 +582,18 @@ protected:
       ACTION_ZOOM,
       // Horizontalized scrolling means treating vertical wheel scrolling as
       // horizontal scrolling during the process of its default action and
       // plugins handling scrolling. Note that delta values as the event object
       // in a DOM event listener won't be affected, and will be still the
       // original values. For more details, refer to
       // mozilla::WheelDeltaAdjustmentStrategy::eHorizontalize
       ACTION_HORIZONTALIZED_SCROLL,
-      ACTION_LAST = ACTION_HORIZONTALIZED_SCROLL,
+      ACTION_PINCH_ZOOM,
+      ACTION_LAST = ACTION_PINCH_ZOOM,
       // Following actions are used only by internal processing.  So, cannot
       // specified by prefs.
       ACTION_SEND_TO_PLUGIN,
     };
     Action ComputeActionFor(const WidgetWheelEvent* aEvent);
 
     /**
      * NeedToComputeLineOrPageDelta() returns if the aEvent needs to be
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -1263,23 +1263,36 @@ APZCTreeManager::ReceiveInputEvent(Input
       FlushRepaintsToClearScreenToGeckoTransform();
 
       ScrollWheelInput& wheelInput = aEvent.AsScrollWheelInput();
       wheelInput.mHandledByAPZ = WillHandleInput(wheelInput);
       if (!wheelInput.mHandledByAPZ) {
         return result;
       }
 
-      MOZ_ASSERT(wheelInput.mAPZAction == APZWheelAction::Scroll);
-
       RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(wheelInput.mOrigin,
                                                             &hitResult);
       if (apzc) {
         MOZ_ASSERT(hitResult != CompositorHitTestInfo::eInvisibleToHitTest);
 
+        if (wheelInput.mAPZAction == APZWheelAction::PinchZoom) {
+          // The mousewheel may have hit a subframe, but we want to send the
+          // pinch-zoom events to the root-content APZC.
+          {
+            RecursiveMutexAutoLock lock(mTreeLock);
+            apzc = FindRootContentApzcForLayersId(apzc->GetLayersId());
+          }
+          if (apzc) {
+            SynthesizePinchGestureFromMouseWheel(wheelInput, apzc);
+          }
+          return nsEventStatus_eConsumeNoDefault;
+        }
+
+        MOZ_ASSERT(wheelInput.mAPZAction == APZWheelAction::Scroll);
+
         // For wheel events, the call to ReceiveInputEvent below may result in
         // scrolling, which changes the async transform. However, the event we
         // want to pass to gecko should be the pre-scroll event coordinates,
         // transformed into the gecko space. (pre-scroll because the mouse
         // cursor is stationary during wheel scrolling, unlike touchmove
         // events). Since we just flushed the pending repaints the transform to
         // gecko space should only consist of overscroll-cancelling transforms.
         ScreenToScreenMatrix4x4 transformToGecko = GetScreenToApzcTransform(apzc)
@@ -1831,16 +1844,73 @@ APZCTreeManager::SetupScrollbarDrag(Mous
                          aApzc->GetGuid().mPresShellId,
                          dragBlockId,
                          dragStart,
                          *thumbData.mDirection));
   }
 }
 
 void
+APZCTreeManager::SynthesizePinchGestureFromMouseWheel(
+    const ScrollWheelInput& aWheelInput,
+    const RefPtr<AsyncPanZoomController>& aTarget)
+{
+  MOZ_ASSERT(aTarget);
+
+  ScreenPoint focusPoint = aWheelInput.mOrigin;
+
+  // Compute span values based on the wheel delta.
+  // See the PinchGestureInput constructor called below for why
+  // it's OK to use ParentLayer coordinates for the span values.
+  ParentLayerCoord oldSpan = 100;
+  ParentLayerCoord newSpan = oldSpan + aWheelInput.mDeltaY;
+
+  // There's no ambiguity as to the target for pinch gesture events.
+  TargetConfirmationFlags confFlags{true};
+
+  PinchGestureInput pinchStart{
+      PinchGestureInput::PINCHGESTURE_START,
+      aWheelInput.mTime,
+      aWheelInput.mTimeStamp,
+      focusPoint,
+      oldSpan,
+      oldSpan,
+      aWheelInput.modifiers};
+  PinchGestureInput pinchScale1{
+      PinchGestureInput::PINCHGESTURE_SCALE,
+      aWheelInput.mTime,
+      aWheelInput.mTimeStamp,
+      focusPoint,
+      oldSpan,
+      oldSpan,
+      aWheelInput.modifiers};
+  PinchGestureInput pinchScale2{
+      PinchGestureInput::PINCHGESTURE_SCALE,
+      aWheelInput.mTime,
+      aWheelInput.mTimeStamp,
+      focusPoint,
+      oldSpan,
+      newSpan,
+      aWheelInput.modifiers};
+  PinchGestureInput pinchEnd{
+      PinchGestureInput::PINCHGESTURE_END,
+      aWheelInput.mTime,
+      aWheelInput.mTimeStamp,
+      PinchGestureInput::BothFingersLifted<ScreenPixel>(),
+      newSpan,
+      newSpan,
+      aWheelInput.modifiers};
+
+  mInputQueue->ReceiveInputEvent(aTarget, confFlags, pinchStart, nullptr);
+  mInputQueue->ReceiveInputEvent(aTarget, confFlags, pinchScale1, nullptr);
+  mInputQueue->ReceiveInputEvent(aTarget, confFlags, pinchScale2, nullptr);
+  mInputQueue->ReceiveInputEvent(aTarget, confFlags, pinchEnd, nullptr);
+}
+
+void
 APZCTreeManager::UpdateWheelTransaction(LayoutDeviceIntPoint aRefPoint,
                                         EventMessage aEventMessage)
 {
   APZThreadUtils::AssertOnControllerThread();
 
   WheelBlockState* txn = mInputQueue->GetActiveWheelTransaction();
   if (!txn) {
     return;
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -687,16 +687,20 @@ private:
    * @return See ReceiveInputEvent() for what the return value means.
    */
   nsEventStatus ProcessTouchInputForScrollbarDrag(MultiTouchInput& aInput,
                                                   const HitTestingTreeNode* aScrollThumbNode,
                                                   ScrollableLayerGuid* aOutTargetGuid,
                                                   uint64_t* aOutInputBlockId);
   void FlushRepaintsToClearScreenToGeckoTransform();
 
+  void SynthesizePinchGestureFromMouseWheel(const ScrollWheelInput& aWheelInput,
+                                            const RefPtr<AsyncPanZoomController>& aTarget);
+
+
   already_AddRefed<HitTestingTreeNode> RecycleOrCreateNode(TreeBuildingState& aState,
                                                            AsyncPanZoomController* aApzc,
                                                            LayersId aLayersId);
   template<class ScrollNode>
   HitTestingTreeNode* PrepareNodeForLayer(const ScrollNode& aLayer,
                                           const FrameMetrics& aMetrics,
                                           LayersId aLayersId,
                                           const AncestorTransform& aAncestorTransform,
--- a/gfx/layers/apz/src/APZUtils.h
+++ b/gfx/layers/apz/src/APZUtils.h
@@ -48,17 +48,18 @@ enum class ScrollSource {
   // Mouse wheel.
   Wheel,
 
   // Keyboard
   Keyboard,
 };
 
 MOZ_DEFINE_ENUM_CLASS_WITH_BASE(APZWheelAction, uint8_t, (
-    Scroll
+    Scroll,
+    PinchZoom
 ))
 
 // Epsilon to be used when comparing 'float' coordinate values
 // with FuzzyEqualsAdditive. The rationale is that 'float' has 7 decimal
 // digits of precision, and coordinate values should be no larger than in the
 // ten thousands. Note also that the smallest legitimate difference in page
 // coordinates is 1 app unit, which is 1/60 of a (CSS pixel), so this epsilon
 // isn't too large.
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2621,21 +2621,22 @@ pref("mousewheel.system_scroll_override_
 pref("mousewheel.system_scroll_override_on_root_content.horizontal.factor", 200);
 
 // mousewheel.*.action can specify the action when you use mosue wheel.
 // When no modifier keys are pressed or two or more modifires are pressed,
 // .default is used.
 // 0: Nothing happens
 // 1: Scrolling contents
 // 2: Go back or go forward, in your history
-// 3: Zoom in or out.
+// 3: Zoom in or out (reflowing zoom).
 // 4: Treat vertical wheel as horizontal scroll
 //      This treats vertical wheel operation (i.e., deltaY) as horizontal
 //      scroll.  deltaX and deltaZ are always ignored.  So, only
 //      "delta_multiplier_y" pref affects the scroll speed.
+// 5: Zoom in or out (pinch zoom).
 pref("mousewheel.default.action", 1);
 pref("mousewheel.with_alt.action", 2);
 pref("mousewheel.with_control.action", 3);
 pref("mousewheel.with_meta.action", 1);  // command key on Mac
 pref("mousewheel.with_shift.action", 4);
 pref("mousewheel.with_win.action", 1);
 
 // mousewheel.*.action.override_x will override the action