Bug 1855360 - Fix the skip-if syntax. a=bustage-fix
[gecko.git] / widget / InputData.cpp
blob3d1695dd8e9c31d31176bd848b10e7133c6bc6b0
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/TextEvents.h"
12 #include "nsContentUtils.h"
13 #include "nsDebug.h"
14 #include "nsThreadUtils.h"
15 #include "mozilla/MouseEvents.h"
16 #include "mozilla/TouchEvents.h"
17 #include "mozilla/SwipeTracker.h"
18 #include "UnitTransforms.h"
20 namespace mozilla {
22 using namespace dom;
24 InputData::~InputData() = default;
26 InputData::InputData(InputType aInputType)
27 : mInputType(aInputType),
28 mFocusSequenceNumber(0),
29 mLayersId{0},
30 modifiers(0) {}
32 InputData::InputData(InputType aInputType, TimeStamp aTimeStamp,
33 Modifiers aModifiers)
34 : mInputType(aInputType),
35 mTimeStamp(aTimeStamp),
36 mFocusSequenceNumber(0),
37 mLayersId{0},
38 modifiers(aModifiers) {}
40 SingleTouchData::SingleTouchData(int32_t aIdentifier,
41 ScreenIntPoint aScreenPoint,
42 ScreenSize aRadius, float aRotationAngle,
43 float aForce)
44 : mIdentifier(aIdentifier),
45 mScreenPoint(aScreenPoint),
46 mRadius(aRadius),
47 mRotationAngle(aRotationAngle),
48 mForce(aForce) {}
50 SingleTouchData::SingleTouchData(int32_t aIdentifier,
51 ParentLayerPoint aLocalScreenPoint,
52 ScreenSize aRadius, float aRotationAngle,
53 float aForce)
54 : mIdentifier(aIdentifier),
55 mLocalScreenPoint(aLocalScreenPoint),
56 mRadius(aRadius),
57 mRotationAngle(aRotationAngle),
58 mForce(aForce) {}
60 SingleTouchData::SingleTouchData()
61 : mIdentifier(0), mRotationAngle(0.0), mForce(0.0) {}
63 already_AddRefed<Touch> SingleTouchData::ToNewDOMTouch() const {
64 MOZ_ASSERT(NS_IsMainThread(),
65 "Can only create dom::Touch instances on main thread");
66 RefPtr<Touch> touch =
67 new Touch(mIdentifier,
68 LayoutDeviceIntPoint::Truncate(mScreenPoint.x, mScreenPoint.y),
69 LayoutDeviceIntPoint::Truncate(mRadius.width, mRadius.height),
70 mRotationAngle, mForce);
71 touch->tiltX = mTiltX;
72 touch->tiltY = mTiltY;
73 touch->twist = mTwist;
74 return touch.forget();
77 MultiTouchInput::MultiTouchInput(MultiTouchType aType, uint32_t aTime,
78 TimeStamp aTimeStamp, Modifiers aModifiers)
79 : InputData(MULTITOUCH_INPUT, aTimeStamp, aModifiers),
80 mType(aType),
81 mHandledByAPZ(false) {}
83 MultiTouchInput::MultiTouchInput()
84 : InputData(MULTITOUCH_INPUT),
85 mType(MULTITOUCH_START),
86 mHandledByAPZ(false) {}
88 MultiTouchInput::MultiTouchInput(const WidgetTouchEvent& aTouchEvent)
89 : InputData(MULTITOUCH_INPUT, aTouchEvent.mTimeStamp,
90 aTouchEvent.mModifiers),
91 mHandledByAPZ(aTouchEvent.mFlags.mHandledByAPZ),
92 mButton(aTouchEvent.mButton),
93 mButtons(aTouchEvent.mButtons) {
94 MOZ_ASSERT(NS_IsMainThread(),
95 "Can only copy from WidgetTouchEvent on main thread");
97 switch (aTouchEvent.mMessage) {
98 case eTouchStart:
99 mType = MULTITOUCH_START;
100 break;
101 case eTouchMove:
102 mType = MULTITOUCH_MOVE;
103 break;
104 case eTouchEnd:
105 mType = MULTITOUCH_END;
106 break;
107 case eTouchCancel:
108 mType = MULTITOUCH_CANCEL;
109 break;
110 default:
111 MOZ_ASSERT_UNREACHABLE("Did not assign a type to a MultiTouchInput");
112 break;
115 mScreenOffset = ViewAs<ExternalPixel>(
116 aTouchEvent.mWidget->WidgetToScreenOffset(),
117 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
119 for (size_t i = 0; i < aTouchEvent.mTouches.Length(); i++) {
120 const Touch* domTouch = aTouchEvent.mTouches[i];
122 // Extract data from weird interfaces.
123 int32_t identifier = domTouch->Identifier();
124 int32_t radiusX = domTouch->RadiusX(CallerType::System);
125 int32_t radiusY = domTouch->RadiusY(CallerType::System);
126 float rotationAngle = domTouch->RotationAngle(CallerType::System);
127 float force = domTouch->Force(CallerType::System);
129 SingleTouchData data(
130 identifier,
131 ViewAs<ScreenPixel>(
132 domTouch->mRefPoint,
133 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent),
134 ScreenSize((float)radiusX, (float)radiusY), rotationAngle, force);
136 mTouches.AppendElement(data);
140 void MultiTouchInput::Translate(const ScreenPoint& aTranslation) {
141 ScreenIntPoint translation = RoundedToInt(aTranslation);
143 for (auto& touchData : mTouches) {
144 for (auto& historicalData : touchData.mHistoricalData) {
145 historicalData.mScreenPoint.MoveBy(translation.x, translation.y);
147 touchData.mScreenPoint.MoveBy(translation.x, translation.y);
151 WidgetTouchEvent MultiTouchInput::ToWidgetEvent(nsIWidget* aWidget,
152 uint16_t aInputSource) const {
153 MOZ_ASSERT(NS_IsMainThread(),
154 "Can only convert To WidgetTouchEvent on main thread");
155 MOZ_ASSERT(aInputSource ==
156 mozilla::dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH ||
157 aInputSource == mozilla::dom::MouseEvent_Binding::MOZ_SOURCE_PEN);
159 EventMessage touchEventMessage = eVoidEvent;
160 switch (mType) {
161 case MULTITOUCH_START:
162 touchEventMessage = eTouchStart;
163 break;
164 case MULTITOUCH_MOVE:
165 touchEventMessage = eTouchMove;
166 break;
167 case MULTITOUCH_END:
168 touchEventMessage = eTouchEnd;
169 break;
170 case MULTITOUCH_CANCEL:
171 touchEventMessage = eTouchCancel;
172 break;
173 default:
174 MOZ_ASSERT_UNREACHABLE(
175 "Did not assign a type to WidgetTouchEvent in MultiTouchInput");
176 break;
179 WidgetTouchEvent event(true, touchEventMessage, aWidget);
180 if (touchEventMessage == eVoidEvent) {
181 return event;
184 event.mModifiers = this->modifiers;
185 event.mTimeStamp = this->mTimeStamp;
186 event.mFlags.mHandledByAPZ = mHandledByAPZ;
187 event.mFocusSequenceNumber = mFocusSequenceNumber;
188 event.mLayersId = mLayersId;
189 event.mInputSource = aInputSource;
190 event.mButton = mButton;
191 event.mButtons = mButtons;
193 for (size_t i = 0; i < mTouches.Length(); i++) {
194 *event.mTouches.AppendElement() = mTouches[i].ToNewDOMTouch();
197 return event;
200 int32_t MultiTouchInput::IndexOfTouch(int32_t aTouchIdentifier) {
201 for (size_t i = 0; i < mTouches.Length(); i++) {
202 if (mTouches[i].mIdentifier == aTouchIdentifier) {
203 return (int32_t)i;
206 return -1;
209 bool MultiTouchInput::TransformToLocal(
210 const ScreenToParentLayerMatrix4x4& aTransform) {
211 for (auto& touchData : mTouches) {
212 for (auto& historicalData : touchData.mHistoricalData) {
213 Maybe<ParentLayerIntPoint> historicalPoint =
214 UntransformBy(aTransform, historicalData.mScreenPoint);
215 if (!historicalPoint) {
216 return false;
218 historicalData.mLocalScreenPoint = *historicalPoint;
220 Maybe<ParentLayerIntPoint> point =
221 UntransformBy(aTransform, touchData.mScreenPoint);
222 if (!point) {
223 return false;
225 touchData.mLocalScreenPoint = *point;
227 return true;
230 MouseInput::MouseInput()
231 : InputData(MOUSE_INPUT),
232 mType(MOUSE_NONE),
233 mButtonType(NONE),
234 mInputSource(0),
235 mButtons(0),
236 mHandledByAPZ(false),
237 mPreventClickEvent(false) {}
239 MouseInput::MouseInput(MouseType aType, ButtonType aButtonType,
240 uint16_t aInputSource, int16_t aButtons,
241 const ScreenPoint& aPoint, TimeStamp aTimeStamp,
242 Modifiers aModifiers)
243 : InputData(MOUSE_INPUT, aTimeStamp, aModifiers),
244 mType(aType),
245 mButtonType(aButtonType),
246 mInputSource(aInputSource),
247 mButtons(aButtons),
248 mOrigin(aPoint),
249 mHandledByAPZ(false),
250 mPreventClickEvent(false) {}
252 MouseInput::MouseInput(const WidgetMouseEventBase& aMouseEvent)
253 : InputData(MOUSE_INPUT, aMouseEvent.mTimeStamp, aMouseEvent.mModifiers),
254 mType(MOUSE_NONE),
255 mButtonType(NONE),
256 mInputSource(aMouseEvent.mInputSource),
257 mButtons(aMouseEvent.mButtons),
258 mHandledByAPZ(aMouseEvent.mFlags.mHandledByAPZ),
259 mPreventClickEvent(aMouseEvent.mClass == eMouseEventClass &&
260 aMouseEvent.AsMouseEvent()->mClickEventPrevented) {
261 MOZ_ASSERT(NS_IsMainThread(),
262 "Can only copy from WidgetTouchEvent on main thread");
264 mButtonType = NONE;
266 switch (aMouseEvent.mButton) {
267 case MouseButton::ePrimary:
268 mButtonType = MouseInput::PRIMARY_BUTTON;
269 break;
270 case MouseButton::eMiddle:
271 mButtonType = MouseInput::MIDDLE_BUTTON;
272 break;
273 case MouseButton::eSecondary:
274 mButtonType = MouseInput::SECONDARY_BUTTON;
275 break;
278 switch (aMouseEvent.mMessage) {
279 case eMouseMove:
280 mType = MOUSE_MOVE;
281 break;
282 case eMouseUp:
283 mType = MOUSE_UP;
284 break;
285 case eMouseDown:
286 mType = MOUSE_DOWN;
287 break;
288 case eDragStart:
289 mType = MOUSE_DRAG_START;
290 break;
291 case eDragEnd:
292 mType = MOUSE_DRAG_END;
293 break;
294 case eMouseEnterIntoWidget:
295 mType = MOUSE_WIDGET_ENTER;
296 break;
297 case eMouseExitFromWidget:
298 mType = MOUSE_WIDGET_EXIT;
299 break;
300 case eMouseExploreByTouch:
301 mType = MOUSE_EXPLORE_BY_TOUCH;
302 break;
303 case eMouseHitTest:
304 mType = MOUSE_HITTEST;
305 break;
306 default:
307 MOZ_ASSERT_UNREACHABLE("Mouse event type not supported");
308 break;
311 mOrigin = ScreenPoint(ViewAs<ScreenPixel>(
312 aMouseEvent.mRefPoint,
313 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
316 bool MouseInput::IsLeftButton() const { return mButtonType == PRIMARY_BUTTON; }
318 bool MouseInput::TransformToLocal(
319 const ScreenToParentLayerMatrix4x4& aTransform) {
320 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
321 if (!point) {
322 return false;
324 mLocalOrigin = *point;
326 return true;
329 WidgetMouseEvent MouseInput::ToWidgetEvent(nsIWidget* aWidget) const {
330 MOZ_ASSERT(NS_IsMainThread(),
331 "Can only convert To WidgetTouchEvent on main thread");
333 EventMessage msg = eVoidEvent;
334 uint32_t clickCount = 0;
335 Maybe<WidgetMouseEvent::ExitFrom> exitFrom;
336 switch (mType) {
337 case MOUSE_MOVE:
338 msg = eMouseMove;
339 break;
340 case MOUSE_UP:
341 msg = eMouseUp;
342 clickCount = 1;
343 break;
344 case MOUSE_DOWN:
345 msg = eMouseDown;
346 clickCount = 1;
347 break;
348 case MOUSE_DRAG_START:
349 msg = eDragStart;
350 break;
351 case MOUSE_DRAG_END:
352 msg = eDragEnd;
353 break;
354 case MOUSE_WIDGET_ENTER:
355 msg = eMouseEnterIntoWidget;
356 break;
357 case MOUSE_WIDGET_EXIT:
358 msg = eMouseExitFromWidget;
359 exitFrom = Some(WidgetMouseEvent::ePlatformChild);
360 break;
361 case MOUSE_EXPLORE_BY_TOUCH:
362 msg = eMouseExploreByTouch;
363 break;
364 case MOUSE_HITTEST:
365 msg = eMouseHitTest;
366 break;
367 default:
368 MOZ_ASSERT_UNREACHABLE(
369 "Did not assign a type to WidgetMouseEvent in MouseInput");
370 break;
373 WidgetMouseEvent event(true, msg, aWidget, WidgetMouseEvent::eReal,
374 WidgetMouseEvent::eNormal);
376 if (msg == eVoidEvent) {
377 return event;
380 switch (mButtonType) {
381 case MouseInput::PRIMARY_BUTTON:
382 event.mButton = MouseButton::ePrimary;
383 break;
384 case MouseInput::MIDDLE_BUTTON:
385 event.mButton = MouseButton::eMiddle;
386 break;
387 case MouseInput::SECONDARY_BUTTON:
388 event.mButton = MouseButton::eSecondary;
389 break;
390 case MouseInput::NONE:
391 default:
392 break;
395 event.mButtons = mButtons;
396 event.mModifiers = modifiers;
397 event.mTimeStamp = mTimeStamp;
398 event.mLayersId = mLayersId;
399 event.mFlags.mHandledByAPZ = mHandledByAPZ;
400 event.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
401 mOrigin,
402 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
403 event.mClickCount = clickCount;
404 event.mInputSource = mInputSource;
405 event.mFocusSequenceNumber = mFocusSequenceNumber;
406 event.mExitFrom = exitFrom;
407 event.mClickEventPrevented = mPreventClickEvent;
409 return event;
412 PanGestureInput::PanGestureInput()
413 : InputData(PANGESTURE_INPUT),
414 mType(PANGESTURE_MAYSTART),
415 mLineOrPageDeltaX(0),
416 mLineOrPageDeltaY(0),
417 mUserDeltaMultiplierX(1.0),
418 mUserDeltaMultiplierY(1.0),
419 mHandledByAPZ(false),
420 mOverscrollBehaviorAllowsSwipe(false),
421 mSimulateMomentum(false),
422 mIsNoLineOrPageDelta(true),
423 mMayTriggerSwipe(false) {}
425 PanGestureInput::PanGestureInput(PanGestureType aType, TimeStamp aTimeStamp,
426 const ScreenPoint& aPanStartPoint,
427 const ScreenPoint& aPanDisplacement,
428 Modifiers aModifiers)
429 : InputData(PANGESTURE_INPUT, aTimeStamp, aModifiers),
430 mType(aType),
431 mPanStartPoint(aPanStartPoint),
432 mPanDisplacement(aPanDisplacement),
433 mLineOrPageDeltaX(0),
434 mLineOrPageDeltaY(0),
435 mUserDeltaMultiplierX(1.0),
436 mUserDeltaMultiplierY(1.0),
437 mHandledByAPZ(false),
438 mOverscrollBehaviorAllowsSwipe(false),
439 mSimulateMomentum(false),
440 mIsNoLineOrPageDelta(true) {
441 mMayTriggerSwipe = SwipeTracker::CanTriggerSwipe(*this);
444 PanGestureInput::PanGestureInput(PanGestureType aType, TimeStamp aTimeStamp,
445 const ScreenPoint& aPanStartPoint,
446 const ScreenPoint& aPanDisplacement,
447 Modifiers aModifiers,
448 IsEligibleForSwipe aIsEligibleForSwipe)
449 : PanGestureInput(aType, aTimeStamp, aPanStartPoint, aPanDisplacement,
450 aModifiers) {
451 mMayTriggerSwipe &= bool(aIsEligibleForSwipe);
454 void PanGestureInput::SetLineOrPageDeltas(int32_t aLineOrPageDeltaX,
455 int32_t aLineOrPageDeltaY) {
456 mLineOrPageDeltaX = aLineOrPageDeltaX;
457 mLineOrPageDeltaY = aLineOrPageDeltaY;
458 mIsNoLineOrPageDelta = false;
461 bool PanGestureInput::IsMomentum() const {
462 switch (mType) {
463 case PanGestureInput::PANGESTURE_MOMENTUMSTART:
464 case PanGestureInput::PANGESTURE_MOMENTUMPAN:
465 case PanGestureInput::PANGESTURE_MOMENTUMEND:
466 return true;
467 default:
468 return false;
472 WidgetWheelEvent PanGestureInput::ToWidgetEvent(nsIWidget* aWidget) const {
473 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
474 wheelEvent.mModifiers = this->modifiers;
475 wheelEvent.mTimeStamp = mTimeStamp;
476 wheelEvent.mLayersId = mLayersId;
477 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
478 mPanStartPoint,
479 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
480 wheelEvent.mButtons = 0;
481 wheelEvent.mMayHaveMomentum = true; // pan inputs may have momentum
482 wheelEvent.mIsMomentum = IsMomentum();
483 wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
484 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
485 wheelEvent.mDeltaX = mPanDisplacement.x;
486 wheelEvent.mDeltaY = mPanDisplacement.y;
487 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
488 wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber;
489 wheelEvent.mIsNoLineOrPageDelta = mIsNoLineOrPageDelta;
490 if (mDeltaType == PanGestureInput::PANDELTA_PAGE) {
491 // widget/gtk is currently the only consumer that uses delta type
492 // PANDELTA_PAGE
493 // Emulate legacy widget/gtk behavior
494 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_LINE;
495 wheelEvent.mScrollType = WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY;
496 wheelEvent.mDeltaX *= 3;
497 wheelEvent.mDeltaY *= 3;
498 } else {
499 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
501 return wheelEvent;
504 bool PanGestureInput::TransformToLocal(
505 const ScreenToParentLayerMatrix4x4& aTransform) {
506 Maybe<ParentLayerPoint> panStartPoint =
507 UntransformBy(aTransform, mPanStartPoint);
508 if (!panStartPoint) {
509 return false;
511 mLocalPanStartPoint = *panStartPoint;
513 if (mDeltaType == PanGestureInput::PANDELTA_PAGE) {
514 // Skip transforming the pan displacement because we want
515 // raw page proportion counts.
516 mLocalPanDisplacement = ViewAs<ParentLayerPixel>(
517 mPanDisplacement, PixelCastJustification::DeltaIsPageProportion);
518 return true;
521 Maybe<ParentLayerPoint> panDisplacement =
522 UntransformVector(aTransform, mPanDisplacement, mPanStartPoint);
523 if (!panDisplacement) {
524 return false;
526 mLocalPanDisplacement = *panDisplacement;
527 return true;
530 ScreenPoint PanGestureInput::UserMultipliedPanDisplacement() const {
531 return ScreenPoint(mPanDisplacement.x * mUserDeltaMultiplierX,
532 mPanDisplacement.y * mUserDeltaMultiplierY);
535 ParentLayerPoint PanGestureInput::UserMultipliedLocalPanDisplacement() const {
536 return ParentLayerPoint(mLocalPanDisplacement.x * mUserDeltaMultiplierX,
537 mLocalPanDisplacement.y * mUserDeltaMultiplierY);
540 static int32_t TakeLargestInt(gfx::Coord* aCoord) {
541 int32_t result(aCoord->value); // truncate towards zero
542 aCoord->value -= result;
543 return result;
546 /* static */ gfx::IntPoint PanGestureInput::GetIntegerDeltaForEvent(
547 bool aIsStart, float x, float y) {
548 static gfx::Point sAccumulator(0.0f, 0.0f);
549 if (aIsStart) {
550 sAccumulator = gfx::Point(0.0f, 0.0f);
552 sAccumulator.x += x;
553 sAccumulator.y += y;
554 return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
555 TakeLargestInt(&sAccumulator.y));
558 PinchGestureInput::PinchGestureInput()
559 : InputData(PINCHGESTURE_INPUT),
560 mType(PINCHGESTURE_START),
561 mSource(UNKNOWN),
562 mHandledByAPZ(false) {}
564 PinchGestureInput::PinchGestureInput(
565 PinchGestureType aType, PinchGestureSource aSource, TimeStamp aTimeStamp,
566 const ExternalPoint& aScreenOffset, const ScreenPoint& aFocusPoint,
567 ScreenCoord aCurrentSpan, ScreenCoord aPreviousSpan, Modifiers aModifiers)
568 : InputData(PINCHGESTURE_INPUT, aTimeStamp, aModifiers),
569 mType(aType),
570 mSource(aSource),
571 mFocusPoint(aFocusPoint),
572 mScreenOffset(aScreenOffset),
573 mCurrentSpan(aCurrentSpan),
574 mPreviousSpan(aPreviousSpan),
575 mLineOrPageDeltaY(0),
576 mHandledByAPZ(false) {}
578 bool PinchGestureInput::TransformToLocal(
579 const ScreenToParentLayerMatrix4x4& aTransform) {
580 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mFocusPoint);
581 if (!point) {
582 return false;
584 mLocalFocusPoint = *point;
585 return true;
588 WidgetWheelEvent PinchGestureInput::ToWidgetEvent(nsIWidget* aWidget) const {
589 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
590 wheelEvent.mModifiers = this->modifiers | MODIFIER_CONTROL;
591 wheelEvent.mTimeStamp = mTimeStamp;
592 wheelEvent.mLayersId = mLayersId;
593 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
594 mFocusPoint,
595 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
596 wheelEvent.mButtons = 0;
597 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
598 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
600 wheelEvent.mDeltaY = ComputeDeltaY(aWidget);
602 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
604 MOZ_ASSERT(mType == PINCHGESTURE_END || wheelEvent.mDeltaY != 0.0);
606 return wheelEvent;
609 double PinchGestureInput::ComputeDeltaY(nsIWidget* aWidget) const {
610 #if defined(XP_DARWIN)
611 // This converts the pinch gesture value to a fake wheel event that has the
612 // control key pressed so that pages can implement custom pinch gesture
613 // handling. It may seem strange that this doesn't use a wheel event with
614 // the deltaZ property set, but this matches Chrome's behavior as described
615 // at https://code.google.com/p/chromium/issues/detail?id=289887
617 // The intent of the formula below is to produce numbers similar to Chrome's
618 // implementation of this feature. Chrome implements deltaY using the formula
619 // "-100 * log(1 + [event magnification])" which is unfortunately incorrect.
620 // All deltas for a single pinch gesture should sum to 0 if the start and end
621 // of a pinch gesture end up in the same place. This doesn't happen in Chrome
622 // because they followed Apple's misleading documentation, which implies that
623 // "1 + [event magnification]" is the scale factor. The scale factor is
624 // instead "pow(ratio, [event magnification])" so "[event magnification]" is
625 // already in log space.
627 // The multiplication by the backing scale factor below counteracts the
628 // division by the backing scale factor in WheelEvent.
630 // We want to set deltaY to |-100.0 * M * GetDefaultScaleInternal()| where M
631 // is [event magnification] but [event magnification] is only available in the
632 // macOS widget code so we have to reverse engineer from mCurrentSpan and
633 // mPreviousSpan (which are derived from [event magnification]) to get it.
634 // Specifically, we know |mCurrentSpan == 100.0| and |mPreviousSpan == 100.0 *
635 // (1.0 - M)|. We can calculate deltaY by solving the mPreviousSpan equation
636 // for M in terms of mPreviousSpan and plugging that into to the formula for
637 // deltaY.
638 return (mPreviousSpan - 100.0) *
639 (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
640 #else
641 // This calculation is based on what the Windows and Linux widget code does.
642 // Specifically, it creates a PinchGestureInput with |mCurrentSpan == 100.0 *
643 // currentScale| and |mPreviousSpan == 100.0 * lastScale| where currentScale
644 // is the scale from the current OS event and lastScale is the scale when the
645 // previous OS event happened. On macOS [event magnification] is a relative
646 // change in scale factor, ie if the scale factor changed from 1 to 1.1 it
647 // will be 0.1, similarly if it changed from 1 to 0.9 it will be -0.1. To
648 // calculate the relative scale change on Windows we would calculate |M =
649 // currentScale - lastScale = (mCurrentSpan-mPreviousSpan)/100| and use the
650 // same formula as the macOS code
651 // (|-100.0 * M * GetDefaultScaleInternal()|).
653 return (mPreviousSpan - mCurrentSpan) *
654 (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
655 #endif
658 bool PinchGestureInput::SetLineOrPageDeltaY(nsIWidget* aWidget) {
659 double deltaY = ComputeDeltaY(aWidget);
660 if (deltaY == 0 && mType != PINCHGESTURE_END) {
661 return false;
663 gfx::IntPoint lineOrPageDelta = PinchGestureInput::GetIntegerDeltaForEvent(
664 (mType == PINCHGESTURE_START), 0, deltaY);
665 mLineOrPageDeltaY = lineOrPageDelta.y;
666 if (mLineOrPageDeltaY == 0) {
667 // For PINCHGESTURE_SCALE events, don't dispatch them. Note that the delta
668 // isn't lost; it remains in the accumulator in GetIntegerDeltaForEvent().
669 if (mType == PINCHGESTURE_SCALE) {
670 return false;
672 // On Windows, drop PINCHGESTURE_START as well (the Windows widget code will
673 // defer the START event until we accumulate enough delta).
674 // The Linux widget code doesn't support this, so instead set the event's
675 // mLineOrPageDeltaY to the smallest nonzero amount in the relevant
676 // direction.
677 if (mType == PINCHGESTURE_START) {
678 #ifdef XP_WIN
679 return false;
680 #else
681 mLineOrPageDeltaY = (deltaY >= 0) ? 1 : -1;
682 #endif
684 // For PINCHGESTURE_END events, not dispatching a DOMMouseScroll for them is
685 // fine.
687 return true;
690 /* static */ gfx::IntPoint PinchGestureInput::GetIntegerDeltaForEvent(
691 bool aIsStart, float x, float y) {
692 static gfx::Point sAccumulator(0.0f, 0.0f);
693 if (aIsStart) {
694 sAccumulator = gfx::Point(0.0f, 0.0f);
696 sAccumulator.x += x;
697 sAccumulator.y += y;
698 return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
699 TakeLargestInt(&sAccumulator.y));
702 TapGestureInput::TapGestureInput()
703 : InputData(TAPGESTURE_INPUT), mType(TAPGESTURE_LONG) {}
705 TapGestureInput::TapGestureInput(TapGestureType aType, TimeStamp aTimeStamp,
706 const ScreenIntPoint& aPoint,
707 Modifiers aModifiers)
708 : InputData(TAPGESTURE_INPUT, aTimeStamp, aModifiers),
709 mType(aType),
710 mPoint(aPoint) {}
712 TapGestureInput::TapGestureInput(TapGestureType aType, TimeStamp aTimeStamp,
713 const ParentLayerPoint& aLocalPoint,
714 Modifiers aModifiers)
715 : InputData(TAPGESTURE_INPUT, aTimeStamp, aModifiers),
716 mType(aType),
717 mLocalPoint(aLocalPoint) {}
719 bool TapGestureInput::TransformToLocal(
720 const ScreenToParentLayerMatrix4x4& aTransform) {
721 Maybe<ParentLayerIntPoint> point = UntransformBy(aTransform, mPoint);
722 if (!point) {
723 return false;
725 mLocalPoint = *point;
726 return true;
729 WidgetSimpleGestureEvent TapGestureInput::ToWidgetEvent(
730 nsIWidget* aWidget) const {
731 WidgetSimpleGestureEvent event(true, eTapGesture, aWidget);
733 event.mTimeStamp = mTimeStamp;
734 event.mLayersId = mLayersId;
735 event.mRefPoint = ViewAs<LayoutDevicePixel>(
736 mPoint,
737 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
738 event.mButtons = 0;
739 event.mClickCount = 1;
740 event.mModifiers = modifiers;
742 return event;
745 ScrollWheelInput::ScrollWheelInput()
746 : InputData(SCROLLWHEEL_INPUT),
747 mDeltaType(SCROLLDELTA_LINE),
748 mScrollMode(SCROLLMODE_INSTANT),
749 mHandledByAPZ(false),
750 mDeltaX(0.0),
751 mDeltaY(0.0),
752 mLineOrPageDeltaX(0),
753 mLineOrPageDeltaY(0),
754 mScrollSeriesNumber(0),
755 mUserDeltaMultiplierX(1.0),
756 mUserDeltaMultiplierY(1.0),
757 mMayHaveMomentum(false),
758 mIsMomentum(false),
759 mAPZAction(APZWheelAction::Scroll) {}
761 ScrollWheelInput::ScrollWheelInput(
762 TimeStamp aTimeStamp, Modifiers aModifiers, ScrollMode aScrollMode,
763 ScrollDeltaType aDeltaType, const ScreenPoint& aOrigin, double aDeltaX,
764 double aDeltaY, bool aAllowToOverrideSystemScrollSpeed,
765 WheelDeltaAdjustmentStrategy aWheelDeltaAdjustmentStrategy)
766 : InputData(SCROLLWHEEL_INPUT, aTimeStamp, aModifiers),
767 mDeltaType(aDeltaType),
768 mScrollMode(aScrollMode),
769 mOrigin(aOrigin),
770 mHandledByAPZ(false),
771 mDeltaX(aDeltaX),
772 mDeltaY(aDeltaY),
773 mLineOrPageDeltaX(0),
774 mLineOrPageDeltaY(0),
775 mScrollSeriesNumber(0),
776 mUserDeltaMultiplierX(1.0),
777 mUserDeltaMultiplierY(1.0),
778 mMayHaveMomentum(false),
779 mIsMomentum(false),
780 mAllowToOverrideSystemScrollSpeed(aAllowToOverrideSystemScrollSpeed),
781 mWheelDeltaAdjustmentStrategy(aWheelDeltaAdjustmentStrategy),
782 mAPZAction(APZWheelAction::Scroll) {}
784 ScrollWheelInput::ScrollWheelInput(const WidgetWheelEvent& aWheelEvent)
785 : InputData(SCROLLWHEEL_INPUT, aWheelEvent.mTimeStamp,
786 aWheelEvent.mModifiers),
787 mDeltaType(DeltaTypeForDeltaMode(aWheelEvent.mDeltaMode)),
788 mScrollMode(SCROLLMODE_INSTANT),
789 mHandledByAPZ(aWheelEvent.mFlags.mHandledByAPZ),
790 mDeltaX(aWheelEvent.mDeltaX),
791 mDeltaY(aWheelEvent.mDeltaY),
792 mWheelTicksX(aWheelEvent.mWheelTicksX),
793 mWheelTicksY(aWheelEvent.mWheelTicksX),
794 mLineOrPageDeltaX(aWheelEvent.mLineOrPageDeltaX),
795 mLineOrPageDeltaY(aWheelEvent.mLineOrPageDeltaY),
796 mScrollSeriesNumber(0),
797 mUserDeltaMultiplierX(1.0),
798 mUserDeltaMultiplierY(1.0),
799 mMayHaveMomentum(aWheelEvent.mMayHaveMomentum),
800 mIsMomentum(aWheelEvent.mIsMomentum),
801 mAllowToOverrideSystemScrollSpeed(
802 aWheelEvent.mAllowToOverrideSystemScrollSpeed),
803 mWheelDeltaAdjustmentStrategy(WheelDeltaAdjustmentStrategy::eNone),
804 mAPZAction(APZWheelAction::Scroll) {
805 mOrigin = ScreenPoint(ViewAs<ScreenPixel>(
806 aWheelEvent.mRefPoint,
807 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
810 ScrollWheelInput::ScrollDeltaType ScrollWheelInput::DeltaTypeForDeltaMode(
811 uint32_t aDeltaMode) {
812 switch (aDeltaMode) {
813 case WheelEvent_Binding::DOM_DELTA_LINE:
814 return SCROLLDELTA_LINE;
815 case WheelEvent_Binding::DOM_DELTA_PAGE:
816 return SCROLLDELTA_PAGE;
817 case WheelEvent_Binding::DOM_DELTA_PIXEL:
818 return SCROLLDELTA_PIXEL;
819 default:
820 MOZ_CRASH();
822 return SCROLLDELTA_LINE;
825 uint32_t ScrollWheelInput::DeltaModeForDeltaType(ScrollDeltaType aDeltaType) {
826 switch (aDeltaType) {
827 case ScrollWheelInput::SCROLLDELTA_LINE:
828 return WheelEvent_Binding::DOM_DELTA_LINE;
829 case ScrollWheelInput::SCROLLDELTA_PAGE:
830 return WheelEvent_Binding::DOM_DELTA_PAGE;
831 case ScrollWheelInput::SCROLLDELTA_PIXEL:
832 default:
833 return WheelEvent_Binding::DOM_DELTA_PIXEL;
837 ScrollUnit ScrollWheelInput::ScrollUnitForDeltaType(
838 ScrollDeltaType aDeltaType) {
839 switch (aDeltaType) {
840 case SCROLLDELTA_LINE:
841 return ScrollUnit::LINES;
842 case SCROLLDELTA_PAGE:
843 return ScrollUnit::PAGES;
844 case SCROLLDELTA_PIXEL:
845 return ScrollUnit::DEVICE_PIXELS;
846 default:
847 MOZ_CRASH();
849 return ScrollUnit::LINES;
852 WidgetWheelEvent ScrollWheelInput::ToWidgetEvent(nsIWidget* aWidget) const {
853 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
854 wheelEvent.mModifiers = this->modifiers;
855 wheelEvent.mTimeStamp = mTimeStamp;
856 wheelEvent.mLayersId = mLayersId;
857 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
858 mOrigin,
859 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
860 wheelEvent.mButtons = 0;
861 wheelEvent.mDeltaMode = DeltaModeForDeltaType(mDeltaType);
862 wheelEvent.mMayHaveMomentum = mMayHaveMomentum;
863 wheelEvent.mIsMomentum = mIsMomentum;
864 wheelEvent.mDeltaX = mDeltaX;
865 wheelEvent.mDeltaY = mDeltaY;
866 wheelEvent.mWheelTicksX = mWheelTicksX;
867 wheelEvent.mWheelTicksY = mWheelTicksY;
868 wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
869 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
870 wheelEvent.mAllowToOverrideSystemScrollSpeed =
871 mAllowToOverrideSystemScrollSpeed;
872 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
873 wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber;
874 return wheelEvent;
877 bool ScrollWheelInput::TransformToLocal(
878 const ScreenToParentLayerMatrix4x4& aTransform) {
879 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
880 if (!point) {
881 return false;
883 mLocalOrigin = *point;
884 return true;
887 bool ScrollWheelInput::IsCustomizedByUserPrefs() const {
888 return mUserDeltaMultiplierX != 1.0 || mUserDeltaMultiplierY != 1.0;
891 KeyboardInput::KeyboardInput(const WidgetKeyboardEvent& aEvent)
892 : InputData(KEYBOARD_INPUT, aEvent.mTimeStamp, aEvent.mModifiers),
893 mKeyCode(aEvent.mKeyCode),
894 mCharCode(aEvent.mCharCode),
895 mHandledByAPZ(false) {
896 switch (aEvent.mMessage) {
897 case eKeyPress: {
898 mType = KeyboardInput::KEY_PRESS;
899 break;
901 case eKeyUp: {
902 mType = KeyboardInput::KEY_UP;
903 break;
905 case eKeyDown: {
906 mType = KeyboardInput::KEY_DOWN;
907 break;
909 default:
910 mType = KeyboardInput::KEY_OTHER;
911 break;
914 aEvent.GetShortcutKeyCandidates(mShortcutCandidates);
917 KeyboardInput::KeyboardInput()
918 : InputData(KEYBOARD_INPUT),
919 mType(KEY_DOWN),
920 mKeyCode(0),
921 mCharCode(0),
922 mHandledByAPZ(false) {}
924 } // namespace mozilla