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