Bug 1755316 - Add audio tests with simultaneous processes r=alwu
[gecko.git] / widget / InputData.cpp
blobd6dfb03c05bcfa08627b48658f273b7e5d885739
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 "UnitTransforms.h"
19 namespace mozilla {
21 using namespace dom;
23 InputData::~InputData() = default;
25 InputData::InputData(InputType aInputType)
26 : mInputType(aInputType),
27 mTime(0),
28 mFocusSequenceNumber(0),
29 mLayersId{0},
30 modifiers(0) {}
32 InputData::InputData(InputType aInputType, uint32_t aTime, TimeStamp aTimeStamp,
33 Modifiers aModifiers)
34 : mInputType(aInputType),
35 mTime(aTime),
36 mTimeStamp(aTimeStamp),
37 mFocusSequenceNumber(0),
38 mLayersId{0},
39 modifiers(aModifiers) {}
41 SingleTouchData::SingleTouchData(int32_t aIdentifier,
42 ScreenIntPoint aScreenPoint,
43 ScreenSize aRadius, float aRotationAngle,
44 float aForce)
45 : mIdentifier(aIdentifier),
46 mScreenPoint(aScreenPoint),
47 mRadius(aRadius),
48 mRotationAngle(aRotationAngle),
49 mForce(aForce) {}
51 SingleTouchData::SingleTouchData(int32_t aIdentifier,
52 ParentLayerPoint aLocalScreenPoint,
53 ScreenSize aRadius, float aRotationAngle,
54 float aForce)
55 : mIdentifier(aIdentifier),
56 mLocalScreenPoint(aLocalScreenPoint),
57 mRadius(aRadius),
58 mRotationAngle(aRotationAngle),
59 mForce(aForce) {}
61 SingleTouchData::SingleTouchData()
62 : mIdentifier(0), mRotationAngle(0.0), mForce(0.0) {}
64 already_AddRefed<Touch> SingleTouchData::ToNewDOMTouch() const {
65 MOZ_ASSERT(NS_IsMainThread(),
66 "Can only create dom::Touch instances on main thread");
67 RefPtr<Touch> touch =
68 new Touch(mIdentifier,
69 LayoutDeviceIntPoint::Truncate(mScreenPoint.x, mScreenPoint.y),
70 LayoutDeviceIntPoint::Truncate(mRadius.width, mRadius.height),
71 mRotationAngle, mForce);
72 touch->tiltX = mTiltX;
73 touch->tiltY = mTiltY;
74 touch->twist = mTwist;
75 return touch.forget();
78 MultiTouchInput::MultiTouchInput(MultiTouchType aType, uint32_t aTime,
79 TimeStamp aTimeStamp, Modifiers aModifiers)
80 : InputData(MULTITOUCH_INPUT, aTime, aTimeStamp, aModifiers),
81 mType(aType),
82 mHandledByAPZ(false) {}
84 MultiTouchInput::MultiTouchInput()
85 : InputData(MULTITOUCH_INPUT),
86 mType(MULTITOUCH_START),
87 mHandledByAPZ(false) {}
89 MultiTouchInput::MultiTouchInput(const MultiTouchInput& aOther)
90 : InputData(MULTITOUCH_INPUT, aOther.mTime, aOther.mTimeStamp,
91 aOther.modifiers),
92 mType(aOther.mType),
93 mScreenOffset(aOther.mScreenOffset),
94 mHandledByAPZ(aOther.mHandledByAPZ),
95 mButton(aOther.mButton),
96 mButtons(aOther.mButtons) {
97 mTouches.AppendElements(aOther.mTouches);
100 MultiTouchInput::MultiTouchInput(const WidgetTouchEvent& aTouchEvent)
101 : InputData(MULTITOUCH_INPUT, aTouchEvent.mTime, aTouchEvent.mTimeStamp,
102 aTouchEvent.mModifiers),
103 mHandledByAPZ(aTouchEvent.mFlags.mHandledByAPZ),
104 mButton(aTouchEvent.mButton),
105 mButtons(aTouchEvent.mButtons) {
106 MOZ_ASSERT(NS_IsMainThread(),
107 "Can only copy from WidgetTouchEvent on main thread");
109 switch (aTouchEvent.mMessage) {
110 case eTouchStart:
111 mType = MULTITOUCH_START;
112 break;
113 case eTouchMove:
114 mType = MULTITOUCH_MOVE;
115 break;
116 case eTouchEnd:
117 mType = MULTITOUCH_END;
118 break;
119 case eTouchCancel:
120 mType = MULTITOUCH_CANCEL;
121 break;
122 default:
123 MOZ_ASSERT_UNREACHABLE("Did not assign a type to a MultiTouchInput");
124 break;
127 mScreenOffset = ViewAs<ExternalPixel>(
128 aTouchEvent.mWidget->WidgetToScreenOffset(),
129 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
131 for (size_t i = 0; i < aTouchEvent.mTouches.Length(); i++) {
132 const Touch* domTouch = aTouchEvent.mTouches[i];
134 // Extract data from weird interfaces.
135 int32_t identifier = domTouch->Identifier();
136 int32_t radiusX = domTouch->RadiusX(CallerType::System);
137 int32_t radiusY = domTouch->RadiusY(CallerType::System);
138 float rotationAngle = domTouch->RotationAngle(CallerType::System);
139 float force = domTouch->Force(CallerType::System);
141 SingleTouchData data(
142 identifier,
143 ViewAs<ScreenPixel>(
144 domTouch->mRefPoint,
145 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent),
146 ScreenSize((float)radiusX, (float)radiusY), rotationAngle, force);
148 mTouches.AppendElement(data);
152 void MultiTouchInput::Translate(const ScreenPoint& aTranslation) {
153 const int32_t xTranslation = (int32_t)(aTranslation.x + 0.5f);
154 const int32_t yTranslation = (int32_t)(aTranslation.y + 0.5f);
156 for (auto& touchData : mTouches) {
157 for (auto& historicalData : touchData.mHistoricalData) {
158 historicalData.mScreenPoint.MoveBy(xTranslation, yTranslation);
160 touchData.mScreenPoint.MoveBy(xTranslation, yTranslation);
164 WidgetTouchEvent MultiTouchInput::ToWidgetEvent(nsIWidget* aWidget,
165 uint16_t aInputSource) const {
166 MOZ_ASSERT(NS_IsMainThread(),
167 "Can only convert To WidgetTouchEvent on main thread");
168 MOZ_ASSERT(aInputSource ==
169 mozilla::dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH ||
170 aInputSource == mozilla::dom::MouseEvent_Binding::MOZ_SOURCE_PEN);
172 EventMessage touchEventMessage = eVoidEvent;
173 switch (mType) {
174 case MULTITOUCH_START:
175 touchEventMessage = eTouchStart;
176 break;
177 case MULTITOUCH_MOVE:
178 touchEventMessage = eTouchMove;
179 break;
180 case MULTITOUCH_END:
181 touchEventMessage = eTouchEnd;
182 break;
183 case MULTITOUCH_CANCEL:
184 touchEventMessage = eTouchCancel;
185 break;
186 default:
187 MOZ_ASSERT_UNREACHABLE(
188 "Did not assign a type to WidgetTouchEvent in MultiTouchInput");
189 break;
192 WidgetTouchEvent event(true, touchEventMessage, aWidget);
193 if (touchEventMessage == eVoidEvent) {
194 return event;
197 event.mModifiers = this->modifiers;
198 event.mTime = this->mTime;
199 event.mTimeStamp = this->mTimeStamp;
200 event.mFlags.mHandledByAPZ = mHandledByAPZ;
201 event.mFocusSequenceNumber = mFocusSequenceNumber;
202 event.mLayersId = mLayersId;
203 event.mInputSource = aInputSource;
204 event.mButton = mButton;
205 event.mButtons = mButtons;
207 for (size_t i = 0; i < mTouches.Length(); i++) {
208 *event.mTouches.AppendElement() = mTouches[i].ToNewDOMTouch();
211 return event;
214 int32_t MultiTouchInput::IndexOfTouch(int32_t aTouchIdentifier) {
215 for (size_t i = 0; i < mTouches.Length(); i++) {
216 if (mTouches[i].mIdentifier == aTouchIdentifier) {
217 return (int32_t)i;
220 return -1;
223 bool MultiTouchInput::TransformToLocal(
224 const ScreenToParentLayerMatrix4x4& aTransform) {
225 for (auto& touchData : mTouches) {
226 for (auto& historicalData : touchData.mHistoricalData) {
227 Maybe<ParentLayerIntPoint> historicalPoint =
228 UntransformBy(aTransform, historicalData.mScreenPoint);
229 if (!historicalPoint) {
230 return false;
232 historicalData.mLocalScreenPoint = *historicalPoint;
234 Maybe<ParentLayerIntPoint> point =
235 UntransformBy(aTransform, touchData.mScreenPoint);
236 if (!point) {
237 return false;
239 touchData.mLocalScreenPoint = *point;
241 return true;
244 MouseInput::MouseInput()
245 : InputData(MOUSE_INPUT),
246 mType(MOUSE_NONE),
247 mButtonType(NONE),
248 mInputSource(0),
249 mButtons(0),
250 mHandledByAPZ(false),
251 mPreventClickEvent(false) {}
253 MouseInput::MouseInput(MouseType aType, ButtonType aButtonType,
254 uint16_t aInputSource, int16_t aButtons,
255 const ScreenPoint& aPoint, uint32_t aTime,
256 TimeStamp aTimeStamp, Modifiers aModifiers)
257 : InputData(MOUSE_INPUT, aTime, aTimeStamp, aModifiers),
258 mType(aType),
259 mButtonType(aButtonType),
260 mInputSource(aInputSource),
261 mButtons(aButtons),
262 mOrigin(aPoint),
263 mHandledByAPZ(false),
264 mPreventClickEvent(false) {}
266 MouseInput::MouseInput(const WidgetMouseEventBase& aMouseEvent)
267 : InputData(MOUSE_INPUT, aMouseEvent.mTime, aMouseEvent.mTimeStamp,
268 aMouseEvent.mModifiers),
269 mType(MOUSE_NONE),
270 mButtonType(NONE),
271 mInputSource(aMouseEvent.mInputSource),
272 mButtons(aMouseEvent.mButtons),
273 mHandledByAPZ(aMouseEvent.mFlags.mHandledByAPZ),
274 mPreventClickEvent(aMouseEvent.mClass == eMouseEventClass &&
275 aMouseEvent.AsMouseEvent()->mClickEventPrevented) {
276 MOZ_ASSERT(NS_IsMainThread(),
277 "Can only copy from WidgetTouchEvent on main thread");
279 mButtonType = NONE;
281 switch (aMouseEvent.mButton) {
282 case MouseButton::ePrimary:
283 mButtonType = MouseInput::PRIMARY_BUTTON;
284 break;
285 case MouseButton::eMiddle:
286 mButtonType = MouseInput::MIDDLE_BUTTON;
287 break;
288 case MouseButton::eSecondary:
289 mButtonType = MouseInput::SECONDARY_BUTTON;
290 break;
293 switch (aMouseEvent.mMessage) {
294 case eMouseMove:
295 mType = MOUSE_MOVE;
296 break;
297 case eMouseUp:
298 mType = MOUSE_UP;
299 break;
300 case eMouseDown:
301 mType = MOUSE_DOWN;
302 break;
303 case eDragStart:
304 mType = MOUSE_DRAG_START;
305 break;
306 case eDragEnd:
307 mType = MOUSE_DRAG_END;
308 break;
309 case eMouseEnterIntoWidget:
310 mType = MOUSE_WIDGET_ENTER;
311 break;
312 case eMouseExitFromWidget:
313 mType = MOUSE_WIDGET_EXIT;
314 break;
315 case eMouseExploreByTouch:
316 mType = MOUSE_EXPLORE_BY_TOUCH;
317 break;
318 case eMouseHitTest:
319 mType = MOUSE_HITTEST;
320 break;
321 default:
322 MOZ_ASSERT_UNREACHABLE("Mouse event type not supported");
323 break;
326 mOrigin = ScreenPoint(ViewAs<ScreenPixel>(
327 aMouseEvent.mRefPoint,
328 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
331 bool MouseInput::IsLeftButton() const { return mButtonType == PRIMARY_BUTTON; }
333 bool MouseInput::TransformToLocal(
334 const ScreenToParentLayerMatrix4x4& aTransform) {
335 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
336 if (!point) {
337 return false;
339 mLocalOrigin = *point;
341 return true;
344 WidgetMouseEvent MouseInput::ToWidgetEvent(nsIWidget* aWidget) const {
345 MOZ_ASSERT(NS_IsMainThread(),
346 "Can only convert To WidgetTouchEvent on main thread");
348 EventMessage msg = eVoidEvent;
349 uint32_t clickCount = 0;
350 Maybe<WidgetMouseEvent::ExitFrom> exitFrom;
351 switch (mType) {
352 case MOUSE_MOVE:
353 msg = eMouseMove;
354 break;
355 case MOUSE_UP:
356 msg = eMouseUp;
357 clickCount = 1;
358 break;
359 case MOUSE_DOWN:
360 msg = eMouseDown;
361 clickCount = 1;
362 break;
363 case MOUSE_DRAG_START:
364 msg = eDragStart;
365 break;
366 case MOUSE_DRAG_END:
367 msg = eDragEnd;
368 break;
369 case MOUSE_WIDGET_ENTER:
370 msg = eMouseEnterIntoWidget;
371 break;
372 case MOUSE_WIDGET_EXIT:
373 msg = eMouseExitFromWidget;
374 exitFrom = Some(WidgetMouseEvent::ePlatformChild);
375 break;
376 case MOUSE_EXPLORE_BY_TOUCH:
377 msg = eMouseExploreByTouch;
378 break;
379 case MOUSE_HITTEST:
380 msg = eMouseHitTest;
381 break;
382 default:
383 MOZ_ASSERT_UNREACHABLE(
384 "Did not assign a type to WidgetMouseEvent in MouseInput");
385 break;
388 WidgetMouseEvent event(true, msg, aWidget, WidgetMouseEvent::eReal,
389 WidgetMouseEvent::eNormal);
391 if (msg == eVoidEvent) {
392 return event;
395 switch (mButtonType) {
396 case MouseInput::PRIMARY_BUTTON:
397 event.mButton = MouseButton::ePrimary;
398 break;
399 case MouseInput::MIDDLE_BUTTON:
400 event.mButton = MouseButton::eMiddle;
401 break;
402 case MouseInput::SECONDARY_BUTTON:
403 event.mButton = MouseButton::eSecondary;
404 break;
405 case MouseInput::NONE:
406 default:
407 break;
410 event.mButtons = mButtons;
411 event.mModifiers = modifiers;
412 event.mTime = mTime;
413 event.mTimeStamp = mTimeStamp;
414 event.mLayersId = mLayersId;
415 event.mFlags.mHandledByAPZ = mHandledByAPZ;
416 event.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
417 mOrigin,
418 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
419 event.mClickCount = clickCount;
420 event.mInputSource = mInputSource;
421 event.mFocusSequenceNumber = mFocusSequenceNumber;
422 event.mExitFrom = exitFrom;
423 event.mClickEventPrevented = mPreventClickEvent;
425 return event;
428 PanGestureInput::PanGestureInput()
429 : InputData(PANGESTURE_INPUT),
430 mType(PANGESTURE_MAYSTART),
431 mLineOrPageDeltaX(0),
432 mLineOrPageDeltaY(0),
433 mUserDeltaMultiplierX(1.0),
434 mUserDeltaMultiplierY(1.0),
435 mHandledByAPZ(false),
436 mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection(false),
437 mOverscrollBehaviorAllowsSwipe(false),
438 mSimulateMomentum(false),
439 mIsNoLineOrPageDelta(true) {}
441 PanGestureInput::PanGestureInput(PanGestureType aType, uint32_t aTime,
442 TimeStamp aTimeStamp,
443 const ScreenPoint& aPanStartPoint,
444 const ScreenPoint& aPanDisplacement,
445 Modifiers aModifiers)
446 : InputData(PANGESTURE_INPUT, aTime, aTimeStamp, aModifiers),
447 mType(aType),
448 mPanStartPoint(aPanStartPoint),
449 mPanDisplacement(aPanDisplacement),
450 mLineOrPageDeltaX(0),
451 mLineOrPageDeltaY(0),
452 mUserDeltaMultiplierX(1.0),
453 mUserDeltaMultiplierY(1.0),
454 mHandledByAPZ(false),
455 mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection(false),
456 mOverscrollBehaviorAllowsSwipe(false),
457 mSimulateMomentum(false),
458 mIsNoLineOrPageDelta(true) {}
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.mTime = mTime;
482 wheelEvent.mTimeStamp = mTimeStamp;
483 wheelEvent.mLayersId = mLayersId;
484 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
485 mPanStartPoint,
486 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
487 wheelEvent.mButtons = 0;
488 wheelEvent.mMayHaveMomentum = true; // pan inputs may have momentum
489 wheelEvent.mIsMomentum = IsMomentum();
490 wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
491 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
492 wheelEvent.mDeltaX = mPanDisplacement.x;
493 wheelEvent.mDeltaY = mPanDisplacement.y;
494 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
495 wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber;
496 wheelEvent.mIsNoLineOrPageDelta = mIsNoLineOrPageDelta;
497 if (mDeltaType == PanGestureInput::PANDELTA_PAGE) {
498 // widget/gtk is currently the only consumer that uses delta type
499 // PANDELTA_PAGE
500 // Emulate legacy widget/gtk behavior
501 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_LINE;
502 wheelEvent.mScrollType = WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY;
503 wheelEvent.mDeltaX *= 3;
504 wheelEvent.mDeltaY *= 3;
505 } else {
506 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
508 return wheelEvent;
511 bool PanGestureInput::TransformToLocal(
512 const ScreenToParentLayerMatrix4x4& aTransform) {
513 Maybe<ParentLayerPoint> panStartPoint =
514 UntransformBy(aTransform, mPanStartPoint);
515 if (!panStartPoint) {
516 return false;
518 mLocalPanStartPoint = *panStartPoint;
520 if (mDeltaType == PanGestureInput::PANDELTA_PAGE) {
521 // Skip transforming the pan displacement because we want
522 // raw page proportion counts.
523 mLocalPanDisplacement.x = mPanDisplacement.x;
524 mLocalPanDisplacement.y = mPanDisplacement.y;
525 return true;
528 Maybe<ParentLayerPoint> panDisplacement =
529 UntransformVector(aTransform, mPanDisplacement, mPanStartPoint);
530 if (!panDisplacement) {
531 return false;
533 mLocalPanDisplacement = *panDisplacement;
534 return true;
537 ScreenPoint PanGestureInput::UserMultipliedPanDisplacement() const {
538 return ScreenPoint(mPanDisplacement.x * mUserDeltaMultiplierX,
539 mPanDisplacement.y * mUserDeltaMultiplierY);
542 ParentLayerPoint PanGestureInput::UserMultipliedLocalPanDisplacement() const {
543 return ParentLayerPoint(mLocalPanDisplacement.x * mUserDeltaMultiplierX,
544 mLocalPanDisplacement.y * mUserDeltaMultiplierY);
547 static int32_t TakeLargestInt(gfx::Float* aFloat) {
548 int32_t result(*aFloat); // truncate towards zero
549 *aFloat -= result;
550 return result;
553 /* static */ gfx::IntPoint PanGestureInput::GetIntegerDeltaForEvent(
554 bool aIsStart, float x, float y) {
555 static gfx::Point sAccumulator(0.0f, 0.0f);
556 if (aIsStart) {
557 sAccumulator = gfx::Point(0.0f, 0.0f);
559 sAccumulator.x += x;
560 sAccumulator.y += y;
561 return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
562 TakeLargestInt(&sAccumulator.y));
565 PinchGestureInput::PinchGestureInput()
566 : InputData(PINCHGESTURE_INPUT),
567 mType(PINCHGESTURE_START),
568 mSource(UNKNOWN),
569 mHandledByAPZ(false) {}
571 PinchGestureInput::PinchGestureInput(
572 PinchGestureType aType, PinchGestureSource aSource, uint32_t aTime,
573 TimeStamp aTimeStamp, const ExternalPoint& aScreenOffset,
574 const ScreenPoint& aFocusPoint, ScreenCoord aCurrentSpan,
575 ScreenCoord aPreviousSpan, Modifiers aModifiers)
576 : InputData(PINCHGESTURE_INPUT, aTime, aTimeStamp, aModifiers),
577 mType(aType),
578 mSource(aSource),
579 mFocusPoint(aFocusPoint),
580 mScreenOffset(aScreenOffset),
581 mCurrentSpan(aCurrentSpan),
582 mPreviousSpan(aPreviousSpan),
583 mLineOrPageDeltaY(0),
584 mHandledByAPZ(false) {}
586 bool PinchGestureInput::TransformToLocal(
587 const ScreenToParentLayerMatrix4x4& aTransform) {
588 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mFocusPoint);
589 if (!point) {
590 return false;
592 mLocalFocusPoint = *point;
593 return true;
596 WidgetWheelEvent PinchGestureInput::ToWidgetEvent(nsIWidget* aWidget) const {
597 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
598 wheelEvent.mModifiers = this->modifiers | MODIFIER_CONTROL;
599 wheelEvent.mTime = mTime;
600 wheelEvent.mTimeStamp = mTimeStamp;
601 wheelEvent.mLayersId = mLayersId;
602 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
603 mFocusPoint,
604 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
605 wheelEvent.mButtons = 0;
606 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
607 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
609 wheelEvent.mDeltaY = ComputeDeltaY(aWidget);
611 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
613 MOZ_ASSERT(mType == PINCHGESTURE_END || wheelEvent.mDeltaY != 0.0);
615 return wheelEvent;
618 double PinchGestureInput::ComputeDeltaY(nsIWidget* aWidget) const {
619 #if defined(OS_MACOSX)
620 // This converts the pinch gesture value to a fake wheel event that has the
621 // control key pressed so that pages can implement custom pinch gesture
622 // handling. It may seem strange that this doesn't use a wheel event with
623 // the deltaZ property set, but this matches Chrome's behavior as described
624 // at https://code.google.com/p/chromium/issues/detail?id=289887
626 // The intent of the formula below is to produce numbers similar to Chrome's
627 // implementation of this feature. Chrome implements deltaY using the formula
628 // "-100 * log(1 + [event magnification])" which is unfortunately incorrect.
629 // All deltas for a single pinch gesture should sum to 0 if the start and end
630 // of a pinch gesture end up in the same place. This doesn't happen in Chrome
631 // because they followed Apple's misleading documentation, which implies that
632 // "1 + [event magnification]" is the scale factor. The scale factor is
633 // instead "pow(ratio, [event magnification])" so "[event magnification]" is
634 // already in log space.
636 // The multiplication by the backing scale factor below counteracts the
637 // division by the backing scale factor in WheelEvent.
639 // We want to set deltaY to |-100.0 * M * GetDefaultScaleInternal()| where M
640 // is [event magnification] but [event magnification] is only available in the
641 // macOS widget code so we have to reverse engineer from mCurrentSpan and
642 // mPreviousSpan (which are derived from [event magnification]) to get it.
643 // Specifically, we know |mCurrentSpan == 100.0| and |mPreviousSpan == 100.0 *
644 // (1.0 - M)|. We can calculate deltaY by solving the mPreviousSpan equation
645 // for M in terms of mPreviousSpan and plugging that into to the formula for
646 // deltaY.
647 return (mPreviousSpan - 100.0) *
648 (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
649 #else
650 // This calculation is based on what the Windows and Linux widget code does.
651 // Specifically, it creates a PinchGestureInput with |mCurrentSpan == 100.0 *
652 // currentScale| and |mPreviousSpan == 100.0 * lastScale| where currentScale
653 // is the scale from the current OS event and lastScale is the scale when the
654 // previous OS event happened. On macOS [event magnification] is a relative
655 // change in scale factor, ie if the scale factor changed from 1 to 1.1 it
656 // will be 0.1, similarly if it changed from 1 to 0.9 it will be -0.1. To
657 // calculate the relative scale change on Windows we would calculate |M =
658 // currentScale - lastScale = (mCurrentSpan-mPreviousSpan)/100| and use the
659 // same formula as the macOS code
660 // (|-100.0 * M * GetDefaultScaleInternal()|).
662 return (mPreviousSpan - mCurrentSpan) *
663 (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
664 #endif
667 bool PinchGestureInput::SetLineOrPageDeltaY(nsIWidget* aWidget) {
668 double deltaY = ComputeDeltaY(aWidget);
669 if (deltaY == 0 && mType != PINCHGESTURE_END) {
670 return false;
672 gfx::IntPoint lineOrPageDelta = PinchGestureInput::GetIntegerDeltaForEvent(
673 (mType == PINCHGESTURE_START), 0, deltaY);
674 mLineOrPageDeltaY = lineOrPageDelta.y;
675 if (mLineOrPageDeltaY == 0) {
676 // For PINCHGESTURE_SCALE events, don't dispatch them. Note that the delta
677 // isn't lost; it remains in the accumulator in GetIntegerDeltaForEvent().
678 if (mType == PINCHGESTURE_SCALE) {
679 return false;
681 // On Windows, drop PINCHGESTURE_START as well (the Windows widget code will
682 // defer the START event until we accumulate enough delta).
683 // The Linux widget code doesn't support this, so instead set the event's
684 // mLineOrPageDeltaY to the smallest nonzero amount in the relevant
685 // direction.
686 if (mType == PINCHGESTURE_START) {
687 #ifdef XP_WIN
688 return false;
689 #else
690 mLineOrPageDeltaY = (deltaY >= 0) ? 1 : -1;
691 #endif
693 // For PINCHGESTURE_END events, not dispatching a DOMMouseScroll for them is
694 // fine.
696 return true;
699 /* static */ gfx::IntPoint PinchGestureInput::GetIntegerDeltaForEvent(
700 bool aIsStart, float x, float y) {
701 static gfx::Point sAccumulator(0.0f, 0.0f);
702 if (aIsStart) {
703 sAccumulator = gfx::Point(0.0f, 0.0f);
705 sAccumulator.x += x;
706 sAccumulator.y += y;
707 return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
708 TakeLargestInt(&sAccumulator.y));
711 TapGestureInput::TapGestureInput()
712 : InputData(TAPGESTURE_INPUT), mType(TAPGESTURE_LONG) {}
714 TapGestureInput::TapGestureInput(TapGestureType aType, uint32_t aTime,
715 TimeStamp aTimeStamp,
716 const ScreenIntPoint& aPoint,
717 Modifiers aModifiers)
718 : InputData(TAPGESTURE_INPUT, aTime, aTimeStamp, aModifiers),
719 mType(aType),
720 mPoint(aPoint) {}
722 TapGestureInput::TapGestureInput(TapGestureType aType, uint32_t aTime,
723 TimeStamp aTimeStamp,
724 const ParentLayerPoint& aLocalPoint,
725 Modifiers aModifiers)
726 : InputData(TAPGESTURE_INPUT, aTime, aTimeStamp, aModifiers),
727 mType(aType),
728 mLocalPoint(aLocalPoint) {}
730 bool TapGestureInput::TransformToLocal(
731 const ScreenToParentLayerMatrix4x4& aTransform) {
732 Maybe<ParentLayerIntPoint> point = UntransformBy(aTransform, mPoint);
733 if (!point) {
734 return false;
736 mLocalPoint = *point;
737 return true;
740 WidgetSimpleGestureEvent TapGestureInput::ToWidgetEvent(
741 nsIWidget* aWidget) const {
742 WidgetSimpleGestureEvent event(true, eTapGesture, aWidget);
744 event.mTime = mTime;
745 event.mTimeStamp = mTimeStamp;
746 event.mLayersId = mLayersId;
747 event.mRefPoint = ViewAs<LayoutDevicePixel>(
748 mPoint,
749 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
750 event.mButtons = 0;
751 event.mClickCount = 1;
752 event.mModifiers = modifiers;
754 return event;
757 ScrollWheelInput::ScrollWheelInput()
758 : InputData(SCROLLWHEEL_INPUT),
759 mDeltaType(SCROLLDELTA_LINE),
760 mScrollMode(SCROLLMODE_INSTANT),
761 mHandledByAPZ(false),
762 mDeltaX(0.0),
763 mDeltaY(0.0),
764 mLineOrPageDeltaX(0),
765 mLineOrPageDeltaY(0),
766 mScrollSeriesNumber(0),
767 mUserDeltaMultiplierX(1.0),
768 mUserDeltaMultiplierY(1.0),
769 mMayHaveMomentum(false),
770 mIsMomentum(false),
771 mAPZAction(APZWheelAction::Scroll) {}
773 ScrollWheelInput::ScrollWheelInput(
774 uint32_t aTime, TimeStamp aTimeStamp, Modifiers aModifiers,
775 ScrollMode aScrollMode, ScrollDeltaType aDeltaType,
776 const ScreenPoint& aOrigin, double aDeltaX, double aDeltaY,
777 bool aAllowToOverrideSystemScrollSpeed,
778 WheelDeltaAdjustmentStrategy aWheelDeltaAdjustmentStrategy)
779 : InputData(SCROLLWHEEL_INPUT, aTime, aTimeStamp, aModifiers),
780 mDeltaType(aDeltaType),
781 mScrollMode(aScrollMode),
782 mOrigin(aOrigin),
783 mHandledByAPZ(false),
784 mDeltaX(aDeltaX),
785 mDeltaY(aDeltaY),
786 mLineOrPageDeltaX(0),
787 mLineOrPageDeltaY(0),
788 mScrollSeriesNumber(0),
789 mUserDeltaMultiplierX(1.0),
790 mUserDeltaMultiplierY(1.0),
791 mMayHaveMomentum(false),
792 mIsMomentum(false),
793 mAllowToOverrideSystemScrollSpeed(aAllowToOverrideSystemScrollSpeed),
794 mWheelDeltaAdjustmentStrategy(aWheelDeltaAdjustmentStrategy),
795 mAPZAction(APZWheelAction::Scroll) {}
797 ScrollWheelInput::ScrollWheelInput(const WidgetWheelEvent& aWheelEvent)
798 : InputData(SCROLLWHEEL_INPUT, aWheelEvent.mTime, aWheelEvent.mTimeStamp,
799 aWheelEvent.mModifiers),
800 mDeltaType(DeltaTypeForDeltaMode(aWheelEvent.mDeltaMode)),
801 mScrollMode(SCROLLMODE_INSTANT),
802 mHandledByAPZ(aWheelEvent.mFlags.mHandledByAPZ),
803 mDeltaX(aWheelEvent.mDeltaX),
804 mDeltaY(aWheelEvent.mDeltaY),
805 mWheelTicksX(aWheelEvent.mWheelTicksX),
806 mWheelTicksY(aWheelEvent.mWheelTicksX),
807 mLineOrPageDeltaX(aWheelEvent.mLineOrPageDeltaX),
808 mLineOrPageDeltaY(aWheelEvent.mLineOrPageDeltaY),
809 mScrollSeriesNumber(0),
810 mUserDeltaMultiplierX(1.0),
811 mUserDeltaMultiplierY(1.0),
812 mMayHaveMomentum(aWheelEvent.mMayHaveMomentum),
813 mIsMomentum(aWheelEvent.mIsMomentum),
814 mAllowToOverrideSystemScrollSpeed(
815 aWheelEvent.mAllowToOverrideSystemScrollSpeed),
816 mWheelDeltaAdjustmentStrategy(WheelDeltaAdjustmentStrategy::eNone),
817 mAPZAction(APZWheelAction::Scroll) {
818 mOrigin = ScreenPoint(ViewAs<ScreenPixel>(
819 aWheelEvent.mRefPoint,
820 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
823 ScrollWheelInput::ScrollDeltaType ScrollWheelInput::DeltaTypeForDeltaMode(
824 uint32_t aDeltaMode) {
825 switch (aDeltaMode) {
826 case WheelEvent_Binding::DOM_DELTA_LINE:
827 return SCROLLDELTA_LINE;
828 case WheelEvent_Binding::DOM_DELTA_PAGE:
829 return SCROLLDELTA_PAGE;
830 case WheelEvent_Binding::DOM_DELTA_PIXEL:
831 return SCROLLDELTA_PIXEL;
832 default:
833 MOZ_CRASH();
835 return SCROLLDELTA_LINE;
838 uint32_t ScrollWheelInput::DeltaModeForDeltaType(ScrollDeltaType aDeltaType) {
839 switch (aDeltaType) {
840 case ScrollWheelInput::SCROLLDELTA_LINE:
841 return WheelEvent_Binding::DOM_DELTA_LINE;
842 case ScrollWheelInput::SCROLLDELTA_PAGE:
843 return WheelEvent_Binding::DOM_DELTA_PAGE;
844 case ScrollWheelInput::SCROLLDELTA_PIXEL:
845 default:
846 return WheelEvent_Binding::DOM_DELTA_PIXEL;
850 ScrollUnit ScrollWheelInput::ScrollUnitForDeltaType(
851 ScrollDeltaType aDeltaType) {
852 switch (aDeltaType) {
853 case SCROLLDELTA_LINE:
854 return ScrollUnit::LINES;
855 case SCROLLDELTA_PAGE:
856 return ScrollUnit::PAGES;
857 case SCROLLDELTA_PIXEL:
858 return ScrollUnit::DEVICE_PIXELS;
859 default:
860 MOZ_CRASH();
862 return ScrollUnit::LINES;
865 WidgetWheelEvent ScrollWheelInput::ToWidgetEvent(nsIWidget* aWidget) const {
866 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
867 wheelEvent.mModifiers = this->modifiers;
868 wheelEvent.mTime = mTime;
869 wheelEvent.mTimeStamp = mTimeStamp;
870 wheelEvent.mLayersId = mLayersId;
871 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
872 mOrigin,
873 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
874 wheelEvent.mButtons = 0;
875 wheelEvent.mDeltaMode = DeltaModeForDeltaType(mDeltaType);
876 wheelEvent.mMayHaveMomentum = mMayHaveMomentum;
877 wheelEvent.mIsMomentum = mIsMomentum;
878 wheelEvent.mDeltaX = mDeltaX;
879 wheelEvent.mDeltaY = mDeltaY;
880 wheelEvent.mWheelTicksX = mWheelTicksX;
881 wheelEvent.mWheelTicksY = mWheelTicksY;
882 wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
883 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
884 wheelEvent.mAllowToOverrideSystemScrollSpeed =
885 mAllowToOverrideSystemScrollSpeed;
886 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
887 wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber;
888 return wheelEvent;
891 bool ScrollWheelInput::TransformToLocal(
892 const ScreenToParentLayerMatrix4x4& aTransform) {
893 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
894 if (!point) {
895 return false;
897 mLocalOrigin = *point;
898 return true;
901 bool ScrollWheelInput::IsCustomizedByUserPrefs() const {
902 return mUserDeltaMultiplierX != 1.0 || mUserDeltaMultiplierY != 1.0;
905 KeyboardInput::KeyboardInput(const WidgetKeyboardEvent& aEvent)
906 : InputData(KEYBOARD_INPUT, aEvent.mTime, aEvent.mTimeStamp,
907 aEvent.mModifiers),
908 mKeyCode(aEvent.mKeyCode),
909 mCharCode(aEvent.mCharCode),
910 mHandledByAPZ(false) {
911 switch (aEvent.mMessage) {
912 case eKeyPress: {
913 mType = KeyboardInput::KEY_PRESS;
914 break;
916 case eKeyUp: {
917 mType = KeyboardInput::KEY_UP;
918 break;
920 case eKeyDown: {
921 mType = KeyboardInput::KEY_DOWN;
922 break;
924 default:
925 mType = KeyboardInput::KEY_OTHER;
926 break;
929 aEvent.GetShortcutKeyCandidates(mShortcutCandidates);
932 KeyboardInput::KeyboardInput()
933 : InputData(KEYBOARD_INPUT),
934 mType(KEY_DOWN),
935 mKeyCode(0),
936 mCharCode(0),
937 mHandledByAPZ(false) {}
939 } // namespace mozilla