diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /widget/BasicEvents.h | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'widget/BasicEvents.h')
-rw-r--r-- | widget/BasicEvents.h | 1335 |
1 files changed, 1335 insertions, 0 deletions
diff --git a/widget/BasicEvents.h b/widget/BasicEvents.h new file mode 100644 index 0000000000..b3707f1cf4 --- /dev/null +++ b/widget/BasicEvents.h @@ -0,0 +1,1335 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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_BasicEvents_h__ +#define mozilla_BasicEvents_h__ + +#include <stdint.h> +#include <type_traits> + +#include "mozilla/EventForwards.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/dom/EventTarget.h" +#include "mozilla/layers/LayersTypes.h" +#include "nsCOMPtr.h" +#include "nsAtom.h" +#include "nsISupportsImpl.h" +#include "nsIWidget.h" +#include "nsString.h" +#include "Units.h" + +#ifdef DEBUG +# include "nsXULAppAPI.h" +#endif // #ifdef DEBUG + +class nsIPrincipal; + +namespace IPC { +template <typename T> +struct ParamTraits; +} // namespace IPC + +namespace mozilla { + +class EventTargetChainItem; + +enum class CrossProcessForwarding { + // eStop prevents the event to be sent to remote process. + eStop, + // eAllow keeps current state of the event whether it's sent to remote + // process. In other words, eAllow does NOT mean that making the event + // sent to remote process when IsCrossProcessForwardingStopped() returns + // true. + eAllow, +}; + +/****************************************************************************** + * mozilla::BaseEventFlags + * + * BaseEventFlags must be a POD struct for safe to use memcpy (including + * in ParamTraits<BaseEventFlags>). So don't make virtual methods, constructor, + * destructor and operators. + * This is necessary for VC which is NOT C++0x compiler. + ******************************************************************************/ + +struct BaseEventFlags { + public: + // If mIsTrusted is true, the event is a trusted event. Otherwise, it's + // an untrusted event. + bool mIsTrusted : 1; + // If mInBubblingPhase is true, the event is in bubbling phase or target + // phase. + bool mInBubblingPhase : 1; + // If mInCapturePhase is true, the event is in capture phase or target phase. + bool mInCapturePhase : 1; + // If mInTargetPhase is true, the event is in target phase. + bool mInTargetPhase : 1; + // If mInSystemGroup is true, the event is being dispatched in system group. + bool mInSystemGroup : 1; + // If mCancelable is true, the event can be consumed. I.e., calling + // dom::Event::PreventDefault() can prevent the default action. + bool mCancelable : 1; + // If mBubbles is true, the event can bubble. Otherwise, cannot be handled + // in bubbling phase. + bool mBubbles : 1; + // If mPropagationStopped is true, dom::Event::StopPropagation() or + // dom::Event::StopImmediatePropagation() has been called. + bool mPropagationStopped : 1; + // If mImmediatePropagationStopped is true, + // dom::Event::StopImmediatePropagation() has been called. + // Note that mPropagationStopped must be true when this is true. + bool mImmediatePropagationStopped : 1; + // If mDefaultPrevented is true, the event has been consumed. + // E.g., dom::Event::PreventDefault() has been called or + // the default action has been performed. + bool mDefaultPrevented : 1; + // If mDefaultPreventedByContent is true, the event has been + // consumed by content. + // Note that mDefaultPrevented must be true when this is true. + bool mDefaultPreventedByContent : 1; + // If mDefaultPreventedByChrome is true, the event has been + // consumed by chrome. + // Note that mDefaultPrevented must be true when this is true. + bool mDefaultPreventedByChrome : 1; + // mMultipleActionsPrevented may be used when default handling don't want to + // be prevented, but only one of the event targets should handle the event. + // For example, when a <label> element is in another <label> element and + // the first <label> element is clicked, that one may set this true. + // Then, the second <label> element won't handle the event. + bool mMultipleActionsPrevented : 1; + // If mIsBeingDispatched is true, the DOM event created from the event is + // dispatching into the DOM tree and not completed. + bool mIsBeingDispatched : 1; + // If mDispatchedAtLeastOnce is true, the event has been dispatched + // as a DOM event and the dispatch has been completed in the process. + // So, this is false even if the event has already been dispatched + // in another process. + bool mDispatchedAtLeastOnce : 1; + // If mIsSynthesizedForTests is true, the event has been synthesized for + // automated tests or something hacky approach of an add-on. + bool mIsSynthesizedForTests : 1; + // If mExceptionWasRaised is true, one of the event handlers has raised an + // exception. + bool mExceptionWasRaised : 1; + // If mRetargetToNonNativeAnonymous is true and the target is in a non-native + // native anonymous subtree, the event target is set to mOriginalTarget. + bool mRetargetToNonNativeAnonymous : 1; + // If mNoContentDispatch is true, the event is never dispatched to the + // event handlers which are added to the contents, onfoo attributes and + // properties. Note that this flag is ignored when + // EventChainPreVisitor::mForceContentDispatch is set true. For exapmle, + // window and document object sets it true. Therefore, web applications + // can handle the event if they add event listeners to the window or the + // document. + // XXX This is an ancient and broken feature, don't use this for new bug + // as far as possible. + bool mNoContentDispatch : 1; + // If mOnlyChromeDispatch is true, the event is dispatched to only chrome. + bool mOnlyChromeDispatch : 1; + // Indicates if the key combination is reserved by chrome. This is set by + // MarkAsReservedByChrome(). + bool mIsReservedByChrome : 1; + // If mOnlySystemGroupDispatchInContent is true, event listeners added to + // the default group for non-chrome EventTarget won't be called. + // Be aware, if this is true, EventDispatcher needs to check if each event + // listener is added to chrome node, so, don't set this to true for the + // events which are fired a lot of times like eMouseMove. + bool mOnlySystemGroupDispatchInContent : 1; + // If mOnlySystemGroupDispatch is true, the event will be dispatched only to + // event listeners added in the system group. + bool mOnlySystemGroupDispatch : 1; + // The event's action will be handled by APZ. The main thread should not + // perform its associated action. + bool mHandledByAPZ : 1; + // True if the event is currently being handled by an event listener that + // was registered as a passive listener. + bool mInPassiveListener : 1; + // If mComposed is true, the event fired by nodes in shadow DOM can cross the + // boundary of shadow DOM and light DOM. + bool mComposed : 1; + // Similar to mComposed. Set it to true to allow events cross the boundary + // between native non-anonymous content and native anonymouse content + bool mComposedInNativeAnonymousContent : 1; + // Set to true for events which are suppressed or delayed so that later a + // DelayedEvent of it is dispatched. This is used when parent side process + // the key event after content side, and may drop the event if the event + // was suppressed or delayed in contents side. + // It is also set to true for the events (in a DelayedInputEvent), which will + // be dispatched afterwards. + bool mIsSuppressedOrDelayed : 1; + // Certain mouse events can be marked as positionless to return 0 from + // coordinate related getters. + bool mIsPositionless : 1; + + // Flags managing state of propagation between processes. + // Note the the following flags shouldn't be referred directly. Use utility + // methods instead. + + // If mNoRemoteProcessDispatch is true, the event is not allowed to be sent + // to remote process. + bool mNoRemoteProcessDispatch : 1; + // If mWantReplyFromContentProcess is true, the event will be redispatched + // in the parent process after the content process has handled it. Useful + // for when the parent process need the know first how the event was used + // by content before handling it itself. + bool mWantReplyFromContentProcess : 1; + // If mPostedToRemoteProcess is true, the event has been posted to the + // remote process (but it's not handled yet if it's not a duplicated event + // instance). + bool mPostedToRemoteProcess : 1; + // If mCameFromAnotherProcess is true, the event came from another process. + bool mCameFromAnotherProcess : 1; + + /** + * Helper methods for methods of DOM Event. + */ + inline void StopPropagation() { mPropagationStopped = true; } + inline void StopImmediatePropagation() { + StopPropagation(); + mImmediatePropagationStopped = true; + } + inline void PreventDefault(bool aCalledByDefaultHandler = true) { + if (!mCancelable) { + return; + } + mDefaultPrevented = true; + // Note that even if preventDefault() has already been called by chrome, + // a call of preventDefault() by content needs to overwrite + // mDefaultPreventedByContent to true because in such case, defaultPrevented + // must be true when web apps check it after they call preventDefault(). + if (aCalledByDefaultHandler) { + StopCrossProcessForwarding(); + mDefaultPreventedByChrome = true; + } else { + mDefaultPreventedByContent = true; + } + } + // This should be used only before dispatching events into the DOM tree. + inline void PreventDefaultBeforeDispatch( + CrossProcessForwarding aCrossProcessForwarding) { + if (!mCancelable) { + return; + } + mDefaultPrevented = true; + if (aCrossProcessForwarding == CrossProcessForwarding::eStop) { + StopCrossProcessForwarding(); + } + } + inline bool DefaultPrevented() const { return mDefaultPrevented; } + inline bool DefaultPreventedByContent() const { + MOZ_ASSERT(!mDefaultPreventedByContent || DefaultPrevented()); + return mDefaultPreventedByContent; + } + inline bool IsTrusted() const { return mIsTrusted; } + inline bool PropagationStopped() const { return mPropagationStopped; } + + // Helper methods to access flags managing state of propagation between + // processes. + + /** + * Prevent to be dispatched to remote process. + */ + inline void StopCrossProcessForwarding() { + MOZ_ASSERT(!mPostedToRemoteProcess); + mNoRemoteProcessDispatch = true; + mWantReplyFromContentProcess = false; + } + /** + * Return true if the event shouldn't be dispatched to remote process. + */ + inline bool IsCrossProcessForwardingStopped() const { + return mNoRemoteProcessDispatch; + } + /** + * Mark the event as waiting reply from remote process. + * If the caller needs to win other keyboard event handlers in chrome, + * the caller should call StopPropagation() too. + * Otherwise, if the caller just needs to know if the event is consumed by + * either content or chrome, it should just call this because the event + * may be reserved by chrome and it needs to be dispatched into the DOM + * tree in chrome for checking if it's reserved before being sent to any + * remote processes. + */ + inline void MarkAsWaitingReplyFromRemoteProcess() { + MOZ_ASSERT(!mPostedToRemoteProcess); + mNoRemoteProcessDispatch = false; + mWantReplyFromContentProcess = true; + } + /** + * Reset "waiting reply from remote process" state. This is useful when + * you dispatch a copy of an event coming from different process. + */ + inline void ResetWaitingReplyFromRemoteProcessState() { + if (IsWaitingReplyFromRemoteProcess()) { + // FYI: mWantReplyFromContentProcess is also used for indicating + // "handled in remote process" state. Therefore, only when + // IsWaitingReplyFromRemoteProcess() returns true, this should + // reset the flag. + mWantReplyFromContentProcess = false; + } + } + /** + * Return true if the event handler should wait reply event. I.e., if this + * returns true, any event handler should do nothing with the event. + */ + inline bool IsWaitingReplyFromRemoteProcess() const { + return !mNoRemoteProcessDispatch && mWantReplyFromContentProcess; + } + /** + * Mark the event as already handled in the remote process. This should be + * called when initializing reply events. + */ + inline void MarkAsHandledInRemoteProcess() { + mNoRemoteProcessDispatch = true; + mWantReplyFromContentProcess = true; + mPostedToRemoteProcess = false; + } + /** + * Return true if the event has already been handled in the remote process. + */ + inline bool IsHandledInRemoteProcess() const { + return mNoRemoteProcessDispatch && mWantReplyFromContentProcess; + } + /** + * Return true if the event should be sent back to its parent process. + */ + inline bool WantReplyFromContentProcess() const { + MOZ_ASSERT(!XRE_IsParentProcess()); + return IsWaitingReplyFromRemoteProcess(); + } + /** + * Mark the event has already posted to a remote process. + */ + inline void MarkAsPostedToRemoteProcess() { + MOZ_ASSERT(!IsCrossProcessForwardingStopped()); + mPostedToRemoteProcess = true; + } + /** + * Reset the cross process dispatching state. This should be used when a + * process receives the event because the state is in the sender. + */ + inline void ResetCrossProcessDispatchingState() { + MOZ_ASSERT(!IsCrossProcessForwardingStopped()); + mPostedToRemoteProcess = false; + // Ignore propagation state in the remote process if it's marked as + // "waiting reply from remote process" because the process needs to + // stop propagation in the process until receiving a reply event. + // Note that the propagation stopped flag is important for the reply event + // handler in the main process because it's used for making whether it's + // ignored by the remote process or not. + if (!XRE_IsParentProcess() && IsWaitingReplyFromRemoteProcess()) { + mPropagationStopped = mImmediatePropagationStopped = false; + } + // mDispatchedAtLeastOnce indicates the state in current process. + mDispatchedAtLeastOnce = false; + } + /** + * Return true if the event has been posted to a remote process. + * Note that MarkAsPostedToRemoteProcess() is called by + * ParamTraits<mozilla::WidgetEvent>. Therefore, it *might* be possible + * that posting the event failed even if this returns true. But that must + * really rare. If that'd be problem for you, you should unmark this in + * BrowserParent or somewhere. + */ + inline bool HasBeenPostedToRemoteProcess() const { + return mPostedToRemoteProcess; + } + /** + * Return true if the event came from another process. + */ + inline bool CameFromAnotherProcess() const { return mCameFromAnotherProcess; } + /** + * Mark the event as coming from another process. + */ + inline void MarkAsComingFromAnotherProcess() { + mCameFromAnotherProcess = true; + } + /** + * Mark the event is reserved by chrome. I.e., shouldn't be dispatched to + * content because it shouldn't be cancelable. + */ + inline void MarkAsReservedByChrome() { + MOZ_ASSERT(!mPostedToRemoteProcess); + mIsReservedByChrome = true; + // For reserved commands (such as Open New Tab), we don't need to wait for + // the content to answer, neither to give a chance for content to override + // its behavior. + StopCrossProcessForwarding(); + // If the event is reserved by chrome, we shouldn't expose the event to + // web contents because such events shouldn't be cancelable. So, it's not + // good behavior to fire such events but to ignore the defaultPrevented + // attribute value in chrome. + mOnlySystemGroupDispatchInContent = true; + } + /** + * Return true if the event is reserved by chrome. + */ + inline bool IsReservedByChrome() const { + MOZ_ASSERT(!mIsReservedByChrome || (IsCrossProcessForwardingStopped() && + mOnlySystemGroupDispatchInContent)); + return mIsReservedByChrome; + } + + inline void Clear() { SetRawFlags(0); } + // Get if either the instance's bit or the aOther's bit is true, the + // instance's bit becomes true. In other words, this works like: + // eventFlags |= aOther; + inline void Union(const BaseEventFlags& aOther) { + RawFlags rawFlags = GetRawFlags() | aOther.GetRawFlags(); + SetRawFlags(rawFlags); + } + + private: + typedef uint64_t RawFlags; + + inline void SetRawFlags(RawFlags aRawFlags) { + static_assert(sizeof(BaseEventFlags) <= sizeof(RawFlags), + "mozilla::EventFlags must not be bigger than the RawFlags"); + memcpy(this, &aRawFlags, sizeof(BaseEventFlags)); + } + inline RawFlags GetRawFlags() const { + RawFlags result = 0; + memcpy(&result, this, sizeof(BaseEventFlags)); + return result; + } +}; + +/****************************************************************************** + * mozilla::EventFlags + ******************************************************************************/ + +struct EventFlags : public BaseEventFlags { + EventFlags() { Clear(); } +}; + +/****************************************************************************** + * mozilla::WidgetEventTime + ******************************************************************************/ + +class WidgetEventTime { + public: + // Timestamp when the message was created. + TimeStamp mTimeStamp; + + WidgetEventTime() : mTimeStamp(TimeStamp::Now()) {} + + explicit WidgetEventTime(const WidgetEventTime* aTime) + : mTimeStamp(aTime ? aTime->mTimeStamp : TimeStamp::Now()) { + MOZ_ASSERT(aTime != this); + MOZ_ASSERT_IF(aTime, !aTime->mTimeStamp.IsNull()); + } + + explicit WidgetEventTime(TimeStamp aTimeStamp) : mTimeStamp(aTimeStamp) {} + + void AssignEventTime(const WidgetEventTime& aOther) { + mTimeStamp = aOther.mTimeStamp; + } +}; + +/****************************************************************************** + * mozilla::WidgetEvent + ******************************************************************************/ + +class WidgetEvent : public WidgetEventTime { + private: + void SetDefaultCancelableAndBubbles() { + switch (mClass) { + case eEditorInputEventClass: + mFlags.mCancelable = false; + mFlags.mBubbles = mFlags.mIsTrusted; + break; + case eMouseEventClass: + mFlags.mCancelable = + (mMessage != eMouseEnter && mMessage != eMouseLeave); + mFlags.mBubbles = (mMessage != eMouseEnter && mMessage != eMouseLeave); + break; + case ePointerEventClass: + mFlags.mCancelable = + (mMessage != ePointerEnter && mMessage != ePointerLeave && + mMessage != ePointerCancel && mMessage != ePointerGotCapture && + mMessage != ePointerLostCapture); + mFlags.mBubbles = + (mMessage != ePointerEnter && mMessage != ePointerLeave); + break; + case eDragEventClass: + mFlags.mCancelable = (mMessage != eDragExit && mMessage != eDragLeave && + mMessage != eDragEnd); + mFlags.mBubbles = true; + break; + case eSMILTimeEventClass: + mFlags.mCancelable = false; + mFlags.mBubbles = false; + break; + case eTransitionEventClass: + case eAnimationEventClass: + mFlags.mCancelable = false; + mFlags.mBubbles = true; + break; + case eCompositionEventClass: + // XXX compositionstart is cancelable in draft of DOM3 Events. + // However, it doesn't make sense for us, we cannot cancel + // composition when we send compositionstart event. + mFlags.mCancelable = false; + mFlags.mBubbles = true; + break; + default: + if (mMessage == eResize || mMessage == eMozVisualResize || + mMessage == eMozVisualScroll || mMessage == eEditorInput || + mMessage == eFormSelect) { + mFlags.mCancelable = false; + } else { + mFlags.mCancelable = true; + } + mFlags.mBubbles = true; + break; + } + } + + protected: + WidgetEvent(bool aIsTrusted, EventMessage aMessage, + EventClassID aEventClassID, + const WidgetEventTime* aTime = nullptr) + : WidgetEventTime(aTime), + mClass(aEventClassID), + mMessage(aMessage), + mRefPoint(0, 0), + mLastRefPoint(0, 0), + mFocusSequenceNumber(0), + mSpecifiedEventType(nullptr), + mPath(nullptr), + mLayersId(layers::LayersId{0}) { + MOZ_COUNT_CTOR(WidgetEvent); + mFlags.Clear(); + mFlags.mIsTrusted = aIsTrusted; + SetDefaultCancelableAndBubbles(); + SetDefaultComposed(); + SetDefaultComposedInNativeAnonymousContent(); + } + + WidgetEvent() : mPath(nullptr) { MOZ_COUNT_CTOR(WidgetEvent); } + + public: + WidgetEvent(bool aIsTrusted, EventMessage aMessage, + const WidgetEventTime* aTime = nullptr) + : WidgetEvent(aIsTrusted, aMessage, eBasicEventClass, aTime) {} + + MOZ_COUNTED_DTOR_VIRTUAL(WidgetEvent) + + WidgetEvent(const WidgetEvent& aOther) : WidgetEventTime(aOther) { + MOZ_COUNT_CTOR(WidgetEvent); + *this = aOther; + } + WidgetEvent& operator=(const WidgetEvent& aOther) = default; + + WidgetEvent(WidgetEvent&& aOther) + : WidgetEventTime(std::move(aOther)), + mClass(aOther.mClass), + mMessage(aOther.mMessage), + mRefPoint(std::move(aOther.mRefPoint)), + mLastRefPoint(std::move(aOther.mLastRefPoint)), + mFocusSequenceNumber(aOther.mFocusSequenceNumber), + mFlags(std::move(aOther.mFlags)), + mSpecifiedEventType(std::move(aOther.mSpecifiedEventType)), + mSpecifiedEventTypeString(std::move(aOther.mSpecifiedEventTypeString)), + mTarget(std::move(aOther.mTarget)), + mCurrentTarget(std::move(aOther.mCurrentTarget)), + mOriginalTarget(std::move(aOther.mOriginalTarget)), + mRelatedTarget(std::move(aOther.mRelatedTarget)), + mOriginalRelatedTarget(std::move(aOther.mOriginalRelatedTarget)), + mPath(std::move(aOther.mPath)) { + MOZ_COUNT_CTOR(WidgetEvent); + } + WidgetEvent& operator=(WidgetEvent&& aOther) = default; + + virtual WidgetEvent* Duplicate() const { + MOZ_ASSERT(mClass == eBasicEventClass, + "Duplicate() must be overridden by sub class"); + WidgetEvent* result = new WidgetEvent(false, mMessage, this); + result->AssignEventData(*this, true); + result->mFlags = mFlags; + return result; + } + + EventClassID mClass; + EventMessage mMessage; + // Relative to the widget of the event, or if there is no widget then it is + // in screen coordinates. Not modified by layout code. + // This is in visual coordinates, i.e. the correct RelativeTo value that + // expresses what this is relative to is `{viewportFrame, Visual}`, where + // `viewportFrame` is the viewport frame of the widget's root document. + LayoutDeviceIntPoint mRefPoint; + // The previous mRefPoint, if known, used to calculate mouse movement deltas. + LayoutDeviceIntPoint mLastRefPoint; + // The sequence number of the last potentially focus changing event handled + // by APZ. This is used to track when that event has been processed by + // content, and focus can be reconfirmed for async keyboard scrolling. + uint64_t mFocusSequenceNumber; + // See BaseEventFlags definition for the detail. + BaseEventFlags mFlags; + + // If JS creates an event with unknown event type or known event type but + // for different event interface, the event type is stored to this. + // NOTE: This is always used if the instance is a WidgetCommandEvent instance + // or "input" event is dispatched with dom::Event class. + RefPtr<nsAtom> mSpecifiedEventType; + + // nsAtom isn't available on non-main thread due to unsafe. Therefore, + // mSpecifiedEventTypeString is used instead of mSpecifiedEventType if + // the event is created in non-main thread. + nsString mSpecifiedEventTypeString; + + // Event targets, needed by DOM Events + // Note that when you need event target for DOM event, you should use + // Get*DOMEventTarget() instead of accessing these members directly. + nsCOMPtr<dom::EventTarget> mTarget; + nsCOMPtr<dom::EventTarget> mCurrentTarget; + nsCOMPtr<dom::EventTarget> mOriginalTarget; + + /// The possible related target + nsCOMPtr<dom::EventTarget> mRelatedTarget; + nsCOMPtr<dom::EventTarget> mOriginalRelatedTarget; + + nsTArray<EventTargetChainItem>* mPath; + + // The LayersId of the content process that this event should be + // dispatched to. This field is only used in the chrome process + // and doesn't get remoted to child processes. + layers::LayersId mLayersId; + + dom::EventTarget* GetDOMEventTarget() const; + dom::EventTarget* GetCurrentDOMEventTarget() const; + dom::EventTarget* GetOriginalDOMEventTarget() const; + + void AssignEventData(const WidgetEvent& aEvent, bool aCopyTargets) { + // mClass should be initialized with the constructor. + // mMessage should be initialized with the constructor. + mRefPoint = aEvent.mRefPoint; + // mLastRefPoint doesn't need to be copied. + mFocusSequenceNumber = aEvent.mFocusSequenceNumber; + // mLayersId intentionally not copied, since it's not used within content + AssignEventTime(aEvent); + // mFlags should be copied manually if it's necessary. + mSpecifiedEventType = aEvent.mSpecifiedEventType; + // mSpecifiedEventTypeString should be copied manually if it's necessary. + mTarget = aCopyTargets ? aEvent.mTarget : nullptr; + mCurrentTarget = aCopyTargets ? aEvent.mCurrentTarget : nullptr; + mOriginalTarget = aCopyTargets ? aEvent.mOriginalTarget : nullptr; + mRelatedTarget = aCopyTargets ? aEvent.mRelatedTarget : nullptr; + mOriginalRelatedTarget = + aCopyTargets ? aEvent.mOriginalRelatedTarget : nullptr; + } + + /** + * Helper methods for methods of DOM Event. + */ + void StopPropagation() { mFlags.StopPropagation(); } + void StopImmediatePropagation() { mFlags.StopImmediatePropagation(); } + void PreventDefault(bool aCalledByDefaultHandler = true, + nsIPrincipal* aPrincipal = nullptr); + + void PreventDefaultBeforeDispatch( + CrossProcessForwarding aCrossProcessForwarding) { + mFlags.PreventDefaultBeforeDispatch(aCrossProcessForwarding); + } + bool DefaultPrevented() const { return mFlags.DefaultPrevented(); } + bool DefaultPreventedByContent() const { + return mFlags.DefaultPreventedByContent(); + } + bool IsTrusted() const { return mFlags.IsTrusted(); } + bool PropagationStopped() const { return mFlags.PropagationStopped(); } + + /** + * Prevent to be dispatched to remote process. + */ + inline void StopCrossProcessForwarding() { + mFlags.StopCrossProcessForwarding(); + } + /** + * Return true if the event shouldn't be dispatched to remote process. + */ + inline bool IsCrossProcessForwardingStopped() const { + return mFlags.IsCrossProcessForwardingStopped(); + } + /** + * Mark the event as waiting reply from remote process. + * Note that this also stops immediate propagation in current process. + */ + inline void MarkAsWaitingReplyFromRemoteProcess() { + mFlags.MarkAsWaitingReplyFromRemoteProcess(); + } + /** + * Reset "waiting reply from remote process" state. This is useful when + * you dispatch a copy of an event coming from different process. + */ + inline void ResetWaitingReplyFromRemoteProcessState() { + mFlags.ResetWaitingReplyFromRemoteProcessState(); + } + /** + * Return true if the event handler should wait reply event. I.e., if this + * returns true, any event handler should do nothing with the event. + */ + inline bool IsWaitingReplyFromRemoteProcess() const { + return mFlags.IsWaitingReplyFromRemoteProcess(); + } + /** + * Mark the event as already handled in the remote process. This should be + * called when initializing reply events. + */ + inline void MarkAsHandledInRemoteProcess() { + mFlags.MarkAsHandledInRemoteProcess(); + } + /** + * Return true if the event has already been handled in the remote process. + * I.e., if this returns true, the event is a reply event. + */ + inline bool IsHandledInRemoteProcess() const { + return mFlags.IsHandledInRemoteProcess(); + } + /** + * Return true if the event should be sent back to its parent process. + * So, usual event handlers shouldn't call this. + */ + inline bool WantReplyFromContentProcess() const { + return mFlags.WantReplyFromContentProcess(); + } + /** + * Mark the event has already posted to a remote process. + */ + inline void MarkAsPostedToRemoteProcess() { + mFlags.MarkAsPostedToRemoteProcess(); + } + /** + * Reset the cross process dispatching state. This should be used when a + * process receives the event because the state is in the sender. + */ + inline void ResetCrossProcessDispatchingState() { + mFlags.ResetCrossProcessDispatchingState(); + } + /** + * Return true if the event has been posted to a remote process. + */ + inline bool HasBeenPostedToRemoteProcess() const { + return mFlags.HasBeenPostedToRemoteProcess(); + } + /** + * Return true if the event came from another process. + */ + inline bool CameFromAnotherProcess() const { + return mFlags.CameFromAnotherProcess(); + } + /** + * Mark the event as coming from another process. + */ + inline void MarkAsComingFromAnotherProcess() { + mFlags.MarkAsComingFromAnotherProcess(); + } + /** + * Mark the event is reserved by chrome. I.e., shouldn't be dispatched to + * content because it shouldn't be cancelable. + */ + inline void MarkAsReservedByChrome() { mFlags.MarkAsReservedByChrome(); } + /** + * Return true if the event is reserved by chrome. + */ + inline bool IsReservedByChrome() const { return mFlags.IsReservedByChrome(); } + + /** + * Utils for checking event types + */ + + /** + * As*Event() returns the pointer of the instance only when the instance is + * the class or one of its derived class. + */ +#define NS_ROOT_EVENT_CLASS(aPrefix, aName) +#define NS_EVENT_CLASS(aPrefix, aName) \ + virtual aPrefix##aName* As##aName(); \ + const aPrefix##aName* As##aName() const; + +#include "mozilla/EventClassList.h" + +#undef NS_EVENT_CLASS +#undef NS_ROOT_EVENT_CLASS + + /** + * Returns true if the event is a query content event. + */ + bool IsQueryContentEvent() const; + /** + * Returns true if the event is a selection event. + */ + bool IsSelectionEvent() const; + /** + * Returns true if the event is a content command event. + */ + bool IsContentCommandEvent() const; + + /** + * Returns true if the event mMessage is one of mouse events. + */ + bool HasMouseEventMessage() const; + /** + * Returns true if the event mMessage is one of drag events. + */ + bool HasDragEventMessage() const; + /** + * Returns true if aMessage or mMessage is one of key events. + */ + static bool IsKeyEventMessage(EventMessage aMessage); + bool HasKeyEventMessage() const { return IsKeyEventMessage(mMessage); } + /** + * Returns true if the event mMessage is one of composition events or text + * event. + */ + bool HasIMEEventMessage() const; + + /** + * Returns true if the event can be sent to remote process. + */ + bool CanBeSentToRemoteProcess() const; + /** + * Returns true if the original target is a remote process and the event + * will be posted to the remote process later. + */ + bool WillBeSentToRemoteProcess() const; + /** + * Returns true if the event is related to IME handling. It includes + * IME events, query content events and selection events. + * Be careful when you use this. + */ + bool IsIMERelatedEvent() const; + + /** + * Whether the event should be handled by the frame of the mouse cursor + * position or not. When it should be handled there (e.g., the mouse events), + * this returns true. + */ + bool IsUsingCoordinates() const; + /** + * Whether the event should be handled by the focused DOM window in the + * same top level window's or not. E.g., key events, IME related events + * (including the query content events, they are used in IME transaction) + * should be handled by the (last) focused window rather than the dispatched + * window. + * + * NOTE: Even if this returns true, the event isn't going to be handled by the + * application level active DOM window which is on another top level window. + * So, when the event is fired on a deactive window, the event is going to be + * handled by the last focused DOM window in the last focused window. + */ + bool IsTargetedAtFocusedWindow() const; + /** + * Whether the event should be handled by the focused content or not. E.g., + * key events, IME related events and other input events which are not handled + * by the frame of the mouse cursor position. + * + * NOTE: Even if this returns true, the event isn't going to be handled by the + * application level active DOM window which is on another top level window. + * So, when the event is fired on a deactive window, the event is going to be + * handled by the last focused DOM element of the last focused DOM window in + * the last focused window. + */ + bool IsTargetedAtFocusedContent() const; + /** + * Whether the event should cause a DOM event. + */ + bool IsAllowedToDispatchDOMEvent() const; + /** + * Whether the event should be dispatched in system group. + */ + bool IsAllowedToDispatchInSystemGroup() const; + /** + * Whether the event should be blocked for fingerprinting resistance. + */ + bool IsBlockedForFingerprintingResistance() const; + /** + * Whether the event handler can flush pending notifications or not. + */ + bool AllowFlushingPendingNotifications() const; + /** + * Initialize mComposed + */ + void SetDefaultComposed() { + switch (mClass) { + case eClipboardEventClass: + mFlags.mComposed = true; + break; + case eCompositionEventClass: + mFlags.mComposed = + mMessage == eCompositionStart || mMessage == eCompositionUpdate || + mMessage == eCompositionChange || mMessage == eCompositionEnd; + break; + case eDragEventClass: + // All drag & drop events are composed + mFlags.mComposed = mMessage == eDrag || mMessage == eDragEnd || + mMessage == eDragEnter || mMessage == eDragExit || + mMessage == eDragLeave || mMessage == eDragOver || + mMessage == eDragStart || mMessage == eDrop; + break; + case eEditorInputEventClass: + mFlags.mComposed = + mMessage == eEditorInput || mMessage == eEditorBeforeInput; + break; + case eFocusEventClass: + mFlags.mComposed = mMessage == eBlur || mMessage == eFocus || + mMessage == eFocusOut || mMessage == eFocusIn; + break; + case eKeyboardEventClass: + mFlags.mComposed = + mMessage == eKeyDown || mMessage == eKeyUp || mMessage == eKeyPress; + break; + case eMouseEventClass: + mFlags.mComposed = + mMessage == eMouseClick || mMessage == eMouseDoubleClick || + mMessage == eMouseAuxClick || mMessage == eMouseDown || + mMessage == eMouseUp || mMessage == eMouseOver || + mMessage == eMouseOut || mMessage == eMouseMove || + mMessage == eContextMenu || mMessage == eXULPopupShowing || + mMessage == eXULPopupHiding || mMessage == eXULPopupShown || + mMessage == eXULPopupHidden; + break; + case ePointerEventClass: + // All pointer events are composed + mFlags.mComposed = + mMessage == ePointerDown || mMessage == ePointerMove || + mMessage == ePointerUp || mMessage == ePointerCancel || + mMessage == ePointerOver || mMessage == ePointerOut || + mMessage == ePointerGotCapture || mMessage == ePointerLostCapture; + break; + case eTouchEventClass: + // All touch events are composed + mFlags.mComposed = mMessage == eTouchStart || mMessage == eTouchEnd || + mMessage == eTouchMove || mMessage == eTouchCancel; + break; + case eUIEventClass: + mFlags.mComposed = mMessage == eLegacyDOMFocusIn || + mMessage == eLegacyDOMFocusOut || + mMessage == eLegacyDOMActivate; + break; + case eWheelEventClass: + // All wheel events are composed + mFlags.mComposed = mMessage == eWheel; + break; + case eMouseScrollEventClass: + // Legacy mouse scroll events are composed too, for consistency with + // wheel. + mFlags.mComposed = mMessage == eLegacyMouseLineOrPageScroll || + mMessage == eLegacyMousePixelScroll; + break; + default: + mFlags.mComposed = false; + break; + } + } + + void SetComposed(const nsAString& aEventTypeArg) { + mFlags.mComposed = // composition events + aEventTypeArg.EqualsLiteral("compositionstart") || + aEventTypeArg.EqualsLiteral("compositionupdate") || + aEventTypeArg.EqualsLiteral("compositionend") || + aEventTypeArg.EqualsLiteral("text") || + // drag and drop events + aEventTypeArg.EqualsLiteral("dragstart") || + aEventTypeArg.EqualsLiteral("drag") || + aEventTypeArg.EqualsLiteral("dragenter") || + aEventTypeArg.EqualsLiteral("dragexit") || + aEventTypeArg.EqualsLiteral("dragleave") || + aEventTypeArg.EqualsLiteral("dragover") || + aEventTypeArg.EqualsLiteral("drop") || + aEventTypeArg.EqualsLiteral("dropend") || + // editor input events + aEventTypeArg.EqualsLiteral("input") || + aEventTypeArg.EqualsLiteral("beforeinput") || + // focus events + aEventTypeArg.EqualsLiteral("blur") || + aEventTypeArg.EqualsLiteral("focus") || + aEventTypeArg.EqualsLiteral("focusin") || + aEventTypeArg.EqualsLiteral("focusout") || + // keyboard events + aEventTypeArg.EqualsLiteral("keydown") || + aEventTypeArg.EqualsLiteral("keyup") || + aEventTypeArg.EqualsLiteral("keypress") || + // mouse events + aEventTypeArg.EqualsLiteral("click") || + aEventTypeArg.EqualsLiteral("dblclick") || + aEventTypeArg.EqualsLiteral("mousedown") || + aEventTypeArg.EqualsLiteral("mouseup") || + aEventTypeArg.EqualsLiteral("mouseenter") || + aEventTypeArg.EqualsLiteral("mouseleave") || + aEventTypeArg.EqualsLiteral("mouseover") || + aEventTypeArg.EqualsLiteral("mouseout") || + aEventTypeArg.EqualsLiteral("mousemove") || + aEventTypeArg.EqualsLiteral("contextmenu") || + // pointer events + aEventTypeArg.EqualsLiteral("pointerdown") || + aEventTypeArg.EqualsLiteral("pointermove") || + aEventTypeArg.EqualsLiteral("pointerup") || + aEventTypeArg.EqualsLiteral("pointercancel") || + aEventTypeArg.EqualsLiteral("pointerover") || + aEventTypeArg.EqualsLiteral("pointerout") || + aEventTypeArg.EqualsLiteral("pointerenter") || + aEventTypeArg.EqualsLiteral("pointerleave") || + aEventTypeArg.EqualsLiteral("gotpointercapture") || + aEventTypeArg.EqualsLiteral("lostpointercapture") || + // touch events + aEventTypeArg.EqualsLiteral("touchstart") || + aEventTypeArg.EqualsLiteral("touchend") || + aEventTypeArg.EqualsLiteral("touchmove") || + aEventTypeArg.EqualsLiteral("touchcancel") || + // UI legacy events + aEventTypeArg.EqualsLiteral("DOMFocusIn") || + aEventTypeArg.EqualsLiteral("DOMFocusOut") || + aEventTypeArg.EqualsLiteral("DOMActivate") || + // wheel events + aEventTypeArg.EqualsLiteral("wheel"); + } + + void SetComposed(bool aComposed) { mFlags.mComposed = aComposed; } + + void SetDefaultComposedInNativeAnonymousContent() { + // For compatibility concerns, we set mComposedInNativeAnonymousContent to + // false for those events we want to stop propagation. + // + // nsVideoFrame may create anonymous image element which fires eLoad, + // eLoadStart, eLoadEnd, eLoadError. We don't want these events cross + // the boundary of NAC + mFlags.mComposedInNativeAnonymousContent = + mMessage != eLoad && mMessage != eLoadStart && mMessage != eLoadEnd && + mMessage != eLoadError; + } + + bool IsUserAction() const; +}; + +/****************************************************************************** + * mozilla::WidgetGUIEvent + ******************************************************************************/ + +class WidgetGUIEvent : public WidgetEvent { + protected: + WidgetGUIEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget, + EventClassID aEventClassID, + const WidgetEventTime* aTime = nullptr) + : WidgetEvent(aIsTrusted, aMessage, aEventClassID, aTime), + mWidget(aWidget) {} + + WidgetGUIEvent() = default; + + public: + virtual WidgetGUIEvent* AsGUIEvent() override { return this; } + + WidgetGUIEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget, + const WidgetEventTime* aTime = nullptr) + : WidgetEvent(aIsTrusted, aMessage, eGUIEventClass, aTime), + mWidget(aWidget) {} + + virtual WidgetEvent* Duplicate() const override { + MOZ_ASSERT(mClass == eGUIEventClass, + "Duplicate() must be overridden by sub class"); + // Not copying widget, it is a weak reference. + WidgetGUIEvent* result = new WidgetGUIEvent(false, mMessage, nullptr, this); + result->AssignGUIEventData(*this, true); + result->mFlags = mFlags; + return result; + } + + // Originator of the event + nsCOMPtr<nsIWidget> mWidget; + + void AssignGUIEventData(const WidgetGUIEvent& aEvent, bool aCopyTargets) { + AssignEventData(aEvent, aCopyTargets); + // widget should be initialized with the constructor. + } +}; + +/****************************************************************************** + * mozilla::Modifier + * + * All modifier keys should be defined here. This is used for managing + * modifier states for DOM Level 3 or later. + ******************************************************************************/ + +enum Modifier { + MODIFIER_NONE = 0x0000, + MODIFIER_ALT = 0x0001, + MODIFIER_ALTGRAPH = 0x0002, + MODIFIER_CAPSLOCK = 0x0004, + MODIFIER_CONTROL = 0x0008, + MODIFIER_FN = 0x0010, + MODIFIER_FNLOCK = 0x0020, + MODIFIER_META = 0x0040, + MODIFIER_NUMLOCK = 0x0080, + MODIFIER_SCROLLLOCK = 0x0100, + MODIFIER_SHIFT = 0x0200, + MODIFIER_SYMBOL = 0x0400, + MODIFIER_SYMBOLLOCK = 0x0800, +}; + +/****************************************************************************** + * Modifier key names. + ******************************************************************************/ + +#define NS_DOM_KEYNAME_ALT "Alt" +#define NS_DOM_KEYNAME_ALTGRAPH "AltGraph" +#define NS_DOM_KEYNAME_CAPSLOCK "CapsLock" +#define NS_DOM_KEYNAME_CONTROL "Control" +#define NS_DOM_KEYNAME_FN "Fn" +#define NS_DOM_KEYNAME_FNLOCK "FnLock" +#define NS_DOM_KEYNAME_META "Meta" +#define NS_DOM_KEYNAME_NUMLOCK "NumLock" +#define NS_DOM_KEYNAME_SCROLLLOCK "ScrollLock" +#define NS_DOM_KEYNAME_SHIFT "Shift" +#define NS_DOM_KEYNAME_SYMBOL "Symbol" +#define NS_DOM_KEYNAME_SYMBOLLOCK "SymbolLock" +#define NS_DOM_KEYNAME_OS "OS" + +/****************************************************************************** + * mozilla::Modifiers + ******************************************************************************/ + +typedef uint16_t Modifiers; + +class MOZ_STACK_CLASS GetModifiersName final : public nsAutoCString { + public: + explicit GetModifiersName(Modifiers aModifiers) { + if (aModifiers & MODIFIER_ALT) { + AssignLiteral(NS_DOM_KEYNAME_ALT); + } + if (aModifiers & MODIFIER_ALTGRAPH) { + MaybeAppendSeparator(); + AppendLiteral(NS_DOM_KEYNAME_ALTGRAPH); + } + if (aModifiers & MODIFIER_CAPSLOCK) { + MaybeAppendSeparator(); + AppendLiteral(NS_DOM_KEYNAME_CAPSLOCK); + } + if (aModifiers & MODIFIER_CONTROL) { + MaybeAppendSeparator(); + AppendLiteral(NS_DOM_KEYNAME_CONTROL); + } + if (aModifiers & MODIFIER_FN) { + MaybeAppendSeparator(); + AppendLiteral(NS_DOM_KEYNAME_FN); + } + if (aModifiers & MODIFIER_FNLOCK) { + MaybeAppendSeparator(); + AppendLiteral(NS_DOM_KEYNAME_FNLOCK); + } + if (aModifiers & MODIFIER_META) { + MaybeAppendSeparator(); + AppendLiteral(NS_DOM_KEYNAME_META); + } + if (aModifiers & MODIFIER_NUMLOCK) { + MaybeAppendSeparator(); + AppendLiteral(NS_DOM_KEYNAME_NUMLOCK); + } + if (aModifiers & MODIFIER_SCROLLLOCK) { + MaybeAppendSeparator(); + AppendLiteral(NS_DOM_KEYNAME_SCROLLLOCK); + } + if (aModifiers & MODIFIER_SHIFT) { + MaybeAppendSeparator(); + AppendLiteral(NS_DOM_KEYNAME_SHIFT); + } + if (aModifiers & MODIFIER_SYMBOL) { + MaybeAppendSeparator(); + AppendLiteral(NS_DOM_KEYNAME_SYMBOL); + } + if (aModifiers & MODIFIER_SYMBOLLOCK) { + MaybeAppendSeparator(); + AppendLiteral(NS_DOM_KEYNAME_SYMBOLLOCK); + } + if (IsEmpty()) { + AssignLiteral("none"); + } + } + + private: + void MaybeAppendSeparator() { + if (!IsEmpty()) { + AppendLiteral(" | "); + } + } +}; + +/****************************************************************************** + * mozilla::WidgetInputEvent + ******************************************************************************/ + +class WidgetInputEvent : public WidgetGUIEvent { + protected: + WidgetInputEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget, + EventClassID aEventClassID, + const WidgetEventTime* aTime = nullptr) + : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, aEventClassID, aTime), + mModifiers(0) {} + + WidgetInputEvent() : mModifiers(0) {} + + public: + virtual WidgetInputEvent* AsInputEvent() override { return this; } + + WidgetInputEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget, + const WidgetEventTime* aTime = nullptr) + : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eInputEventClass, aTime), + mModifiers(0) {} + + virtual WidgetEvent* Duplicate() const override { + MOZ_ASSERT(mClass == eInputEventClass, + "Duplicate() must be overridden by sub class"); + // Not copying widget, it is a weak reference. + WidgetInputEvent* result = + new WidgetInputEvent(false, mMessage, nullptr, this); + result->AssignInputEventData(*this, true); + result->mFlags = mFlags; + return result; + } + + /** + * Returns a modifier of "Accel" virtual modifier which is used for shortcut + * key. + */ + static Modifier AccelModifier(); + + /** + * GetModifier() returns a modifier flag which is activated by aDOMKeyName. + */ + static Modifier GetModifier(const nsAString& aDOMKeyName); + + // true indicates the accel key on the environment is down + bool IsAccel() const { return ((mModifiers & AccelModifier()) != 0); } + + // true indicates the shift key is down + bool IsShift() const { return ((mModifiers & MODIFIER_SHIFT) != 0); } + // true indicates the control key is down + bool IsControl() const { return ((mModifiers & MODIFIER_CONTROL) != 0); } + // true indicates the alt key is down + bool IsAlt() const { return ((mModifiers & MODIFIER_ALT) != 0); } + // true indicates the meta key is down (Command key on macOS, Windows logo key + // on Windows, Super/Hyper key on Linux, Meta key on Android). + bool IsMeta() const { return ((mModifiers & MODIFIER_META) != 0); } + // true indicates the alt graph key is down + // NOTE: on Mac, the option key press causes both IsAlt() and IsAltGrpah() + // return true. + bool IsAltGraph() const { return ((mModifiers & MODIFIER_ALTGRAPH) != 0); } + // true indicates the CapLock LED is turn on. + bool IsCapsLocked() const { return ((mModifiers & MODIFIER_CAPSLOCK) != 0); } + // true indicates the NumLock LED is turn on. + bool IsNumLocked() const { return ((mModifiers & MODIFIER_NUMLOCK) != 0); } + // true indicates the ScrollLock LED is turn on. + bool IsScrollLocked() const { + return ((mModifiers & MODIFIER_SCROLLLOCK) != 0); + } + + // true indicates the Fn key is down, but this is not supported by native + // key event on any platform. + bool IsFn() const { return ((mModifiers & MODIFIER_FN) != 0); } + // true indicates the FnLock LED is turn on, but we don't know such + // keyboards nor platforms. + bool IsFnLocked() const { return ((mModifiers & MODIFIER_FNLOCK) != 0); } + // true indicates the Symbol is down, but this is not supported by native + // key event on any platforms. + bool IsSymbol() const { return ((mModifiers & MODIFIER_SYMBOL) != 0); } + // true indicates the SymbolLock LED is turn on, but we don't know such + // keyboards nor platforms. + bool IsSymbolLocked() const { + return ((mModifiers & MODIFIER_SYMBOLLOCK) != 0); + } + + void InitBasicModifiers(bool aCtrlKey, bool aAltKey, bool aShiftKey, + bool aMetaKey) { + mModifiers = 0; + if (aCtrlKey) { + mModifiers |= MODIFIER_CONTROL; + } + if (aAltKey) { + mModifiers |= MODIFIER_ALT; + } + if (aShiftKey) { + mModifiers |= MODIFIER_SHIFT; + } + if (aMetaKey) { + mModifiers |= MODIFIER_META; + } + } + + Modifiers mModifiers; + + void AssignInputEventData(const WidgetInputEvent& aEvent, bool aCopyTargets) { + AssignGUIEventData(aEvent, aCopyTargets); + + mModifiers = aEvent.mModifiers; + } +}; + +/****************************************************************************** + * mozilla::InternalUIEvent + * + * XXX Why this inherits WidgetGUIEvent rather than WidgetEvent? + ******************************************************************************/ + +class InternalUIEvent : public WidgetGUIEvent { + protected: + InternalUIEvent() : mDetail(0), mCausedByUntrustedEvent(false) {} + + InternalUIEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget, + EventClassID aEventClassID, + const WidgetEventTime* aTime = nullptr) + : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, aEventClassID, aTime), + mDetail(0), + mCausedByUntrustedEvent(false) {} + + InternalUIEvent(bool aIsTrusted, EventMessage aMessage, + EventClassID aEventClassID, + const WidgetEventTime* aTime = nullptr) + : WidgetGUIEvent(aIsTrusted, aMessage, nullptr, aEventClassID, aTime), + mDetail(0), + mCausedByUntrustedEvent(false) {} + + public: + virtual InternalUIEvent* AsUIEvent() override { return this; } + + /** + * If the UIEvent is caused by another event (e.g., click event), + * aEventCausesThisEvent should be the event. If there is no such event, + * this should be nullptr. + */ + InternalUIEvent(bool aIsTrusted, EventMessage aMessage, + const WidgetEvent* aEventCausesThisEvent, + const WidgetEventTime* aTime = nullptr) + : WidgetGUIEvent(aIsTrusted, aMessage, nullptr, eUIEventClass, aTime), + mDetail(0), + mCausedByUntrustedEvent(aEventCausesThisEvent && + !aEventCausesThisEvent->IsTrusted()) {} + + virtual WidgetEvent* Duplicate() const override { + MOZ_ASSERT(mClass == eUIEventClass, + "Duplicate() must be overridden by sub class"); + InternalUIEvent* result = + new InternalUIEvent(false, mMessage, nullptr, this); + result->AssignUIEventData(*this, true); + result->mFlags = mFlags; + return result; + } + + int32_t mDetail; + // mCausedByUntrustedEvent is true if the event is caused by untrusted event. + bool mCausedByUntrustedEvent; + + // If you check the event is a trusted event and NOT caused by an untrusted + // event, IsTrustable() returns what you expected. + bool IsTrustable() const { return IsTrusted() && !mCausedByUntrustedEvent; } + + void AssignUIEventData(const InternalUIEvent& aEvent, bool aCopyTargets) { + AssignGUIEventData(aEvent, aCopyTargets); + + mDetail = aEvent.mDetail; + mCausedByUntrustedEvent = aEvent.mCausedByUntrustedEvent; + } +}; + +} // namespace mozilla + +#endif // mozilla_BasicEvents_h__ |