Event.h (18947B)
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_dom_Event_h_ 8 #define mozilla_dom_Event_h_ 9 10 #include <cstdint> 11 12 #include "Units.h" 13 #include "js/TypeDecls.h" 14 #include "mozilla/AlreadyAddRefed.h" 15 #include "mozilla/Assertions.h" 16 #include "mozilla/Attributes.h" 17 #include "mozilla/BasicEvents.h" 18 #include "mozilla/Maybe.h" 19 #include "mozilla/RefPtr.h" 20 #include "mozilla/WeakPtr.h" 21 #include "mozilla/dom/BindingDeclarations.h" 22 #include "nsCOMPtr.h" 23 #include "nsCycleCollectionParticipant.h" 24 #include "nsID.h" 25 #include "nsISupports.h" 26 #include "nsStringFwd.h" 27 #include "nsWrapperCache.h" 28 29 class PickleIterator; 30 class nsCycleCollectionTraversalCallback; 31 class nsIContent; 32 class nsIGlobalObject; 33 class nsIPrincipal; 34 class nsPIDOMWindowInner; 35 class nsPresContext; 36 37 namespace IPC { 38 class Message; 39 class MessageReader; 40 class MessageWriter; 41 } // namespace IPC 42 43 namespace mozilla::dom { 44 45 class BeforeUnloadEvent; 46 class CustomEvent; 47 class Document; 48 class DragEvent; 49 class EventTarget; 50 class EventMessageAutoOverride; 51 // ExtendableEvent is a ServiceWorker event that is not 52 // autogenerated since it has some extra methods. 53 class ExtendableEvent; 54 class KeyboardEvent; 55 class MouseEvent; 56 class MessageEvent; 57 class PointerEvent; 58 class TimeEvent; 59 class ToggleEvent; 60 class UIEvent; 61 class WantsPopupControlCheck; 62 class XULCommandEvent; 63 struct EventInit; 64 65 #define GENERATED_EVENT(EventClass_) class EventClass_; 66 #include "mozilla/dom/GeneratedEventList.h" 67 #undef GENERATED_EVENT 68 69 // IID for Event 70 #define NS_EVENT_IID \ 71 {0x71139716, 0x4d91, 0x4dee, {0xba, 0xf9, 0xe3, 0x3b, 0x80, 0xc1, 0x61, 0x61}} 72 73 class Event : public nsISupports, public nsWrapperCache { 74 public: 75 NS_INLINE_DECL_STATIC_IID(NS_EVENT_IID) 76 77 Event(EventTarget* aOwner, nsPresContext* aPresContext, WidgetEvent* aEvent); 78 explicit Event(nsPIDOMWindowInner* aWindow); 79 80 protected: 81 virtual ~Event(); 82 83 void LastRelease(); 84 85 private: 86 void ConstructorInit(EventTarget* aOwner, nsPresContext* aPresContext, 87 WidgetEvent* aEvent); 88 89 void UpdateDefaultPreventedOnContentForDragEvent(); 90 91 public: 92 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 93 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_WRAPPERCACHE_CLASS(Event) 94 95 nsIGlobalObject* GetParentObject() const { return mOwner; } 96 97 JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final; 98 99 virtual JSObject* WrapObjectInternal(JSContext* aCx, 100 JS::Handle<JSObject*> aGivenProto); 101 102 #define GENERATED_EVENT(EventClass_) \ 103 virtual EventClass_* As##EventClass_() { return nullptr; } 104 #include "mozilla/dom/GeneratedEventList.h" 105 #undef GENERATED_EVENT 106 107 // ExtendableEvent is a ServiceWorker event that is not 108 // autogenerated since it has some extra methods. 109 virtual ExtendableEvent* AsExtendableEvent() { return nullptr; } 110 111 virtual TimeEvent* AsTimeEvent() { return nullptr; } 112 113 // BeforeUnloadEvent is not autogenerated because it has a setter. 114 virtual BeforeUnloadEvent* AsBeforeUnloadEvent() { return nullptr; } 115 116 // KeyboardEvent has all sorts of non-autogeneratable bits so far. 117 virtual KeyboardEvent* AsKeyboardEvent() { return nullptr; } 118 119 // DragEvent has a non-autogeneratable initDragEvent. 120 virtual DragEvent* AsDragEvent() { return nullptr; } 121 122 // XULCommandEvent has a non-autogeneratable initCommandEvent. 123 virtual XULCommandEvent* AsXULCommandEvent() { return nullptr; } 124 125 // MouseEvent has a non-autogeneratable initMouseEvent and other 126 // non-autogeneratable methods. 127 virtual MouseEvent* AsMouseEvent() { return nullptr; } 128 129 virtual PointerEvent* AsPointerEvent() { return nullptr; } 130 131 // UIEvent has a non-autogeneratable initUIEvent. 132 virtual UIEvent* AsUIEvent() { return nullptr; } 133 134 // CustomEvent has a non-autogeneratable initCustomEvent. 135 virtual CustomEvent* AsCustomEvent() { return nullptr; } 136 137 // MessageEvent has a non-autogeneratable initMessageEvent and more. 138 virtual MessageEvent* AsMessageEvent() { return nullptr; } 139 140 // ToggleEvent has a non-autogeneratable initToggleEvent. 141 virtual ToggleEvent* AsToggleEvent() { return nullptr; } 142 143 void InitEvent(const nsAString& aEventTypeArg, bool aCanBubble, 144 bool aCancelable) { 145 InitEvent(aEventTypeArg, aCanBubble ? CanBubble::eYes : CanBubble::eNo, 146 aCancelable ? Cancelable::eYes : Cancelable::eNo); 147 } 148 149 void InitEvent(const nsAString& aEventTypeArg, mozilla::CanBubble, 150 mozilla::Cancelable, 151 mozilla::Composed = mozilla::Composed::eDefault); 152 153 void SetTarget(EventTarget* aTarget); 154 virtual void DuplicatePrivateData(); 155 bool IsDispatchStopped(); 156 WidgetEvent* WidgetEventPtr(); 157 const WidgetEvent* WidgetEventPtr() const { 158 return const_cast<Event*>(this)->WidgetEventPtr(); 159 } 160 virtual void Serialize(IPC::MessageWriter* aWriter, 161 bool aSerializeInterfaceType); 162 virtual bool Deserialize(IPC::MessageReader* aReader); 163 void SetOwner(EventTarget* aOwner); 164 void StopCrossProcessForwarding(); 165 void SetTrusted(bool aTrusted); 166 167 // When listening to chrome EventTargets, in the parent process, nsWindowRoot 168 // might receive events we've already handled via 169 // InProcessBrowserChildMessageManager, and handlers should call this to avoid 170 // handling the same event twice. 171 bool ShouldIgnoreChromeEventTargetListener() const; 172 173 void InitPresContextData(nsPresContext* aPresContext); 174 175 // Returns true if the event should be trusted. 176 bool Init(EventTarget* aGlobal); 177 178 static const char16_t* GetEventName(EventMessage aEventType); 179 180 /** 181 * Return clientX and clientY values for aEvent fired at 182 * aWidgetOrScreenRelativePoint. If you do not want fractional values as 183 * the result, you should floor aWidgetRelativePoint and aDefaultClientPoint 184 * before calling this method like defined by the Pointer Events spec. 185 * https://w3c.github.io/pointerevents/#event-coordinates 186 * And finally round the result to the integer. 187 * Note that if you want fractional values and the source of 188 * aWidgetOrScreenRelativePoint and aDefaultClientPoint is an untrusted 189 * event, the result may not be representable with floats, i.e., CSSPoint. 190 * However, if it's trusted point, the result is representable with floats 191 * because we use CSSPoint to convert to/from app units. 192 * 193 * Note that if and only if aEvent->mWidget is nullptr, 194 * aWidgetOrScreenRelativePoint is treated as screen point because it's 195 * impossible to compute screen point from widget relative point without the 196 * widget. 197 */ 198 static CSSDoublePoint GetClientCoords( 199 nsPresContext* aPresContext, WidgetEvent* aEvent, 200 const LayoutDeviceDoublePoint& aWidgetOrScreenRelativePoint, 201 const CSSDoublePoint& aDefaultClientPoint); 202 203 /** 204 * Return pageX and pageY values for aEvent fired at 205 * aWidgetOrScreenRelativePoint, which are client point + scroll position 206 * of the root scrollable frame. If you do not want fractional values as the 207 * result, you should floor aWidgetOrScreenRelativePoint and 208 * aDefaultClientPoint before calling this method like defined by the Pointer 209 * Events spec. https://w3c.github.io/pointerevents/#event-coordinates And 210 * finally round the result to the integer. Note that if you want fractional 211 * values and the source of aWidgetOrScreenRelativePoint and 212 * aDefaultClientPoint is an untrusted event, the result may not be 213 * representable with floats, i.e., CSSPoint. However, if it's trusted point, 214 * the result is representable with floats because we use CSSPoint to convert 215 * to/from app units. 216 * 217 * Note that if and only if aEvent->mWidget is nullptr, 218 * aWidgetOrScreenRelativePoint is treated as screen point because it's 219 * impossible to compute screen point from widget relative point without the 220 * widget. 221 */ 222 static CSSDoublePoint GetPageCoords( 223 nsPresContext* aPresContext, WidgetEvent* aEvent, 224 const LayoutDeviceDoublePoint& aWidgetOrScreenRelativePoint, 225 const CSSDoublePoint& aDefaultClientPoint); 226 227 /** 228 * Return screenX and screenY values for aEvent fired at 229 * aWidgetOrScreenRelativePoint. If aEvent does not support exposing the 230 * ref point, this returns Nothing. If you do not want fractional values as 231 * the result, you should floor aWidgetOrScreenRelativePoint and 232 * aDefaultClientPoint before calling this method like defined by the Pointer 233 * Events spec. https://w3c.github.io/pointerevents/#event-coordinates And 234 * finally round the result to the integer. Note that if you want fractional 235 * values and the source of aWidgetOrScreenRelativePoint and 236 * aDefaultClientPoint is an untrusted event, the result may not be 237 * representable with floats, i.e., CSSPoint. However, if it's trusted point, 238 * the result is representable with floats because we use CSSPoint to convert 239 * to/from app units. 240 * 241 * Note that if and only if aEvent->mWidget is nullptr, 242 * aWidgetOrScreenRelativePoint is treated as screen point because it's 243 * impossible to compute screen point from widget relative point without the 244 * widget. 245 */ 246 static Maybe<CSSDoublePoint> GetScreenCoords( 247 nsPresContext* aPresContext, WidgetEvent* aEvent, 248 const LayoutDeviceDoublePoint& aWidgetOrScreenRelativePoint); 249 250 /** 251 * Return offsetX and offsetY values for aEvent fired at 252 * aWidgetOrScreenRelativePoint, which are offset in the target element. 253 * If you do not want fractional values as the result, you should floor 254 * aWidgetOrScreenRelativePoint and aDefaultClientPoint before calling 255 * this method like defined by the Pointer Events spec. 256 * https://w3c.github.io/pointerevents/#event-coordinates And finally round 257 * the result to the integer. Note that if you want fractional values and the 258 * source of aWidgetOrScreenRelativePoint and aDefaultClientPoint is an 259 * untrusted event, the result may not be representable with floats, i.e., 260 * CSSPoint. However, if it's trusted point, the result is representable with 261 * floats because we use CSSPoint to convert to/from app units. 262 * 263 * Note that if and only if aEvent->mWidget is nullptr, 264 * aWidgetOrScreenRelativePoint is treated as screen point because it's 265 * impossible to compute screen point from widget relative point without the 266 * widget. 267 * 268 * Be aware, this may flush the layout. 269 */ 270 MOZ_CAN_RUN_SCRIPT 271 static CSSDoublePoint GetOffsetCoords( 272 nsPresContext* aPresContext, WidgetEvent* aEvent, 273 const LayoutDeviceDoublePoint& aWidgetOrScreenRelativePoint, 274 const CSSDoublePoint& aDefaultClientPoint); 275 276 static already_AddRefed<Event> Constructor(EventTarget* aEventTarget, 277 const nsAString& aType, 278 const EventInit& aParam); 279 280 static already_AddRefed<Event> Constructor(const GlobalObject& aGlobal, 281 const nsAString& aType, 282 const EventInit& aParam); 283 284 void GetType(nsAString& aType) const; 285 286 EventTarget* GetTarget() const; 287 EventTarget* GetCurrentTarget() const; 288 289 // This method returns the document which is associated with the event target. 290 already_AddRefed<Document> GetDocument() const; 291 292 void ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath); 293 294 uint16_t EventPhase() const; 295 296 void StopPropagation(); 297 298 void StopImmediatePropagation(); 299 300 bool Bubbles() const { return mEvent->mFlags.mBubbles; } 301 302 bool Cancelable() const { return mEvent->mFlags.mCancelable; } 303 304 bool Composed() const { return mEvent->mFlags.mComposed; } 305 306 bool CancelBubble() const { return mEvent->PropagationStopped(); } 307 void SetCancelBubble(bool aCancelBubble) { 308 if (aCancelBubble) { 309 mEvent->StopPropagation(); 310 } 311 } 312 313 // For C++ consumers only! 314 void PreventDefault(); 315 316 // You MUST NOT call PreventDefault(JSContext*, CallerType) from C++ code. A 317 // call of this method always sets Event.defaultPrevented true for web 318 // contents. If default action handler calls this, web applications see wrong 319 // defaultPrevented value. 320 virtual void PreventDefault(JSContext* aCx, CallerType aCallerType); 321 322 // You MUST NOT call DefaultPrevented(CallerType) from C++ code. This may 323 // return false even if PreventDefault() has been called. 324 // See comments in its implementation for the details. 325 bool DefaultPrevented(CallerType aCallerType) const; 326 327 bool DefaultPrevented() const { return mEvent->DefaultPrevented(); } 328 329 bool DefaultPreventedByChrome() const { 330 return mEvent->mFlags.mDefaultPreventedByChrome; 331 } 332 333 bool DefaultPreventedByContent() const { 334 return mEvent->mFlags.mDefaultPreventedByContent; 335 } 336 337 void PreventMultipleActions() { 338 mEvent->mFlags.mMultipleActionsPrevented = true; 339 } 340 341 bool MultipleActionsPrevented() const { 342 return mEvent->mFlags.mMultipleActionsPrevented; 343 } 344 345 bool ReturnValue(CallerType aCallerType) const; 346 347 void SetReturnValue(bool aReturnValue, CallerType aCallerType); 348 349 bool IsTrusted() const { return mEvent->IsTrusted(); } 350 351 bool IsSynthesized() const { return mEvent->mFlags.mIsSynthesizedForTests; } 352 353 bool IsSafeToBeDispatchedAsynchronously() const { 354 // If mEvent is not created by dom::Event nor its subclasses, its lifetime 355 // is not guaranteed. So, only when mEventIsInternal is true, it's safe 356 // to be dispatched asynchronously. 357 return mEventIsInternal; 358 } 359 360 double TimeStamp(); 361 362 EventTarget* GetOriginalTarget() const; 363 EventTarget* GetOriginalTarget(CallerType aCallerType) const; 364 EventTarget* GetExplicitOriginalTarget() const; 365 EventTarget* GetComposedTarget() const; 366 367 /** 368 * @param aCalledByDefaultHandler Should be true when this is called by 369 * C++ or Chrome. Otherwise, e.g., called 370 * by a call of Event.preventDefault() in 371 * content script, false. 372 */ 373 void PreventDefaultInternal(bool aCalledByDefaultHandler, 374 nsIPrincipal* aPrincipal = nullptr); 375 376 bool IsMainThreadEvent() { return mIsMainThreadEvent; } 377 378 void MarkUninitialized() { 379 mEvent->mMessage = eVoidEvent; 380 mEvent->mSpecifiedEventTypeString.Truncate(); 381 mEvent->mSpecifiedEventType = nullptr; 382 } 383 384 /** 385 * For WidgetEvent, return it's type in string. 386 * 387 * @param aEvent is a WidgetEvent to get its type. 388 * @param aType is a string where to return the type. 389 */ 390 static void GetWidgetEventType(WidgetEvent* aEvent, nsAString& aType); 391 392 void RequestReplyFromRemoteContent() { 393 mEvent->MarkAsWaitingReplyFromRemoteProcess(); 394 } 395 396 bool IsWaitingReplyFromRemoteContent() const { 397 return mEvent->IsWaitingReplyFromRemoteProcess(); 398 } 399 400 bool IsReplyEventFromRemoteContent() const { 401 return mEvent->IsHandledInRemoteProcess(); 402 } 403 404 static bool IsDragExitEnabled(JSContext* aCx, JSObject* aGlobal); 405 406 protected: 407 // Internal helper functions 408 void SetEventType(const nsAString& aEventTypeArg); 409 nsIContent* GetTargetFromFrame(); 410 411 friend class EventMessageAutoOverride; 412 friend class PopupBlocker; 413 friend class WantsPopupControlCheck; 414 void SetWantsPopupControlCheck(bool aCheck) { 415 mWantsPopupControlCheck = aCheck; 416 } 417 418 bool GetWantsPopupControlCheck() { 419 return IsTrusted() && mWantsPopupControlCheck; 420 } 421 422 void SetComposed(bool aComposed) { mEvent->SetComposed(aComposed); } 423 424 already_AddRefed<EventTarget> EnsureWebAccessibleRelatedTarget( 425 EventTarget* aRelatedTarget); 426 427 [[nodiscard]] MOZ_CAN_RUN_SCRIPT static nsIFrame* 428 GetPrimaryFrameOfEventTarget(const nsPresContext& aPresContext, 429 const WidgetEvent& aEvent); 430 431 mozilla::WidgetEvent* mEvent; 432 // When the private data of this event is duplicated, mPresContext is 433 // cleared by Event::DuplicatePrivateData(). However, only 434 // MouseEvent::DuplicatePrivateData() restores mPresContext after calling 435 // Event::DuplicatePrivateData() to compute the offset point later. 436 // Therefore, only `MouseEvent` and its subclasses may keep storing 437 // mPresContext until destroyed. 438 WeakPtr<nsPresContext> mPresContext; 439 nsCOMPtr<EventTarget> mExplicitOriginalTarget; 440 nsCOMPtr<nsIGlobalObject> mOwner; 441 bool mEventIsInternal; 442 bool mPrivateDataDuplicated; 443 bool mIsMainThreadEvent; 444 // True when popup control check should rely on event.type, not 445 // WidgetEvent.mMessage. 446 bool mWantsPopupControlCheck; 447 }; 448 449 /** 450 * RAII helper-class to override an event's message (i.e. its DOM-exposed 451 * type), for as long as the object is alive. Restores the original 452 * EventMessage when destructed. 453 * 454 * Notable requirements: 455 * - The original & overriding messages must be known (not eUnidentifiedEvent). 456 * - The original & overriding messages must be different. 457 * - The passed-in Event must outlive this RAII helper. 458 */ 459 class MOZ_RAII EventMessageAutoOverride { 460 public: 461 explicit EventMessageAutoOverride(Event* aEvent, 462 EventMessage aOverridingMessage) 463 : mEvent(aEvent), mOrigMessage(mEvent->mEvent->mMessage) { 464 MOZ_ASSERT(aOverridingMessage != mOrigMessage, 465 "Don't use this class if you're not actually overriding"); 466 MOZ_ASSERT(aOverridingMessage != eUnidentifiedEvent, 467 "Only use this class with a valid overriding EventMessage"); 468 MOZ_ASSERT(mOrigMessage != eUnidentifiedEvent && 469 mEvent->mEvent->mSpecifiedEventTypeString.IsEmpty(), 470 "Only use this class on events whose overridden type is " 471 "known (so we can restore it properly)"); 472 473 mEvent->mEvent->mMessage = aOverridingMessage; 474 } 475 476 ~EventMessageAutoOverride() { mEvent->mEvent->mMessage = mOrigMessage; } 477 478 protected: 479 // Non-owning ref, which should be safe since we're a stack-allocated object 480 // with limited lifetime. Whoever creates us should keep mEvent alive. 481 Event* const MOZ_NON_OWNING_REF mEvent; 482 const EventMessage mOrigMessage; 483 }; 484 485 class MOZ_STACK_CLASS WantsPopupControlCheck { 486 public: 487 explicit WantsPopupControlCheck(Event* aEvent) : mEvent(aEvent) { 488 mOriginalWantsPopupControlCheck = mEvent->GetWantsPopupControlCheck(); 489 mEvent->SetWantsPopupControlCheck(mEvent->IsTrusted()); 490 } 491 492 ~WantsPopupControlCheck() { 493 mEvent->SetWantsPopupControlCheck(mOriginalWantsPopupControlCheck); 494 } 495 496 private: 497 Event* mEvent; 498 bool mOriginalWantsPopupControlCheck; 499 }; 500 501 } // namespace mozilla::dom 502 503 already_AddRefed<mozilla::dom::Event> NS_NewDOMEvent( 504 mozilla::dom::EventTarget* aOwner, nsPresContext* aPresContext, 505 mozilla::WidgetEvent* aEvent); 506 507 #endif // mozilla_dom_Event_h_