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