Bug 1658001. Populate wheelEvent.mLineOrPageDeltaY in PinchGestureInput::ToWidgetWheel for pinch gestures produced from direct manipulation. r=kats
authorTimothy Nikkel <tnikkel@gmail.com>
Tue, 11 Aug 2020 09:08:06 +0000
changeset 544365 bd9655461cbce5a309ba79ec6ab5cb71855356b2
parent 544364 3555578b1b2542b0a1ec36a4446ae2f11b6e45a2
child 544366 5e401631f3ef750246698f5a3ebb1e608fd9a160
push id123992
push usertnikkel@mozilla.com
push dateWed, 12 Aug 2020 07:00:48 +0000
treeherderautoland@bd9655461cbc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1658001
milestone81.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 1658001. Populate wheelEvent.mLineOrPageDeltaY in PinchGestureInput::ToWidgetWheel for pinch gestures produced from direct manipulation. r=kats We do this analogously to how PanGestureInput does it except that the delta's that we compute mLineOrPageDeltaY from are computed by us instead of provided to us. mLineOrPageDeltaY being non-zero is what EventStateManager::DispatchLegacyMouseScrollEvents uses to decide to send legacy mouse events, so we need to populate it to get those legacy events to send. This fix is Windows only on purpose as pinches on macOS don't seem to send wheel events (Windows sends ctrl+wheel). When Linux gets implemented it will need to be determined what to do. Differential Revision: https://phabricator.services.mozilla.com/D86495
widget/InputData.cpp
widget/InputData.h
widget/nsGUIEventIPC.h
widget/windows/DirectManipulationOwner.cpp
--- a/widget/InputData.cpp
+++ b/widget/InputData.cpp
@@ -525,16 +525,17 @@ PinchGestureInput::PinchGestureInput(
     ScreenCoord aPreviousSpan, Modifiers aModifiers)
     : InputData(PINCHGESTURE_INPUT, aTime, aTimeStamp, aModifiers),
       mType(aType),
       mSource(aSource),
       mFocusPoint(aFocusPoint),
       mScreenOffset(aScreenOffset),
       mCurrentSpan(aCurrentSpan),
       mPreviousSpan(aPreviousSpan),
+      mLineOrPageDeltaY(0),
       mHandledByAPZ(false) {}
 
 bool PinchGestureInput::TransformToLocal(
     const ScreenToParentLayerMatrix4x4& aTransform) {
   Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mFocusPoint);
   if (!point) {
     return false;
   }
@@ -550,16 +551,26 @@ WidgetWheelEvent PinchGestureInput::ToWi
   wheelEvent.mTimeStamp = mTimeStamp;
   wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
       mFocusPoint,
       PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
   wheelEvent.mButtons = 0;
   wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
   wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
 
+  wheelEvent.mDeltaY = ComputeDeltaY(aWidget);
+
+  wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
+
+  MOZ_ASSERT(mType == PINCHGESTURE_END || wheelEvent.mDeltaY != 0.0);
+
+  return wheelEvent;
+}
+
+double PinchGestureInput::ComputeDeltaY(nsIWidget* aWidget) const {
 #if defined(OS_MACOSX)
   // This converts the pinch gesture value to 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
@@ -578,41 +589,49 @@ WidgetWheelEvent PinchGestureInput::ToWi
   // We want to set deltaY to |-100.0 * M * GetDefaultScaleInternal()| where M
   // is [event magnification] but [event magnification] is only available in the
   // macOS widget code so we have to reverse engineer from mCurrentSpan and
   // mPreviousSpan (which are derived from [event magnification]) to get it.
   // Specifically, we know |mCurrentSpan == 100.0| and |mPreviousSpan == 100.0 *
   // (1.0 - M)|. We can calculate deltaY by solving the mPreviousSpan equation
   // for M in terms of mPreviousSpan and plugging that into to the formula for
   // deltaY.
-  wheelEvent.mDeltaY = (mPreviousSpan - 100.0) *
-                       (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
+  return (mPreviousSpan - 100.0) *
+         (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
 #else
   // This calculation is based on what the Windows widget code does.
   // Specifically, it creates a PinchGestureInput with |mCurrentSpan == 100.0 *
   // currentScale| and |mPreviousSpan == 100.0 * lastScale| where currentScale
   // is the scale from the current OS event and lastScale is the scale when the
   // previous OS event happened. On macOS [event magnification] is a relative
   // change in scale factor, ie if the scale factor changed from 1 to 1.1 it
   // will be 0.1, similarly if it changed from 1 to 0.9 it will be -0.1. To
   // calculate the relative scale change on Windows we would calculate |M =
   // currentScale - lastScale = (mCurrentSpan-mPreviousSpan)/100| and use the
   // same formula as the macOS code
   // (|-100.0 * M * GetDefaultScaleInternal()|).
 
   // XXX When we write the code for other platforms to do the same we'll need to
   // make sure this calculation is reasonable.
 
-  wheelEvent.mDeltaY = (mPreviousSpan - mCurrentSpan) *
-                       (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
+  return (mPreviousSpan - mCurrentSpan) *
+         (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
 #endif
+}
 
-  MOZ_ASSERT(mType == PINCHGESTURE_END || wheelEvent.mDeltaY != 0.0);
-
-  return wheelEvent;
+/* static */ gfx::IntPoint PinchGestureInput::GetIntegerDeltaForEvent(
+    bool aIsStart, float x, float y) {
+  static gfx::Point sAccumulator(0.0f, 0.0f);
+  if (aIsStart) {
+    sAccumulator = gfx::Point(0.0f, 0.0f);
+  }
+  sAccumulator.x += x;
+  sAccumulator.y += y;
+  return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
+                       TakeLargestInt(&sAccumulator.y));
 }
 
 TapGestureInput::TapGestureInput()
     : InputData(TAPGESTURE_INPUT), mType(TAPGESTURE_LONG) {}
 
 TapGestureInput::TapGestureInput(TapGestureType aType, uint32_t aTime,
                                  TimeStamp aTimeStamp,
                                  const ScreenIntPoint& aPoint,
--- a/widget/InputData.h
+++ b/widget/InputData.h
@@ -470,16 +470,20 @@ class PinchGestureInput : public InputDa
                     const ExternalPoint& aScreenOffset,
                     const ScreenPoint& aFocusPoint, ScreenCoord aCurrentSpan,
                     ScreenCoord aPreviousSpan, Modifiers aModifiers);
 
   bool TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform);
 
   WidgetWheelEvent ToWidgetWheelEvent(nsIWidget* aWidget) const;
 
+  double ComputeDeltaY(nsIWidget* aWidget) const;
+
+  static gfx::IntPoint GetIntegerDeltaForEvent(bool aIsStart, float x, float y);
+
   // Warning, this class is serialized and sent over IPC. Any change to its
   // fields must be reflected in its ParamTraits<>, in nsGUIEventIPC.h
   PinchGestureType mType;
 
   // Some indication of the input device that generated this pinch gesture.
   PinchGestureSource mSource;
 
   // Center point of the pinch gesture. That is, if there are two fingers on the
@@ -504,16 +508,24 @@ class PinchGestureInput : public InputDa
   // The distance between the touches responsible for the pinch gesture.
   ScreenCoord mCurrentSpan;
 
   // The previous |mCurrentSpan| in the PinchGestureInput preceding this one.
   // This is only really relevant during a PINCHGESTURE_SCALE because when it is
   // of this type then there must have been a history of spans.
   ScreenCoord mPreviousSpan;
 
+  // We accumulate (via GetIntegerDeltaForEvent) the deltaY that would be
+  // computed by ToWidgetWheelEvent, and then whenever we get a whole integer
+  // value we put it in mLineOrPageDeltaY. Since we only ever use deltaY we
+  // don't need a mLineOrPageDeltaX. This field is used to dispatch legacy mouse
+  // events which are only dispatched when the corresponding field on
+  // WidgetWheelEvent is non-zero.
+  int32_t mLineOrPageDeltaY;
+
   bool mHandledByAPZ;
 };
 
 /**
  * Encapsulation class for tap events. In general, these will be generated by
  * a gesture listener by looking at SingleTouchData/MultiTouchInput instances
  * and determining whether or not the user was trying to do a gesture.
  */
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -1301,29 +1301,31 @@ struct ParamTraits<mozilla::PinchGesture
     WriteParam(aMsg, static_cast<const mozilla::InputData&>(aParam));
     WriteParam(aMsg, aParam.mType);
     WriteParam(aMsg, aParam.mSource);
     WriteParam(aMsg, aParam.mScreenOffset);
     WriteParam(aMsg, aParam.mFocusPoint);
     WriteParam(aMsg, aParam.mLocalFocusPoint);
     WriteParam(aMsg, aParam.mCurrentSpan);
     WriteParam(aMsg, aParam.mPreviousSpan);
+    WriteParam(aMsg, aParam.mLineOrPageDeltaY);
     WriteParam(aMsg, aParam.mHandledByAPZ);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter,
                    paramType* aResult) {
     return ReadParam(aMsg, aIter, static_cast<mozilla::InputData*>(aResult)) &&
            ReadParam(aMsg, aIter, &aResult->mType) &&
            ReadParam(aMsg, aIter, &aResult->mSource) &&
            ReadParam(aMsg, aIter, &aResult->mScreenOffset) &&
            ReadParam(aMsg, aIter, &aResult->mFocusPoint) &&
            ReadParam(aMsg, aIter, &aResult->mLocalFocusPoint) &&
            ReadParam(aMsg, aIter, &aResult->mCurrentSpan) &&
            ReadParam(aMsg, aIter, &aResult->mPreviousSpan) &&
+           ReadParam(aMsg, aIter, &aResult->mLineOrPageDeltaY) &&
            ReadParam(aMsg, aIter, &aResult->mHandledByAPZ);
   }
 };
 
 template <>
 struct ParamTraits<mozilla::TapGestureInput::TapGestureType>
     : public ContiguousEnumSerializerInclusive<
           mozilla::TapGestureInput::TapGestureType,
--- a/widget/windows/DirectManipulationOwner.cpp
+++ b/widget/windows/DirectManipulationOwner.cpp
@@ -410,16 +410,20 @@ void DManipEventHandler::SendPinch(Phase
                           eventIntervalTime,
                           eventTimeStamp,
                           screenOffset,
                           position,
                           100.0 * ((aPhase == Phase::eEnd) ? 1.f : aScale),
                           100.0 * ((aPhase == Phase::eEnd) ? 1.f : mLastScale),
                           mods};
 
+  gfx::IntPoint lineOrPageDelta = PinchGestureInput::GetIntegerDeltaForEvent(
+      (aPhase == Phase::eStart), 0, event.ComputeDeltaY(mWindow));
+  event.mLineOrPageDeltaY = lineOrPageDelta.y;
+
   mWindow->SendAnAPZEvent(event);
 }
 
 void DManipEventHandler::SendPan(Phase aPhase, float x, float y,
                                  bool aIsInertia) {
   if (!mWindow) {
     return;
   }