gecko-dev/widget/BasicEvents.h
Masayuki Nakano fe2b9f4618 Bug 903746 - part 1: Add TextEvent r=smaug
Unfortunately, we returned a `CompositionEvent` for
`Document.createEvent("textevent")` because we had a text event which we stopped
exposing to the web and was replaced with `eCompositionChange` event.
Therefore, this change could potentially have a compatibility risk.

Differential Revision: https://phabricator.services.mozilla.com/D200120
2024-04-08 12:29:59 +00:00

1340 lines
50 KiB
C++

/* -*- 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 eLegacyTextEventClass:
mFlags.mCancelable = mFlags.mIsTrusted && mMessage == eLegacyTextInput;
mFlags.mBubbles = mFlags.mIsTrusted && mMessage == eLegacyTextInput;
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__