Bug 1734943 [wpt PR 31170] - Correct scrolling contents cull rect, a=testonly
[gecko.git] / widget / InputData.cpp
blob040fcf52db74476d753fc955eeb78f3a368ac04f
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 eMouseHitTest:
316 mType = MOUSE_HITTEST;
317 break;
318 default:
319 MOZ_ASSERT_UNREACHABLE("Mouse event type not supported");
320 break;
323 mOrigin = ScreenPoint(ViewAs<ScreenPixel>(
324 aMouseEvent.mRefPoint,
325 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
328 bool MouseInput::IsLeftButton() const { return mButtonType == PRIMARY_BUTTON; }
330 bool MouseInput::TransformToLocal(
331 const ScreenToParentLayerMatrix4x4& aTransform) {
332 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
333 if (!point) {
334 return false;
336 mLocalOrigin = *point;
338 return true;
341 WidgetMouseEvent MouseInput::ToWidgetEvent(nsIWidget* aWidget) const {
342 MOZ_ASSERT(NS_IsMainThread(),
343 "Can only convert To WidgetTouchEvent on main thread");
345 EventMessage msg = eVoidEvent;
346 uint32_t clickCount = 0;
347 Maybe<WidgetMouseEvent::ExitFrom> exitFrom;
348 switch (mType) {
349 case MOUSE_MOVE:
350 msg = eMouseMove;
351 break;
352 case MOUSE_UP:
353 msg = eMouseUp;
354 clickCount = 1;
355 break;
356 case MOUSE_DOWN:
357 msg = eMouseDown;
358 clickCount = 1;
359 break;
360 case MOUSE_DRAG_START:
361 msg = eDragStart;
362 break;
363 case MOUSE_DRAG_END:
364 msg = eDragEnd;
365 break;
366 case MOUSE_WIDGET_ENTER:
367 msg = eMouseEnterIntoWidget;
368 break;
369 case MOUSE_WIDGET_EXIT:
370 msg = eMouseExitFromWidget;
371 exitFrom = Some(WidgetMouseEvent::ePlatformChild);
372 break;
373 case MOUSE_HITTEST:
374 msg = eMouseHitTest;
375 break;
376 default:
377 MOZ_ASSERT_UNREACHABLE(
378 "Did not assign a type to WidgetMouseEvent in MouseInput");
379 break;
382 WidgetMouseEvent event(true, msg, aWidget, WidgetMouseEvent::eReal,
383 WidgetMouseEvent::eNormal);
385 if (msg == eVoidEvent) {
386 return event;
389 switch (mButtonType) {
390 case MouseInput::PRIMARY_BUTTON:
391 event.mButton = MouseButton::ePrimary;
392 break;
393 case MouseInput::MIDDLE_BUTTON:
394 event.mButton = MouseButton::eMiddle;
395 break;
396 case MouseInput::SECONDARY_BUTTON:
397 event.mButton = MouseButton::eSecondary;
398 break;
399 case MouseInput::NONE:
400 default:
401 break;
404 event.mButtons = mButtons;
405 event.mModifiers = modifiers;
406 event.mTime = mTime;
407 event.mTimeStamp = mTimeStamp;
408 event.mLayersId = mLayersId;
409 event.mFlags.mHandledByAPZ = mHandledByAPZ;
410 event.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
411 mOrigin,
412 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
413 event.mClickCount = clickCount;
414 event.mInputSource = mInputSource;
415 event.mFocusSequenceNumber = mFocusSequenceNumber;
416 event.mExitFrom = exitFrom;
417 event.mClickEventPrevented = mPreventClickEvent;
419 return event;
422 PanGestureInput::PanGestureInput()
423 : InputData(PANGESTURE_INPUT),
424 mType(PANGESTURE_MAYSTART),
425 mLineOrPageDeltaX(0),
426 mLineOrPageDeltaY(0),
427 mUserDeltaMultiplierX(1.0),
428 mUserDeltaMultiplierY(1.0),
429 mHandledByAPZ(false),
430 mFollowedByMomentum(false),
431 mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection(false),
432 mOverscrollBehaviorAllowsSwipe(false),
433 mSimulateMomentum(false),
434 mIsNoLineOrPageDelta(true) {}
436 PanGestureInput::PanGestureInput(PanGestureType aType, uint32_t aTime,
437 TimeStamp aTimeStamp,
438 const ScreenPoint& aPanStartPoint,
439 const ScreenPoint& aPanDisplacement,
440 Modifiers aModifiers)
441 : InputData(PANGESTURE_INPUT, aTime, aTimeStamp, aModifiers),
442 mType(aType),
443 mPanStartPoint(aPanStartPoint),
444 mPanDisplacement(aPanDisplacement),
445 mLineOrPageDeltaX(0),
446 mLineOrPageDeltaY(0),
447 mUserDeltaMultiplierX(1.0),
448 mUserDeltaMultiplierY(1.0),
449 mHandledByAPZ(false),
450 mFollowedByMomentum(false),
451 mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection(false),
452 mOverscrollBehaviorAllowsSwipe(false),
453 mSimulateMomentum(false),
454 mIsNoLineOrPageDelta(true) {}
456 void PanGestureInput::SetLineOrPageDeltas(int32_t aLineOrPageDeltaX,
457 int32_t aLineOrPageDeltaY) {
458 mLineOrPageDeltaX = aLineOrPageDeltaX;
459 mLineOrPageDeltaY = aLineOrPageDeltaY;
460 mIsNoLineOrPageDelta = false;
463 bool PanGestureInput::IsMomentum() const {
464 switch (mType) {
465 case PanGestureInput::PANGESTURE_MOMENTUMSTART:
466 case PanGestureInput::PANGESTURE_MOMENTUMPAN:
467 case PanGestureInput::PANGESTURE_MOMENTUMEND:
468 return true;
469 default:
470 return false;
474 WidgetWheelEvent PanGestureInput::ToWidgetEvent(nsIWidget* aWidget) const {
475 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
476 wheelEvent.mModifiers = this->modifiers;
477 wheelEvent.mTime = mTime;
478 wheelEvent.mTimeStamp = mTimeStamp;
479 wheelEvent.mLayersId = mLayersId;
480 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
481 mPanStartPoint,
482 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
483 wheelEvent.mButtons = 0;
484 wheelEvent.mMayHaveMomentum = true; // pan inputs may have momentum
485 wheelEvent.mIsMomentum = IsMomentum();
486 wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
487 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
488 wheelEvent.mDeltaX = mPanDisplacement.x;
489 wheelEvent.mDeltaY = mPanDisplacement.y;
490 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
491 wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber;
492 wheelEvent.mIsNoLineOrPageDelta = mIsNoLineOrPageDelta;
493 if (mDeltaType == PanGestureInput::PANDELTA_PAGE) {
494 // widget/gtk is currently the only consumer that uses delta type
495 // PANDELTA_PAGE
496 // Emulate legacy widget/gtk behavior
497 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_LINE;
498 wheelEvent.mScrollType = WidgetWheelEvent::SCROLL_ASYNCHRONOUSELY;
499 wheelEvent.mDeltaX *= 3;
500 wheelEvent.mDeltaY *= 3;
501 } else {
502 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
504 return wheelEvent;
507 bool PanGestureInput::TransformToLocal(
508 const ScreenToParentLayerMatrix4x4& aTransform) {
509 Maybe<ParentLayerPoint> panStartPoint =
510 UntransformBy(aTransform, mPanStartPoint);
511 if (!panStartPoint) {
512 return false;
514 mLocalPanStartPoint = *panStartPoint;
516 if (mDeltaType == PanGestureInput::PANDELTA_PAGE) {
517 // Skip transforming the pan displacement because we want
518 // raw page proportion counts.
519 mLocalPanDisplacement.x = mPanDisplacement.x;
520 mLocalPanDisplacement.y = mPanDisplacement.y;
521 return true;
524 Maybe<ParentLayerPoint> panDisplacement =
525 UntransformVector(aTransform, mPanDisplacement, mPanStartPoint);
526 if (!panDisplacement) {
527 return false;
529 mLocalPanDisplacement = *panDisplacement;
530 return true;
533 ScreenPoint PanGestureInput::UserMultipliedPanDisplacement() const {
534 return ScreenPoint(mPanDisplacement.x * mUserDeltaMultiplierX,
535 mPanDisplacement.y * mUserDeltaMultiplierY);
538 ParentLayerPoint PanGestureInput::UserMultipliedLocalPanDisplacement() const {
539 return ParentLayerPoint(mLocalPanDisplacement.x * mUserDeltaMultiplierX,
540 mLocalPanDisplacement.y * mUserDeltaMultiplierY);
543 static int32_t TakeLargestInt(gfx::Float* aFloat) {
544 int32_t result(*aFloat); // truncate towards zero
545 *aFloat -= result;
546 return result;
549 /* static */ gfx::IntPoint PanGestureInput::GetIntegerDeltaForEvent(
550 bool aIsStart, float x, float y) {
551 static gfx::Point sAccumulator(0.0f, 0.0f);
552 if (aIsStart) {
553 sAccumulator = gfx::Point(0.0f, 0.0f);
555 sAccumulator.x += x;
556 sAccumulator.y += y;
557 return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
558 TakeLargestInt(&sAccumulator.y));
561 PinchGestureInput::PinchGestureInput()
562 : InputData(PINCHGESTURE_INPUT),
563 mType(PINCHGESTURE_START),
564 mSource(UNKNOWN),
565 mHandledByAPZ(false) {}
567 PinchGestureInput::PinchGestureInput(
568 PinchGestureType aType, PinchGestureSource aSource, uint32_t aTime,
569 TimeStamp aTimeStamp, const ExternalPoint& aScreenOffset,
570 const ScreenPoint& aFocusPoint, ScreenCoord aCurrentSpan,
571 ScreenCoord aPreviousSpan, Modifiers aModifiers)
572 : InputData(PINCHGESTURE_INPUT, aTime, aTimeStamp, aModifiers),
573 mType(aType),
574 mSource(aSource),
575 mFocusPoint(aFocusPoint),
576 mScreenOffset(aScreenOffset),
577 mCurrentSpan(aCurrentSpan),
578 mPreviousSpan(aPreviousSpan),
579 mLineOrPageDeltaY(0),
580 mHandledByAPZ(false) {}
582 bool PinchGestureInput::TransformToLocal(
583 const ScreenToParentLayerMatrix4x4& aTransform) {
584 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mFocusPoint);
585 if (!point) {
586 return false;
588 mLocalFocusPoint = *point;
589 return true;
592 WidgetWheelEvent PinchGestureInput::ToWidgetEvent(nsIWidget* aWidget) const {
593 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
594 wheelEvent.mModifiers = this->modifiers | MODIFIER_CONTROL;
595 wheelEvent.mTime = mTime;
596 wheelEvent.mTimeStamp = mTimeStamp;
597 wheelEvent.mLayersId = mLayersId;
598 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
599 mFocusPoint,
600 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
601 wheelEvent.mButtons = 0;
602 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
603 wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
605 wheelEvent.mDeltaY = ComputeDeltaY(aWidget);
607 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
609 MOZ_ASSERT(mType == PINCHGESTURE_END || wheelEvent.mDeltaY != 0.0);
611 return wheelEvent;
614 double PinchGestureInput::ComputeDeltaY(nsIWidget* aWidget) const {
615 #if defined(OS_MACOSX)
616 // This converts the pinch gesture value to a fake wheel event that has the
617 // control key pressed so that pages can implement custom pinch gesture
618 // handling. It may seem strange that this doesn't use a wheel event with
619 // the deltaZ property set, but this matches Chrome's behavior as described
620 // at https://code.google.com/p/chromium/issues/detail?id=289887
622 // The intent of the formula below is to produce numbers similar to Chrome's
623 // implementation of this feature. Chrome implements deltaY using the formula
624 // "-100 * log(1 + [event magnification])" which is unfortunately incorrect.
625 // All deltas for a single pinch gesture should sum to 0 if the start and end
626 // of a pinch gesture end up in the same place. This doesn't happen in Chrome
627 // because they followed Apple's misleading documentation, which implies that
628 // "1 + [event magnification]" is the scale factor. The scale factor is
629 // instead "pow(ratio, [event magnification])" so "[event magnification]" is
630 // already in log space.
632 // The multiplication by the backing scale factor below counteracts the
633 // division by the backing scale factor in WheelEvent.
635 // We want to set deltaY to |-100.0 * M * GetDefaultScaleInternal()| where M
636 // is [event magnification] but [event magnification] is only available in the
637 // macOS widget code so we have to reverse engineer from mCurrentSpan and
638 // mPreviousSpan (which are derived from [event magnification]) to get it.
639 // Specifically, we know |mCurrentSpan == 100.0| and |mPreviousSpan == 100.0 *
640 // (1.0 - M)|. We can calculate deltaY by solving the mPreviousSpan equation
641 // for M in terms of mPreviousSpan and plugging that into to the formula for
642 // deltaY.
643 return (mPreviousSpan - 100.0) *
644 (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
645 #else
646 // This calculation is based on what the Windows and Linux widget code does.
647 // Specifically, it creates a PinchGestureInput with |mCurrentSpan == 100.0 *
648 // currentScale| and |mPreviousSpan == 100.0 * lastScale| where currentScale
649 // is the scale from the current OS event and lastScale is the scale when the
650 // previous OS event happened. On macOS [event magnification] is a relative
651 // change in scale factor, ie if the scale factor changed from 1 to 1.1 it
652 // will be 0.1, similarly if it changed from 1 to 0.9 it will be -0.1. To
653 // calculate the relative scale change on Windows we would calculate |M =
654 // currentScale - lastScale = (mCurrentSpan-mPreviousSpan)/100| and use the
655 // same formula as the macOS code
656 // (|-100.0 * M * GetDefaultScaleInternal()|).
658 return (mPreviousSpan - mCurrentSpan) *
659 (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f);
660 #endif
663 bool PinchGestureInput::SetLineOrPageDeltaY(nsIWidget* aWidget) {
664 double deltaY = ComputeDeltaY(aWidget);
665 if (deltaY == 0 && mType != PINCHGESTURE_END) {
666 return false;
668 gfx::IntPoint lineOrPageDelta = PinchGestureInput::GetIntegerDeltaForEvent(
669 (mType == PINCHGESTURE_START), 0, deltaY);
670 mLineOrPageDeltaY = lineOrPageDelta.y;
671 if (mLineOrPageDeltaY == 0) {
672 // For PINCHGESTURE_SCALE events, don't dispatch them. Note that the delta
673 // isn't lost; it remains in the accumulator in GetIntegerDeltaForEvent().
674 if (mType == PINCHGESTURE_SCALE) {
675 return false;
677 // On Windows, drop PINCHGESTURE_START as well (the Windows widget code will
678 // defer the START event until we accumulate enough delta).
679 // The Linux widget code doesn't support this, so instead set the event's
680 // mLineOrPageDeltaY to the smallest nonzero amount in the relevant
681 // direction.
682 if (mType == PINCHGESTURE_START) {
683 #ifdef XP_WIN
684 return false;
685 #else
686 mLineOrPageDeltaY = (deltaY >= 0) ? 1 : -1;
687 #endif
689 // For PINCHGESTURE_END events, not dispatching a DOMMouseScroll for them is
690 // fine.
692 return true;
695 /* static */ gfx::IntPoint PinchGestureInput::GetIntegerDeltaForEvent(
696 bool aIsStart, float x, float y) {
697 static gfx::Point sAccumulator(0.0f, 0.0f);
698 if (aIsStart) {
699 sAccumulator = gfx::Point(0.0f, 0.0f);
701 sAccumulator.x += x;
702 sAccumulator.y += y;
703 return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
704 TakeLargestInt(&sAccumulator.y));
707 TapGestureInput::TapGestureInput()
708 : InputData(TAPGESTURE_INPUT), mType(TAPGESTURE_LONG) {}
710 TapGestureInput::TapGestureInput(TapGestureType aType, uint32_t aTime,
711 TimeStamp aTimeStamp,
712 const ScreenIntPoint& aPoint,
713 Modifiers aModifiers)
714 : InputData(TAPGESTURE_INPUT, aTime, aTimeStamp, aModifiers),
715 mType(aType),
716 mPoint(aPoint) {}
718 TapGestureInput::TapGestureInput(TapGestureType aType, uint32_t aTime,
719 TimeStamp aTimeStamp,
720 const ParentLayerPoint& aLocalPoint,
721 Modifiers aModifiers)
722 : InputData(TAPGESTURE_INPUT, aTime, aTimeStamp, aModifiers),
723 mType(aType),
724 mLocalPoint(aLocalPoint) {}
726 bool TapGestureInput::TransformToLocal(
727 const ScreenToParentLayerMatrix4x4& aTransform) {
728 Maybe<ParentLayerIntPoint> point = UntransformBy(aTransform, mPoint);
729 if (!point) {
730 return false;
732 mLocalPoint = *point;
733 return true;
736 WidgetSimpleGestureEvent TapGestureInput::ToWidgetEvent(
737 nsIWidget* aWidget) const {
738 WidgetSimpleGestureEvent event(true, eTapGesture, aWidget);
740 event.mTime = mTime;
741 event.mTimeStamp = mTimeStamp;
742 event.mLayersId = mLayersId;
743 event.mRefPoint = ViewAs<LayoutDevicePixel>(
744 mPoint,
745 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
746 event.mButtons = 0;
747 event.mClickCount = 1;
748 event.mModifiers = modifiers;
750 return event;
753 ScrollWheelInput::ScrollWheelInput()
754 : InputData(SCROLLWHEEL_INPUT),
755 mDeltaType(SCROLLDELTA_LINE),
756 mScrollMode(SCROLLMODE_INSTANT),
757 mHandledByAPZ(false),
758 mDeltaX(0.0),
759 mDeltaY(0.0),
760 mLineOrPageDeltaX(0),
761 mLineOrPageDeltaY(0),
762 mScrollSeriesNumber(0),
763 mUserDeltaMultiplierX(1.0),
764 mUserDeltaMultiplierY(1.0),
765 mMayHaveMomentum(false),
766 mIsMomentum(false),
767 mAPZAction(APZWheelAction::Scroll) {}
769 ScrollWheelInput::ScrollWheelInput(
770 uint32_t aTime, TimeStamp aTimeStamp, Modifiers aModifiers,
771 ScrollMode aScrollMode, ScrollDeltaType aDeltaType,
772 const ScreenPoint& aOrigin, double aDeltaX, double aDeltaY,
773 bool aAllowToOverrideSystemScrollSpeed,
774 WheelDeltaAdjustmentStrategy aWheelDeltaAdjustmentStrategy)
775 : InputData(SCROLLWHEEL_INPUT, aTime, aTimeStamp, aModifiers),
776 mDeltaType(aDeltaType),
777 mScrollMode(aScrollMode),
778 mOrigin(aOrigin),
779 mHandledByAPZ(false),
780 mDeltaX(aDeltaX),
781 mDeltaY(aDeltaY),
782 mLineOrPageDeltaX(0),
783 mLineOrPageDeltaY(0),
784 mScrollSeriesNumber(0),
785 mUserDeltaMultiplierX(1.0),
786 mUserDeltaMultiplierY(1.0),
787 mMayHaveMomentum(false),
788 mIsMomentum(false),
789 mAllowToOverrideSystemScrollSpeed(aAllowToOverrideSystemScrollSpeed),
790 mWheelDeltaAdjustmentStrategy(aWheelDeltaAdjustmentStrategy),
791 mAPZAction(APZWheelAction::Scroll) {}
793 ScrollWheelInput::ScrollWheelInput(const WidgetWheelEvent& aWheelEvent)
794 : InputData(SCROLLWHEEL_INPUT, aWheelEvent.mTime, aWheelEvent.mTimeStamp,
795 aWheelEvent.mModifiers),
796 mDeltaType(DeltaTypeForDeltaMode(aWheelEvent.mDeltaMode)),
797 mScrollMode(SCROLLMODE_INSTANT),
798 mHandledByAPZ(aWheelEvent.mFlags.mHandledByAPZ),
799 mDeltaX(aWheelEvent.mDeltaX),
800 mDeltaY(aWheelEvent.mDeltaY),
801 mWheelTicksX(aWheelEvent.mWheelTicksX),
802 mWheelTicksY(aWheelEvent.mWheelTicksX),
803 mLineOrPageDeltaX(aWheelEvent.mLineOrPageDeltaX),
804 mLineOrPageDeltaY(aWheelEvent.mLineOrPageDeltaY),
805 mScrollSeriesNumber(0),
806 mUserDeltaMultiplierX(1.0),
807 mUserDeltaMultiplierY(1.0),
808 mMayHaveMomentum(aWheelEvent.mMayHaveMomentum),
809 mIsMomentum(aWheelEvent.mIsMomentum),
810 mAllowToOverrideSystemScrollSpeed(
811 aWheelEvent.mAllowToOverrideSystemScrollSpeed),
812 mWheelDeltaAdjustmentStrategy(WheelDeltaAdjustmentStrategy::eNone),
813 mAPZAction(APZWheelAction::Scroll) {
814 mOrigin = ScreenPoint(ViewAs<ScreenPixel>(
815 aWheelEvent.mRefPoint,
816 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
819 ScrollWheelInput::ScrollDeltaType ScrollWheelInput::DeltaTypeForDeltaMode(
820 uint32_t aDeltaMode) {
821 switch (aDeltaMode) {
822 case WheelEvent_Binding::DOM_DELTA_LINE:
823 return SCROLLDELTA_LINE;
824 case WheelEvent_Binding::DOM_DELTA_PAGE:
825 return SCROLLDELTA_PAGE;
826 case WheelEvent_Binding::DOM_DELTA_PIXEL:
827 return SCROLLDELTA_PIXEL;
828 default:
829 MOZ_CRASH();
831 return SCROLLDELTA_LINE;
834 uint32_t ScrollWheelInput::DeltaModeForDeltaType(ScrollDeltaType aDeltaType) {
835 switch (aDeltaType) {
836 case ScrollWheelInput::SCROLLDELTA_LINE:
837 return WheelEvent_Binding::DOM_DELTA_LINE;
838 case ScrollWheelInput::SCROLLDELTA_PAGE:
839 return WheelEvent_Binding::DOM_DELTA_PAGE;
840 case ScrollWheelInput::SCROLLDELTA_PIXEL:
841 default:
842 return WheelEvent_Binding::DOM_DELTA_PIXEL;
846 ScrollUnit ScrollWheelInput::ScrollUnitForDeltaType(
847 ScrollDeltaType aDeltaType) {
848 switch (aDeltaType) {
849 case SCROLLDELTA_LINE:
850 return ScrollUnit::LINES;
851 case SCROLLDELTA_PAGE:
852 return ScrollUnit::PAGES;
853 case SCROLLDELTA_PIXEL:
854 return ScrollUnit::DEVICE_PIXELS;
855 default:
856 MOZ_CRASH();
858 return ScrollUnit::LINES;
861 WidgetWheelEvent ScrollWheelInput::ToWidgetEvent(nsIWidget* aWidget) const {
862 WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
863 wheelEvent.mModifiers = this->modifiers;
864 wheelEvent.mTime = mTime;
865 wheelEvent.mTimeStamp = mTimeStamp;
866 wheelEvent.mLayersId = mLayersId;
867 wheelEvent.mRefPoint = RoundedToInt(ViewAs<LayoutDevicePixel>(
868 mOrigin,
869 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
870 wheelEvent.mButtons = 0;
871 wheelEvent.mDeltaMode = DeltaModeForDeltaType(mDeltaType);
872 wheelEvent.mMayHaveMomentum = mMayHaveMomentum;
873 wheelEvent.mIsMomentum = mIsMomentum;
874 wheelEvent.mDeltaX = mDeltaX;
875 wheelEvent.mDeltaY = mDeltaY;
876 wheelEvent.mWheelTicksX = mWheelTicksX;
877 wheelEvent.mWheelTicksY = mWheelTicksY;
878 wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
879 wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
880 wheelEvent.mAllowToOverrideSystemScrollSpeed =
881 mAllowToOverrideSystemScrollSpeed;
882 wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
883 wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber;
884 return wheelEvent;
887 bool ScrollWheelInput::TransformToLocal(
888 const ScreenToParentLayerMatrix4x4& aTransform) {
889 Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
890 if (!point) {
891 return false;
893 mLocalOrigin = *point;
894 return true;
897 bool ScrollWheelInput::IsCustomizedByUserPrefs() const {
898 return mUserDeltaMultiplierX != 1.0 || mUserDeltaMultiplierY != 1.0;
901 KeyboardInput::KeyboardInput(const WidgetKeyboardEvent& aEvent)
902 : InputData(KEYBOARD_INPUT, aEvent.mTime, aEvent.mTimeStamp,
903 aEvent.mModifiers),
904 mKeyCode(aEvent.mKeyCode),
905 mCharCode(aEvent.mCharCode),
906 mHandledByAPZ(false) {
907 switch (aEvent.mMessage) {
908 case eKeyPress: {
909 mType = KeyboardInput::KEY_PRESS;
910 break;
912 case eKeyUp: {
913 mType = KeyboardInput::KEY_UP;
914 break;
916 case eKeyDown: {
917 mType = KeyboardInput::KEY_DOWN;
918 break;
920 default:
921 mType = KeyboardInput::KEY_OTHER;
922 break;
925 aEvent.GetShortcutKeyCandidates(mShortcutCandidates);
928 KeyboardInput::KeyboardInput()
929 : InputData(KEYBOARD_INPUT),
930 mType(KEY_DOWN),
931 mKeyCode(0),
932 mCharCode(0),
933 mHandledByAPZ(false) {}
935 } // namespace mozilla