1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "mozilla/dom/MouseEventBinding.h"
9 #include "mozilla/dom/Touch.h"
10 #include "mozilla/dom/WheelEventBinding.h"
11 #include "mozilla/MouseEvents.h"
12 #include "mozilla/StaticPrefs_dom.h"
13 #include "mozilla/SwipeTracker.h"
14 #include "mozilla/TextEvents.h"
15 #include "mozilla/TouchEvents.h"
16 #include "nsContentUtils.h"
18 #include "nsThreadUtils.h"
19 #include "UnitTransforms.h"
20 #include <type_traits>
26 template WidgetMouseEvent
MouseInput::ToWidgetEvent(nsIWidget
* aWidget
) const;
27 template WidgetPointerEvent
MouseInput::ToWidgetEvent(nsIWidget
* aWidget
) const;
29 InputData::~InputData() = default;
31 InputData::InputData(InputType aInputType
)
32 : mInputType(aInputType
),
33 mFocusSequenceNumber(0),
37 InputData::InputData(InputType aInputType
, TimeStamp aTimeStamp
,
39 : mInputType(aInputType
),
40 mTimeStamp(aTimeStamp
),
41 mFocusSequenceNumber(0),
43 modifiers(aModifiers
) {}
45 SingleTouchData::SingleTouchData(int32_t aIdentifier
,
46 ScreenIntPoint aScreenPoint
,
47 ScreenSize aRadius
, float aRotationAngle
,
49 : mIdentifier(aIdentifier
),
50 mScreenPoint(aScreenPoint
),
52 mRotationAngle(aRotationAngle
),
55 SingleTouchData::SingleTouchData(int32_t aIdentifier
,
56 ParentLayerPoint aLocalScreenPoint
,
57 ScreenSize aRadius
, float aRotationAngle
,
59 : mIdentifier(aIdentifier
),
60 mLocalScreenPoint(aLocalScreenPoint
),
62 mRotationAngle(aRotationAngle
),
65 SingleTouchData::SingleTouchData()
66 : mIdentifier(0), mRotationAngle(0.0), mForce(0.0) {}
68 already_AddRefed
<Touch
> SingleTouchData::ToNewDOMTouch() const {
69 MOZ_ASSERT(NS_IsMainThread(),
70 "Can only create dom::Touch instances on main thread");
72 new Touch(mIdentifier
,
73 LayoutDeviceIntPoint::Truncate(mScreenPoint
.x
, mScreenPoint
.y
),
74 LayoutDeviceIntPoint::Truncate(mRadius
.width
, mRadius
.height
),
75 mRotationAngle
, mForce
);
76 touch
->tiltX
= mTiltX
;
77 touch
->tiltY
= mTiltY
;
78 touch
->twist
= mTwist
;
79 return touch
.forget();
82 MultiTouchInput::MultiTouchInput(MultiTouchType aType
, uint32_t aTime
,
83 TimeStamp aTimeStamp
, Modifiers aModifiers
)
84 : InputData(MULTITOUCH_INPUT
, aTimeStamp
, aModifiers
),
86 mHandledByAPZ(false) {}
88 MultiTouchInput::MultiTouchInput()
89 : InputData(MULTITOUCH_INPUT
),
90 mType(MULTITOUCH_START
),
91 mHandledByAPZ(false) {}
93 MultiTouchInput::MultiTouchInput(const WidgetTouchEvent
& aTouchEvent
)
94 : InputData(MULTITOUCH_INPUT
, aTouchEvent
.mTimeStamp
,
95 aTouchEvent
.mModifiers
),
96 mHandledByAPZ(aTouchEvent
.mFlags
.mHandledByAPZ
),
97 mButton(aTouchEvent
.mButton
),
98 mButtons(aTouchEvent
.mButtons
) {
99 MOZ_ASSERT(NS_IsMainThread(),
100 "Can only copy from WidgetTouchEvent on main thread");
102 switch (aTouchEvent
.mMessage
) {
104 mType
= MULTITOUCH_START
;
107 mType
= MULTITOUCH_MOVE
;
110 mType
= MULTITOUCH_END
;
113 mType
= MULTITOUCH_CANCEL
;
116 MOZ_ASSERT_UNREACHABLE("Did not assign a type to a MultiTouchInput");
120 mScreenOffset
= ViewAs
<ExternalPixel
>(
121 aTouchEvent
.mWidget
->WidgetToScreenOffset(),
122 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent
);
124 for (size_t i
= 0; i
< aTouchEvent
.mTouches
.Length(); i
++) {
125 const Touch
* domTouch
= aTouchEvent
.mTouches
[i
];
127 // Extract data from weird interfaces.
128 int32_t identifier
= domTouch
->Identifier();
129 int32_t radiusX
= domTouch
->RadiusX(CallerType::System
);
130 int32_t radiusY
= domTouch
->RadiusY(CallerType::System
);
131 float rotationAngle
= domTouch
->RotationAngle(CallerType::System
);
132 float force
= domTouch
->Force(CallerType::System
);
134 SingleTouchData
data(
138 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent
),
139 ScreenSize((float)radiusX
, (float)radiusY
), rotationAngle
, force
);
141 mTouches
.AppendElement(data
);
145 void MultiTouchInput::Translate(const ScreenPoint
& aTranslation
) {
146 ScreenIntPoint translation
= RoundedToInt(aTranslation
);
148 for (auto& touchData
: mTouches
) {
149 for (auto& historicalData
: touchData
.mHistoricalData
) {
150 historicalData
.mScreenPoint
.MoveBy(translation
.x
, translation
.y
);
152 touchData
.mScreenPoint
.MoveBy(translation
.x
, translation
.y
);
156 WidgetTouchEvent
MultiTouchInput::ToWidgetEvent(nsIWidget
* aWidget
,
157 uint16_t aInputSource
) const {
158 MOZ_ASSERT(NS_IsMainThread(),
159 "Can only convert To WidgetTouchEvent on main thread");
160 MOZ_ASSERT(aInputSource
==
161 mozilla::dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH
||
162 aInputSource
== mozilla::dom::MouseEvent_Binding::MOZ_SOURCE_PEN
);
164 EventMessage touchEventMessage
= eVoidEvent
;
166 case MULTITOUCH_START
:
167 touchEventMessage
= eTouchStart
;
169 case MULTITOUCH_MOVE
:
170 touchEventMessage
= eTouchMove
;
173 touchEventMessage
= eTouchEnd
;
175 case MULTITOUCH_CANCEL
:
176 touchEventMessage
= eTouchCancel
;
179 MOZ_ASSERT_UNREACHABLE(
180 "Did not assign a type to WidgetTouchEvent in MultiTouchInput");
184 WidgetTouchEvent
event(true, touchEventMessage
, aWidget
);
185 if (touchEventMessage
== eVoidEvent
) {
189 event
.mModifiers
= this->modifiers
;
190 event
.mTimeStamp
= this->mTimeStamp
;
191 event
.mFlags
.mHandledByAPZ
= mHandledByAPZ
;
192 event
.mFocusSequenceNumber
= mFocusSequenceNumber
;
193 event
.mLayersId
= mLayersId
;
194 event
.mInputSource
= aInputSource
;
195 event
.mButton
= mButton
;
196 event
.mButtons
= mButtons
;
198 for (size_t i
= 0; i
< mTouches
.Length(); i
++) {
199 *event
.mTouches
.AppendElement() = mTouches
[i
].ToNewDOMTouch();
205 int32_t MultiTouchInput::IndexOfTouch(int32_t aTouchIdentifier
) {
206 for (size_t i
= 0; i
< mTouches
.Length(); i
++) {
207 if (mTouches
[i
].mIdentifier
== aTouchIdentifier
) {
214 bool MultiTouchInput::TransformToLocal(
215 const ScreenToParentLayerMatrix4x4
& aTransform
) {
216 for (auto& touchData
: mTouches
) {
217 for (auto& historicalData
: touchData
.mHistoricalData
) {
218 Maybe
<ParentLayerIntPoint
> historicalPoint
=
219 UntransformBy(aTransform
, historicalData
.mScreenPoint
);
220 if (!historicalPoint
) {
223 historicalData
.mLocalScreenPoint
= *historicalPoint
;
225 Maybe
<ParentLayerIntPoint
> point
=
226 UntransformBy(aTransform
, touchData
.mScreenPoint
);
230 touchData
.mLocalScreenPoint
= *point
;
235 MouseInput::MouseInput()
236 : InputData(MOUSE_INPUT
),
241 mHandledByAPZ(false),
242 mPreventClickEvent(false) {}
244 MouseInput::MouseInput(MouseType aType
, ButtonType aButtonType
,
245 uint16_t aInputSource
, int16_t aButtons
,
246 const ScreenPoint
& aPoint
, TimeStamp aTimeStamp
,
247 Modifiers aModifiers
)
248 : InputData(MOUSE_INPUT
, aTimeStamp
, aModifiers
),
250 mButtonType(aButtonType
),
251 mInputSource(aInputSource
),
254 mHandledByAPZ(false),
255 mPreventClickEvent(false) {}
257 MouseInput::MouseInput(const WidgetMouseEventBase
& aMouseEvent
)
258 : InputData(MOUSE_INPUT
, aMouseEvent
.mTimeStamp
, aMouseEvent
.mModifiers
),
261 mInputSource(aMouseEvent
.mInputSource
),
262 mButtons(aMouseEvent
.mButtons
),
263 mHandledByAPZ(aMouseEvent
.mFlags
.mHandledByAPZ
),
264 mPreventClickEvent(aMouseEvent
.mClass
== eMouseEventClass
&&
265 aMouseEvent
.AsMouseEvent()->mClickEventPrevented
) {
266 MOZ_ASSERT(NS_IsMainThread(),
267 "Can only copy from WidgetTouchEvent on main thread");
271 switch (aMouseEvent
.mButton
) {
272 case MouseButton::ePrimary
:
273 mButtonType
= MouseInput::PRIMARY_BUTTON
;
275 case MouseButton::eMiddle
:
276 mButtonType
= MouseInput::MIDDLE_BUTTON
;
278 case MouseButton::eSecondary
:
279 mButtonType
= MouseInput::SECONDARY_BUTTON
;
283 switch (aMouseEvent
.mMessage
) {
294 mType
= MOUSE_DRAG_START
;
297 mType
= MOUSE_DRAG_END
;
299 case eMouseEnterIntoWidget
:
300 mType
= MOUSE_WIDGET_ENTER
;
302 case eMouseExitFromWidget
:
303 mType
= MOUSE_WIDGET_EXIT
;
305 case eMouseExploreByTouch
:
306 mType
= MOUSE_EXPLORE_BY_TOUCH
;
309 mType
= MOUSE_HITTEST
;
312 mType
= MOUSE_CONTEXTMENU
;
315 MOZ_ASSERT_UNREACHABLE("Mouse event type not supported");
319 mOrigin
= ScreenPoint(ViewAs
<ScreenPixel
>(
320 aMouseEvent
.mRefPoint
,
321 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent
));
324 bool MouseInput::IsLeftButton() const { return mButtonType
== PRIMARY_BUTTON
; }
326 bool MouseInput::TransformToLocal(
327 const ScreenToParentLayerMatrix4x4
& aTransform
) {
328 Maybe
<ParentLayerPoint
> point
= UntransformBy(aTransform
, mOrigin
);
332 mLocalOrigin
= *point
;
337 bool MouseInput::IsPointerEventType() const {
339 dom_w3c_pointer_events_dispatch_click_as_pointer_event() &&
340 mType
== MOUSE_CONTEXTMENU
;
343 template <class WidgetMouseOrPointerEvent
>
344 WidgetMouseOrPointerEvent
MouseInput::ToWidgetEvent(nsIWidget
* aWidget
) const {
345 MOZ_ASSERT(NS_IsMainThread(),
346 "Can only convert To WidgetTouchEvent on main thread");
348 const DebugOnly
<bool> isPointerEvent
=
349 std::is_same
<WidgetMouseOrPointerEvent
, WidgetPointerEvent
>::value
;
350 const DebugOnly
<bool> isMouseEvent
=
351 std::is_same
<WidgetMouseOrPointerEvent
, WidgetMouseEvent
>::value
;
352 MOZ_ASSERT(!IsPointerEventType() || isPointerEvent
,
353 "Please use ToWidgetEvent<WidgetPointerEvent>() for the instance");
354 MOZ_ASSERT(IsPointerEventType() || isMouseEvent
,
355 "Please use ToWidgetEvent<WidgetMouseEvent>() for the instance");
357 EventMessage msg
= eVoidEvent
;
358 uint32_t clickCount
= 0;
359 Maybe
<WidgetMouseEvent::ExitFrom
> exitFrom
;
372 case MOUSE_DRAG_START
:
378 case MOUSE_WIDGET_ENTER
:
379 msg
= eMouseEnterIntoWidget
;
381 case MOUSE_WIDGET_EXIT
:
382 msg
= eMouseExitFromWidget
;
383 exitFrom
= Some(WidgetMouseEvent::ePlatformChild
);
385 case MOUSE_EXPLORE_BY_TOUCH
:
386 msg
= eMouseExploreByTouch
;
391 case MOUSE_CONTEXTMENU
:
393 MOZ_ASSERT(mButtonType
== MouseInput::SECONDARY_BUTTON
);
396 MOZ_ASSERT_UNREACHABLE(
397 "Did not assign a type to WidgetMouseEvent in MouseInput");
401 WidgetMouseOrPointerEvent
event(true, msg
, aWidget
);
403 if (msg
== eVoidEvent
) {
407 switch (mButtonType
) {
408 case MouseInput::PRIMARY_BUTTON
:
409 event
.mButton
= MouseButton::ePrimary
;
411 case MouseInput::MIDDLE_BUTTON
:
412 event
.mButton
= MouseButton::eMiddle
;
414 case MouseInput::SECONDARY_BUTTON
:
415 event
.mButton
= MouseButton::eSecondary
;
417 case MouseInput::NONE
:
422 event
.mButtons
= mButtons
;
423 event
.mModifiers
= modifiers
;
424 event
.mTimeStamp
= mTimeStamp
;
425 event
.mLayersId
= mLayersId
;
426 event
.mFlags
.mHandledByAPZ
= mHandledByAPZ
;
427 event
.mRefPoint
= RoundedToInt(ViewAs
<LayoutDevicePixel
>(
429 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent
));
430 event
.mClickCount
= clickCount
;
431 event
.mInputSource
= mInputSource
;
432 event
.mFocusSequenceNumber
= mFocusSequenceNumber
;
433 event
.mExitFrom
= exitFrom
;
434 event
.mClickEventPrevented
= mPreventClickEvent
;
439 PanGestureInput::PanGestureInput()
440 : InputData(PANGESTURE_INPUT
),
441 mType(PANGESTURE_MAYSTART
),
442 mLineOrPageDeltaX(0),
443 mLineOrPageDeltaY(0),
444 mUserDeltaMultiplierX(1.0),
445 mUserDeltaMultiplierY(1.0),
446 mHandledByAPZ(false),
447 mOverscrollBehaviorAllowsSwipe(false),
448 mSimulateMomentum(false),
449 mIsNoLineOrPageDelta(true),
450 mMayTriggerSwipe(false) {}
452 PanGestureInput::PanGestureInput(PanGestureType aType
, TimeStamp aTimeStamp
,
453 const ScreenPoint
& aPanStartPoint
,
454 const ScreenPoint
& aPanDisplacement
,
455 Modifiers aModifiers
)
456 : InputData(PANGESTURE_INPUT
, aTimeStamp
, aModifiers
),
458 mPanStartPoint(aPanStartPoint
),
459 mPanDisplacement(aPanDisplacement
),
460 mLineOrPageDeltaX(0),
461 mLineOrPageDeltaY(0),
462 mUserDeltaMultiplierX(1.0),
463 mUserDeltaMultiplierY(1.0),
464 mHandledByAPZ(false),
465 mOverscrollBehaviorAllowsSwipe(false),
466 mSimulateMomentum(false),
467 mIsNoLineOrPageDelta(true) {
468 mMayTriggerSwipe
= SwipeTracker::CanTriggerSwipe(*this);
471 PanGestureInput::PanGestureInput(PanGestureType aType
, TimeStamp aTimeStamp
,
472 const ScreenPoint
& aPanStartPoint
,
473 const ScreenPoint
& aPanDisplacement
,
474 Modifiers aModifiers
,
475 IsEligibleForSwipe aIsEligibleForSwipe
)
476 : PanGestureInput(aType
, aTimeStamp
, aPanStartPoint
, aPanDisplacement
,
478 mMayTriggerSwipe
&= bool(aIsEligibleForSwipe
);
481 void PanGestureInput::SetLineOrPageDeltas(int32_t aLineOrPageDeltaX
,
482 int32_t aLineOrPageDeltaY
) {
483 mLineOrPageDeltaX
= aLineOrPageDeltaX
;
484 mLineOrPageDeltaY
= aLineOrPageDeltaY
;
485 mIsNoLineOrPageDelta
= false;
488 bool PanGestureInput::IsMomentum() const {
490 case PanGestureInput::PANGESTURE_MOMENTUMSTART
:
491 case PanGestureInput::PANGESTURE_MOMENTUMPAN
:
492 case PanGestureInput::PANGESTURE_MOMENTUMEND
:
499 WidgetWheelEvent
PanGestureInput::ToWidgetEvent(nsIWidget
* aWidget
) const {
500 WidgetWheelEvent
wheelEvent(true, eWheel
, aWidget
);
501 wheelEvent
.mModifiers
= this->modifiers
;
502 wheelEvent
.mTimeStamp
= mTimeStamp
;
503 wheelEvent
.mLayersId
= mLayersId
;
504 wheelEvent
.mRefPoint
= RoundedToInt(ViewAs
<LayoutDevicePixel
>(
506 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent
));
507 wheelEvent
.mButtons
= 0;
508 wheelEvent
.mMayHaveMomentum
= true; // pan inputs may have momentum
509 wheelEvent
.mIsMomentum
= IsMomentum();
510 wheelEvent
.mLineOrPageDeltaX
= mLineOrPageDeltaX
;
511 wheelEvent
.mLineOrPageDeltaY
= mLineOrPageDeltaY
;
512 wheelEvent
.mDeltaX
= mPanDisplacement
.x
;
513 wheelEvent
.mDeltaY
= mPanDisplacement
.y
;
514 wheelEvent
.mFlags
.mHandledByAPZ
= mHandledByAPZ
;
515 wheelEvent
.mFocusSequenceNumber
= mFocusSequenceNumber
;
516 wheelEvent
.mIsNoLineOrPageDelta
= mIsNoLineOrPageDelta
;
517 if (mDeltaType
== PanGestureInput::PANDELTA_PAGE
) {
518 // widget/gtk is currently the only consumer that uses delta type
520 // Emulate legacy widget/gtk behavior
521 wheelEvent
.mDeltaMode
= WheelEvent_Binding::DOM_DELTA_LINE
;
522 wheelEvent
.mScrollType
= WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY
;
523 wheelEvent
.mDeltaX
*= 3;
524 wheelEvent
.mDeltaY
*= 3;
526 wheelEvent
.mDeltaMode
= WheelEvent_Binding::DOM_DELTA_PIXEL
;
531 bool PanGestureInput::TransformToLocal(
532 const ScreenToParentLayerMatrix4x4
& aTransform
) {
533 Maybe
<ParentLayerPoint
> panStartPoint
=
534 UntransformBy(aTransform
, mPanStartPoint
);
535 if (!panStartPoint
) {
538 mLocalPanStartPoint
= *panStartPoint
;
540 if (mDeltaType
== PanGestureInput::PANDELTA_PAGE
) {
541 // Skip transforming the pan displacement because we want
542 // raw page proportion counts.
543 mLocalPanDisplacement
= ViewAs
<ParentLayerPixel
>(
544 mPanDisplacement
, PixelCastJustification::DeltaIsPageProportion
);
548 Maybe
<ParentLayerPoint
> panDisplacement
=
549 UntransformVector(aTransform
, mPanDisplacement
, mPanStartPoint
);
550 if (!panDisplacement
) {
553 mLocalPanDisplacement
= *panDisplacement
;
557 ScreenPoint
PanGestureInput::UserMultipliedPanDisplacement() const {
558 return ScreenPoint(mPanDisplacement
.x
* mUserDeltaMultiplierX
,
559 mPanDisplacement
.y
* mUserDeltaMultiplierY
);
562 ParentLayerPoint
PanGestureInput::UserMultipliedLocalPanDisplacement() const {
563 return ParentLayerPoint(mLocalPanDisplacement
.x
* mUserDeltaMultiplierX
,
564 mLocalPanDisplacement
.y
* mUserDeltaMultiplierY
);
567 static int32_t TakeLargestInt(gfx::Coord
* aCoord
) {
568 int32_t result(aCoord
->value
); // truncate towards zero
569 aCoord
->value
-= result
;
573 /* static */ gfx::IntPoint
PanGestureInput::GetIntegerDeltaForEvent(
574 bool aIsStart
, float x
, float y
) {
575 static gfx::Point
sAccumulator(0.0f
, 0.0f
);
577 sAccumulator
= gfx::Point(0.0f
, 0.0f
);
581 return gfx::IntPoint(TakeLargestInt(&sAccumulator
.x
),
582 TakeLargestInt(&sAccumulator
.y
));
585 PinchGestureInput::PinchGestureInput()
586 : InputData(PINCHGESTURE_INPUT
),
587 mType(PINCHGESTURE_START
),
589 mHandledByAPZ(false) {}
591 PinchGestureInput::PinchGestureInput(
592 PinchGestureType aType
, PinchGestureSource aSource
, TimeStamp aTimeStamp
,
593 const ExternalPoint
& aScreenOffset
, const ScreenPoint
& aFocusPoint
,
594 ScreenCoord aCurrentSpan
, ScreenCoord aPreviousSpan
, Modifiers aModifiers
)
595 : InputData(PINCHGESTURE_INPUT
, aTimeStamp
, aModifiers
),
598 mFocusPoint(aFocusPoint
),
599 mScreenOffset(aScreenOffset
),
600 mCurrentSpan(aCurrentSpan
),
601 mPreviousSpan(aPreviousSpan
),
602 mLineOrPageDeltaY(0),
603 mHandledByAPZ(false) {}
605 bool PinchGestureInput::TransformToLocal(
606 const ScreenToParentLayerMatrix4x4
& aTransform
) {
607 Maybe
<ParentLayerPoint
> point
= UntransformBy(aTransform
, mFocusPoint
);
611 mLocalFocusPoint
= *point
;
615 WidgetWheelEvent
PinchGestureInput::ToWidgetEvent(nsIWidget
* aWidget
) const {
616 WidgetWheelEvent
wheelEvent(true, eWheel
, aWidget
);
617 wheelEvent
.mModifiers
= this->modifiers
| MODIFIER_CONTROL
;
618 wheelEvent
.mTimeStamp
= mTimeStamp
;
619 wheelEvent
.mLayersId
= mLayersId
;
620 wheelEvent
.mRefPoint
= RoundedToInt(ViewAs
<LayoutDevicePixel
>(
622 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent
));
623 wheelEvent
.mButtons
= 0;
624 wheelEvent
.mFlags
.mHandledByAPZ
= mHandledByAPZ
;
625 wheelEvent
.mDeltaMode
= WheelEvent_Binding::DOM_DELTA_PIXEL
;
627 wheelEvent
.mDeltaY
= ComputeDeltaY(aWidget
);
629 wheelEvent
.mLineOrPageDeltaY
= mLineOrPageDeltaY
;
631 MOZ_ASSERT(mType
== PINCHGESTURE_END
|| wheelEvent
.mDeltaY
!= 0.0);
636 double PinchGestureInput::ComputeDeltaY(nsIWidget
* aWidget
) const {
637 #if defined(XP_DARWIN)
638 // This converts the pinch gesture value to a fake wheel event that has the
639 // control key pressed so that pages can implement custom pinch gesture
640 // handling. It may seem strange that this doesn't use a wheel event with
641 // the deltaZ property set, but this matches Chrome's behavior as described
642 // at https://code.google.com/p/chromium/issues/detail?id=289887
644 // The intent of the formula below is to produce numbers similar to Chrome's
645 // implementation of this feature. Chrome implements deltaY using the formula
646 // "-100 * log(1 + [event magnification])" which is unfortunately incorrect.
647 // All deltas for a single pinch gesture should sum to 0 if the start and end
648 // of a pinch gesture end up in the same place. This doesn't happen in Chrome
649 // because they followed Apple's misleading documentation, which implies that
650 // "1 + [event magnification]" is the scale factor. The scale factor is
651 // instead "pow(ratio, [event magnification])" so "[event magnification]" is
652 // already in log space.
654 // The multiplication by the backing scale factor below counteracts the
655 // division by the backing scale factor in WheelEvent.
657 // We want to set deltaY to |-100.0 * M * GetDefaultScaleInternal()| where M
658 // is [event magnification] but [event magnification] is only available in the
659 // macOS widget code so we have to reverse engineer from mCurrentSpan and
660 // mPreviousSpan (which are derived from [event magnification]) to get it.
661 // Specifically, we know |mCurrentSpan == 100.0| and |mPreviousSpan == 100.0 *
662 // (1.0 - M)|. We can calculate deltaY by solving the mPreviousSpan equation
663 // for M in terms of mPreviousSpan and plugging that into to the formula for
665 return (mPreviousSpan
- 100.0) *
666 (aWidget
? aWidget
->GetDefaultScaleInternal() : 1.f
);
668 // This calculation is based on what the Windows and Linux widget code does.
669 // Specifically, it creates a PinchGestureInput with |mCurrentSpan == 100.0 *
670 // currentScale| and |mPreviousSpan == 100.0 * lastScale| where currentScale
671 // is the scale from the current OS event and lastScale is the scale when the
672 // previous OS event happened. On macOS [event magnification] is a relative
673 // change in scale factor, ie if the scale factor changed from 1 to 1.1 it
674 // will be 0.1, similarly if it changed from 1 to 0.9 it will be -0.1. To
675 // calculate the relative scale change on Windows we would calculate |M =
676 // currentScale - lastScale = (mCurrentSpan-mPreviousSpan)/100| and use the
677 // same formula as the macOS code
678 // (|-100.0 * M * GetDefaultScaleInternal()|).
680 return (mPreviousSpan
- mCurrentSpan
) *
681 (aWidget
? aWidget
->GetDefaultScaleInternal() : 1.f
);
685 bool PinchGestureInput::SetLineOrPageDeltaY(nsIWidget
* aWidget
) {
686 double deltaY
= ComputeDeltaY(aWidget
);
687 if (deltaY
== 0 && mType
!= PINCHGESTURE_END
) {
690 gfx::IntPoint lineOrPageDelta
= PinchGestureInput::GetIntegerDeltaForEvent(
691 (mType
== PINCHGESTURE_START
), 0, deltaY
);
692 mLineOrPageDeltaY
= lineOrPageDelta
.y
;
693 if (mLineOrPageDeltaY
== 0) {
694 // For PINCHGESTURE_SCALE events, don't dispatch them. Note that the delta
695 // isn't lost; it remains in the accumulator in GetIntegerDeltaForEvent().
696 if (mType
== PINCHGESTURE_SCALE
) {
699 // On Windows, drop PINCHGESTURE_START as well (the Windows widget code will
700 // defer the START event until we accumulate enough delta).
701 // The Linux widget code doesn't support this, so instead set the event's
702 // mLineOrPageDeltaY to the smallest nonzero amount in the relevant
704 if (mType
== PINCHGESTURE_START
) {
708 mLineOrPageDeltaY
= (deltaY
>= 0) ? 1 : -1;
711 // For PINCHGESTURE_END events, not dispatching a DOMMouseScroll for them is
717 /* static */ gfx::IntPoint
PinchGestureInput::GetIntegerDeltaForEvent(
718 bool aIsStart
, float x
, float y
) {
719 static gfx::Point
sAccumulator(0.0f
, 0.0f
);
721 sAccumulator
= gfx::Point(0.0f
, 0.0f
);
725 return gfx::IntPoint(TakeLargestInt(&sAccumulator
.x
),
726 TakeLargestInt(&sAccumulator
.y
));
729 TapGestureInput::TapGestureInput()
730 : InputData(TAPGESTURE_INPUT
), mType(TAPGESTURE_LONG
) {}
732 TapGestureInput::TapGestureInput(TapGestureType aType
, TimeStamp aTimeStamp
,
733 const ScreenIntPoint
& aPoint
,
734 Modifiers aModifiers
)
735 : InputData(TAPGESTURE_INPUT
, aTimeStamp
, aModifiers
),
739 TapGestureInput::TapGestureInput(TapGestureType aType
, TimeStamp aTimeStamp
,
740 const ParentLayerPoint
& aLocalPoint
,
741 Modifiers aModifiers
)
742 : InputData(TAPGESTURE_INPUT
, aTimeStamp
, aModifiers
),
744 mLocalPoint(aLocalPoint
) {}
746 bool TapGestureInput::TransformToLocal(
747 const ScreenToParentLayerMatrix4x4
& aTransform
) {
748 Maybe
<ParentLayerIntPoint
> point
= UntransformBy(aTransform
, mPoint
);
752 mLocalPoint
= *point
;
756 WidgetSimpleGestureEvent
TapGestureInput::ToWidgetEvent(
757 nsIWidget
* aWidget
) const {
758 WidgetSimpleGestureEvent
event(true, eTapGesture
, aWidget
);
760 event
.mTimeStamp
= mTimeStamp
;
761 event
.mLayersId
= mLayersId
;
762 event
.mRefPoint
= ViewAs
<LayoutDevicePixel
>(
764 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent
);
766 event
.mClickCount
= 1;
767 event
.mModifiers
= modifiers
;
772 ScrollWheelInput::ScrollWheelInput()
773 : InputData(SCROLLWHEEL_INPUT
),
774 mDeltaType(SCROLLDELTA_LINE
),
775 mScrollMode(SCROLLMODE_INSTANT
),
776 mHandledByAPZ(false),
779 mLineOrPageDeltaX(0),
780 mLineOrPageDeltaY(0),
781 mScrollSeriesNumber(0),
782 mUserDeltaMultiplierX(1.0),
783 mUserDeltaMultiplierY(1.0),
784 mMayHaveMomentum(false),
786 mAPZAction(APZWheelAction::Scroll
) {}
788 ScrollWheelInput::ScrollWheelInput(
789 TimeStamp aTimeStamp
, Modifiers aModifiers
, ScrollMode aScrollMode
,
790 ScrollDeltaType aDeltaType
, const ScreenPoint
& aOrigin
, double aDeltaX
,
791 double aDeltaY
, bool aAllowToOverrideSystemScrollSpeed
,
792 WheelDeltaAdjustmentStrategy aWheelDeltaAdjustmentStrategy
)
793 : InputData(SCROLLWHEEL_INPUT
, aTimeStamp
, aModifiers
),
794 mDeltaType(aDeltaType
),
795 mScrollMode(aScrollMode
),
797 mHandledByAPZ(false),
800 mLineOrPageDeltaX(0),
801 mLineOrPageDeltaY(0),
802 mScrollSeriesNumber(0),
803 mUserDeltaMultiplierX(1.0),
804 mUserDeltaMultiplierY(1.0),
805 mMayHaveMomentum(false),
807 mAllowToOverrideSystemScrollSpeed(aAllowToOverrideSystemScrollSpeed
),
808 mWheelDeltaAdjustmentStrategy(aWheelDeltaAdjustmentStrategy
),
809 mAPZAction(APZWheelAction::Scroll
) {}
811 ScrollWheelInput::ScrollWheelInput(const WidgetWheelEvent
& aWheelEvent
)
812 : InputData(SCROLLWHEEL_INPUT
, aWheelEvent
.mTimeStamp
,
813 aWheelEvent
.mModifiers
),
814 mDeltaType(DeltaTypeForDeltaMode(aWheelEvent
.mDeltaMode
)),
815 mScrollMode(SCROLLMODE_INSTANT
),
816 mHandledByAPZ(aWheelEvent
.mFlags
.mHandledByAPZ
),
817 mDeltaX(aWheelEvent
.mDeltaX
),
818 mDeltaY(aWheelEvent
.mDeltaY
),
819 mWheelTicksX(aWheelEvent
.mWheelTicksX
),
820 mWheelTicksY(aWheelEvent
.mWheelTicksX
),
821 mLineOrPageDeltaX(aWheelEvent
.mLineOrPageDeltaX
),
822 mLineOrPageDeltaY(aWheelEvent
.mLineOrPageDeltaY
),
823 mScrollSeriesNumber(0),
824 mUserDeltaMultiplierX(1.0),
825 mUserDeltaMultiplierY(1.0),
826 mMayHaveMomentum(aWheelEvent
.mMayHaveMomentum
),
827 mIsMomentum(aWheelEvent
.mIsMomentum
),
828 mAllowToOverrideSystemScrollSpeed(
829 aWheelEvent
.mAllowToOverrideSystemScrollSpeed
),
830 mWheelDeltaAdjustmentStrategy(WheelDeltaAdjustmentStrategy::eNone
),
831 mAPZAction(APZWheelAction::Scroll
) {
832 mOrigin
= ScreenPoint(ViewAs
<ScreenPixel
>(
833 aWheelEvent
.mRefPoint
,
834 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent
));
837 ScrollWheelInput::ScrollDeltaType
ScrollWheelInput::DeltaTypeForDeltaMode(
838 uint32_t aDeltaMode
) {
839 switch (aDeltaMode
) {
840 case WheelEvent_Binding::DOM_DELTA_LINE
:
841 return SCROLLDELTA_LINE
;
842 case WheelEvent_Binding::DOM_DELTA_PAGE
:
843 return SCROLLDELTA_PAGE
;
844 case WheelEvent_Binding::DOM_DELTA_PIXEL
:
845 return SCROLLDELTA_PIXEL
;
849 return SCROLLDELTA_LINE
;
852 uint32_t ScrollWheelInput::DeltaModeForDeltaType(ScrollDeltaType aDeltaType
) {
853 switch (aDeltaType
) {
854 case ScrollWheelInput::SCROLLDELTA_LINE
:
855 return WheelEvent_Binding::DOM_DELTA_LINE
;
856 case ScrollWheelInput::SCROLLDELTA_PAGE
:
857 return WheelEvent_Binding::DOM_DELTA_PAGE
;
858 case ScrollWheelInput::SCROLLDELTA_PIXEL
:
860 return WheelEvent_Binding::DOM_DELTA_PIXEL
;
864 ScrollUnit
ScrollWheelInput::ScrollUnitForDeltaType(
865 ScrollDeltaType aDeltaType
) {
866 switch (aDeltaType
) {
867 case SCROLLDELTA_LINE
:
868 return ScrollUnit::LINES
;
869 case SCROLLDELTA_PAGE
:
870 return ScrollUnit::PAGES
;
871 case SCROLLDELTA_PIXEL
:
872 return ScrollUnit::DEVICE_PIXELS
;
876 return ScrollUnit::LINES
;
879 WidgetWheelEvent
ScrollWheelInput::ToWidgetEvent(nsIWidget
* aWidget
) const {
880 WidgetWheelEvent
wheelEvent(true, eWheel
, aWidget
);
881 wheelEvent
.mModifiers
= this->modifiers
;
882 wheelEvent
.mTimeStamp
= mTimeStamp
;
883 wheelEvent
.mLayersId
= mLayersId
;
884 wheelEvent
.mRefPoint
= RoundedToInt(ViewAs
<LayoutDevicePixel
>(
886 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent
));
887 wheelEvent
.mButtons
= 0;
888 wheelEvent
.mDeltaMode
= DeltaModeForDeltaType(mDeltaType
);
889 wheelEvent
.mMayHaveMomentum
= mMayHaveMomentum
;
890 wheelEvent
.mIsMomentum
= mIsMomentum
;
891 wheelEvent
.mDeltaX
= mDeltaX
;
892 wheelEvent
.mDeltaY
= mDeltaY
;
893 wheelEvent
.mWheelTicksX
= mWheelTicksX
;
894 wheelEvent
.mWheelTicksY
= mWheelTicksY
;
895 wheelEvent
.mLineOrPageDeltaX
= mLineOrPageDeltaX
;
896 wheelEvent
.mLineOrPageDeltaY
= mLineOrPageDeltaY
;
897 wheelEvent
.mAllowToOverrideSystemScrollSpeed
=
898 mAllowToOverrideSystemScrollSpeed
;
899 wheelEvent
.mFlags
.mHandledByAPZ
= mHandledByAPZ
;
900 wheelEvent
.mFocusSequenceNumber
= mFocusSequenceNumber
;
904 bool ScrollWheelInput::TransformToLocal(
905 const ScreenToParentLayerMatrix4x4
& aTransform
) {
906 Maybe
<ParentLayerPoint
> point
= UntransformBy(aTransform
, mOrigin
);
910 mLocalOrigin
= *point
;
914 bool ScrollWheelInput::IsCustomizedByUserPrefs() const {
915 return mUserDeltaMultiplierX
!= 1.0 || mUserDeltaMultiplierY
!= 1.0;
918 KeyboardInput::KeyboardInput(const WidgetKeyboardEvent
& aEvent
)
919 : InputData(KEYBOARD_INPUT
, aEvent
.mTimeStamp
, aEvent
.mModifiers
),
920 mKeyCode(aEvent
.mKeyCode
),
921 mCharCode(aEvent
.mCharCode
),
922 mHandledByAPZ(false) {
923 switch (aEvent
.mMessage
) {
925 mType
= KeyboardInput::KEY_PRESS
;
929 mType
= KeyboardInput::KEY_UP
;
933 mType
= KeyboardInput::KEY_DOWN
;
937 mType
= KeyboardInput::KEY_OTHER
;
941 aEvent
.GetShortcutKeyCandidates(mShortcutCandidates
);
944 KeyboardInput::KeyboardInput()
945 : InputData(KEYBOARD_INPUT
),
949 mHandledByAPZ(false) {}
951 } // namespace mozilla