Bug 1909074. Don't pass OFFSET_BY_ORIGIN to GetResultingTransformMatrix when it's...
[gecko.git] / widget / InputData.cpp
blob2e68645abfe11b944e66c22bd3941544390ddccd
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/. */
6 #include "InputData.h"
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"
17 #include "nsDebug.h"
18 #include "nsThreadUtils.h"
19 #include "UnitTransforms.h"
20 #include <type_traits>
22 namespace mozilla {
24 using namespace dom;
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),
34 mLayersId{0},
35 modifiers(0) {}
37 InputData::InputData(InputType aInputType, TimeStamp aTimeStamp,
38 Modifiers aModifiers)
39 : mInputType(aInputType),
40 mTimeStamp(aTimeStamp),
41 mFocusSequenceNumber(0),
42 mLayersId{0},
43 modifiers(aModifiers) {}
45 SingleTouchData::SingleTouchData(int32_t aIdentifier,
46 ScreenIntPoint aScreenPoint,
47 ScreenSize aRadius, float aRotationAngle,
48 float aForce)
49 : mIdentifier(aIdentifier),
50 mScreenPoint(aScreenPoint),
51 mRadius(aRadius),
52 mRotationAngle(aRotationAngle),
53 mForce(aForce) {}
55 SingleTouchData::SingleTouchData(int32_t aIdentifier,
56 ParentLayerPoint aLocalScreenPoint,
57 ScreenSize aRadius, float aRotationAngle,
58 float aForce)
59 : mIdentifier(aIdentifier),
60 mLocalScreenPoint(aLocalScreenPoint),
61 mRadius(aRadius),
62 mRotationAngle(aRotationAngle),
63 mForce(aForce) {}
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");
71 RefPtr<Touch> touch =
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),
85 mType(aType),
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) {
103 case eTouchStart:
104 mType = MULTITOUCH_START;
105 break;
106 case eTouchMove:
107 mType = MULTITOUCH_MOVE;
108 break;
109 case eTouchEnd:
110 mType = MULTITOUCH_END;
111 break;
112 case eTouchCancel:
113 mType = MULTITOUCH_CANCEL;
114 break;
115 default:
116 MOZ_ASSERT_UNREACHABLE("Did not assign a type to a MultiTouchInput");
117 break;
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(
135 identifier,
136 ViewAs<ScreenPixel>(
137 domTouch->mRefPoint,
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;
165 switch (mType) {
166 case MULTITOUCH_START:
167 touchEventMessage = eTouchStart;
168 break;
169 case MULTITOUCH_MOVE:
170 touchEventMessage = eTouchMove;
171 break;
172 case MULTITOUCH_END:
173 touchEventMessage = eTouchEnd;
174 break;
175 case MULTITOUCH_CANCEL:
176 touchEventMessage = eTouchCancel;
177 break;
178 default:
179 MOZ_ASSERT_UNREACHABLE(
180 "Did not assign a type to WidgetTouchEvent in MultiTouchInput");
181 break;
184 WidgetTouchEvent event(true, touchEventMessage, aWidget);
185 if (touchEventMessage == eVoidEvent) {
186 return event;
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();
202 return event;
205 int32_t MultiTouchInput::IndexOfTouch(int32_t aTouchIdentifier) {
206 for (size_t i = 0; i < mTouches.Length(); i++) {
207 if (mTouches[i].mIdentifier == aTouchIdentifier) {
208 return (int32_t)i;
211 return -1;
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) {
221 return false;
223 historicalData.mLocalScreenPoint = *historicalPoint;
225 Maybe<ParentLayerIntPoint> point =
226 UntransformBy(aTransform, touchData.mScreenPoint);
227 if (!point) {
228 return false;
230 touchData.mLocalScreenPoint = *point;
232 return true;
235 MouseInput::MouseInput()
236 : InputData(MOUSE_INPUT),
237 mType(MOUSE_NONE),
238 mButtonType(NONE),
239 mInputSource(0),
240 mButtons(0),
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),
249 mType(aType),
250 mButtonType(aButtonType),
251 mInputSource(aInputSource),
252 mButtons(aButtons),
253 mOrigin(aPoint),
254 mHandledByAPZ(false),
255 mPreventClickEvent(false) {}
257 MouseInput::MouseInput(const WidgetMouseEventBase& aMouseEvent)
258 : InputData(MOUSE_INPUT, aMouseEvent.mTimeStamp, aMouseEvent.mModifiers),
259 mType(MOUSE_NONE),
260 mButtonType(NONE),
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");
269 mButtonType = NONE;
271 switch (aMouseEvent.mButton) {
272 case MouseButton::ePrimary:
273 mButtonType = MouseInput::PRIMARY_BUTTON;
274 break;
275 case MouseButton::eMiddle:
276 mButtonType = MouseInput::MIDDLE_BUTTON;
277 break;
278 case MouseButton::eSecondary:
279 mButtonType = MouseInput::SECONDARY_BUTTON;
280 break;
283 switch (aMouseEvent.mMessage) {
284 case eMouseMove:
285 mType = MOUSE_MOVE;
286 break;
287 case eMouseUp:
288 mType = MOUSE_UP;
289 break;
290 case eMouseDown:
291 mType = MOUSE_DOWN;
292 break;
293 case eDragStart:
294 mType = MOUSE_DRAG_START;
295 break;
296 case eDragEnd:
297 mType = MOUSE_DRAG_END;
298 break;
299 case eMouseEnterIntoWidget:
300 mType = MOUSE_WIDGET_ENTER;
301 break;
302 case eMouseExitFromWidget:
303 mType = MOUSE_WIDGET_EXIT;
304 break;
305 case eMouseExploreByTouch:
306 mType = MOUSE_EXPLORE_BY_TOUCH;
307 break;
308 case eMouseHitTest:
309 mType = MOUSE_HITTEST;
310 break;
311 case eContextMenu:
312 mType = MOUSE_CONTEXTMENU;
313 break;
314 default:
315 MOZ_ASSERT_UNREACHABLE("Mouse event type not supported");
316 break;
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);
329 if (!point) {
330 return false;
332 mLocalOrigin = *point;
334 return true;
337 bool MouseInput::IsPointerEventType() const {
338 return StaticPrefs::
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;
360 switch (mType) {
361 case MOUSE_MOVE:
362 msg = eMouseMove;
363 break;
364 case MOUSE_UP:
365 msg = eMouseUp;
366 clickCount = 1;
367 break;
368 case MOUSE_DOWN:
369 msg = eMouseDown;
370 clickCount = 1;
371 break;
372 case MOUSE_DRAG_START:
373 msg = eDragStart;
374 break;
375 case MOUSE_DRAG_END:
376 msg = eDragEnd;
377 break;
378 case MOUSE_WIDGET_ENTER:
379 msg = eMouseEnterIntoWidget;
380 break;
381 case MOUSE_WIDGET_EXIT:
382 msg = eMouseExitFromWidget;
383 exitFrom = Some(WidgetMouseEvent::ePlatformChild);
384 break;
385 case MOUSE_EXPLORE_BY_TOUCH:
386 msg = eMouseExploreByTouch;
387 break;
388 case MOUSE_HITTEST:
389 msg = eMouseHitTest;
390 break;
391 case MOUSE_CONTEXTMENU:
392 msg = eContextMenu;
393 MOZ_ASSERT(mButtonType == MouseInput::SECONDARY_BUTTON);
394 break;
395 default:
396 MOZ_ASSERT_UNREACHABLE(
397 "Did not assign a type to WidgetMouseEvent in MouseInput");
398 break;
401 WidgetMouseOrPointerEvent event(true, msg, aWidget);
403 if (msg == eVoidEvent) {
404 return event;
407 switch (mButtonType) {
408 case MouseInput::PRIMARY_BUTTON:
409 event.mButton = MouseButton::ePrimary;
410 break;
411 case MouseInput::MIDDLE_BUTTON:
412 event.mButton = MouseButton::eMiddle;
413 break;
414 case MouseInput::SECONDARY_BUTTON:
415 event.mButton = MouseButton::eSecondary;
416 break;
417 case MouseInput::NONE:
418 default:
419 break;
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>(
428 mOrigin,
429 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
430 event.mClickCount = clickCount;
431 event.mInputSource = mInputSource;
432 event.mFocusSequenceNumber = mFocusSequenceNumber;
433 event.mExitFrom = exitFrom;
434 event.mClickEventPrevented = mPreventClickEvent;
436 return event;
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),
457 mType(aType),
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,
477 aModifiers) {
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 {
489 switch (mType) {
490 case PanGestureInput::PANGESTURE_MOMENTUMSTART:
491 case PanGestureInput::PANGESTURE_MOMENTUMPAN:
492 case PanGestureInput::PANGESTURE_MOMENTUMEND:
493 return true;
494 default:
495 return false;
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>(
505 mPanStartPoint,
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
519 // PANDELTA_PAGE
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;
525 } else {
526 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
528 return wheelEvent;
531 bool PanGestureInput::TransformToLocal(
532 const ScreenToParentLayerMatrix4x4& aTransform) {
533 Maybe<ParentLayerPoint> panStartPoint =
534 UntransformBy(aTransform, mPanStartPoint);
535 if (!panStartPoint) {
536 return false;
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);
545 return true;
548 Maybe<ParentLayerPoint> panDisplacement =
549 UntransformVector(aTransform, mPanDisplacement, mPanStartPoint);
550 if (!panDisplacement) {
551 return false;
553 mLocalPanDisplacement = *panDisplacement;
554 return true;
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;
570 return result;
573 /* static */ gfx::IntPoint PanGestureInput::GetIntegerDeltaForEvent(
574 bool aIsStart, float x, float y) {
575 static gfx::Point sAccumulator(0.0f, 0.0f);
576 if (aIsStart) {
577 sAccumulator = gfx::Point(0.0f, 0.0f);
579 sAccumulator.x += x;
580 sAccumulator.y += y;
581 return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
582 TakeLargestInt(&sAccumulator.y));
585 PinchGestureInput::PinchGestureInput()
586 : InputData(PINCHGESTURE_INPUT),
587 mType(PINCHGESTURE_START),
588 mSource(UNKNOWN),
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),
596 mType(aType),
597 mSource(aSource),
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);
608 if (!point) {
609 return false;
611 mLocalFocusPoint = *point;
612 return true;
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>(
621 mFocusPoint,
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);
633 return wheelEvent;
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
664 // deltaY.
665 return (mPreviousSpan - 100.0) *
666 (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
667 #else
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);
682 #endif
685 bool PinchGestureInput::SetLineOrPageDeltaY(nsIWidget* aWidget) {
686 double deltaY = ComputeDeltaY(aWidget);
687 if (deltaY == 0 && mType != PINCHGESTURE_END) {
688 return false;
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) {
697 return false;
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
703 // direction.
704 if (mType == PINCHGESTURE_START) {
705 #ifdef XP_WIN
706 return false;
707 #else
708 mLineOrPageDeltaY = (deltaY >= 0) ? 1 : -1;
709 #endif
711 // For PINCHGESTURE_END events, not dispatching a DOMMouseScroll for them is
712 // fine.
714 return true;
717 /* static */ gfx::IntPoint PinchGestureInput::GetIntegerDeltaForEvent(
718 bool aIsStart, float x, float y) {
719 static gfx::Point sAccumulator(0.0f, 0.0f);
720 if (aIsStart) {
721 sAccumulator = gfx::Point(0.0f, 0.0f);
723 sAccumulator.x += x;
724 sAccumulator.y += y;
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),
736 mType(aType),
737 mPoint(aPoint) {}
739 TapGestureInput::TapGestureInput(TapGestureType aType, TimeStamp aTimeStamp,
740 const ParentLayerPoint& aLocalPoint,
741 Modifiers aModifiers)
742 : InputData(TAPGESTURE_INPUT, aTimeStamp, aModifiers),
743 mType(aType),
744 mLocalPoint(aLocalPoint) {}
746 bool TapGestureInput::TransformToLocal(
747 const ScreenToParentLayerMatrix4x4& aTransform) {
748 Maybe<ParentLayerIntPoint> point = UntransformBy(aTransform, mPoint);
749 if (!point) {
750 return false;
752 mLocalPoint = *point;
753 return true;
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>(
763 mPoint,
764 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
765 event.mButtons = 0;
766 event.mClickCount = 1;
767 event.mModifiers = modifiers;
769 return event;
772 ScrollWheelInput::ScrollWheelInput()
773 : InputData(SCROLLWHEEL_INPUT),
774 mDeltaType(SCROLLDELTA_LINE),
775 mScrollMode(SCROLLMODE_INSTANT),
776 mHandledByAPZ(false),
777 mDeltaX(0.0),
778 mDeltaY(0.0),
779 mLineOrPageDeltaX(0),
780 mLineOrPageDeltaY(0),
781 mScrollSeriesNumber(0),
782 mUserDeltaMultiplierX(1.0),
783 mUserDeltaMultiplierY(1.0),
784 mMayHaveMomentum(false),
785 mIsMomentum(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),
796 mOrigin(aOrigin),
797 mHandledByAPZ(false),
798 mDeltaX(aDeltaX),
799 mDeltaY(aDeltaY),
800 mLineOrPageDeltaX(0),
801 mLineOrPageDeltaY(0),
802 mScrollSeriesNumber(0),
803 mUserDeltaMultiplierX(1.0),
804 mUserDeltaMultiplierY(1.0),
805 mMayHaveMomentum(false),
806 mIsMomentum(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;
846 default:
847 MOZ_CRASH();
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:
859 default:
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;
873 default:
874 MOZ_CRASH();
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>(
885 mOrigin,
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;
901 return wheelEvent;
904 bool ScrollWheelInput::TransformToLocal(
905 const ScreenToParentLayerMatrix4x4& aTransform) {
906 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
907 if (!point) {
908 return false;
910 mLocalOrigin = *point;
911 return true;
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) {
924 case eKeyPress: {
925 mType = KeyboardInput::KEY_PRESS;
926 break;
928 case eKeyUp: {
929 mType = KeyboardInput::KEY_UP;
930 break;
932 case eKeyDown: {
933 mType = KeyboardInput::KEY_DOWN;
934 break;
936 default:
937 mType = KeyboardInput::KEY_OTHER;
938 break;
941 aEvent.GetShortcutKeyCandidates(mShortcutCandidates);
944 KeyboardInput::KeyboardInput()
945 : InputData(KEYBOARD_INPUT),
946 mType(KEY_DOWN),
947 mKeyCode(0),
948 mCharCode(0),
949 mHandledByAPZ(false) {}
951 } // namespace mozilla