Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / widget / InputData.cpp
blob273970cf0bbae7eb45c1a43f3a2014a3c086449b
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;
28 template WidgetDragEvent MouseInput::ToWidgetEvent(nsIWidget* aWidget) const;
30 InputData::~InputData() = default;
32 InputData::InputData(InputType aInputType)
33 : mInputType(aInputType),
34 mFocusSequenceNumber(0),
35 mLayersId{0},
36 modifiers(0) {}
38 InputData::InputData(InputType aInputType, TimeStamp aTimeStamp,
39 Modifiers aModifiers)
40 : mInputType(aInputType),
41 mTimeStamp(aTimeStamp),
42 mFocusSequenceNumber(0),
43 mLayersId{0},
44 modifiers(aModifiers) {}
46 SingleTouchData::SingleTouchData(int32_t aIdentifier,
47 ScreenIntPoint aScreenPoint,
48 ScreenSize aRadius, float aRotationAngle,
49 float aForce)
50 : mIdentifier(aIdentifier),
51 mScreenPoint(aScreenPoint),
52 mRadius(aRadius),
53 mRotationAngle(aRotationAngle),
54 mForce(aForce) {}
56 SingleTouchData::SingleTouchData(int32_t aIdentifier,
57 ParentLayerPoint aLocalScreenPoint,
58 ScreenSize aRadius, float aRotationAngle,
59 float aForce)
60 : mIdentifier(aIdentifier),
61 mLocalScreenPoint(aLocalScreenPoint),
62 mRadius(aRadius),
63 mRotationAngle(aRotationAngle),
64 mForce(aForce) {}
66 SingleTouchData::SingleTouchData()
67 : mIdentifier(0), mRotationAngle(0.0), mForce(0.0) {}
69 already_AddRefed<Touch> SingleTouchData::ToNewDOMTouch() const {
70 MOZ_ASSERT(NS_IsMainThread(),
71 "Can only create dom::Touch instances on main thread");
72 RefPtr<Touch> touch =
73 new Touch(mIdentifier,
74 LayoutDeviceIntPoint::Truncate(mScreenPoint.x, mScreenPoint.y),
75 LayoutDeviceIntPoint::Truncate(mRadius.width, mRadius.height),
76 mRotationAngle, mForce);
77 touch->tiltX = mTiltX;
78 touch->tiltY = mTiltY;
79 touch->twist = mTwist;
80 return touch.forget();
83 MultiTouchInput::MultiTouchInput(MultiTouchType aType, uint32_t aTime,
84 TimeStamp aTimeStamp, Modifiers aModifiers)
85 : InputData(MULTITOUCH_INPUT, aTimeStamp, aModifiers),
86 mType(aType),
87 mHandledByAPZ(false) {}
89 MultiTouchInput::MultiTouchInput()
90 : InputData(MULTITOUCH_INPUT),
91 mType(MULTITOUCH_START),
92 mHandledByAPZ(false) {}
94 MultiTouchInput::MultiTouchInput(const WidgetTouchEvent& aTouchEvent)
95 : InputData(MULTITOUCH_INPUT, aTouchEvent.mTimeStamp,
96 aTouchEvent.mModifiers),
97 mHandledByAPZ(aTouchEvent.mFlags.mHandledByAPZ),
98 mButton(aTouchEvent.mButton),
99 mButtons(aTouchEvent.mButtons) {
100 MOZ_ASSERT(NS_IsMainThread(),
101 "Can only copy from WidgetTouchEvent on main thread");
103 switch (aTouchEvent.mMessage) {
104 case eTouchStart:
105 mType = MULTITOUCH_START;
106 break;
107 case eTouchMove:
108 mType = MULTITOUCH_MOVE;
109 break;
110 case eTouchEnd:
111 mType = MULTITOUCH_END;
112 break;
113 case eTouchCancel:
114 mType = MULTITOUCH_CANCEL;
115 break;
116 default:
117 MOZ_ASSERT_UNREACHABLE("Did not assign a type to a MultiTouchInput");
118 break;
121 mScreenOffset = ViewAs<ExternalPixel>(
122 aTouchEvent.mWidget->WidgetToScreenOffset(),
123 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
125 for (size_t i = 0; i < aTouchEvent.mTouches.Length(); i++) {
126 const Touch* domTouch = aTouchEvent.mTouches[i];
128 // Extract data from weird interfaces.
129 int32_t identifier = domTouch->Identifier();
130 int32_t radiusX = domTouch->RadiusX(CallerType::System);
131 int32_t radiusY = domTouch->RadiusY(CallerType::System);
132 float rotationAngle = domTouch->RotationAngle(CallerType::System);
133 float force = domTouch->Force(CallerType::System);
135 SingleTouchData data(
136 identifier,
137 ViewAs<ScreenPixel>(
138 domTouch->mRefPoint,
139 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent),
140 ScreenSize((float)radiusX, (float)radiusY), rotationAngle, force);
142 mTouches.AppendElement(data);
146 void MultiTouchInput::Translate(const ScreenPoint& aTranslation) {
147 ScreenIntPoint translation = RoundedToInt(aTranslation);
149 for (auto& touchData : mTouches) {
150 for (auto& historicalData : touchData.mHistoricalData) {
151 historicalData.mScreenPoint.MoveBy(translation.x, translation.y);
153 touchData.mScreenPoint.MoveBy(translation.x, translation.y);
157 WidgetTouchEvent MultiTouchInput::ToWidgetEvent(nsIWidget* aWidget,
158 uint16_t aInputSource) const {
159 MOZ_ASSERT(NS_IsMainThread(),
160 "Can only convert To WidgetTouchEvent on main thread");
161 MOZ_ASSERT(aInputSource ==
162 mozilla::dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH ||
163 aInputSource == mozilla::dom::MouseEvent_Binding::MOZ_SOURCE_PEN);
165 EventMessage touchEventMessage = eVoidEvent;
166 switch (mType) {
167 case MULTITOUCH_START:
168 touchEventMessage = eTouchStart;
169 break;
170 case MULTITOUCH_MOVE:
171 touchEventMessage = eTouchMove;
172 break;
173 case MULTITOUCH_END:
174 touchEventMessage = eTouchEnd;
175 break;
176 case MULTITOUCH_CANCEL:
177 touchEventMessage = eTouchCancel;
178 break;
179 default:
180 MOZ_ASSERT_UNREACHABLE(
181 "Did not assign a type to WidgetTouchEvent in MultiTouchInput");
182 break;
185 WidgetTouchEvent event(true, touchEventMessage, aWidget);
186 if (touchEventMessage == eVoidEvent) {
187 return event;
190 event.mModifiers = this->modifiers;
191 event.mTimeStamp = this->mTimeStamp;
192 event.mFlags.mHandledByAPZ = mHandledByAPZ;
193 event.mFocusSequenceNumber = mFocusSequenceNumber;
194 event.mLayersId = mLayersId;
195 event.mInputSource = aInputSource;
196 event.mButton = mButton;
197 event.mButtons = mButtons;
199 for (size_t i = 0; i < mTouches.Length(); i++) {
200 *event.mTouches.AppendElement() = mTouches[i].ToNewDOMTouch();
203 return event;
206 int32_t MultiTouchInput::IndexOfTouch(int32_t aTouchIdentifier) {
207 for (size_t i = 0; i < mTouches.Length(); i++) {
208 if (mTouches[i].mIdentifier == aTouchIdentifier) {
209 return (int32_t)i;
212 return -1;
215 bool MultiTouchInput::TransformToLocal(
216 const ScreenToParentLayerMatrix4x4& aTransform) {
217 for (auto& touchData : mTouches) {
218 for (auto& historicalData : touchData.mHistoricalData) {
219 Maybe<ParentLayerIntPoint> historicalPoint =
220 UntransformBy(aTransform, historicalData.mScreenPoint);
221 if (!historicalPoint) {
222 return false;
224 historicalData.mLocalScreenPoint = *historicalPoint;
226 Maybe<ParentLayerIntPoint> point =
227 UntransformBy(aTransform, touchData.mScreenPoint);
228 if (!point) {
229 return false;
231 touchData.mLocalScreenPoint = *point;
233 return true;
236 MouseInput::MouseInput()
237 : InputData(MOUSE_INPUT),
238 mType(MOUSE_NONE),
239 mButtonType(NONE),
240 mInputSource(0),
241 mButtons(0),
242 mHandledByAPZ(false),
243 mPreventClickEvent(false),
244 mIgnoreCapturingContent(false),
245 mSynthesizeMoveAfterDispatch(false) {}
247 MouseInput::MouseInput(MouseType aType, ButtonType aButtonType,
248 uint16_t aInputSource, int16_t aButtons,
249 const ScreenPoint& aPoint, TimeStamp aTimeStamp,
250 Modifiers aModifiers)
251 : InputData(MOUSE_INPUT, aTimeStamp, aModifiers),
252 mType(aType),
253 mButtonType(aButtonType),
254 mInputSource(aInputSource),
255 mButtons(aButtons),
256 mOrigin(aPoint),
257 mHandledByAPZ(false),
258 mPreventClickEvent(false),
259 mIgnoreCapturingContent(false),
260 mSynthesizeMoveAfterDispatch(false) {}
262 MouseInput::MouseInput(const WidgetMouseEventBase& aMouseEvent)
263 : InputData(MOUSE_INPUT, aMouseEvent.mTimeStamp, aMouseEvent.mModifiers),
264 mType(MOUSE_NONE),
265 mButtonType(NONE),
266 mInputSource(aMouseEvent.mInputSource),
267 mButtons(aMouseEvent.mButtons),
268 mHandledByAPZ(aMouseEvent.mFlags.mHandledByAPZ),
269 mPreventClickEvent(aMouseEvent.mClass == eMouseEventClass &&
270 static_cast<const WidgetMouseEvent&>(aMouseEvent)
271 .mClickEventPrevented),
272 mIgnoreCapturingContent((aMouseEvent.mClass == eMouseEventClass ||
273 aMouseEvent.mClass == ePointerEventClass) &&
274 static_cast<const WidgetMouseEvent&>(aMouseEvent)
275 .mIgnoreCapturingContent),
276 mSynthesizeMoveAfterDispatch(
277 (aMouseEvent.mClass == eMouseEventClass ||
278 aMouseEvent.mClass == ePointerEventClass) &&
279 static_cast<const WidgetMouseEvent&>(aMouseEvent)
280 .mSynthesizeMoveAfterDispatch) {
281 MOZ_ASSERT(NS_IsMainThread(),
282 "Can only copy from WidgetTouchEvent on main thread");
284 mButtonType = NONE;
286 switch (aMouseEvent.mButton) {
287 case MouseButton::ePrimary:
288 mButtonType = MouseInput::PRIMARY_BUTTON;
289 break;
290 case MouseButton::eMiddle:
291 mButtonType = MouseInput::MIDDLE_BUTTON;
292 break;
293 case MouseButton::eSecondary:
294 mButtonType = MouseInput::SECONDARY_BUTTON;
295 break;
298 switch (aMouseEvent.mMessage) {
299 case eMouseMove:
300 mType = MOUSE_MOVE;
301 break;
302 case eMouseUp:
303 mType = MOUSE_UP;
304 break;
305 case eMouseDown:
306 mType = MOUSE_DOWN;
307 break;
308 case eDragStart:
309 mType = MOUSE_DRAG_START;
310 break;
311 case eDragEnd:
312 mType = MOUSE_DRAG_END;
313 break;
314 case eDragEnter:
315 mType = MOUSE_DRAG_ENTER;
316 break;
317 case eDragOver:
318 mType = MOUSE_DRAG_OVER;
319 break;
320 case eDragExit:
321 mType = MOUSE_DRAG_EXIT;
322 break;
323 case eDrop:
324 mType = MOUSE_DROP;
325 break;
326 case eMouseEnterIntoWidget:
327 mType = MOUSE_WIDGET_ENTER;
328 break;
329 case eMouseExitFromWidget:
330 mType = MOUSE_WIDGET_EXIT;
331 break;
332 case eMouseExploreByTouch:
333 mType = MOUSE_EXPLORE_BY_TOUCH;
334 break;
335 case eMouseHitTest:
336 mType = MOUSE_HITTEST;
337 break;
338 case eContextMenu:
339 mType = MOUSE_CONTEXTMENU;
340 break;
341 default:
342 MOZ_ASSERT_UNREACHABLE("Mouse event type not supported");
343 break;
346 mOrigin = ScreenPoint(ViewAs<ScreenPixel>(
347 aMouseEvent.mRefPoint,
348 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
351 bool MouseInput::IsLeftButton() const { return mButtonType == PRIMARY_BUTTON; }
353 bool MouseInput::TransformToLocal(
354 const ScreenToParentLayerMatrix4x4& aTransform) {
355 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
356 if (!point) {
357 return false;
359 mLocalOrigin = *point;
361 return true;
364 bool MouseInput::IsPointerEventType() const {
365 return mType == MOUSE_CONTEXTMENU;
368 template <class WidgetMouseOrPointerEvent>
369 WidgetMouseOrPointerEvent MouseInput::ToWidgetEvent(nsIWidget* aWidget) const {
370 MOZ_ASSERT(NS_IsMainThread(),
371 "Can only convert To WidgetTouchEvent on main thread");
373 const DebugOnly<bool> isPointerEvent =
374 std::is_same<WidgetMouseOrPointerEvent, WidgetPointerEvent>::value;
375 const DebugOnly<bool> isMouseEvent =
376 std::is_same<WidgetMouseOrPointerEvent, WidgetMouseEvent>::value;
377 const DebugOnly<bool> isDragEvent =
378 std::is_same<WidgetMouseOrPointerEvent, WidgetDragEvent>::value;
379 MOZ_ASSERT(!IsPointerEventType() || isPointerEvent,
380 "Please use ToWidgetEvent<WidgetPointerEvent>() for the instance");
381 MOZ_ASSERT(IsPointerEventType() || isMouseEvent || isDragEvent,
382 "Please use ToWidgetEvent<WidgetMouseEvent>() or "
383 "ToWidgetEvent<WidgetDragEvent>() for the instance");
385 EventMessage msg = eVoidEvent;
386 uint32_t clickCount = 0;
387 Maybe<WidgetMouseEvent::ExitFrom> exitFrom;
388 switch (mType) {
389 case MOUSE_MOVE:
390 msg = eMouseMove;
391 break;
392 case MOUSE_UP:
393 msg = eMouseUp;
394 clickCount = 1;
395 break;
396 case MOUSE_DOWN:
397 msg = eMouseDown;
398 clickCount = 1;
399 break;
400 case MOUSE_DRAG_START:
401 msg = eDragStart;
402 break;
403 case MOUSE_DRAG_END:
404 msg = eDragEnd;
405 break;
406 case MOUSE_DRAG_ENTER:
407 msg = eDragEnter;
408 break;
409 case MOUSE_DRAG_OVER:
410 msg = eDragOver;
411 break;
412 case MOUSE_DRAG_EXIT:
413 msg = eDragExit;
414 break;
415 case MOUSE_DROP:
416 msg = eDrop;
417 break;
418 case MOUSE_WIDGET_ENTER:
419 msg = eMouseEnterIntoWidget;
420 break;
421 case MOUSE_WIDGET_EXIT:
422 msg = eMouseExitFromWidget;
423 exitFrom = Some(WidgetMouseEvent::ePlatformChild);
424 break;
425 case MOUSE_EXPLORE_BY_TOUCH:
426 msg = eMouseExploreByTouch;
427 break;
428 case MOUSE_HITTEST:
429 msg = eMouseHitTest;
430 break;
431 case MOUSE_CONTEXTMENU:
432 msg = eContextMenu;
433 MOZ_ASSERT(mButtonType == MouseInput::SECONDARY_BUTTON);
434 break;
435 default:
436 MOZ_ASSERT_UNREACHABLE(
437 "Did not assign a type to WidgetMouseEvent in MouseInput");
438 break;
441 WidgetMouseOrPointerEvent event(true, msg, aWidget);
443 if (msg == eVoidEvent) {
444 return event;
447 switch (mButtonType) {
448 case MouseInput::PRIMARY_BUTTON:
449 event.mButton = MouseButton::ePrimary;
450 break;
451 case MouseInput::MIDDLE_BUTTON:
452 event.mButton = MouseButton::eMiddle;
453 break;
454 case MouseInput::SECONDARY_BUTTON:
455 event.mButton = MouseButton::eSecondary;
456 break;
457 case MouseInput::NONE:
458 default:
459 break;
462 event.mButtons = mButtons;
463 event.mModifiers = modifiers;
464 event.mTimeStamp = mTimeStamp;
465 event.mLayersId = mLayersId;
466 event.mFlags.mHandledByAPZ = mHandledByAPZ;
467 event.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
468 mOrigin,
469 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
470 event.mClickCount = clickCount;
471 event.mInputSource = mInputSource;
472 event.mFocusSequenceNumber = mFocusSequenceNumber;
473 event.mExitFrom = exitFrom;
474 event.mClickEventPrevented = mPreventClickEvent;
475 event.mIgnoreCapturingContent = mIgnoreCapturingContent;
476 event.mSynthesizeMoveAfterDispatch = mSynthesizeMoveAfterDispatch;
478 return event;
481 PanGestureInput::PanGestureInput()
482 : InputData(PANGESTURE_INPUT),
483 mType(PANGESTURE_MAYSTART),
484 mLineOrPageDeltaX(0),
485 mLineOrPageDeltaY(0),
486 mUserDeltaMultiplierX(1.0),
487 mUserDeltaMultiplierY(1.0),
488 mHandledByAPZ(false),
489 mOverscrollBehaviorAllowsSwipe(false),
490 mSimulateMomentum(false),
491 mIsNoLineOrPageDelta(true),
492 mMayTriggerSwipe(false) {}
494 PanGestureInput::PanGestureInput(PanGestureType aType, TimeStamp aTimeStamp,
495 const ScreenPoint& aPanStartPoint,
496 const ScreenPoint& aPanDisplacement,
497 Modifiers aModifiers)
498 : InputData(PANGESTURE_INPUT, aTimeStamp, aModifiers),
499 mType(aType),
500 mPanStartPoint(aPanStartPoint),
501 mPanDisplacement(aPanDisplacement),
502 mLineOrPageDeltaX(0),
503 mLineOrPageDeltaY(0),
504 mUserDeltaMultiplierX(1.0),
505 mUserDeltaMultiplierY(1.0),
506 mHandledByAPZ(false),
507 mOverscrollBehaviorAllowsSwipe(false),
508 mSimulateMomentum(false),
509 mIsNoLineOrPageDelta(true) {
510 mMayTriggerSwipe = SwipeTracker::CanTriggerSwipe(*this);
513 PanGestureInput::PanGestureInput(PanGestureType aType, TimeStamp aTimeStamp,
514 const ScreenPoint& aPanStartPoint,
515 const ScreenPoint& aPanDisplacement,
516 Modifiers aModifiers,
517 IsEligibleForSwipe aIsEligibleForSwipe)
518 : PanGestureInput(aType, aTimeStamp, aPanStartPoint, aPanDisplacement,
519 aModifiers) {
520 mMayTriggerSwipe &= bool(aIsEligibleForSwipe);
523 void PanGestureInput::SetLineOrPageDeltas(int32_t aLineOrPageDeltaX,
524 int32_t aLineOrPageDeltaY) {
525 mLineOrPageDeltaX = aLineOrPageDeltaX;
526 mLineOrPageDeltaY = aLineOrPageDeltaY;
527 mIsNoLineOrPageDelta = false;
530 bool PanGestureInput::IsMomentum() const {
531 switch (mType) {
532 case PanGestureInput::PANGESTURE_MOMENTUMSTART:
533 case PanGestureInput::PANGESTURE_MOMENTUMPAN:
534 case PanGestureInput::PANGESTURE_MOMENTUMEND:
535 return true;
536 default:
537 return false;
541 WidgetWheelEvent PanGestureInput::ToWidgetEvent(nsIWidget* aWidget) const {
542 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
543 wheelEvent.mModifiers = this->modifiers;
544 wheelEvent.mTimeStamp = mTimeStamp;
545 wheelEvent.mLayersId = mLayersId;
546 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
547 mPanStartPoint,
548 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
549 wheelEvent.mButtons = 0;
550 wheelEvent.mMayHaveMomentum = true; // pan inputs may have momentum
551 wheelEvent.mIsMomentum = IsMomentum();
552 wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
553 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
554 wheelEvent.mDeltaX = mPanDisplacement.x;
555 wheelEvent.mDeltaY = mPanDisplacement.y;
556 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
557 wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber;
558 wheelEvent.mIsNoLineOrPageDelta = mIsNoLineOrPageDelta;
559 if (mDeltaType == PanGestureInput::PANDELTA_PAGE) {
560 // widget/gtk is currently the only consumer that uses delta type
561 // PANDELTA_PAGE
562 // Emulate legacy widget/gtk behavior
563 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_LINE;
564 wheelEvent.mScrollType = WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY;
565 wheelEvent.mDeltaX *= 3;
566 wheelEvent.mDeltaY *= 3;
567 } else {
568 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
570 return wheelEvent;
573 bool PanGestureInput::TransformToLocal(
574 const ScreenToParentLayerMatrix4x4& aTransform) {
575 Maybe<ParentLayerPoint> panStartPoint =
576 UntransformBy(aTransform, mPanStartPoint);
577 if (!panStartPoint) {
578 return false;
580 mLocalPanStartPoint = *panStartPoint;
582 if (mDeltaType == PanGestureInput::PANDELTA_PAGE) {
583 // Skip transforming the pan displacement because we want
584 // raw page proportion counts.
585 mLocalPanDisplacement = ViewAs<ParentLayerPixel>(
586 mPanDisplacement, PixelCastJustification::DeltaIsPageProportion);
587 return true;
590 Maybe<ParentLayerPoint> panDisplacement =
591 UntransformVector(aTransform, mPanDisplacement, mPanStartPoint);
592 if (!panDisplacement) {
593 return false;
595 mLocalPanDisplacement = *panDisplacement;
596 return true;
599 ScreenPoint PanGestureInput::UserMultipliedPanDisplacement() const {
600 return ScreenPoint(mPanDisplacement.x * mUserDeltaMultiplierX,
601 mPanDisplacement.y * mUserDeltaMultiplierY);
604 ParentLayerPoint PanGestureInput::UserMultipliedLocalPanDisplacement() const {
605 return ParentLayerPoint(mLocalPanDisplacement.x * mUserDeltaMultiplierX,
606 mLocalPanDisplacement.y * mUserDeltaMultiplierY);
609 static int32_t TakeLargestInt(gfx::Coord* aCoord) {
610 int32_t result(aCoord->value); // truncate towards zero
611 aCoord->value -= result;
612 return result;
615 /* static */ gfx::IntPoint PanGestureInput::GetIntegerDeltaForEvent(
616 bool aIsStart, float x, float y) {
617 static gfx::Point sAccumulator(0.0f, 0.0f);
618 if (aIsStart) {
619 sAccumulator = gfx::Point(0.0f, 0.0f);
621 sAccumulator.x += x;
622 sAccumulator.y += y;
623 return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
624 TakeLargestInt(&sAccumulator.y));
627 PinchGestureInput::PinchGestureInput()
628 : InputData(PINCHGESTURE_INPUT),
629 mType(PINCHGESTURE_START),
630 mSource(UNKNOWN),
631 mHandledByAPZ(false) {}
633 PinchGestureInput::PinchGestureInput(
634 PinchGestureType aType, PinchGestureSource aSource, TimeStamp aTimeStamp,
635 const ExternalPoint& aScreenOffset, const ScreenPoint& aFocusPoint,
636 ScreenCoord aCurrentSpan, ScreenCoord aPreviousSpan, Modifiers aModifiers)
637 : InputData(PINCHGESTURE_INPUT, aTimeStamp, aModifiers),
638 mType(aType),
639 mSource(aSource),
640 mFocusPoint(aFocusPoint),
641 mScreenOffset(aScreenOffset),
642 mCurrentSpan(aCurrentSpan),
643 mPreviousSpan(aPreviousSpan),
644 mLineOrPageDeltaY(0),
645 mHandledByAPZ(false) {}
647 bool PinchGestureInput::TransformToLocal(
648 const ScreenToParentLayerMatrix4x4& aTransform) {
649 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mFocusPoint);
650 if (!point) {
651 return false;
653 mLocalFocusPoint = *point;
654 return true;
657 WidgetWheelEvent PinchGestureInput::ToWidgetEvent(nsIWidget* aWidget) const {
658 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
659 wheelEvent.mModifiers = this->modifiers | MODIFIER_CONTROL;
660 wheelEvent.mTimeStamp = mTimeStamp;
661 wheelEvent.mLayersId = mLayersId;
662 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
663 mFocusPoint,
664 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
665 wheelEvent.mButtons = 0;
666 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
667 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
669 wheelEvent.mDeltaY = ComputeDeltaY(aWidget);
671 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
673 MOZ_ASSERT(mType == PINCHGESTURE_END || wheelEvent.mDeltaY != 0.0);
675 return wheelEvent;
678 double PinchGestureInput::ComputeDeltaY(nsIWidget* aWidget) const {
679 #if defined(XP_DARWIN)
680 // This converts the pinch gesture value to a fake wheel event that has the
681 // control key pressed so that pages can implement custom pinch gesture
682 // handling. It may seem strange that this doesn't use a wheel event with
683 // the deltaZ property set, but this matches Chrome's behavior as described
684 // at https://code.google.com/p/chromium/issues/detail?id=289887
686 // The intent of the formula below is to produce numbers similar to Chrome's
687 // implementation of this feature. Chrome implements deltaY using the formula
688 // "-100 * log(1 + [event magnification])" which is unfortunately incorrect.
689 // All deltas for a single pinch gesture should sum to 0 if the start and end
690 // of a pinch gesture end up in the same place. This doesn't happen in Chrome
691 // because they followed Apple's misleading documentation, which implies that
692 // "1 + [event magnification]" is the scale factor. The scale factor is
693 // instead "pow(ratio, [event magnification])" so "[event magnification]" is
694 // already in log space.
696 // The multiplication by the backing scale factor below counteracts the
697 // division by the backing scale factor in WheelEvent.
699 // We want to set deltaY to |-100.0 * M * GetDefaultScaleInternal()| where M
700 // is [event magnification] but [event magnification] is only available in the
701 // macOS widget code so we have to reverse engineer from mCurrentSpan and
702 // mPreviousSpan (which are derived from [event magnification]) to get it.
703 // Specifically, we know |mCurrentSpan == 100.0| and |mPreviousSpan == 100.0 *
704 // (1.0 - M)|. We can calculate deltaY by solving the mPreviousSpan equation
705 // for M in terms of mPreviousSpan and plugging that into to the formula for
706 // deltaY.
707 return (mPreviousSpan - 100.0) *
708 (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
709 #else
710 // This calculation is based on what the Windows and Linux widget code does.
711 // Specifically, it creates a PinchGestureInput with |mCurrentSpan == 100.0 *
712 // currentScale| and |mPreviousSpan == 100.0 * lastScale| where currentScale
713 // is the scale from the current OS event and lastScale is the scale when the
714 // previous OS event happened. On macOS [event magnification] is a relative
715 // change in scale factor, ie if the scale factor changed from 1 to 1.1 it
716 // will be 0.1, similarly if it changed from 1 to 0.9 it will be -0.1. To
717 // calculate the relative scale change on Windows we would calculate |M =
718 // currentScale - lastScale = (mCurrentSpan-mPreviousSpan)/100| and use the
719 // same formula as the macOS code
720 // (|-100.0 * M * GetDefaultScaleInternal()|).
722 return (mPreviousSpan - mCurrentSpan) *
723 (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
724 #endif
727 bool PinchGestureInput::SetLineOrPageDeltaY(nsIWidget* aWidget) {
728 double deltaY = ComputeDeltaY(aWidget);
729 if (deltaY == 0 && mType != PINCHGESTURE_END) {
730 return false;
732 gfx::IntPoint lineOrPageDelta = PinchGestureInput::GetIntegerDeltaForEvent(
733 (mType == PINCHGESTURE_START), 0, deltaY);
734 mLineOrPageDeltaY = lineOrPageDelta.y;
735 if (mLineOrPageDeltaY == 0) {
736 // For PINCHGESTURE_SCALE events, don't dispatch them. Note that the delta
737 // isn't lost; it remains in the accumulator in GetIntegerDeltaForEvent().
738 if (mType == PINCHGESTURE_SCALE) {
739 return false;
741 // On Windows, drop PINCHGESTURE_START as well (the Windows widget code will
742 // defer the START event until we accumulate enough delta).
743 // The Linux widget code doesn't support this, so instead set the event's
744 // mLineOrPageDeltaY to the smallest nonzero amount in the relevant
745 // direction.
746 if (mType == PINCHGESTURE_START) {
747 #ifdef XP_WIN
748 return false;
749 #else
750 mLineOrPageDeltaY = (deltaY >= 0) ? 1 : -1;
751 #endif
753 // For PINCHGESTURE_END events, not dispatching a DOMMouseScroll for them is
754 // fine.
756 return true;
759 /* static */ gfx::IntPoint PinchGestureInput::GetIntegerDeltaForEvent(
760 bool aIsStart, float x, float y) {
761 static gfx::Point sAccumulator(0.0f, 0.0f);
762 if (aIsStart) {
763 sAccumulator = gfx::Point(0.0f, 0.0f);
765 sAccumulator.x += x;
766 sAccumulator.y += y;
767 return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
768 TakeLargestInt(&sAccumulator.y));
771 TapGestureInput::TapGestureInput()
772 : InputData(TAPGESTURE_INPUT), mType(TAPGESTURE_LONG) {}
774 TapGestureInput::TapGestureInput(TapGestureType aType, TimeStamp aTimeStamp,
775 const ScreenIntPoint& aPoint,
776 Modifiers aModifiers)
777 : InputData(TAPGESTURE_INPUT, aTimeStamp, aModifiers),
778 mType(aType),
779 mPoint(aPoint) {}
781 TapGestureInput::TapGestureInput(TapGestureType aType, TimeStamp aTimeStamp,
782 const ParentLayerPoint& aLocalPoint,
783 Modifiers aModifiers)
784 : InputData(TAPGESTURE_INPUT, aTimeStamp, aModifiers),
785 mType(aType),
786 mLocalPoint(aLocalPoint) {}
788 bool TapGestureInput::TransformToLocal(
789 const ScreenToParentLayerMatrix4x4& aTransform) {
790 Maybe<ParentLayerIntPoint> point = UntransformBy(aTransform, mPoint);
791 if (!point) {
792 return false;
794 mLocalPoint = *point;
795 return true;
798 WidgetSimpleGestureEvent TapGestureInput::ToWidgetEvent(
799 nsIWidget* aWidget) const {
800 WidgetSimpleGestureEvent event(true, eTapGesture, aWidget);
802 event.mTimeStamp = mTimeStamp;
803 event.mLayersId = mLayersId;
804 event.mRefPoint = ViewAs<LayoutDevicePixel>(
805 mPoint,
806 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
807 event.mButtons = 0;
808 event.mClickCount = 1;
809 event.mModifiers = modifiers;
811 return event;
814 ScrollWheelInput::ScrollWheelInput()
815 : InputData(SCROLLWHEEL_INPUT),
816 mDeltaType(SCROLLDELTA_LINE),
817 mScrollMode(SCROLLMODE_INSTANT),
818 mHandledByAPZ(false),
819 mDeltaX(0.0),
820 mDeltaY(0.0),
821 mLineOrPageDeltaX(0),
822 mLineOrPageDeltaY(0),
823 mScrollSeriesNumber(0),
824 mUserDeltaMultiplierX(1.0),
825 mUserDeltaMultiplierY(1.0),
826 mMayHaveMomentum(false),
827 mIsMomentum(false),
828 mAPZAction(APZWheelAction::Scroll) {}
830 ScrollWheelInput::ScrollWheelInput(
831 TimeStamp aTimeStamp, Modifiers aModifiers, ScrollMode aScrollMode,
832 ScrollDeltaType aDeltaType, const ScreenPoint& aOrigin, double aDeltaX,
833 double aDeltaY, bool aAllowToOverrideSystemScrollSpeed,
834 WheelDeltaAdjustmentStrategy aWheelDeltaAdjustmentStrategy)
835 : InputData(SCROLLWHEEL_INPUT, aTimeStamp, aModifiers),
836 mDeltaType(aDeltaType),
837 mScrollMode(aScrollMode),
838 mOrigin(aOrigin),
839 mHandledByAPZ(false),
840 mDeltaX(aDeltaX),
841 mDeltaY(aDeltaY),
842 mLineOrPageDeltaX(0),
843 mLineOrPageDeltaY(0),
844 mScrollSeriesNumber(0),
845 mUserDeltaMultiplierX(1.0),
846 mUserDeltaMultiplierY(1.0),
847 mMayHaveMomentum(false),
848 mIsMomentum(false),
849 mAllowToOverrideSystemScrollSpeed(aAllowToOverrideSystemScrollSpeed),
850 mWheelDeltaAdjustmentStrategy(aWheelDeltaAdjustmentStrategy),
851 mAPZAction(APZWheelAction::Scroll) {}
853 ScrollWheelInput::ScrollWheelInput(const WidgetWheelEvent& aWheelEvent)
854 : InputData(SCROLLWHEEL_INPUT, aWheelEvent.mTimeStamp,
855 aWheelEvent.mModifiers),
856 mDeltaType(DeltaTypeForDeltaMode(aWheelEvent.mDeltaMode)),
857 mScrollMode(SCROLLMODE_INSTANT),
858 mHandledByAPZ(aWheelEvent.mFlags.mHandledByAPZ),
859 mDeltaX(aWheelEvent.mDeltaX),
860 mDeltaY(aWheelEvent.mDeltaY),
861 mWheelTicksX(aWheelEvent.mWheelTicksX),
862 mWheelTicksY(aWheelEvent.mWheelTicksX),
863 mLineOrPageDeltaX(aWheelEvent.mLineOrPageDeltaX),
864 mLineOrPageDeltaY(aWheelEvent.mLineOrPageDeltaY),
865 mScrollSeriesNumber(0),
866 mUserDeltaMultiplierX(1.0),
867 mUserDeltaMultiplierY(1.0),
868 mMayHaveMomentum(aWheelEvent.mMayHaveMomentum),
869 mIsMomentum(aWheelEvent.mIsMomentum),
870 mAllowToOverrideSystemScrollSpeed(
871 aWheelEvent.mAllowToOverrideSystemScrollSpeed),
872 mWheelDeltaAdjustmentStrategy(WheelDeltaAdjustmentStrategy::eNone),
873 mAPZAction(APZWheelAction::Scroll) {
874 mOrigin = ScreenPoint(ViewAs<ScreenPixel>(
875 aWheelEvent.mRefPoint,
876 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
879 ScrollWheelInput::ScrollDeltaType ScrollWheelInput::DeltaTypeForDeltaMode(
880 uint32_t aDeltaMode) {
881 switch (aDeltaMode) {
882 case WheelEvent_Binding::DOM_DELTA_LINE:
883 return SCROLLDELTA_LINE;
884 case WheelEvent_Binding::DOM_DELTA_PAGE:
885 return SCROLLDELTA_PAGE;
886 case WheelEvent_Binding::DOM_DELTA_PIXEL:
887 return SCROLLDELTA_PIXEL;
888 default:
889 MOZ_CRASH();
891 return SCROLLDELTA_LINE;
894 uint32_t ScrollWheelInput::DeltaModeForDeltaType(ScrollDeltaType aDeltaType) {
895 switch (aDeltaType) {
896 case ScrollWheelInput::SCROLLDELTA_LINE:
897 return WheelEvent_Binding::DOM_DELTA_LINE;
898 case ScrollWheelInput::SCROLLDELTA_PAGE:
899 return WheelEvent_Binding::DOM_DELTA_PAGE;
900 case ScrollWheelInput::SCROLLDELTA_PIXEL:
901 default:
902 return WheelEvent_Binding::DOM_DELTA_PIXEL;
906 ScrollUnit ScrollWheelInput::ScrollUnitForDeltaType(
907 ScrollDeltaType aDeltaType) {
908 switch (aDeltaType) {
909 case SCROLLDELTA_LINE:
910 return ScrollUnit::LINES;
911 case SCROLLDELTA_PAGE:
912 return ScrollUnit::PAGES;
913 case SCROLLDELTA_PIXEL:
914 return ScrollUnit::DEVICE_PIXELS;
915 default:
916 MOZ_CRASH();
918 return ScrollUnit::LINES;
921 WidgetWheelEvent ScrollWheelInput::ToWidgetEvent(nsIWidget* aWidget) const {
922 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
923 wheelEvent.mModifiers = this->modifiers;
924 wheelEvent.mTimeStamp = mTimeStamp;
925 wheelEvent.mLayersId = mLayersId;
926 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
927 mOrigin,
928 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
929 wheelEvent.mButtons = 0;
930 wheelEvent.mDeltaMode = DeltaModeForDeltaType(mDeltaType);
931 wheelEvent.mMayHaveMomentum = mMayHaveMomentum;
932 wheelEvent.mIsMomentum = mIsMomentum;
933 wheelEvent.mDeltaX = mDeltaX;
934 wheelEvent.mDeltaY = mDeltaY;
935 wheelEvent.mWheelTicksX = mWheelTicksX;
936 wheelEvent.mWheelTicksY = mWheelTicksY;
937 wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
938 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
939 wheelEvent.mAllowToOverrideSystemScrollSpeed =
940 mAllowToOverrideSystemScrollSpeed;
941 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
942 wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber;
943 return wheelEvent;
946 bool ScrollWheelInput::TransformToLocal(
947 const ScreenToParentLayerMatrix4x4& aTransform) {
948 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
949 if (!point) {
950 return false;
952 mLocalOrigin = *point;
953 return true;
956 bool ScrollWheelInput::IsCustomizedByUserPrefs() const {
957 return mUserDeltaMultiplierX != 1.0 || mUserDeltaMultiplierY != 1.0;
960 KeyboardInput::KeyboardInput(const WidgetKeyboardEvent& aEvent)
961 : InputData(KEYBOARD_INPUT, aEvent.mTimeStamp, aEvent.mModifiers),
962 mKeyCode(aEvent.mKeyCode),
963 mCharCode(aEvent.mCharCode),
964 mHandledByAPZ(false) {
965 switch (aEvent.mMessage) {
966 case eKeyPress: {
967 mType = KeyboardInput::KEY_PRESS;
968 break;
970 case eKeyUp: {
971 mType = KeyboardInput::KEY_UP;
972 break;
974 case eKeyDown: {
975 mType = KeyboardInput::KEY_DOWN;
976 break;
978 default:
979 mType = KeyboardInput::KEY_OTHER;
980 break;
983 aEvent.GetShortcutKeyCandidates(mShortcutCandidates);
986 KeyboardInput::KeyboardInput()
987 : InputData(KEYBOARD_INPUT),
988 mType(KEY_DOWN),
989 mKeyCode(0),
990 mCharCode(0),
991 mHandledByAPZ(false) {}
993 } // namespace mozilla