Bug 1942006 - Upstream a variety of Servo-specific code from Servo's downstream fork...
[gecko.git] / widget / MouseEvents.h
blob5ca1a6fa13233b1bd00ee0467732c5875c51d343
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 #ifndef mozilla_MouseEvents_h__
7 #define mozilla_MouseEvents_h__
9 #include <stdint.h>
10 #include <math.h>
12 #include "mozilla/BasicEvents.h"
13 #include "mozilla/EventForwards.h"
14 #include "mozilla/MathAlgorithms.h"
15 #include "mozilla/dom/DataTransfer.h"
16 #include "mozilla/ipc/IPCForwards.h"
17 #include "nsCOMPtr.h"
19 namespace mozilla {
21 namespace dom {
22 class PBrowserParent;
23 class PBrowserChild;
24 class PBrowserBridgeParent;
25 } // namespace dom
27 class WidgetPointerEvent;
28 } // namespace mozilla
30 namespace mozilla {
31 class WidgetPointerEventHolder final {
32 public:
33 nsTArray<WidgetPointerEvent> mEvents;
34 NS_INLINE_DECL_REFCOUNTING(WidgetPointerEventHolder)
36 private:
37 virtual ~WidgetPointerEventHolder() = default;
40 /******************************************************************************
41 * mozilla::WidgetPointerHelper
42 ******************************************************************************/
44 class WidgetPointerHelper {
45 public:
46 uint32_t pointerId;
47 int32_t tiltX;
48 int32_t tiltY;
49 int32_t twist;
50 float tangentialPressure;
51 bool convertToPointer;
52 RefPtr<WidgetPointerEventHolder> mCoalescedWidgetEvents;
54 WidgetPointerHelper()
55 : pointerId(0),
56 tiltX(0),
57 tiltY(0),
58 twist(0),
59 tangentialPressure(0),
60 convertToPointer(true) {}
62 WidgetPointerHelper(uint32_t aPointerId, uint32_t aTiltX, uint32_t aTiltY,
63 uint32_t aTwist = 0, float aTangentialPressure = 0)
64 : pointerId(aPointerId),
65 tiltX(aTiltX),
66 tiltY(aTiltY),
67 twist(aTwist),
68 tangentialPressure(aTangentialPressure),
69 convertToPointer(true) {}
71 explicit WidgetPointerHelper(const WidgetPointerHelper& aHelper) = default;
73 constexpr static double kPi =
74 #ifdef M_PI
75 M_PI;
76 #else
77 3.14159265358979323846;
78 #endif
79 constexpr static double kHalfPi =
80 #ifdef M_PI_2
81 M_PI_2;
82 #else
83 1.57079632679489661923;
84 #endif
85 constexpr static double kDoublePi = kPi * 2;
87 constexpr static double GetDefaultAltitudeAngle() { return kHalfPi; }
88 constexpr static double GetDefaultAzimuthAngle() { return 0.0; }
90 double ComputeAltitudeAngle() const {
91 return ComputeAltitudeAngle(tiltX, tiltY);
93 double ComputeAzimuthAngle() const {
94 return ComputeAzimuthAngle(tiltX, tiltY);
97 static double ComputeAltitudeAngle(int32_t aTiltX, int32_t aTiltY);
98 static double ComputeAzimuthAngle(int32_t aTiltX, int32_t aTiltY);
100 static double ComputeTiltX(double aAltitudeAngle, double aAzimuthAngle);
101 static double ComputeTiltY(double aAltitudeAngle, double aAzimuthAngle);
103 void AssignPointerHelperData(const WidgetPointerHelper& aEvent,
104 bool aCopyCoalescedEvents = false) {
105 pointerId = aEvent.pointerId;
106 tiltX = aEvent.tiltX;
107 tiltY = aEvent.tiltY;
108 twist = aEvent.twist;
109 tangentialPressure = aEvent.tangentialPressure;
110 convertToPointer = aEvent.convertToPointer;
111 if (aCopyCoalescedEvents) {
112 mCoalescedWidgetEvents = aEvent.mCoalescedWidgetEvents;
116 private:
117 static int32_t GetValidTiltValue(int32_t aTilt);
118 static double GetValidAltitudeAngle(double aAltitudeAngle);
119 static double GetValidAzimuthAngle(double aAzimuthAngle);
122 /******************************************************************************
123 * mozilla::WidgetMouseEventBase
124 ******************************************************************************/
126 class WidgetMouseEventBase : public WidgetInputEvent {
127 private:
128 friend class dom::PBrowserParent;
129 friend class dom::PBrowserChild;
130 friend class dom::PBrowserBridgeParent;
131 ALLOW_DEPRECATED_READPARAM
133 protected:
134 WidgetMouseEventBase()
135 : mPressure(0),
136 mButton(0),
137 mButtons(0),
138 mInputSource(/* MouseEvent_Binding::MOZ_SOURCE_MOUSE = */ 1) {}
139 // Including MouseEventBinding.h here leads to an include loop, so
140 // we have to hardcode MouseEvent_Binding::MOZ_SOURCE_MOUSE.
142 WidgetMouseEventBase(bool aIsTrusted, EventMessage aMessage,
143 nsIWidget* aWidget, EventClassID aEventClassID,
144 const WidgetEventTime* aTime = nullptr)
145 : WidgetInputEvent(aIsTrusted, aMessage, aWidget, aEventClassID, aTime),
146 mPressure(0),
147 mButton(0),
148 mButtons(0),
149 mInputSource(/* MouseEvent_Binding::MOZ_SOURCE_MOUSE = */ 1) {}
150 // Including MouseEventBinding.h here leads to an include loop, so
151 // we have to hardcode MouseEvent_Binding::MOZ_SOURCE_MOUSE.
153 public:
154 virtual WidgetMouseEventBase* AsMouseEventBase() override { return this; }
156 virtual WidgetEvent* Duplicate() const override {
157 MOZ_CRASH("WidgetMouseEventBase must not be most-subclass");
160 // Finger or touch pressure of event. It ranges between 0.0 and 1.0.
161 float mPressure;
163 // Pressed button ID of mousedown or mouseup event.
164 // This is set only when pressing a button causes the event.
165 int16_t mButton;
167 // Flags of all pressed buttons at the event fired.
168 // This is set at any mouse event, don't be confused with |mButton|.
169 int16_t mButtons;
171 // Possible values a in MouseEvent
172 uint16_t mInputSource;
174 bool IsLeftButtonPressed() const {
175 return !!(mButtons & MouseButtonsFlag::ePrimaryFlag);
177 bool IsRightButtonPressed() const {
178 return !!(mButtons & MouseButtonsFlag::eSecondaryFlag);
180 bool IsMiddleButtonPressed() const {
181 return !!(mButtons & MouseButtonsFlag::eMiddleFlag);
183 bool Is4thButtonPressed() const {
184 return !!(mButtons & MouseButtonsFlag::e4thFlag);
186 bool Is5thButtonPressed() const {
187 return !!(mButtons & MouseButtonsFlag::e5thFlag);
190 void AssignMouseEventBaseData(const WidgetMouseEventBase& aEvent,
191 bool aCopyTargets) {
192 AssignInputEventData(aEvent, aCopyTargets);
194 mButton = aEvent.mButton;
195 mButtons = aEvent.mButtons;
196 mPressure = aEvent.mPressure;
197 mInputSource = aEvent.mInputSource;
201 * Returns true if left click event.
203 bool IsLeftClickEvent() const {
204 return mMessage == ePointerClick && mButton == MouseButton::ePrimary;
208 * Returns true if this event changes a button state to "pressed".
210 [[nodiscard]] bool IsPressingButton() const {
211 MOZ_ASSERT(IsTrusted());
212 if (mClass == eMouseEventClass) {
213 return mMessage == eMouseDown;
215 if (mButton == MouseButton::eNotPressed) {
216 return false;
218 // If this is an ePointerDown event whose mButton is not "not pressed", this
219 // is a button pressing event.
220 if (mMessage == ePointerDown) {
221 return true;
223 // If 2 or more buttons are pressed at same time, they are sent with
224 // pointermove rather than pointerdown. Therefore, let's check whether
225 // mButtons contains the proper flag for the pressing button.
226 const bool buttonsContainButton = !!(
227 mButtons & MouseButtonsFlagToChange(static_cast<MouseButton>(mButton)));
228 return mMessage == ePointerMove && buttonsContainButton;
232 * Returns true if this event changes a button state to "released".
234 [[nodiscard]] bool IsReleasingButton() const {
235 MOZ_ASSERT(IsTrusted());
236 if (mClass == eMouseEventClass) {
237 return mMessage == eMouseUp;
239 if (mButton == MouseButton::eNotPressed) {
240 return false;
242 // If this is an ePointerUp event whose mButton is not "not pressed", this
243 // is a button release event.
244 if (mMessage == ePointerUp) {
245 return true;
247 // If the releasing button is not the last button of pressing buttons, web
248 // apps notified by pointermove rather than pointerup. Therefore, let's
249 // check whether mButtons loses the proper flag for the releasing button.
250 const bool buttonsLoseTheButton = !(
251 mButtons & MouseButtonsFlagToChange(static_cast<MouseButton>(mButton)));
252 return mMessage == ePointerMove && buttonsLoseTheButton;
256 * Returns true if the input source supports hover state like a mouse.
258 [[nodiscard]] bool InputSourceSupportsHover() const;
261 * Returns true if corresponding DOM event should use fractional coordinates.
263 [[nodiscard]] bool DOMEventShouldUseFractionalCoords() const;
266 /******************************************************************************
267 * mozilla::WidgetMouseEvent
268 ******************************************************************************/
270 class WidgetMouseEvent : public WidgetMouseEventBase,
271 public WidgetPointerHelper {
272 private:
273 friend class dom::PBrowserParent;
274 friend class dom::PBrowserChild;
275 friend class dom::PBrowserBridgeParent;
276 ALLOW_DEPRECATED_READPARAM
278 public:
279 typedef bool ReasonType;
280 enum Reason : ReasonType { eReal, eSynthesized };
282 typedef uint8_t ContextMenuTriggerType;
283 enum ContextMenuTrigger : ContextMenuTriggerType {
284 eNormal,
285 eContextMenuKey,
286 eControlClick
289 typedef uint8_t ExitFromType;
290 enum ExitFrom : ExitFromType {
291 ePlatformChild,
292 ePlatformTopLevel,
293 ePuppet,
294 ePuppetParentToPuppetChild
297 protected:
298 WidgetMouseEvent() = default;
300 WidgetMouseEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
301 EventClassID aEventClassID, Reason aReason,
302 ContextMenuTrigger aContextMenuTrigger,
303 const WidgetEventTime* aTime = nullptr)
304 : WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, aEventClassID,
305 aTime),
306 mReason(aReason),
307 mContextMenuTrigger(aContextMenuTrigger) {}
309 #ifdef DEBUG
310 void AssertContextMenuEventButtonConsistency() const;
311 #endif
313 public:
314 virtual WidgetMouseEvent* AsMouseEvent() override { return this; }
316 WidgetMouseEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
317 Reason aReason = eReal,
318 ContextMenuTrigger aContextMenuTrigger = eNormal,
319 const WidgetEventTime* aTime = nullptr)
320 : WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, eMouseEventClass,
321 aTime),
322 mReason(aReason),
323 mContextMenuTrigger(aContextMenuTrigger) {
324 MOZ_ASSERT_IF(aIsTrusted, !IsPointerEventMessage(mMessage));
325 if (aMessage == eContextMenu) {
326 mButton = (mContextMenuTrigger == eNormal) ? MouseButton::eSecondary
327 : MouseButton::ePrimary;
331 #ifdef DEBUG
332 virtual ~WidgetMouseEvent() { AssertContextMenuEventButtonConsistency(); }
333 #endif
335 virtual WidgetEvent* Duplicate() const override {
336 MOZ_ASSERT(mClass == eMouseEventClass,
337 "Duplicate() must be overridden by sub class");
338 // Not copying widget, it is a weak reference.
339 WidgetMouseEvent* result = new WidgetMouseEvent(
340 false, mMessage, nullptr, mReason, mContextMenuTrigger, this);
341 result->AssignMouseEventData(*this, true);
342 result->mFlags = mFlags;
343 return result;
346 // If during mouseup handling we detect that click event might need to be
347 // dispatched, this is setup to be the target of the click event.
348 nsCOMPtr<dom::EventTarget> mClickTarget;
350 // mReason indicates the reason why the event is fired:
351 // - Representing mouse operation.
352 // - Synthesized for emulating mousemove event when the content under the
353 // mouse cursor is scrolled.
354 Reason mReason = eReal;
356 // mContextMenuTrigger is valid only when mMessage is eContextMenu.
357 // This indicates if the context menu event is caused by context menu key or
358 // other reasons (typically, a click of right mouse button).
359 ContextMenuTrigger mContextMenuTrigger = eNormal;
361 // mExitFrom contains a value only when mMessage is eMouseExitFromWidget.
362 // This indicates if the mouse cursor exits from a top level platform widget,
363 // a child widget or a puppet widget.
364 Maybe<ExitFrom> mExitFrom;
366 // mClickCount may be non-zero value when mMessage is eMouseDown, eMouseUp,
367 // ePointerClick or eMouseDoubleClick. The number is count of mouse clicks.
368 // Otherwise, this must be 0.
369 uint32_t mClickCount = 0;
371 // Whether the event should ignore scroll frame bounds during dispatch.
372 bool mIgnoreRootScrollFrame = false;
374 // Whether the event should be dispatched on a target limited in capturing
375 // content.
376 bool mIgnoreCapturingContent = false;
378 // Whether the event shouldn't cause click event.
379 bool mClickEventPrevented = false;
381 // If this is set to true while the event is being dispatched,
382 // PresShell::EventHandler::FinalizeHandlingEvent will dispatch a synthesized
383 // eMouseMove or ePointerMove.
384 bool mSynthesizeMoveAfterDispatch = false;
386 void AssignMouseEventData(const WidgetMouseEvent& aEvent, bool aCopyTargets) {
387 AssignMouseEventBaseData(aEvent, aCopyTargets);
388 AssignPointerHelperData(aEvent, /* aCopyCoalescedEvents */ true);
390 mReason = aEvent.mReason;
391 mContextMenuTrigger = aEvent.mContextMenuTrigger;
392 mExitFrom = aEvent.mExitFrom;
393 mClickCount = aEvent.mClickCount;
394 mIgnoreRootScrollFrame = aEvent.mIgnoreRootScrollFrame;
395 mIgnoreCapturingContent = aEvent.mIgnoreCapturingContent;
396 mClickEventPrevented = aEvent.mClickEventPrevented;
400 * Returns true if the event is a context menu event caused by key.
402 bool IsContextMenuKeyEvent() const {
403 return mMessage == eContextMenu && mContextMenuTrigger == eContextMenuKey;
407 * Returns true if the event is a real mouse event. Otherwise, i.e., it's
408 * a synthesized event by scroll or something, returns false.
410 bool IsReal() const { return mReason == eReal; }
413 * Returns true if middle click paste is enabled.
415 static bool IsMiddleClickPasteEnabled();
418 /******************************************************************************
419 * mozilla::WidgetDragEvent
420 ******************************************************************************/
422 class WidgetDragEvent : public WidgetMouseEvent {
423 private:
424 friend class mozilla::dom::PBrowserParent;
425 friend class mozilla::dom::PBrowserChild;
426 ALLOW_DEPRECATED_READPARAM
428 protected:
429 WidgetDragEvent()
430 : mUserCancelled(false),
431 mDefaultPreventedOnContent(false),
432 mInHTMLEditorEventListener(false) {}
434 public:
435 virtual WidgetDragEvent* AsDragEvent() override { return this; }
437 WidgetDragEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
438 const WidgetEventTime* aTime = nullptr)
439 : WidgetMouseEvent(aIsTrusted, aMessage, aWidget, eDragEventClass, eReal,
440 eNormal, aTime),
441 mUserCancelled(false),
442 mDefaultPreventedOnContent(false),
443 mInHTMLEditorEventListener(false) {}
445 virtual WidgetEvent* Duplicate() const override {
446 MOZ_ASSERT(mClass == eDragEventClass,
447 "Duplicate() must be overridden by sub class");
448 // Not copying widget, it is a weak reference.
449 WidgetDragEvent* result =
450 new WidgetDragEvent(false, mMessage, nullptr, this);
451 result->AssignDragEventData(*this, true);
452 result->mFlags = mFlags;
453 return result;
456 // The dragging data.
457 nsCOMPtr<dom::DataTransfer> mDataTransfer;
459 // If this is true, user has cancelled the drag operation.
460 bool mUserCancelled;
461 // If this is true, the drag event's preventDefault() is called on content.
462 bool mDefaultPreventedOnContent;
463 // If this event is currently being handled by HTMLEditorEventListener.
464 bool mInHTMLEditorEventListener;
466 // XXX Not tested by test_assign_event_data.html
467 void AssignDragEventData(const WidgetDragEvent& aEvent, bool aCopyTargets) {
468 AssignMouseEventData(aEvent, aCopyTargets);
470 mDataTransfer = aEvent.mDataTransfer;
471 // XXX mUserCancelled isn't copied, is this intentionally?
472 mUserCancelled = false;
473 mDefaultPreventedOnContent = aEvent.mDefaultPreventedOnContent;
474 // XXX mInHTMLEditorEventListener isn't copied, is this intentionally?
475 mInHTMLEditorEventListener = false;
478 bool CanConvertToInputData() const {
479 return mMessage == eDragStart || mMessage == eDragEnd ||
480 mMessage == eDragEnter || mMessage == eDragOver ||
481 mMessage == eDragExit || mMessage == eDrop;
485 * Should be called before dispatching the DOM tree if this event is
486 * synthesized for tests because drop effect is initialized before
487 * dispatching from widget if it's not synthesized event, but synthesized
488 * events are not initialized in the path.
490 void InitDropEffectForTests();
493 /******************************************************************************
494 * mozilla::WidgetMouseScrollEvent
496 * This is used for legacy DOM mouse scroll events, i.e.,
497 * DOMMouseScroll and MozMousePixelScroll event. These events are NOT hanbled
498 * by ESM even if widget dispatches them. Use new WidgetWheelEvent instead.
499 ******************************************************************************/
501 class WidgetMouseScrollEvent : public WidgetMouseEventBase {
502 private:
503 WidgetMouseScrollEvent() : mDelta(0), mIsHorizontal(false) {}
505 public:
506 virtual WidgetMouseScrollEvent* AsMouseScrollEvent() override { return this; }
508 WidgetMouseScrollEvent(bool aIsTrusted, EventMessage aMessage,
509 nsIWidget* aWidget,
510 const WidgetEventTime* aTime = nullptr)
511 : WidgetMouseEventBase(aIsTrusted, aMessage, aWidget,
512 eMouseScrollEventClass, aTime),
513 mDelta(0),
514 mIsHorizontal(false) {}
516 virtual WidgetEvent* Duplicate() const override {
517 MOZ_ASSERT(mClass == eMouseScrollEventClass,
518 "Duplicate() must be overridden by sub class");
519 // Not copying widget, it is a weak reference.
520 WidgetMouseScrollEvent* result =
521 new WidgetMouseScrollEvent(false, mMessage, nullptr, this);
522 result->AssignMouseScrollEventData(*this, true);
523 result->mFlags = mFlags;
524 return result;
527 // The delta value of mouse scroll event.
528 // If the event message is eLegacyMouseLineOrPageScroll, the value indicates
529 // scroll amount in lines. However, if the value is
530 // UIEvent::SCROLL_PAGE_UP or UIEvent::SCROLL_PAGE_DOWN, the
531 // value inducates one page scroll. If the event message is
532 // eLegacyMousePixelScroll, the value indicates scroll amount in pixels.
533 int32_t mDelta;
535 // If this is true, it may cause to scroll horizontally.
536 // Otherwise, vertically.
537 bool mIsHorizontal;
539 void AssignMouseScrollEventData(const WidgetMouseScrollEvent& aEvent,
540 bool aCopyTargets) {
541 AssignMouseEventBaseData(aEvent, aCopyTargets);
543 mDelta = aEvent.mDelta;
544 mIsHorizontal = aEvent.mIsHorizontal;
548 /******************************************************************************
549 * mozilla::WidgetWheelEvent
550 ******************************************************************************/
552 class WidgetWheelEvent : public WidgetMouseEventBase {
553 private:
554 friend class mozilla::dom::PBrowserParent;
555 friend class mozilla::dom::PBrowserChild;
556 ALLOW_DEPRECATED_READPARAM
558 WidgetWheelEvent()
559 : mDeltaX(0.0),
560 mDeltaY(0.0),
561 mDeltaZ(0.0),
562 mOverflowDeltaX(0.0),
563 mOverflowDeltaY(0.0)
564 // Including WheelEventBinding.h here leads to an include loop, so
565 // we have to hardcode WheelEvent_Binding::DOM_DELTA_PIXEL.
567 mDeltaMode(/* WheelEvent_Binding::DOM_DELTA_PIXEL = */ 0),
568 mLineOrPageDeltaX(0),
569 mLineOrPageDeltaY(0),
570 mScrollType(SCROLL_DEFAULT),
571 mCustomizedByUserPrefs(false),
572 mMayHaveMomentum(false),
573 mIsMomentum(false),
574 mIsNoLineOrPageDelta(false),
575 mViewPortIsOverscrolled(false),
576 mCanTriggerSwipe(false),
577 mAllowToOverrideSystemScrollSpeed(false),
578 mDeltaValuesHorizontalizedForDefaultHandler(false) {}
580 public:
581 virtual WidgetWheelEvent* AsWheelEvent() override { return this; }
583 WidgetWheelEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
584 const WidgetEventTime* aTime = nullptr)
585 : WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, eWheelEventClass,
586 aTime),
587 mDeltaX(0.0),
588 mDeltaY(0.0),
589 mDeltaZ(0.0),
590 mOverflowDeltaX(0.0),
591 mOverflowDeltaY(0.0)
592 // Including WheelEventBinding.h here leads to an include loop, so
593 // we have to hardcode WheelEvent_Binding::DOM_DELTA_PIXEL.
595 mDeltaMode(/* WheelEvent_Binding::DOM_DELTA_PIXEL = */ 0),
596 mLineOrPageDeltaX(0),
597 mLineOrPageDeltaY(0),
598 mScrollType(SCROLL_DEFAULT),
599 mCustomizedByUserPrefs(false),
600 mMayHaveMomentum(false),
601 mIsMomentum(false),
602 mIsNoLineOrPageDelta(false),
603 mViewPortIsOverscrolled(false),
604 mCanTriggerSwipe(false),
605 mAllowToOverrideSystemScrollSpeed(true),
606 mDeltaValuesHorizontalizedForDefaultHandler(false) {}
608 virtual WidgetEvent* Duplicate() const override {
609 MOZ_ASSERT(mClass == eWheelEventClass,
610 "Duplicate() must be overridden by sub class");
611 // Not copying widget, it is a weak reference.
612 WidgetWheelEvent* result =
613 new WidgetWheelEvent(false, mMessage, nullptr, this);
614 result->AssignWheelEventData(*this, true);
615 result->mFlags = mFlags;
616 return result;
619 // Scroll gestures that start at the edge of the scrollable range can result
620 // in a swipe gesture. For the first wheel event of such a gesture, call
621 // TriggersSwipe() after the event has been processed in order to find out
622 // whether a swipe should be started.
623 bool TriggersSwipe() const {
624 return mCanTriggerSwipe && mViewPortIsOverscrolled &&
625 this->mOverflowDeltaX != 0.0;
628 // NOTE: mDeltaX, mDeltaY and mDeltaZ may be customized by
629 // mousewheel.*.delta_multiplier_* prefs which are applied by
630 // EventStateManager. So, after widget dispatches this event,
631 // these delta values may have different values than before.
632 double mDeltaX;
633 double mDeltaY;
634 double mDeltaZ;
636 // The mousewheel tick counts.
637 double mWheelTicksX = 0.0;
638 double mWheelTicksY = 0.0;
640 enum class DeltaModeCheckingState : uint8_t {
641 // Neither deltaMode nor the delta values have been accessed.
642 Unknown,
643 // The delta values have been accessed, without checking deltaMode first.
644 Unchecked,
645 // The deltaMode has been checked.
646 Checked,
649 // For compat reasons, we might expose a DOM_DELTA_LINE event as
650 // DOM_DELTA_PIXEL instead. Whether we do that depends on whether the event
651 // has been asked for the deltaMode before the deltas. If it has, we assume
652 // that the page will correctly handle DOM_DELTA_LINE. This variable tracks
653 // that state. See bug 1392460.
654 DeltaModeCheckingState mDeltaModeCheckingState =
655 DeltaModeCheckingState::Unknown;
657 // The amount of scrolling per line or page, without accounting for mouse
658 // wheel transactions etc.
660 // Computed by EventStateManager::DeltaAccumulator::InitLineOrPageDelta.
661 nsSize mScrollAmount;
663 // overflowed delta values for scroll, these values are set by
664 // EventStateManger. If the default action of the wheel event isn't scroll,
665 // these values are always zero. Otherwise, remaining delta values which are
666 // not used by scroll are set.
667 // NOTE: mDeltaX, mDeltaY and mDeltaZ may be modified by EventStateManager.
668 // However, mOverflowDeltaX and mOverflowDeltaY indicate unused original
669 // delta values which are not applied the delta_multiplier prefs.
670 // So, if widget wanted to know the actual direction to be scrolled,
671 // it would need to check the mDeltaX and mDeltaY.
672 double mOverflowDeltaX;
673 double mOverflowDeltaY;
675 // Should be one of WheelEvent_Binding::DOM_DELTA_*
676 uint32_t mDeltaMode;
678 // If widget sets mLineOrPageDelta, EventStateManager will dispatch
679 // eLegacyMouseLineOrPageScroll event for compatibility. Note that the delta
680 // value means pages if the mDeltaMode is DOM_DELTA_PAGE, otherwise, lines.
681 int32_t mLineOrPageDeltaX;
682 int32_t mLineOrPageDeltaY;
684 // When the default action for an wheel event is moving history or zooming,
685 // need to chose a delta value for doing it.
686 int32_t GetPreferredIntDelta() {
687 if (!mLineOrPageDeltaX && !mLineOrPageDeltaY) {
688 return 0;
690 if (mLineOrPageDeltaY && !mLineOrPageDeltaX) {
691 return mLineOrPageDeltaY;
693 if (mLineOrPageDeltaX && !mLineOrPageDeltaY) {
694 return mLineOrPageDeltaX;
696 if ((mLineOrPageDeltaX < 0 && mLineOrPageDeltaY > 0) ||
697 (mLineOrPageDeltaX > 0 && mLineOrPageDeltaY < 0)) {
698 return 0; // We cannot guess the answer in this case.
700 return (Abs(mLineOrPageDeltaX) > Abs(mLineOrPageDeltaY))
701 ? mLineOrPageDeltaX
702 : mLineOrPageDeltaY;
705 // Scroll type
706 // The default value is SCROLL_DEFAULT, which means EventStateManager will
707 // select preferred scroll type automatically.
708 enum ScrollType : uint8_t {
709 SCROLL_DEFAULT,
710 SCROLL_SYNCHRONOUSLY,
711 SCROLL_ASYNCHRONOUSLY,
712 SCROLL_SMOOTHLY
714 ScrollType mScrollType;
716 // If the delta values are computed from prefs, this value is true.
717 // Otherwise, i.e., they are computed from native events, false.
718 bool mCustomizedByUserPrefs;
720 // true if the momentum events directly tied to this event may follow it.
721 bool mMayHaveMomentum;
722 // true if the event is caused by momentum.
723 bool mIsMomentum;
725 // If device event handlers don't know when they should set mLineOrPageDeltaX
726 // and mLineOrPageDeltaY, this is true. Otherwise, false.
727 // If mIsNoLineOrPageDelta is true, ESM will generate
728 // eLegacyMouseLineOrPageScroll events when accumulated delta values reach
729 // a line height.
730 bool mIsNoLineOrPageDelta;
732 // Whether or not the parent of the currently overscrolled frame is the
733 // ViewPort. This is false in situations when an element on the page is being
734 // overscrolled (such as a text field), but true when the 'page' is being
735 // overscrolled.
736 bool mViewPortIsOverscrolled;
738 // The wheel event can trigger a swipe to start if it's overscrolling the
739 // viewport.
740 bool mCanTriggerSwipe;
742 // If mAllowToOverrideSystemScrollSpeed is true, the scroll speed may be
743 // overridden. Otherwise, the scroll speed won't be overridden even if
744 // it's enabled by the pref.
745 bool mAllowToOverrideSystemScrollSpeed;
747 // After the event's default action handler has adjusted its delta's values
748 // for horizontalizing a vertical wheel scroll, this variable will be set to
749 // true.
750 bool mDeltaValuesHorizontalizedForDefaultHandler;
752 void AssignWheelEventData(const WidgetWheelEvent& aEvent, bool aCopyTargets) {
753 AssignMouseEventBaseData(aEvent, aCopyTargets);
755 mDeltaX = aEvent.mDeltaX;
756 mDeltaY = aEvent.mDeltaY;
757 mDeltaZ = aEvent.mDeltaZ;
758 mDeltaMode = aEvent.mDeltaMode;
759 mScrollAmount = aEvent.mScrollAmount;
760 mCustomizedByUserPrefs = aEvent.mCustomizedByUserPrefs;
761 mMayHaveMomentum = aEvent.mMayHaveMomentum;
762 mIsMomentum = aEvent.mIsMomentum;
763 mIsNoLineOrPageDelta = aEvent.mIsNoLineOrPageDelta;
764 mLineOrPageDeltaX = aEvent.mLineOrPageDeltaX;
765 mLineOrPageDeltaY = aEvent.mLineOrPageDeltaY;
766 mScrollType = aEvent.mScrollType;
767 mOverflowDeltaX = aEvent.mOverflowDeltaX;
768 mOverflowDeltaY = aEvent.mOverflowDeltaY;
769 mViewPortIsOverscrolled = aEvent.mViewPortIsOverscrolled;
770 mCanTriggerSwipe = aEvent.mCanTriggerSwipe;
771 mAllowToOverrideSystemScrollSpeed =
772 aEvent.mAllowToOverrideSystemScrollSpeed;
773 mDeltaValuesHorizontalizedForDefaultHandler =
774 aEvent.mDeltaValuesHorizontalizedForDefaultHandler;
777 // System scroll speed settings may be too slow at using Gecko. In such
778 // case, we should override the scroll speed computed with system settings.
779 // Following methods return preferred delta values which are multiplied by
780 // factors specified by prefs. If system scroll speed shouldn't be
781 // overridden (e.g., this feature is disabled by pref), they return raw
782 // delta values.
783 double OverriddenDeltaX() const;
784 double OverriddenDeltaY() const;
786 // Compute the overridden delta value. This may be useful for suppressing
787 // too fast scroll by system scroll speed overriding when widget sets
788 // mAllowToOverrideSystemScrollSpeed.
789 static double ComputeOverriddenDelta(double aDelta, bool aIsForVertical);
791 private:
792 static bool sInitialized;
793 static bool sIsSystemScrollSpeedOverrideEnabled;
794 static int32_t sOverrideFactorX;
795 static int32_t sOverrideFactorY;
796 static void Initialize();
799 /******************************************************************************
800 * mozilla::WidgetPointerEvent
801 ******************************************************************************/
803 class WidgetPointerEvent : public WidgetMouseEvent {
804 friend class mozilla::dom::PBrowserParent;
805 friend class mozilla::dom::PBrowserChild;
806 ALLOW_DEPRECATED_READPARAM
808 WidgetPointerEvent() = default;
810 public:
811 virtual WidgetPointerEvent* AsPointerEvent() override { return this; }
813 WidgetPointerEvent(bool aIsTrusted, EventMessage aMsg, nsIWidget* w,
814 const WidgetEventTime* aTime)
815 : WidgetMouseEvent(aIsTrusted, aMsg, w, ePointerEventClass, eReal,
816 eNormal, aTime) {
817 if (aMsg == eContextMenu) {
818 mButton = (mContextMenuTrigger == eNormal) ? MouseButton::eSecondary
819 : MouseButton::ePrimary;
823 WidgetPointerEvent(bool aIsTrusted, EventMessage aMsg, nsIWidget* w,
824 ContextMenuTrigger aContextMenuTrigger = eNormal,
825 const WidgetEventTime* aTime = nullptr)
826 : WidgetMouseEvent(aIsTrusted, aMsg, w, ePointerEventClass, eReal,
827 aContextMenuTrigger, aTime) {
828 if (aMsg == eContextMenu) {
829 mButton = (mContextMenuTrigger == eNormal) ? MouseButton::eSecondary
830 : MouseButton::ePrimary;
834 explicit WidgetPointerEvent(const WidgetMouseEvent& aEvent)
835 : WidgetMouseEvent(aEvent) {
836 mClass = ePointerEventClass;
839 virtual WidgetEvent* Duplicate() const override {
840 MOZ_ASSERT(mClass == ePointerEventClass,
841 "Duplicate() must be overridden by sub class");
842 // Not copying widget, it is a weak reference.
843 WidgetPointerEvent* result = new WidgetPointerEvent(
844 false, mMessage, nullptr, mContextMenuTrigger, this);
845 result->AssignPointerEventData(*this, true);
846 result->mFlags = mFlags;
847 return result;
850 double mWidth = 1.0;
851 double mHeight = 1.0;
852 bool mIsPrimary = true;
853 bool mFromTouchEvent = false;
855 // XXX Not tested by test_assign_event_data.html
856 void AssignPointerEventData(const WidgetPointerEvent& aEvent,
857 bool aCopyTargets) {
858 AssignMouseEventData(aEvent, aCopyTargets);
860 mWidth = aEvent.mWidth;
861 mHeight = aEvent.mHeight;
862 mIsPrimary = aEvent.mIsPrimary;
863 mFromTouchEvent = aEvent.mFromTouchEvent;
867 } // namespace mozilla
869 #endif // mozilla_MouseEvents_h__