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 const WidgetTouchEvent& aTouchEvent, 181 const 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