Bug 1253840 - Remove .ini file as it's no longer necessary by passing on all platform...
[gecko.git] / widget / InputData.cpp
blob0265aab5a815ff7a6aaf7270a10f8fb3e31e4415
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 const int32_t xTranslation = (int32_t)(aTranslation.x + 0.5f);
142 const int32_t yTranslation = (int32_t)(aTranslation.y + 0.5f);
144 for (auto& touchData : mTouches) {
145 for (auto& historicalData : touchData.mHistoricalData) {
146 historicalData.mScreenPoint.MoveBy(xTranslation, yTranslation);
148 touchData.mScreenPoint.MoveBy(xTranslation, yTranslation);
152 WidgetTouchEvent MultiTouchInput::ToWidgetEvent(nsIWidget* aWidget,
153 uint16_t aInputSource) const {
154 MOZ_ASSERT(NS_IsMainThread(),
155 "Can only convert To WidgetTouchEvent on main thread");
156 MOZ_ASSERT(aInputSource ==
157 mozilla::dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH ||
158 aInputSource == mozilla::dom::MouseEvent_Binding::MOZ_SOURCE_PEN);
160 EventMessage touchEventMessage = eVoidEvent;
161 switch (mType) {
162 case MULTITOUCH_START:
163 touchEventMessage = eTouchStart;
164 break;
165 case MULTITOUCH_MOVE:
166 touchEventMessage = eTouchMove;
167 break;
168 case MULTITOUCH_END:
169 touchEventMessage = eTouchEnd;
170 break;
171 case MULTITOUCH_CANCEL:
172 touchEventMessage = eTouchCancel;
173 break;
174 default:
175 MOZ_ASSERT_UNREACHABLE(
176 "Did not assign a type to WidgetTouchEvent in MultiTouchInput");
177 break;
180 WidgetTouchEvent event(true, touchEventMessage, aWidget);
181 if (touchEventMessage == eVoidEvent) {
182 return event;
185 event.mModifiers = this->modifiers;
186 event.mTimeStamp = this->mTimeStamp;
187 event.mFlags.mHandledByAPZ = mHandledByAPZ;
188 event.mFocusSequenceNumber = mFocusSequenceNumber;
189 event.mLayersId = mLayersId;
190 event.mInputSource = aInputSource;
191 event.mButton = mButton;
192 event.mButtons = mButtons;
194 for (size_t i = 0; i < mTouches.Length(); i++) {
195 *event.mTouches.AppendElement() = mTouches[i].ToNewDOMTouch();
198 return event;
201 int32_t MultiTouchInput::IndexOfTouch(int32_t aTouchIdentifier) {
202 for (size_t i = 0; i < mTouches.Length(); i++) {
203 if (mTouches[i].mIdentifier == aTouchIdentifier) {
204 return (int32_t)i;
207 return -1;
210 bool MultiTouchInput::TransformToLocal(
211 const ScreenToParentLayerMatrix4x4& aTransform) {
212 for (auto& touchData : mTouches) {
213 for (auto& historicalData : touchData.mHistoricalData) {
214 Maybe<ParentLayerIntPoint> historicalPoint =
215 UntransformBy(aTransform, historicalData.mScreenPoint);
216 if (!historicalPoint) {
217 return false;
219 historicalData.mLocalScreenPoint = *historicalPoint;
221 Maybe<ParentLayerIntPoint> point =
222 UntransformBy(aTransform, touchData.mScreenPoint);
223 if (!point) {
224 return false;
226 touchData.mLocalScreenPoint = *point;
228 return true;
231 MouseInput::MouseInput()
232 : InputData(MOUSE_INPUT),
233 mType(MOUSE_NONE),
234 mButtonType(NONE),
235 mInputSource(0),
236 mButtons(0),
237 mHandledByAPZ(false),
238 mPreventClickEvent(false) {}
240 MouseInput::MouseInput(MouseType aType, ButtonType aButtonType,
241 uint16_t aInputSource, int16_t aButtons,
242 const ScreenPoint& aPoint, TimeStamp aTimeStamp,
243 Modifiers aModifiers)
244 : InputData(MOUSE_INPUT, aTimeStamp, aModifiers),
245 mType(aType),
246 mButtonType(aButtonType),
247 mInputSource(aInputSource),
248 mButtons(aButtons),
249 mOrigin(aPoint),
250 mHandledByAPZ(false),
251 mPreventClickEvent(false) {}
253 MouseInput::MouseInput(const WidgetMouseEventBase& aMouseEvent)
254 : InputData(MOUSE_INPUT, aMouseEvent.mTimeStamp, aMouseEvent.mModifiers),
255 mType(MOUSE_NONE),
256 mButtonType(NONE),
257 mInputSource(aMouseEvent.mInputSource),
258 mButtons(aMouseEvent.mButtons),
259 mHandledByAPZ(aMouseEvent.mFlags.mHandledByAPZ),
260 mPreventClickEvent(aMouseEvent.mClass == eMouseEventClass &&
261 aMouseEvent.AsMouseEvent()->mClickEventPrevented) {
262 MOZ_ASSERT(NS_IsMainThread(),
263 "Can only copy from WidgetTouchEvent on main thread");
265 mButtonType = NONE;
267 switch (aMouseEvent.mButton) {
268 case MouseButton::ePrimary:
269 mButtonType = MouseInput::PRIMARY_BUTTON;
270 break;
271 case MouseButton::eMiddle:
272 mButtonType = MouseInput::MIDDLE_BUTTON;
273 break;
274 case MouseButton::eSecondary:
275 mButtonType = MouseInput::SECONDARY_BUTTON;
276 break;
279 switch (aMouseEvent.mMessage) {
280 case eMouseMove:
281 mType = MOUSE_MOVE;
282 break;
283 case eMouseUp:
284 mType = MOUSE_UP;
285 break;
286 case eMouseDown:
287 mType = MOUSE_DOWN;
288 break;
289 case eDragStart:
290 mType = MOUSE_DRAG_START;
291 break;
292 case eDragEnd:
293 mType = MOUSE_DRAG_END;
294 break;
295 case eMouseEnterIntoWidget:
296 mType = MOUSE_WIDGET_ENTER;
297 break;
298 case eMouseExitFromWidget:
299 mType = MOUSE_WIDGET_EXIT;
300 break;
301 case eMouseExploreByTouch:
302 mType = MOUSE_EXPLORE_BY_TOUCH;
303 break;
304 case eMouseHitTest:
305 mType = MOUSE_HITTEST;
306 break;
307 default:
308 MOZ_ASSERT_UNREACHABLE("Mouse event type not supported");
309 break;
312 mOrigin = ScreenPoint(ViewAs<ScreenPixel>(
313 aMouseEvent.mRefPoint,
314 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
317 bool MouseInput::IsLeftButton() const { return mButtonType == PRIMARY_BUTTON; }
319 bool MouseInput::TransformToLocal(
320 const ScreenToParentLayerMatrix4x4& aTransform) {
321 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
322 if (!point) {
323 return false;
325 mLocalOrigin = *point;
327 return true;
330 WidgetMouseEvent MouseInput::ToWidgetEvent(nsIWidget* aWidget) const {
331 MOZ_ASSERT(NS_IsMainThread(),
332 "Can only convert To WidgetTouchEvent on main thread");
334 EventMessage msg = eVoidEvent;
335 uint32_t clickCount = 0;
336 Maybe<WidgetMouseEvent::ExitFrom> exitFrom;
337 switch (mType) {
338 case MOUSE_MOVE:
339 msg = eMouseMove;
340 break;
341 case MOUSE_UP:
342 msg = eMouseUp;
343 clickCount = 1;
344 break;
345 case MOUSE_DOWN:
346 msg = eMouseDown;
347 clickCount = 1;
348 break;
349 case MOUSE_DRAG_START:
350 msg = eDragStart;
351 break;
352 case MOUSE_DRAG_END:
353 msg = eDragEnd;
354 break;
355 case MOUSE_WIDGET_ENTER:
356 msg = eMouseEnterIntoWidget;
357 break;
358 case MOUSE_WIDGET_EXIT:
359 msg = eMouseExitFromWidget;
360 exitFrom = Some(WidgetMouseEvent::ePlatformChild);
361 break;
362 case MOUSE_EXPLORE_BY_TOUCH:
363 msg = eMouseExploreByTouch;
364 break;
365 case MOUSE_HITTEST:
366 msg = eMouseHitTest;
367 break;
368 default:
369 MOZ_ASSERT_UNREACHABLE(
370 "Did not assign a type to WidgetMouseEvent in MouseInput");
371 break;
374 WidgetMouseEvent event(true, msg, aWidget, WidgetMouseEvent::eReal,
375 WidgetMouseEvent::eNormal);
377 if (msg == eVoidEvent) {
378 return event;
381 switch (mButtonType) {
382 case MouseInput::PRIMARY_BUTTON:
383 event.mButton = MouseButton::ePrimary;
384 break;
385 case MouseInput::MIDDLE_BUTTON:
386 event.mButton = MouseButton::eMiddle;
387 break;
388 case MouseInput::SECONDARY_BUTTON:
389 event.mButton = MouseButton::eSecondary;
390 break;
391 case MouseInput::NONE:
392 default:
393 break;
396 event.mButtons = mButtons;
397 event.mModifiers = modifiers;
398 event.mTimeStamp = mTimeStamp;
399 event.mLayersId = mLayersId;
400 event.mFlags.mHandledByAPZ = mHandledByAPZ;
401 event.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
402 mOrigin,
403 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
404 event.mClickCount = clickCount;
405 event.mInputSource = mInputSource;
406 event.mFocusSequenceNumber = mFocusSequenceNumber;
407 event.mExitFrom = exitFrom;
408 event.mClickEventPrevented = mPreventClickEvent;
410 return event;
413 PanGestureInput::PanGestureInput()
414 : InputData(PANGESTURE_INPUT),
415 mType(PANGESTURE_MAYSTART),
416 mLineOrPageDeltaX(0),
417 mLineOrPageDeltaY(0),
418 mUserDeltaMultiplierX(1.0),
419 mUserDeltaMultiplierY(1.0),
420 mHandledByAPZ(false),
421 mOverscrollBehaviorAllowsSwipe(false),
422 mSimulateMomentum(false),
423 mIsNoLineOrPageDelta(true),
424 mMayTriggerSwipe(false) {}
426 PanGestureInput::PanGestureInput(PanGestureType aType, TimeStamp aTimeStamp,
427 const ScreenPoint& aPanStartPoint,
428 const ScreenPoint& aPanDisplacement,
429 Modifiers aModifiers)
430 : InputData(PANGESTURE_INPUT, aTimeStamp, aModifiers),
431 mType(aType),
432 mPanStartPoint(aPanStartPoint),
433 mPanDisplacement(aPanDisplacement),
434 mLineOrPageDeltaX(0),
435 mLineOrPageDeltaY(0),
436 mUserDeltaMultiplierX(1.0),
437 mUserDeltaMultiplierY(1.0),
438 mHandledByAPZ(false),
439 mOverscrollBehaviorAllowsSwipe(false),
440 mSimulateMomentum(false),
441 mIsNoLineOrPageDelta(true) {
442 mMayTriggerSwipe = SwipeTracker::CanTriggerSwipe(*this);
445 PanGestureInput::PanGestureInput(PanGestureType aType, TimeStamp aTimeStamp,
446 const ScreenPoint& aPanStartPoint,
447 const ScreenPoint& aPanDisplacement,
448 Modifiers aModifiers,
449 IsEligibleForSwipe aIsEligibleForSwipe)
450 : PanGestureInput(aType, aTimeStamp, aPanStartPoint, aPanDisplacement,
451 aModifiers) {
452 mMayTriggerSwipe &= bool(aIsEligibleForSwipe);
455 void PanGestureInput::SetLineOrPageDeltas(int32_t aLineOrPageDeltaX,
456 int32_t aLineOrPageDeltaY) {
457 mLineOrPageDeltaX = aLineOrPageDeltaX;
458 mLineOrPageDeltaY = aLineOrPageDeltaY;
459 mIsNoLineOrPageDelta = false;
462 bool PanGestureInput::IsMomentum() const {
463 switch (mType) {
464 case PanGestureInput::PANGESTURE_MOMENTUMSTART:
465 case PanGestureInput::PANGESTURE_MOMENTUMPAN:
466 case PanGestureInput::PANGESTURE_MOMENTUMEND:
467 return true;
468 default:
469 return false;
473 WidgetWheelEvent PanGestureInput::ToWidgetEvent(nsIWidget* aWidget) const {
474 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
475 wheelEvent.mModifiers = this->modifiers;
476 wheelEvent.mTimeStamp = mTimeStamp;
477 wheelEvent.mLayersId = mLayersId;
478 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
479 mPanStartPoint,
480 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
481 wheelEvent.mButtons = 0;
482 wheelEvent.mMayHaveMomentum = true; // pan inputs may have momentum
483 wheelEvent.mIsMomentum = IsMomentum();
484 wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
485 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
486 wheelEvent.mDeltaX = mPanDisplacement.x;
487 wheelEvent.mDeltaY = mPanDisplacement.y;
488 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
489 wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber;
490 wheelEvent.mIsNoLineOrPageDelta = mIsNoLineOrPageDelta;
491 if (mDeltaType == PanGestureInput::PANDELTA_PAGE) {
492 // widget/gtk is currently the only consumer that uses delta type
493 // PANDELTA_PAGE
494 // Emulate legacy widget/gtk behavior
495 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_LINE;
496 wheelEvent.mScrollType = WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY;
497 wheelEvent.mDeltaX *= 3;
498 wheelEvent.mDeltaY *= 3;
499 } else {
500 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
502 return wheelEvent;
505 bool PanGestureInput::TransformToLocal(
506 const ScreenToParentLayerMatrix4x4& aTransform) {
507 Maybe<ParentLayerPoint> panStartPoint =
508 UntransformBy(aTransform, mPanStartPoint);
509 if (!panStartPoint) {
510 return false;
512 mLocalPanStartPoint = *panStartPoint;
514 if (mDeltaType == PanGestureInput::PANDELTA_PAGE) {
515 // Skip transforming the pan displacement because we want
516 // raw page proportion counts.
517 mLocalPanDisplacement = ViewAs<ParentLayerPixel>(
518 mPanDisplacement, PixelCastJustification::DeltaIsPageProportion);
519 return true;
522 Maybe<ParentLayerPoint> panDisplacement =
523 UntransformVector(aTransform, mPanDisplacement, mPanStartPoint);
524 if (!panDisplacement) {
525 return false;
527 mLocalPanDisplacement = *panDisplacement;
528 return true;
531 ScreenPoint PanGestureInput::UserMultipliedPanDisplacement() const {
532 return ScreenPoint(mPanDisplacement.x * mUserDeltaMultiplierX,
533 mPanDisplacement.y * mUserDeltaMultiplierY);
536 ParentLayerPoint PanGestureInput::UserMultipliedLocalPanDisplacement() const {
537 return ParentLayerPoint(mLocalPanDisplacement.x * mUserDeltaMultiplierX,
538 mLocalPanDisplacement.y * mUserDeltaMultiplierY);
541 static int32_t TakeLargestInt(gfx::Coord* aCoord) {
542 int32_t result(aCoord->value); // truncate towards zero
543 aCoord->value -= result;
544 return result;
547 /* static */ gfx::IntPoint PanGestureInput::GetIntegerDeltaForEvent(
548 bool aIsStart, float x, float y) {
549 static gfx::Point sAccumulator(0.0f, 0.0f);
550 if (aIsStart) {
551 sAccumulator = gfx::Point(0.0f, 0.0f);
553 sAccumulator.x += x;
554 sAccumulator.y += y;
555 return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
556 TakeLargestInt(&sAccumulator.y));
559 PinchGestureInput::PinchGestureInput()
560 : InputData(PINCHGESTURE_INPUT),
561 mType(PINCHGESTURE_START),
562 mSource(UNKNOWN),
563 mHandledByAPZ(false) {}
565 PinchGestureInput::PinchGestureInput(
566 PinchGestureType aType, PinchGestureSource aSource, TimeStamp aTimeStamp,
567 const ExternalPoint& aScreenOffset, const ScreenPoint& aFocusPoint,
568 ScreenCoord aCurrentSpan, ScreenCoord aPreviousSpan, Modifiers aModifiers)
569 : InputData(PINCHGESTURE_INPUT, aTimeStamp, aModifiers),
570 mType(aType),
571 mSource(aSource),
572 mFocusPoint(aFocusPoint),
573 mScreenOffset(aScreenOffset),
574 mCurrentSpan(aCurrentSpan),
575 mPreviousSpan(aPreviousSpan),
576 mLineOrPageDeltaY(0),
577 mHandledByAPZ(false) {}
579 bool PinchGestureInput::TransformToLocal(
580 const ScreenToParentLayerMatrix4x4& aTransform) {
581 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mFocusPoint);
582 if (!point) {
583 return false;
585 mLocalFocusPoint = *point;
586 return true;
589 WidgetWheelEvent PinchGestureInput::ToWidgetEvent(nsIWidget* aWidget) const {
590 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
591 wheelEvent.mModifiers = this->modifiers | MODIFIER_CONTROL;
592 wheelEvent.mTimeStamp = mTimeStamp;
593 wheelEvent.mLayersId = mLayersId;
594 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
595 mFocusPoint,
596 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
597 wheelEvent.mButtons = 0;
598 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
599 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
601 wheelEvent.mDeltaY = ComputeDeltaY(aWidget);
603 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
605 MOZ_ASSERT(mType == PINCHGESTURE_END || wheelEvent.mDeltaY != 0.0);
607 return wheelEvent;
610 double PinchGestureInput::ComputeDeltaY(nsIWidget* aWidget) const {
611 #if defined(OS_MACOSX)
612 // This converts the pinch gesture value to a fake wheel event that has the
613 // control key pressed so that pages can implement custom pinch gesture
614 // handling. It may seem strange that this doesn't use a wheel event with
615 // the deltaZ property set, but this matches Chrome's behavior as described
616 // at https://code.google.com/p/chromium/issues/detail?id=289887
618 // The intent of the formula below is to produce numbers similar to Chrome's
619 // implementation of this feature. Chrome implements deltaY using the formula
620 // "-100 * log(1 + [event magnification])" which is unfortunately incorrect.
621 // All deltas for a single pinch gesture should sum to 0 if the start and end
622 // of a pinch gesture end up in the same place. This doesn't happen in Chrome
623 // because they followed Apple's misleading documentation, which implies that
624 // "1 + [event magnification]" is the scale factor. The scale factor is
625 // instead "pow(ratio, [event magnification])" so "[event magnification]" is
626 // already in log space.
628 // The multiplication by the backing scale factor below counteracts the
629 // division by the backing scale factor in WheelEvent.
631 // We want to set deltaY to |-100.0 * M * GetDefaultScaleInternal()| where M
632 // is [event magnification] but [event magnification] is only available in the
633 // macOS widget code so we have to reverse engineer from mCurrentSpan and
634 // mPreviousSpan (which are derived from [event magnification]) to get it.
635 // Specifically, we know |mCurrentSpan == 100.0| and |mPreviousSpan == 100.0 *
636 // (1.0 - M)|. We can calculate deltaY by solving the mPreviousSpan equation
637 // for M in terms of mPreviousSpan and plugging that into to the formula for
638 // deltaY.
639 return (mPreviousSpan - 100.0) *
640 (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
641 #else
642 // This calculation is based on what the Windows and Linux widget code does.
643 // Specifically, it creates a PinchGestureInput with |mCurrentSpan == 100.0 *
644 // currentScale| and |mPreviousSpan == 100.0 * lastScale| where currentScale
645 // is the scale from the current OS event and lastScale is the scale when the
646 // previous OS event happened. On macOS [event magnification] is a relative
647 // change in scale factor, ie if the scale factor changed from 1 to 1.1 it
648 // will be 0.1, similarly if it changed from 1 to 0.9 it will be -0.1. To
649 // calculate the relative scale change on Windows we would calculate |M =
650 // currentScale - lastScale = (mCurrentSpan-mPreviousSpan)/100| and use the
651 // same formula as the macOS code
652 // (|-100.0 * M * GetDefaultScaleInternal()|).
654 return (mPreviousSpan - mCurrentSpan) *
655 (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
656 #endif
659 bool PinchGestureInput::SetLineOrPageDeltaY(nsIWidget* aWidget) {
660 double deltaY = ComputeDeltaY(aWidget);
661 if (deltaY == 0 && mType != PINCHGESTURE_END) {
662 return false;
664 gfx::IntPoint lineOrPageDelta = PinchGestureInput::GetIntegerDeltaForEvent(
665 (mType == PINCHGESTURE_START), 0, deltaY);
666 mLineOrPageDeltaY = lineOrPageDelta.y;
667 if (mLineOrPageDeltaY == 0) {
668 // For PINCHGESTURE_SCALE events, don't dispatch them. Note that the delta
669 // isn't lost; it remains in the accumulator in GetIntegerDeltaForEvent().
670 if (mType == PINCHGESTURE_SCALE) {
671 return false;
673 // On Windows, drop PINCHGESTURE_START as well (the Windows widget code will
674 // defer the START event until we accumulate enough delta).
675 // The Linux widget code doesn't support this, so instead set the event's
676 // mLineOrPageDeltaY to the smallest nonzero amount in the relevant
677 // direction.
678 if (mType == PINCHGESTURE_START) {
679 #ifdef XP_WIN
680 return false;
681 #else
682 mLineOrPageDeltaY = (deltaY >= 0) ? 1 : -1;
683 #endif
685 // For PINCHGESTURE_END events, not dispatching a DOMMouseScroll for them is
686 // fine.
688 return true;
691 /* static */ gfx::IntPoint PinchGestureInput::GetIntegerDeltaForEvent(
692 bool aIsStart, float x, float y) {
693 static gfx::Point sAccumulator(0.0f, 0.0f);
694 if (aIsStart) {
695 sAccumulator = gfx::Point(0.0f, 0.0f);
697 sAccumulator.x += x;
698 sAccumulator.y += y;
699 return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
700 TakeLargestInt(&sAccumulator.y));
703 TapGestureInput::TapGestureInput()
704 : InputData(TAPGESTURE_INPUT), mType(TAPGESTURE_LONG) {}
706 TapGestureInput::TapGestureInput(TapGestureType aType, TimeStamp aTimeStamp,
707 const ScreenIntPoint& aPoint,
708 Modifiers aModifiers)
709 : InputData(TAPGESTURE_INPUT, aTimeStamp, aModifiers),
710 mType(aType),
711 mPoint(aPoint) {}
713 TapGestureInput::TapGestureInput(TapGestureType aType, TimeStamp aTimeStamp,
714 const ParentLayerPoint& aLocalPoint,
715 Modifiers aModifiers)
716 : InputData(TAPGESTURE_INPUT, aTimeStamp, aModifiers),
717 mType(aType),
718 mLocalPoint(aLocalPoint) {}
720 bool TapGestureInput::TransformToLocal(
721 const ScreenToParentLayerMatrix4x4& aTransform) {
722 Maybe<ParentLayerIntPoint> point = UntransformBy(aTransform, mPoint);
723 if (!point) {
724 return false;
726 mLocalPoint = *point;
727 return true;
730 WidgetSimpleGestureEvent TapGestureInput::ToWidgetEvent(
731 nsIWidget* aWidget) const {
732 WidgetSimpleGestureEvent event(true, eTapGesture, aWidget);
734 event.mTimeStamp = mTimeStamp;
735 event.mLayersId = mLayersId;
736 event.mRefPoint = ViewAs<LayoutDevicePixel>(
737 mPoint,
738 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
739 event.mButtons = 0;
740 event.mClickCount = 1;
741 event.mModifiers = modifiers;
743 return event;
746 ScrollWheelInput::ScrollWheelInput()
747 : InputData(SCROLLWHEEL_INPUT),
748 mDeltaType(SCROLLDELTA_LINE),
749 mScrollMode(SCROLLMODE_INSTANT),
750 mHandledByAPZ(false),
751 mDeltaX(0.0),
752 mDeltaY(0.0),
753 mLineOrPageDeltaX(0),
754 mLineOrPageDeltaY(0),
755 mScrollSeriesNumber(0),
756 mUserDeltaMultiplierX(1.0),
757 mUserDeltaMultiplierY(1.0),
758 mMayHaveMomentum(false),
759 mIsMomentum(false),
760 mAPZAction(APZWheelAction::Scroll) {}
762 ScrollWheelInput::ScrollWheelInput(
763 TimeStamp aTimeStamp, Modifiers aModifiers, ScrollMode aScrollMode,
764 ScrollDeltaType aDeltaType, const ScreenPoint& aOrigin, double aDeltaX,
765 double aDeltaY, bool aAllowToOverrideSystemScrollSpeed,
766 WheelDeltaAdjustmentStrategy aWheelDeltaAdjustmentStrategy)
767 : InputData(SCROLLWHEEL_INPUT, aTimeStamp, aModifiers),
768 mDeltaType(aDeltaType),
769 mScrollMode(aScrollMode),
770 mOrigin(aOrigin),
771 mHandledByAPZ(false),
772 mDeltaX(aDeltaX),
773 mDeltaY(aDeltaY),
774 mLineOrPageDeltaX(0),
775 mLineOrPageDeltaY(0),
776 mScrollSeriesNumber(0),
777 mUserDeltaMultiplierX(1.0),
778 mUserDeltaMultiplierY(1.0),
779 mMayHaveMomentum(false),
780 mIsMomentum(false),
781 mAllowToOverrideSystemScrollSpeed(aAllowToOverrideSystemScrollSpeed),
782 mWheelDeltaAdjustmentStrategy(aWheelDeltaAdjustmentStrategy),
783 mAPZAction(APZWheelAction::Scroll) {}
785 ScrollWheelInput::ScrollWheelInput(const WidgetWheelEvent& aWheelEvent)
786 : InputData(SCROLLWHEEL_INPUT, aWheelEvent.mTimeStamp,
787 aWheelEvent.mModifiers),
788 mDeltaType(DeltaTypeForDeltaMode(aWheelEvent.mDeltaMode)),
789 mScrollMode(SCROLLMODE_INSTANT),
790 mHandledByAPZ(aWheelEvent.mFlags.mHandledByAPZ),
791 mDeltaX(aWheelEvent.mDeltaX),
792 mDeltaY(aWheelEvent.mDeltaY),
793 mWheelTicksX(aWheelEvent.mWheelTicksX),
794 mWheelTicksY(aWheelEvent.mWheelTicksX),
795 mLineOrPageDeltaX(aWheelEvent.mLineOrPageDeltaX),
796 mLineOrPageDeltaY(aWheelEvent.mLineOrPageDeltaY),
797 mScrollSeriesNumber(0),
798 mUserDeltaMultiplierX(1.0),
799 mUserDeltaMultiplierY(1.0),
800 mMayHaveMomentum(aWheelEvent.mMayHaveMomentum),
801 mIsMomentum(aWheelEvent.mIsMomentum),
802 mAllowToOverrideSystemScrollSpeed(
803 aWheelEvent.mAllowToOverrideSystemScrollSpeed),
804 mWheelDeltaAdjustmentStrategy(WheelDeltaAdjustmentStrategy::eNone),
805 mAPZAction(APZWheelAction::Scroll) {
806 mOrigin = ScreenPoint(ViewAs<ScreenPixel>(
807 aWheelEvent.mRefPoint,
808 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
811 ScrollWheelInput::ScrollDeltaType ScrollWheelInput::DeltaTypeForDeltaMode(
812 uint32_t aDeltaMode) {
813 switch (aDeltaMode) {
814 case WheelEvent_Binding::DOM_DELTA_LINE:
815 return SCROLLDELTA_LINE;
816 case WheelEvent_Binding::DOM_DELTA_PAGE:
817 return SCROLLDELTA_PAGE;
818 case WheelEvent_Binding::DOM_DELTA_PIXEL:
819 return SCROLLDELTA_PIXEL;
820 default:
821 MOZ_CRASH();
823 return SCROLLDELTA_LINE;
826 uint32_t ScrollWheelInput::DeltaModeForDeltaType(ScrollDeltaType aDeltaType) {
827 switch (aDeltaType) {
828 case ScrollWheelInput::SCROLLDELTA_LINE:
829 return WheelEvent_Binding::DOM_DELTA_LINE;
830 case ScrollWheelInput::SCROLLDELTA_PAGE:
831 return WheelEvent_Binding::DOM_DELTA_PAGE;
832 case ScrollWheelInput::SCROLLDELTA_PIXEL:
833 default:
834 return WheelEvent_Binding::DOM_DELTA_PIXEL;
838 ScrollUnit ScrollWheelInput::ScrollUnitForDeltaType(
839 ScrollDeltaType aDeltaType) {
840 switch (aDeltaType) {
841 case SCROLLDELTA_LINE:
842 return ScrollUnit::LINES;
843 case SCROLLDELTA_PAGE:
844 return ScrollUnit::PAGES;
845 case SCROLLDELTA_PIXEL:
846 return ScrollUnit::DEVICE_PIXELS;
847 default:
848 MOZ_CRASH();
850 return ScrollUnit::LINES;
853 WidgetWheelEvent ScrollWheelInput::ToWidgetEvent(nsIWidget* aWidget) const {
854 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
855 wheelEvent.mModifiers = this->modifiers;
856 wheelEvent.mTimeStamp = mTimeStamp;
857 wheelEvent.mLayersId = mLayersId;
858 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
859 mOrigin,
860 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
861 wheelEvent.mButtons = 0;
862 wheelEvent.mDeltaMode = DeltaModeForDeltaType(mDeltaType);
863 wheelEvent.mMayHaveMomentum = mMayHaveMomentum;
864 wheelEvent.mIsMomentum = mIsMomentum;
865 wheelEvent.mDeltaX = mDeltaX;
866 wheelEvent.mDeltaY = mDeltaY;
867 wheelEvent.mWheelTicksX = mWheelTicksX;
868 wheelEvent.mWheelTicksY = mWheelTicksY;
869 wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
870 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
871 wheelEvent.mAllowToOverrideSystemScrollSpeed =
872 mAllowToOverrideSystemScrollSpeed;
873 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
874 wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber;
875 return wheelEvent;
878 bool ScrollWheelInput::TransformToLocal(
879 const ScreenToParentLayerMatrix4x4& aTransform) {
880 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
881 if (!point) {
882 return false;
884 mLocalOrigin = *point;
885 return true;
888 bool ScrollWheelInput::IsCustomizedByUserPrefs() const {
889 return mUserDeltaMultiplierX != 1.0 || mUserDeltaMultiplierY != 1.0;
892 KeyboardInput::KeyboardInput(const WidgetKeyboardEvent& aEvent)
893 : InputData(KEYBOARD_INPUT, aEvent.mTimeStamp, aEvent.mModifiers),
894 mKeyCode(aEvent.mKeyCode),
895 mCharCode(aEvent.mCharCode),
896 mHandledByAPZ(false) {
897 switch (aEvent.mMessage) {
898 case eKeyPress: {
899 mType = KeyboardInput::KEY_PRESS;
900 break;
902 case eKeyUp: {
903 mType = KeyboardInput::KEY_UP;
904 break;
906 case eKeyDown: {
907 mType = KeyboardInput::KEY_DOWN;
908 break;
910 default:
911 mType = KeyboardInput::KEY_OTHER;
912 break;
915 aEvent.GetShortcutKeyCandidates(mShortcutCandidates);
918 KeyboardInput::KeyboardInput()
919 : InputData(KEYBOARD_INPUT),
920 mType(KEY_DOWN),
921 mKeyCode(0),
922 mCharCode(0),
923 mHandledByAPZ(false) {}
925 } // namespace mozilla