1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_PointerEventHandler_h
8 #define mozilla_PointerEventHandler_h
10 #include "mozilla/EventForwards.h"
11 #include "mozilla/MouseEvents.h"
12 #include "mozilla/TouchEvents.h"
13 #include "mozilla/WeakPtr.h"
15 // XXX Avoid including this here by moving function bodies to the cpp file
16 #include "mozilla/dom/Document.h"
17 #include "mozilla/dom/Element.h"
33 class PointerCaptureInfo final
{
35 RefPtr
<dom::Element
> mPendingElement
;
36 RefPtr
<dom::Element
> mOverrideElement
;
38 explicit PointerCaptureInfo(dom::Element
* aPendingElement
)
39 : mPendingElement(aPendingElement
) {
40 MOZ_COUNT_CTOR(PointerCaptureInfo
);
43 MOZ_COUNTED_DTOR(PointerCaptureInfo
)
45 bool Empty() { return !(mPendingElement
|| mOverrideElement
); }
48 class PointerInfo final
{
50 uint16_t mPointerType
;
54 bool mPreventMouseEventByContent
;
55 WeakPtr
<dom::Document
> mActiveDocument
;
56 explicit PointerInfo(bool aActiveState
, uint16_t aPointerType
,
57 bool aPrimaryState
, bool aFromTouchEvent
,
58 dom::Document
* aActiveDocument
)
59 : mPointerType(aPointerType
),
60 mActiveState(aActiveState
),
61 mPrimaryState(aPrimaryState
),
62 mFromTouchEvent(aFromTouchEvent
),
63 mPreventMouseEventByContent(false),
64 mActiveDocument(aActiveDocument
) {}
67 class PointerEventHandler final
{
69 // Called in nsLayoutStatics::Initialize/Shutdown to initialize pointer event
70 // related static variables.
71 static void InitializeStatics();
72 static void ReleaseStatics();
74 // Return the preference value of implicit capture.
75 static bool IsPointerEventImplicitCaptureForTouchEnabled();
77 // Called in ESM::PreHandleEvent to update current active pointers in a hash
79 static void UpdateActivePointerState(WidgetMouseEvent
* aEvent
,
80 nsIContent
* aTargetContent
= nullptr);
82 // Request/release pointer capture of the specified pointer by the element.
83 static void RequestPointerCaptureById(uint32_t aPointerId
,
84 dom::Element
* aElement
);
85 static void ReleasePointerCaptureById(uint32_t aPointerId
);
86 static void ReleaseAllPointerCapture();
88 // Set/release pointer capture of the specified pointer by the remote target.
89 // Should only be called in parent process.
90 static bool SetPointerCaptureRemoteTarget(uint32_t aPointerId
,
91 dom::BrowserParent
* aBrowserParent
);
92 static void ReleasePointerCaptureRemoteTarget(
93 dom::BrowserParent
* aBrowserParent
);
94 static void ReleasePointerCaptureRemoteTarget(uint32_t aPointerId
);
95 static void ReleaseAllPointerCaptureRemoteTarget();
97 // Get the pointer capturing remote target of the specified pointer.
98 static dom::BrowserParent
* GetPointerCapturingRemoteTarget(
101 // Get the pointer captured info of the specified pointer.
102 static PointerCaptureInfo
* GetPointerCaptureInfo(uint32_t aPointerId
);
104 // Return the PointerInfo if the pointer with aPointerId is situated in device
105 // , nullptr otherwise.
106 static const PointerInfo
* GetPointerInfo(uint32_t aPointerId
);
108 // CheckPointerCaptureState checks cases, when got/lostpointercapture events
111 static void MaybeProcessPointerCapture(WidgetGUIEvent
* aEvent
);
113 static void ProcessPointerCaptureForMouse(WidgetMouseEvent
* aEvent
);
115 static void ProcessPointerCaptureForTouch(WidgetTouchEvent
* aEvent
);
117 static void CheckPointerCaptureState(WidgetPointerEvent
* aEvent
);
119 // Implicitly get and release capture of current pointer for touch.
120 static void ImplicitlyCapturePointer(nsIFrame
* aFrame
, WidgetEvent
* aEvent
);
122 static void ImplicitlyReleasePointerCapture(WidgetEvent
* aEvent
);
123 MOZ_CAN_RUN_SCRIPT
static void MaybeImplicitlyReleasePointerCapture(
124 WidgetGUIEvent
* aEvent
);
127 * GetPointerCapturingContent returns a target element which captures the
128 * pointer. It's applied to mouse or pointer event (except mousedown and
129 * pointerdown). When capturing, return the element. Otherwise, nullptr.
131 * @param aEvent A mouse event or pointer event which may be
134 * @return Target element for aEvent.
136 static dom::Element
* GetPointerCapturingElement(WidgetGUIEvent
* aEvent
);
138 static dom::Element
* GetPointerCapturingElement(uint32_t aPointerId
);
140 // Release pointer capture if captured by the specified content or it's
141 // descendant. This is called to handle the case that the pointer capturing
142 // content or it's parent is removed from the document.
143 static void ReleaseIfCaptureByDescendant(nsIContent
* aContent
);
146 * This function handles the case when content had called preventDefault on
147 * the active pointer. In that case we have to prevent firing subsequent mouse
148 * to content. We check the flag PointerInfo::mPreventMouseEventByContent and
149 * call PreventDefault(false) to stop default behaviors and stop firing mouse
150 * events to content and chrome.
152 * note: mouse transition events are excluded
153 * note: we have to clean mPreventMouseEventByContent on pointerup for those
154 * devices support hover
155 * note: we don't suppress firing mouse events to chrome and system group
156 * handlers because they may implement default behaviors
158 static void PreHandlePointerEventsPreventDefault(
159 WidgetPointerEvent
* aPointerEvent
, WidgetGUIEvent
* aMouseOrTouchEvent
);
162 * This function handles the preventDefault behavior of pointerdown. When user
163 * preventDefault on pointerdown, We have to mark the active pointer to
164 * prevent sebsequent mouse events (except mouse transition events) and
167 * We add mPreventMouseEventByContent flag in PointerInfo to represent the
168 * active pointer won't firing compatible mouse events. It's set to true when
169 * content preventDefault on pointerdown
171 static void PostHandlePointerEventsPreventDefault(
172 WidgetPointerEvent
* aPointerEvent
, WidgetGUIEvent
* aMouseOrTouchEvent
);
175 * Dispatch a pointer event for aMouseOrTouchEvent to aEventTargetContent.
177 * @param aShell The PresShell which is handling the event.
178 * @param aEventTargetFrame The frame for aEventTargetContent.
179 * @param aEventTargetContent The event target node.
180 * @param aMouseOrTouchEvent A mouse or touch event.
181 * @param aDontRetargetEvents If true, this won't dispatch event with
182 * different PresShell from aShell. Otherwise,
183 * pointer events may be fired on different
184 * document if and only if aMouseOrTOuchEvent is a
185 * touch event except eTouchStart.
186 * @param aState [out] The result of the pointer event.
187 * @param aMouseOrTouchEventTarget
188 * [out] The event target for the following mouse
189 * or touch event. If aEventTargetContent has not
190 * been removed from the tree, this is always set
191 * to it. If aEventTargetContent is removed from
192 * the tree and aMouseOrTouchEvent is a mouse
193 * event, this is set to inclusive ancestor of
194 * aEventTargetContent which is still connected.
195 * If aEventTargetContent is removed from the tree
196 * and aMouseOrTouchEvent is a touch event, this is
197 * set to aEventTargetContent because touch event
198 * should be dispatched even on disconnected node.
199 * FIXME: If the event is a touch event but the
200 * message is not eTouchStart, this won't be set.
202 MOZ_CAN_RUN_SCRIPT
static void DispatchPointerFromMouseOrTouch(
203 PresShell
* aShell
, nsIFrame
* aEventTargetFrame
,
204 nsIContent
* aEventTargetContent
, WidgetGUIEvent
* aMouseOrTouchEvent
,
205 bool aDontRetargetEvents
, nsEventStatus
* aStatus
,
206 nsIContent
** aMouseOrTouchEventTarget
= nullptr);
209 * Synthesize eMouseMove or ePointerMove to dispatch mouse/pointer boundary
210 * events if they are required. This dispatches the event on the widget.
211 * Therefore, this dispatches the event on correct document in the same
212 * process. However, if there is a popup under the pointer or a document in a
213 * different process, this does not work as you expected.
215 MOZ_CAN_RUN_SCRIPT
static void SynthesizeMoveToDispatchBoundaryEvents(
216 const WidgetMouseEvent
* aEvent
);
218 static void InitPointerEventFromMouse(WidgetPointerEvent
* aPointerEvent
,
219 WidgetMouseEvent
* aMouseEvent
,
220 EventMessage aMessage
);
222 static void InitPointerEventFromTouch(WidgetPointerEvent
& aPointerEvent
,
223 const WidgetTouchEvent
& aTouchEvent
,
224 const mozilla::dom::Touch
& aTouch
);
226 static void InitCoalescedEventFromPointerEvent(
227 WidgetPointerEvent
& aCoalescedEvent
,
228 const WidgetPointerEvent
& aSourceEvent
);
230 static bool ShouldGeneratePointerEventFromMouse(WidgetGUIEvent
* aEvent
) {
231 return aEvent
->mMessage
== eMouseDown
|| aEvent
->mMessage
== eMouseUp
||
232 (aEvent
->mMessage
== eMouseMove
&&
233 aEvent
->AsMouseEvent()->IsReal()) ||
234 aEvent
->mMessage
== eMouseExitFromWidget
;
237 static bool ShouldGeneratePointerEventFromTouch(WidgetGUIEvent
* aEvent
) {
238 return aEvent
->mMessage
== eTouchStart
|| aEvent
->mMessage
== eTouchMove
||
239 aEvent
->mMessage
== eTouchEnd
|| aEvent
->mMessage
== eTouchCancel
||
240 aEvent
->mMessage
== eTouchPointerCancel
;
243 static MOZ_ALWAYS_INLINE
int32_t GetSpoofedPointerIdForRFP() {
244 return sSpoofedPointerId
.valueOr(0);
247 static void NotifyDestroyPresContext(nsPresContext
* aPresContext
);
249 static bool IsDragAndDropEnabled(WidgetMouseEvent
& aEvent
);
252 // Get proper pointer event message for a mouse or touch event.
253 static EventMessage
ToPointerEventMessage(
254 const WidgetGUIEvent
* aMouseOrTouchEvent
);
256 // Set pointer capture of the specified pointer by the element.
257 static void SetPointerCaptureById(uint32_t aPointerId
,
258 dom::Element
* aElement
);
260 // GetPointerType returns pointer type like mouse, pen or touch for pointer
261 // event with pointerId. The return value must be one of
262 // MouseEvent_Binding::MOZ_SOURCE_*
263 static uint16_t GetPointerType(uint32_t aPointerId
);
265 // GetPointerPrimaryState returns state of attribute isPrimary for pointer
266 // event with pointerId
267 static bool GetPointerPrimaryState(uint32_t aPointerId
);
269 // HasActiveTouchPointer returns true if there is active pointer event that is
270 // generated from touch event.
271 static bool HasActiveTouchPointer();
274 static void DispatchGotOrLostPointerCaptureEvent(
275 bool aIsGotCapture
, const WidgetPointerEvent
* aPointerEvent
,
276 dom::Element
* aCaptureTarget
);
278 // The cached spoofed pointer ID for fingerprinting resistance. We will use a
279 // mouse pointer id for desktop. For mobile, we should use the touch pointer
280 // id as the spoofed one, and this work will be addressed in Bug 1492775.
281 static Maybe
<int32_t> sSpoofedPointerId
;
283 // A helper function to cache the pointer id of the spoofed interface, we
284 // would only cache the pointer id once. After that, we would always stick to
285 // that pointer id for fingerprinting resistance.
286 static void MaybeCacheSpoofedPointerID(uint16_t aInputSource
,
287 uint32_t aPointerId
);
290 } // namespace mozilla
292 #endif // mozilla_PointerEventHandler_h