/* -*- 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_dom_Event_h_ #define mozilla_dom_Event_h_ #include #include "Units.h" #include "js/TypeDecls.h" #include "mozilla/AlreadyAddRefed.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/BasicEvents.h" #include "mozilla/RefPtr.h" #include "mozilla/Maybe.h" #include "mozilla/dom/BindingDeclarations.h" #include "nsCOMPtr.h" #include "nsCycleCollectionParticipant.h" #include "nsID.h" #include "nsISupports.h" #include "nsStringFwd.h" #include "nsWrapperCache.h" class PickleIterator; class nsCycleCollectionTraversalCallback; class nsIContent; class nsIGlobalObject; class nsIPrincipal; class nsPIDOMWindowInner; class nsPresContext; namespace IPC { class Message; class MessageReader; class MessageWriter; } // namespace IPC namespace mozilla::dom { class BeforeUnloadEvent; class CustomEvent; class Document; class DragEvent; class EventTarget; class EventMessageAutoOverride; // ExtendableEvent is a ServiceWorker event that is not // autogenerated since it has some extra methods. class ExtendableEvent; class KeyboardEvent; class MouseEvent; class MessageEvent; class TimeEvent; class UIEvent; class WantsPopupControlCheck; class XULCommandEvent; struct EventInit; #define GENERATED_EVENT(EventClass_) class EventClass_; #include "mozilla/dom/GeneratedEventList.h" #undef GENERATED_EVENT // IID for Event #define NS_EVENT_IID \ { \ 0x71139716, 0x4d91, 0x4dee, { \ 0xba, 0xf9, 0xe3, 0x3b, 0x80, 0xc1, 0x61, 0x61 \ } \ } class Event : public nsISupports, public nsWrapperCache { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_EVENT_IID) Event(EventTarget* aOwner, nsPresContext* aPresContext, WidgetEvent* aEvent); explicit Event(nsPIDOMWindowInner* aWindow); protected: virtual ~Event(); private: void ConstructorInit(EventTarget* aOwner, nsPresContext* aPresContext, WidgetEvent* aEvent); public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(Event) nsIGlobalObject* GetParentObject() { return mOwner; } JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) final; virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle aGivenProto); #define GENERATED_EVENT(EventClass_) \ virtual EventClass_* As##EventClass_() { return nullptr; } #include "mozilla/dom/GeneratedEventList.h" #undef GENERATED_EVENT // ExtendableEvent is a ServiceWorker event that is not // autogenerated since it has some extra methods. virtual ExtendableEvent* AsExtendableEvent() { return nullptr; } virtual TimeEvent* AsTimeEvent() { return nullptr; } // BeforeUnloadEvent is not autogenerated because it has a setter. virtual BeforeUnloadEvent* AsBeforeUnloadEvent() { return nullptr; } // KeyboardEvent has all sorts of non-autogeneratable bits so far. virtual KeyboardEvent* AsKeyboardEvent() { return nullptr; } // DragEvent has a non-autogeneratable initDragEvent. virtual DragEvent* AsDragEvent() { return nullptr; } // XULCommandEvent has a non-autogeneratable initCommandEvent. virtual XULCommandEvent* AsXULCommandEvent() { return nullptr; } // MouseEvent has a non-autogeneratable initMouseEvent and other // non-autogeneratable methods. virtual MouseEvent* AsMouseEvent() { return nullptr; } // UIEvent has a non-autogeneratable initUIEvent. virtual UIEvent* AsUIEvent() { return nullptr; } // CustomEvent has a non-autogeneratable initCustomEvent. virtual CustomEvent* AsCustomEvent() { return nullptr; } // MessageEvent has a non-autogeneratable initMessageEvent and more. virtual MessageEvent* AsMessageEvent() { return nullptr; } void InitEvent(const nsAString& aEventTypeArg, bool aCanBubble, bool aCancelable) { InitEvent(aEventTypeArg, aCanBubble ? CanBubble::eYes : CanBubble::eNo, aCancelable ? Cancelable::eYes : Cancelable::eNo); } void InitEvent(const nsAString& aEventTypeArg, mozilla::CanBubble, mozilla::Cancelable, mozilla::Composed = mozilla::Composed::eDefault); void SetTarget(EventTarget* aTarget); virtual void DuplicatePrivateData(); bool IsDispatchStopped(); WidgetEvent* WidgetEventPtr(); const WidgetEvent* WidgetEventPtr() const { return const_cast(this)->WidgetEventPtr(); } virtual void Serialize(IPC::MessageWriter* aWriter, bool aSerializeInterfaceType); virtual bool Deserialize(IPC::MessageReader* aReader); void SetOwner(EventTarget* aOwner); void StopCrossProcessForwarding(); void SetTrusted(bool aTrusted); // When listening to chrome EventTargets, in the parent process, nsWindowRoot // might receive events we've already handled via // InProcessBrowserChildMessageManager, and handlers should call this to avoid // handling the same event twice. bool ShouldIgnoreChromeEventTargetListener() const; void InitPresContextData(nsPresContext* aPresContext); // Returns true if the event should be trusted. bool Init(EventTarget* aGlobal); static const char16_t* GetEventName(EventMessage aEventType); static CSSIntPoint GetClientCoords(nsPresContext* aPresContext, WidgetEvent* aEvent, LayoutDeviceIntPoint aPoint, CSSIntPoint aDefaultPoint); static CSSIntPoint GetPageCoords(nsPresContext* aPresContext, WidgetEvent* aEvent, LayoutDeviceIntPoint aPoint, CSSIntPoint aDefaultPoint); static Maybe GetScreenCoords(nsPresContext* aPresContext, WidgetEvent* aEvent, LayoutDeviceIntPoint aPoint); MOZ_CAN_RUN_SCRIPT_BOUNDARY static CSSIntPoint GetOffsetCoords(nsPresContext* aPresContext, WidgetEvent* aEvent, LayoutDeviceIntPoint aPoint, CSSIntPoint aDefaultPoint); static already_AddRefed Constructor(EventTarget* aEventTarget, const nsAString& aType, const EventInit& aParam); static already_AddRefed Constructor(const GlobalObject& aGlobal, const nsAString& aType, const EventInit& aParam); void GetType(nsAString& aType) const; EventTarget* GetTarget() const; EventTarget* GetCurrentTarget() const; // This method returns the document which is associated with the event target. already_AddRefed GetDocument() const; void ComposedPath(nsTArray>& aPath); uint16_t EventPhase() const; void StopPropagation(); void StopImmediatePropagation(); bool Bubbles() const { return mEvent->mFlags.mBubbles; } bool Cancelable() const { return mEvent->mFlags.mCancelable; } bool Composed() const { return mEvent->mFlags.mComposed; } bool CancelBubble() const { return mEvent->PropagationStopped(); } void SetCancelBubble(bool aCancelBubble) { if (aCancelBubble) { mEvent->StopPropagation(); } } // For C++ consumers only! void PreventDefault(); // You MUST NOT call PreventDefault(JSContext*, CallerType) from C++ code. A // call of this method always sets Event.defaultPrevented true for web // contents. If default action handler calls this, web applications see wrong // defaultPrevented value. virtual void PreventDefault(JSContext* aCx, CallerType aCallerType); // You MUST NOT call DefaultPrevented(CallerType) from C++ code. This may // return false even if PreventDefault() has been called. // See comments in its implementation for the details. bool DefaultPrevented(CallerType aCallerType) const; bool DefaultPrevented() const { return mEvent->DefaultPrevented(); } bool DefaultPreventedByChrome() const { return mEvent->mFlags.mDefaultPreventedByChrome; } bool DefaultPreventedByContent() const { return mEvent->mFlags.mDefaultPreventedByContent; } void PreventMultipleActions() { mEvent->mFlags.mMultipleActionsPrevented = true; } bool MultipleActionsPrevented() const { return mEvent->mFlags.mMultipleActionsPrevented; } bool ReturnValue(CallerType aCallerType) const; void SetReturnValue(bool aReturnValue, CallerType aCallerType); bool IsTrusted() const { return mEvent->IsTrusted(); } bool IsSynthesized() const { return mEvent->mFlags.mIsSynthesizedForTests; } bool IsSafeToBeDispatchedAsynchronously() const { // If mEvent is not created by dom::Event nor its subclasses, its lifetime // is not guaranteed. So, only when mEventIsInternal is true, it's safe // to be dispatched asynchronously. return mEventIsInternal; } double TimeStamp(); EventTarget* GetOriginalTarget() const; EventTarget* GetExplicitOriginalTarget() const; EventTarget* GetComposedTarget() const; /** * @param aCalledByDefaultHandler Should be true when this is called by * C++ or Chrome. Otherwise, e.g., called * by a call of Event.preventDefault() in * content script, false. */ void PreventDefaultInternal(bool aCalledByDefaultHandler, nsIPrincipal* aPrincipal = nullptr); bool IsMainThreadEvent() { return mIsMainThreadEvent; } void MarkUninitialized() { mEvent->mMessage = eVoidEvent; mEvent->mSpecifiedEventTypeString.Truncate(); mEvent->mSpecifiedEventType = nullptr; } /** * For WidgetEvent, return it's type in string. * * @param aEvent is a WidgetEvent to get its type. * @param aType is a string where to return the type. */ static void GetWidgetEventType(WidgetEvent* aEvent, nsAString& aType); void RequestReplyFromRemoteContent() { mEvent->MarkAsWaitingReplyFromRemoteProcess(); } bool IsWaitingReplyFromRemoteContent() const { return mEvent->IsWaitingReplyFromRemoteProcess(); } bool IsReplyEventFromRemoteContent() const { return mEvent->IsHandledInRemoteProcess(); } static bool IsDragExitEnabled(JSContext* aCx, JSObject* aGlobal); protected: // Internal helper functions void SetEventType(const nsAString& aEventTypeArg); already_AddRefed GetTargetFromFrame(); friend class EventMessageAutoOverride; friend class PopupBlocker; friend class WantsPopupControlCheck; void SetWantsPopupControlCheck(bool aCheck) { mWantsPopupControlCheck = aCheck; } bool GetWantsPopupControlCheck() { return IsTrusted() && mWantsPopupControlCheck; } void SetComposed(bool aComposed) { mEvent->SetComposed(aComposed); } already_AddRefed EnsureWebAccessibleRelatedTarget( EventTarget* aRelatedTarget); mozilla::WidgetEvent* mEvent; RefPtr mPresContext; nsCOMPtr mExplicitOriginalTarget; nsCOMPtr mOwner; bool mEventIsInternal; bool mPrivateDataDuplicated; bool mIsMainThreadEvent; // True when popup control check should rely on event.type, not // WidgetEvent.mMessage. bool mWantsPopupControlCheck; }; /** * RAII helper-class to override an event's message (i.e. its DOM-exposed * type), for as long as the object is alive. Restores the original * EventMessage when destructed. * * Notable requirements: * - The original & overriding messages must be known (not eUnidentifiedEvent). * - The original & overriding messages must be different. * - The passed-in Event must outlive this RAII helper. */ class MOZ_RAII EventMessageAutoOverride { public: explicit EventMessageAutoOverride(Event* aEvent, EventMessage aOverridingMessage) : mEvent(aEvent), mOrigMessage(mEvent->mEvent->mMessage) { MOZ_ASSERT(aOverridingMessage != mOrigMessage, "Don't use this class if you're not actually overriding"); MOZ_ASSERT(aOverridingMessage != eUnidentifiedEvent, "Only use this class with a valid overriding EventMessage"); MOZ_ASSERT(mOrigMessage != eUnidentifiedEvent && mEvent->mEvent->mSpecifiedEventTypeString.IsEmpty(), "Only use this class on events whose overridden type is " "known (so we can restore it properly)"); mEvent->mEvent->mMessage = aOverridingMessage; } ~EventMessageAutoOverride() { mEvent->mEvent->mMessage = mOrigMessage; } protected: // Non-owning ref, which should be safe since we're a stack-allocated object // with limited lifetime. Whoever creates us should keep mEvent alive. Event* const MOZ_NON_OWNING_REF mEvent; const EventMessage mOrigMessage; }; class MOZ_STACK_CLASS WantsPopupControlCheck { public: explicit WantsPopupControlCheck(Event* aEvent) : mEvent(aEvent) { mOriginalWantsPopupControlCheck = mEvent->GetWantsPopupControlCheck(); mEvent->SetWantsPopupControlCheck(mEvent->IsTrusted()); } ~WantsPopupControlCheck() { mEvent->SetWantsPopupControlCheck(mOriginalWantsPopupControlCheck); } private: Event* mEvent; bool mOriginalWantsPopupControlCheck; }; NS_DEFINE_STATIC_IID_ACCESSOR(Event, NS_EVENT_IID) } // namespace mozilla::dom already_AddRefed NS_NewDOMEvent( mozilla::dom::EventTarget* aOwner, nsPresContext* aPresContext, mozilla::WidgetEvent* aEvent); #endif // mozilla_dom_Event_h_