Bug 1874684 - Part 6: Limit day length calculations to safe integers. r=mgaudet
[gecko.git] / widget / InputData.cpp
blob8f06a51c1c2b3d898496a4391643527fdf809945
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 case eContextMenu:
307 mType = MOUSE_CONTEXTMENU;
308 break;
309 default:
310 MOZ_ASSERT_UNREACHABLE("Mouse event type not supported");
311 break;
314 mOrigin = ScreenPoint(ViewAs<ScreenPixel>(
315 aMouseEvent.mRefPoint,
316 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
319 bool MouseInput::IsLeftButton() const { return mButtonType == PRIMARY_BUTTON; }
321 bool MouseInput::TransformToLocal(
322 const ScreenToParentLayerMatrix4x4& aTransform) {
323 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
324 if (!point) {
325 return false;
327 mLocalOrigin = *point;
329 return true;
332 WidgetMouseEvent MouseInput::ToWidgetEvent(nsIWidget* aWidget) const {
333 MOZ_ASSERT(NS_IsMainThread(),
334 "Can only convert To WidgetTouchEvent on main thread");
336 EventMessage msg = eVoidEvent;
337 uint32_t clickCount = 0;
338 Maybe<WidgetMouseEvent::ExitFrom> exitFrom;
339 switch (mType) {
340 case MOUSE_MOVE:
341 msg = eMouseMove;
342 break;
343 case MOUSE_UP:
344 msg = eMouseUp;
345 clickCount = 1;
346 break;
347 case MOUSE_DOWN:
348 msg = eMouseDown;
349 clickCount = 1;
350 break;
351 case MOUSE_DRAG_START:
352 msg = eDragStart;
353 break;
354 case MOUSE_DRAG_END:
355 msg = eDragEnd;
356 break;
357 case MOUSE_WIDGET_ENTER:
358 msg = eMouseEnterIntoWidget;
359 break;
360 case MOUSE_WIDGET_EXIT:
361 msg = eMouseExitFromWidget;
362 exitFrom = Some(WidgetMouseEvent::ePlatformChild);
363 break;
364 case MOUSE_EXPLORE_BY_TOUCH:
365 msg = eMouseExploreByTouch;
366 break;
367 case MOUSE_HITTEST:
368 msg = eMouseHitTest;
369 break;
370 case MOUSE_CONTEXTMENU:
371 msg = eContextMenu;
372 break;
373 default:
374 MOZ_ASSERT_UNREACHABLE(
375 "Did not assign a type to WidgetMouseEvent in MouseInput");
376 break;
379 WidgetMouseEvent event(true, msg, aWidget, WidgetMouseEvent::eReal,
380 WidgetMouseEvent::eNormal);
382 if (msg == eVoidEvent) {
383 return event;
386 switch (mButtonType) {
387 case MouseInput::PRIMARY_BUTTON:
388 event.mButton = MouseButton::ePrimary;
389 break;
390 case MouseInput::MIDDLE_BUTTON:
391 event.mButton = MouseButton::eMiddle;
392 break;
393 case MouseInput::SECONDARY_BUTTON:
394 event.mButton = MouseButton::eSecondary;
395 break;
396 case MouseInput::NONE:
397 default:
398 break;
401 event.mButtons = mButtons;
402 event.mModifiers = modifiers;
403 event.mTimeStamp = mTimeStamp;
404 event.mLayersId = mLayersId;
405 event.mFlags.mHandledByAPZ = mHandledByAPZ;
406 event.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
407 mOrigin,
408 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
409 event.mClickCount = clickCount;
410 event.mInputSource = mInputSource;
411 event.mFocusSequenceNumber = mFocusSequenceNumber;
412 event.mExitFrom = exitFrom;
413 event.mClickEventPrevented = mPreventClickEvent;
415 return event;
418 PanGestureInput::PanGestureInput()
419 : InputData(PANGESTURE_INPUT),
420 mType(PANGESTURE_MAYSTART),
421 mLineOrPageDeltaX(0),
422 mLineOrPageDeltaY(0),
423 mUserDeltaMultiplierX(1.0),
424 mUserDeltaMultiplierY(1.0),
425 mHandledByAPZ(false),
426 mOverscrollBehaviorAllowsSwipe(false),
427 mSimulateMomentum(false),
428 mIsNoLineOrPageDelta(true),
429 mMayTriggerSwipe(false) {}
431 PanGestureInput::PanGestureInput(PanGestureType aType, TimeStamp aTimeStamp,
432 const ScreenPoint& aPanStartPoint,
433 const ScreenPoint& aPanDisplacement,
434 Modifiers aModifiers)
435 : InputData(PANGESTURE_INPUT, aTimeStamp, aModifiers),
436 mType(aType),
437 mPanStartPoint(aPanStartPoint),
438 mPanDisplacement(aPanDisplacement),
439 mLineOrPageDeltaX(0),
440 mLineOrPageDeltaY(0),
441 mUserDeltaMultiplierX(1.0),
442 mUserDeltaMultiplierY(1.0),
443 mHandledByAPZ(false),
444 mOverscrollBehaviorAllowsSwipe(false),
445 mSimulateMomentum(false),
446 mIsNoLineOrPageDelta(true) {
447 mMayTriggerSwipe = SwipeTracker::CanTriggerSwipe(*this);
450 PanGestureInput::PanGestureInput(PanGestureType aType, TimeStamp aTimeStamp,
451 const ScreenPoint& aPanStartPoint,
452 const ScreenPoint& aPanDisplacement,
453 Modifiers aModifiers,
454 IsEligibleForSwipe aIsEligibleForSwipe)
455 : PanGestureInput(aType, aTimeStamp, aPanStartPoint, aPanDisplacement,
456 aModifiers) {
457 mMayTriggerSwipe &= bool(aIsEligibleForSwipe);
460 void PanGestureInput::SetLineOrPageDeltas(int32_t aLineOrPageDeltaX,
461 int32_t aLineOrPageDeltaY) {
462 mLineOrPageDeltaX = aLineOrPageDeltaX;
463 mLineOrPageDeltaY = aLineOrPageDeltaY;
464 mIsNoLineOrPageDelta = false;
467 bool PanGestureInput::IsMomentum() const {
468 switch (mType) {
469 case PanGestureInput::PANGESTURE_MOMENTUMSTART:
470 case PanGestureInput::PANGESTURE_MOMENTUMPAN:
471 case PanGestureInput::PANGESTURE_MOMENTUMEND:
472 return true;
473 default:
474 return false;
478 WidgetWheelEvent PanGestureInput::ToWidgetEvent(nsIWidget* aWidget) const {
479 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
480 wheelEvent.mModifiers = this->modifiers;
481 wheelEvent.mTimeStamp = mTimeStamp;
482 wheelEvent.mLayersId = mLayersId;
483 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
484 mPanStartPoint,
485 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
486 wheelEvent.mButtons = 0;
487 wheelEvent.mMayHaveMomentum = true; // pan inputs may have momentum
488 wheelEvent.mIsMomentum = IsMomentum();
489 wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
490 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
491 wheelEvent.mDeltaX = mPanDisplacement.x;
492 wheelEvent.mDeltaY = mPanDisplacement.y;
493 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
494 wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber;
495 wheelEvent.mIsNoLineOrPageDelta = mIsNoLineOrPageDelta;
496 if (mDeltaType == PanGestureInput::PANDELTA_PAGE) {
497 // widget/gtk is currently the only consumer that uses delta type
498 // PANDELTA_PAGE
499 // Emulate legacy widget/gtk behavior
500 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_LINE;
501 wheelEvent.mScrollType = WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY;
502 wheelEvent.mDeltaX *= 3;
503 wheelEvent.mDeltaY *= 3;
504 } else {
505 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
507 return wheelEvent;
510 bool PanGestureInput::TransformToLocal(
511 const ScreenToParentLayerMatrix4x4& aTransform) {
512 Maybe<ParentLayerPoint> panStartPoint =
513 UntransformBy(aTransform, mPanStartPoint);
514 if (!panStartPoint) {
515 return false;
517 mLocalPanStartPoint = *panStartPoint;
519 if (mDeltaType == PanGestureInput::PANDELTA_PAGE) {
520 // Skip transforming the pan displacement because we want
521 // raw page proportion counts.
522 mLocalPanDisplacement = ViewAs<ParentLayerPixel>(
523 mPanDisplacement, PixelCastJustification::DeltaIsPageProportion);
524 return true;
527 Maybe<ParentLayerPoint> panDisplacement =
528 UntransformVector(aTransform, mPanDisplacement, mPanStartPoint);
529 if (!panDisplacement) {
530 return false;
532 mLocalPanDisplacement = *panDisplacement;
533 return true;
536 ScreenPoint PanGestureInput::UserMultipliedPanDisplacement() const {
537 return ScreenPoint(mPanDisplacement.x * mUserDeltaMultiplierX,
538 mPanDisplacement.y * mUserDeltaMultiplierY);
541 ParentLayerPoint PanGestureInput::UserMultipliedLocalPanDisplacement() const {
542 return ParentLayerPoint(mLocalPanDisplacement.x * mUserDeltaMultiplierX,
543 mLocalPanDisplacement.y * mUserDeltaMultiplierY);
546 static int32_t TakeLargestInt(gfx::Coord* aCoord) {
547 int32_t result(aCoord->value); // truncate towards zero
548 aCoord->value -= result;
549 return result;
552 /* static */ gfx::IntPoint PanGestureInput::GetIntegerDeltaForEvent(
553 bool aIsStart, float x, float y) {
554 static gfx::Point sAccumulator(0.0f, 0.0f);
555 if (aIsStart) {
556 sAccumulator = gfx::Point(0.0f, 0.0f);
558 sAccumulator.x += x;
559 sAccumulator.y += y;
560 return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
561 TakeLargestInt(&sAccumulator.y));
564 PinchGestureInput::PinchGestureInput()
565 : InputData(PINCHGESTURE_INPUT),
566 mType(PINCHGESTURE_START),
567 mSource(UNKNOWN),
568 mHandledByAPZ(false) {}
570 PinchGestureInput::PinchGestureInput(
571 PinchGestureType aType, PinchGestureSource aSource, TimeStamp aTimeStamp,
572 const ExternalPoint& aScreenOffset, const ScreenPoint& aFocusPoint,
573 ScreenCoord aCurrentSpan, ScreenCoord aPreviousSpan, Modifiers aModifiers)
574 : InputData(PINCHGESTURE_INPUT, aTimeStamp, aModifiers),
575 mType(aType),
576 mSource(aSource),
577 mFocusPoint(aFocusPoint),
578 mScreenOffset(aScreenOffset),
579 mCurrentSpan(aCurrentSpan),
580 mPreviousSpan(aPreviousSpan),
581 mLineOrPageDeltaY(0),
582 mHandledByAPZ(false) {}
584 bool PinchGestureInput::TransformToLocal(
585 const ScreenToParentLayerMatrix4x4& aTransform) {
586 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mFocusPoint);
587 if (!point) {
588 return false;
590 mLocalFocusPoint = *point;
591 return true;
594 WidgetWheelEvent PinchGestureInput::ToWidgetEvent(nsIWidget* aWidget) const {
595 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
596 wheelEvent.mModifiers = this->modifiers | MODIFIER_CONTROL;
597 wheelEvent.mTimeStamp = mTimeStamp;
598 wheelEvent.mLayersId = mLayersId;
599 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
600 mFocusPoint,
601 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
602 wheelEvent.mButtons = 0;
603 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
604 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
606 wheelEvent.mDeltaY = ComputeDeltaY(aWidget);
608 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
610 MOZ_ASSERT(mType == PINCHGESTURE_END || wheelEvent.mDeltaY != 0.0);
612 return wheelEvent;
615 double PinchGestureInput::ComputeDeltaY(nsIWidget* aWidget) const {
616 #if defined(XP_DARWIN)
617 // This converts the pinch gesture value to a fake wheel event that has the
618 // control key pressed so that pages can implement custom pinch gesture
619 // handling. It may seem strange that this doesn't use a wheel event with
620 // the deltaZ property set, but this matches Chrome's behavior as described
621 // at https://code.google.com/p/chromium/issues/detail?id=289887
623 // The intent of the formula below is to produce numbers similar to Chrome's
624 // implementation of this feature. Chrome implements deltaY using the formula
625 // "-100 * log(1 + [event magnification])" which is unfortunately incorrect.
626 // All deltas for a single pinch gesture should sum to 0 if the start and end
627 // of a pinch gesture end up in the same place. This doesn't happen in Chrome
628 // because they followed Apple's misleading documentation, which implies that
629 // "1 + [event magnification]" is the scale factor. The scale factor is
630 // instead "pow(ratio, [event magnification])" so "[event magnification]" is
631 // already in log space.
633 // The multiplication by the backing scale factor below counteracts the
634 // division by the backing scale factor in WheelEvent.
636 // We want to set deltaY to |-100.0 * M * GetDefaultScaleInternal()| where M
637 // is [event magnification] but [event magnification] is only available in the
638 // macOS widget code so we have to reverse engineer from mCurrentSpan and
639 // mPreviousSpan (which are derived from [event magnification]) to get it.
640 // Specifically, we know |mCurrentSpan == 100.0| and |mPreviousSpan == 100.0 *
641 // (1.0 - M)|. We can calculate deltaY by solving the mPreviousSpan equation
642 // for M in terms of mPreviousSpan and plugging that into to the formula for
643 // deltaY.
644 return (mPreviousSpan - 100.0) *
645 (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
646 #else
647 // This calculation is based on what the Windows and Linux widget code does.
648 // Specifically, it creates a PinchGestureInput with |mCurrentSpan == 100.0 *
649 // currentScale| and |mPreviousSpan == 100.0 * lastScale| where currentScale
650 // is the scale from the current OS event and lastScale is the scale when the
651 // previous OS event happened. On macOS [event magnification] is a relative
652 // change in scale factor, ie if the scale factor changed from 1 to 1.1 it
653 // will be 0.1, similarly if it changed from 1 to 0.9 it will be -0.1. To
654 // calculate the relative scale change on Windows we would calculate |M =
655 // currentScale - lastScale = (mCurrentSpan-mPreviousSpan)/100| and use the
656 // same formula as the macOS code
657 // (|-100.0 * M * GetDefaultScaleInternal()|).
659 return (mPreviousSpan - mCurrentSpan) *
660 (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
661 #endif
664 bool PinchGestureInput::SetLineOrPageDeltaY(nsIWidget* aWidget) {
665 double deltaY = ComputeDeltaY(aWidget);
666 if (deltaY == 0 && mType != PINCHGESTURE_END) {
667 return false;
669 gfx::IntPoint lineOrPageDelta = PinchGestureInput::GetIntegerDeltaForEvent(
670 (mType == PINCHGESTURE_START), 0, deltaY);
671 mLineOrPageDeltaY = lineOrPageDelta.y;
672 if (mLineOrPageDeltaY == 0) {
673 // For PINCHGESTURE_SCALE events, don't dispatch them. Note that the delta
674 // isn't lost; it remains in the accumulator in GetIntegerDeltaForEvent().
675 if (mType == PINCHGESTURE_SCALE) {
676 return false;
678 // On Windows, drop PINCHGESTURE_START as well (the Windows widget code will
679 // defer the START event until we accumulate enough delta).
680 // The Linux widget code doesn't support this, so instead set the event's
681 // mLineOrPageDeltaY to the smallest nonzero amount in the relevant
682 // direction.
683 if (mType == PINCHGESTURE_START) {
684 #ifdef XP_WIN
685 return false;
686 #else
687 mLineOrPageDeltaY = (deltaY >= 0) ? 1 : -1;
688 #endif
690 // For PINCHGESTURE_END events, not dispatching a DOMMouseScroll for them is
691 // fine.
693 return true;
696 /* static */ gfx::IntPoint PinchGestureInput::GetIntegerDeltaForEvent(
697 bool aIsStart, float x, float y) {
698 static gfx::Point sAccumulator(0.0f, 0.0f);
699 if (aIsStart) {
700 sAccumulator = gfx::Point(0.0f, 0.0f);
702 sAccumulator.x += x;
703 sAccumulator.y += y;
704 return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
705 TakeLargestInt(&sAccumulator.y));
708 TapGestureInput::TapGestureInput()
709 : InputData(TAPGESTURE_INPUT), mType(TAPGESTURE_LONG) {}
711 TapGestureInput::TapGestureInput(TapGestureType aType, TimeStamp aTimeStamp,
712 const ScreenIntPoint& aPoint,
713 Modifiers aModifiers)
714 : InputData(TAPGESTURE_INPUT, aTimeStamp, aModifiers),
715 mType(aType),
716 mPoint(aPoint) {}
718 TapGestureInput::TapGestureInput(TapGestureType aType, TimeStamp aTimeStamp,
719 const ParentLayerPoint& aLocalPoint,
720 Modifiers aModifiers)
721 : InputData(TAPGESTURE_INPUT, aTimeStamp, aModifiers),
722 mType(aType),
723 mLocalPoint(aLocalPoint) {}
725 bool TapGestureInput::TransformToLocal(
726 const ScreenToParentLayerMatrix4x4& aTransform) {
727 Maybe<ParentLayerIntPoint> point = UntransformBy(aTransform, mPoint);
728 if (!point) {
729 return false;
731 mLocalPoint = *point;
732 return true;
735 WidgetSimpleGestureEvent TapGestureInput::ToWidgetEvent(
736 nsIWidget* aWidget) const {
737 WidgetSimpleGestureEvent event(true, eTapGesture, aWidget);
739 event.mTimeStamp = mTimeStamp;
740 event.mLayersId = mLayersId;
741 event.mRefPoint = ViewAs<LayoutDevicePixel>(
742 mPoint,
743 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
744 event.mButtons = 0;
745 event.mClickCount = 1;
746 event.mModifiers = modifiers;
748 return event;
751 ScrollWheelInput::ScrollWheelInput()
752 : InputData(SCROLLWHEEL_INPUT),
753 mDeltaType(SCROLLDELTA_LINE),
754 mScrollMode(SCROLLMODE_INSTANT),
755 mHandledByAPZ(false),
756 mDeltaX(0.0),
757 mDeltaY(0.0),
758 mLineOrPageDeltaX(0),
759 mLineOrPageDeltaY(0),
760 mScrollSeriesNumber(0),
761 mUserDeltaMultiplierX(1.0),
762 mUserDeltaMultiplierY(1.0),
763 mMayHaveMomentum(false),
764 mIsMomentum(false),
765 mAPZAction(APZWheelAction::Scroll) {}
767 ScrollWheelInput::ScrollWheelInput(
768 TimeStamp aTimeStamp, Modifiers aModifiers, ScrollMode aScrollMode,
769 ScrollDeltaType aDeltaType, const ScreenPoint& aOrigin, double aDeltaX,
770 double aDeltaY, bool aAllowToOverrideSystemScrollSpeed,
771 WheelDeltaAdjustmentStrategy aWheelDeltaAdjustmentStrategy)
772 : InputData(SCROLLWHEEL_INPUT, aTimeStamp, aModifiers),
773 mDeltaType(aDeltaType),
774 mScrollMode(aScrollMode),
775 mOrigin(aOrigin),
776 mHandledByAPZ(false),
777 mDeltaX(aDeltaX),
778 mDeltaY(aDeltaY),
779 mLineOrPageDeltaX(0),
780 mLineOrPageDeltaY(0),
781 mScrollSeriesNumber(0),
782 mUserDeltaMultiplierX(1.0),
783 mUserDeltaMultiplierY(1.0),
784 mMayHaveMomentum(false),
785 mIsMomentum(false),
786 mAllowToOverrideSystemScrollSpeed(aAllowToOverrideSystemScrollSpeed),
787 mWheelDeltaAdjustmentStrategy(aWheelDeltaAdjustmentStrategy),
788 mAPZAction(APZWheelAction::Scroll) {}
790 ScrollWheelInput::ScrollWheelInput(const WidgetWheelEvent& aWheelEvent)
791 : InputData(SCROLLWHEEL_INPUT, aWheelEvent.mTimeStamp,
792 aWheelEvent.mModifiers),
793 mDeltaType(DeltaTypeForDeltaMode(aWheelEvent.mDeltaMode)),
794 mScrollMode(SCROLLMODE_INSTANT),
795 mHandledByAPZ(aWheelEvent.mFlags.mHandledByAPZ),
796 mDeltaX(aWheelEvent.mDeltaX),
797 mDeltaY(aWheelEvent.mDeltaY),
798 mWheelTicksX(aWheelEvent.mWheelTicksX),
799 mWheelTicksY(aWheelEvent.mWheelTicksX),
800 mLineOrPageDeltaX(aWheelEvent.mLineOrPageDeltaX),
801 mLineOrPageDeltaY(aWheelEvent.mLineOrPageDeltaY),
802 mScrollSeriesNumber(0),
803 mUserDeltaMultiplierX(1.0),
804 mUserDeltaMultiplierY(1.0),
805 mMayHaveMomentum(aWheelEvent.mMayHaveMomentum),
806 mIsMomentum(aWheelEvent.mIsMomentum),
807 mAllowToOverrideSystemScrollSpeed(
808 aWheelEvent.mAllowToOverrideSystemScrollSpeed),
809 mWheelDeltaAdjustmentStrategy(WheelDeltaAdjustmentStrategy::eNone),
810 mAPZAction(APZWheelAction::Scroll) {
811 mOrigin = ScreenPoint(ViewAs<ScreenPixel>(
812 aWheelEvent.mRefPoint,
813 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
816 ScrollWheelInput::ScrollDeltaType ScrollWheelInput::DeltaTypeForDeltaMode(
817 uint32_t aDeltaMode) {
818 switch (aDeltaMode) {
819 case WheelEvent_Binding::DOM_DELTA_LINE:
820 return SCROLLDELTA_LINE;
821 case WheelEvent_Binding::DOM_DELTA_PAGE:
822 return SCROLLDELTA_PAGE;
823 case WheelEvent_Binding::DOM_DELTA_PIXEL:
824 return SCROLLDELTA_PIXEL;
825 default:
826 MOZ_CRASH();
828 return SCROLLDELTA_LINE;
831 uint32_t ScrollWheelInput::DeltaModeForDeltaType(ScrollDeltaType aDeltaType) {
832 switch (aDeltaType) {
833 case ScrollWheelInput::SCROLLDELTA_LINE:
834 return WheelEvent_Binding::DOM_DELTA_LINE;
835 case ScrollWheelInput::SCROLLDELTA_PAGE:
836 return WheelEvent_Binding::DOM_DELTA_PAGE;
837 case ScrollWheelInput::SCROLLDELTA_PIXEL:
838 default:
839 return WheelEvent_Binding::DOM_DELTA_PIXEL;
843 ScrollUnit ScrollWheelInput::ScrollUnitForDeltaType(
844 ScrollDeltaType aDeltaType) {
845 switch (aDeltaType) {
846 case SCROLLDELTA_LINE:
847 return ScrollUnit::LINES;
848 case SCROLLDELTA_PAGE:
849 return ScrollUnit::PAGES;
850 case SCROLLDELTA_PIXEL:
851 return ScrollUnit::DEVICE_PIXELS;
852 default:
853 MOZ_CRASH();
855 return ScrollUnit::LINES;
858 WidgetWheelEvent ScrollWheelInput::ToWidgetEvent(nsIWidget* aWidget) const {
859 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
860 wheelEvent.mModifiers = this->modifiers;
861 wheelEvent.mTimeStamp = mTimeStamp;
862 wheelEvent.mLayersId = mLayersId;
863 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
864 mOrigin,
865 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
866 wheelEvent.mButtons = 0;
867 wheelEvent.mDeltaMode = DeltaModeForDeltaType(mDeltaType);
868 wheelEvent.mMayHaveMomentum = mMayHaveMomentum;
869 wheelEvent.mIsMomentum = mIsMomentum;
870 wheelEvent.mDeltaX = mDeltaX;
871 wheelEvent.mDeltaY = mDeltaY;
872 wheelEvent.mWheelTicksX = mWheelTicksX;
873 wheelEvent.mWheelTicksY = mWheelTicksY;
874 wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
875 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
876 wheelEvent.mAllowToOverrideSystemScrollSpeed =
877 mAllowToOverrideSystemScrollSpeed;
878 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
879 wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber;
880 return wheelEvent;
883 bool ScrollWheelInput::TransformToLocal(
884 const ScreenToParentLayerMatrix4x4& aTransform) {
885 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
886 if (!point) {
887 return false;
889 mLocalOrigin = *point;
890 return true;
893 bool ScrollWheelInput::IsCustomizedByUserPrefs() const {
894 return mUserDeltaMultiplierX != 1.0 || mUserDeltaMultiplierY != 1.0;
897 KeyboardInput::KeyboardInput(const WidgetKeyboardEvent& aEvent)
898 : InputData(KEYBOARD_INPUT, aEvent.mTimeStamp, aEvent.mModifiers),
899 mKeyCode(aEvent.mKeyCode),
900 mCharCode(aEvent.mCharCode),
901 mHandledByAPZ(false) {
902 switch (aEvent.mMessage) {
903 case eKeyPress: {
904 mType = KeyboardInput::KEY_PRESS;
905 break;
907 case eKeyUp: {
908 mType = KeyboardInput::KEY_UP;
909 break;
911 case eKeyDown: {
912 mType = KeyboardInput::KEY_DOWN;
913 break;
915 default:
916 mType = KeyboardInput::KEY_OTHER;
917 break;
920 aEvent.GetShortcutKeyCandidates(mShortcutCandidates);
923 KeyboardInput::KeyboardInput()
924 : InputData(KEYBOARD_INPUT),
925 mType(KEY_DOWN),
926 mKeyCode(0),
927 mCharCode(0),
928 mHandledByAPZ(false) {}
930 } // namespace mozilla