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