gecko-dev/widget/BasicEvents.h

1194 строки
40 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 "mozilla/dom/EventTarget.h"
#include "mozilla/EventForwards.h"
#include "mozilla/TimeStamp.h"
#include "nsCOMPtr.h"
#include "nsIAtom.h"
#include "nsISupportsImpl.h"
#include "nsIWidget.h"
#include "nsString.h"
#include "Units.h"
namespace IPC {
template<typename T>
struct ParamTraits;
} // namespace IPC
namespace mozilla {
/******************************************************************************
* 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 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.
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 mNoCrossProcessBoundaryForwarding is true, the event is not allowed to
// cross process boundary.
bool mNoCrossProcessBoundaryForwarding : 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;
// 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 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;
// The event's action will be handled by APZ. The main thread should not
// perform its associated action. This is currently only relevant for
// wheel and touch events.
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;
// True if the event is suppressed or delayed. This is used when parent side
// process the key event after content side, parent side may drop the key
// event if it was suppressed or delayed in content side.
bool mIsSuppressedOrDelayed : 1;
// If the event is being handled in target phase, returns true.
inline bool InTargetPhase() const
{
return (mInBubblingPhase && mInCapturePhase);
}
/**
* Helper methods for methods of DOM Event.
*/
inline void StopPropagation()
{
mPropagationStopped = true;
}
inline void StopImmediatePropagation()
{
StopPropagation();
mImmediatePropagationStopped = true;
}
inline void StopCrossProcessForwarding()
{
mNoCrossProcessBoundaryForwarding = true;
}
inline void PreventDefault(bool aCalledByDefaultHandler = true)
{
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) {
mDefaultPreventedByChrome = true;
} else {
mDefaultPreventedByContent = true;
}
}
// This should be used only before dispatching events into the DOM tree.
inline void PreventDefaultBeforeDispatch()
{
mDefaultPrevented = true;
}
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;
}
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 uint32_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:
// Elapsed time, in milliseconds, from a platform-specific zero time
// to the time the message was created
uint64_t mTime;
// Timestamp when the message was created. Set in parallel to 'time' until we
// determine if it is safe to drop 'time' (see bug 77992).
TimeStamp mTimeStamp;
WidgetEventTime()
: mTime(0)
, mTimeStamp(TimeStamp::Now())
{
}
WidgetEventTime(uint64_t aTime,
TimeStamp aTimeStamp)
: mTime(aTime)
, mTimeStamp(aTimeStamp)
{
}
void AssignEventTime(const WidgetEventTime& aOther)
{
mTime = aOther.mTime;
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:
case eSVGZoomEventClass:
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) {
mFlags.mCancelable = false;
} else {
mFlags.mCancelable = true;
}
mFlags.mBubbles = true;
break;
}
}
protected:
WidgetEvent(bool aIsTrusted,
EventMessage aMessage,
EventClassID aEventClassID)
: WidgetEventTime()
, mClass(aEventClassID)
, mMessage(aMessage)
, mRefPoint(0, 0)
, mLastRefPoint(0, 0)
, mSpecifiedEventType(nullptr)
{
MOZ_COUNT_CTOR(WidgetEvent);
mFlags.Clear();
mFlags.mIsTrusted = aIsTrusted;
SetDefaultCancelableAndBubbles();
SetDefaultComposed();
SetDefaultComposedInNativeAnonymousContent();
}
WidgetEvent()
: WidgetEventTime()
{
MOZ_COUNT_CTOR(WidgetEvent);
}
public:
WidgetEvent(bool aIsTrusted, EventMessage aMessage)
: WidgetEvent(aIsTrusted, aMessage, eBasicEventClass)
{
}
virtual ~WidgetEvent()
{
MOZ_COUNT_DTOR(WidgetEvent);
}
WidgetEvent(const WidgetEvent& aOther)
{
MOZ_COUNT_CTOR(WidgetEvent);
*this = aOther;
}
virtual WidgetEvent* Duplicate() const
{
MOZ_ASSERT(mClass == eBasicEventClass,
"Duplicate() must be overridden by sub class");
WidgetEvent* result = new WidgetEvent(false, mMessage);
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.
LayoutDeviceIntPoint mRefPoint;
// The previous mRefPoint, if known, used to calculate mouse movement deltas.
LayoutDeviceIntPoint mLastRefPoint;
// 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.
nsCOMPtr<nsIAtom> mSpecifiedEventType;
// nsIAtom 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
nsCOMPtr<dom::EventTarget> mTarget;
nsCOMPtr<dom::EventTarget> mCurrentTarget;
nsCOMPtr<dom::EventTarget> mOriginalTarget;
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.
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;
}
/**
* Helper methods for methods of DOM Event.
*/
void StopPropagation() { mFlags.StopPropagation(); }
void StopImmediatePropagation() { mFlags.StopImmediatePropagation(); }
void StopCrossProcessForwarding() { mFlags.StopCrossProcessForwarding(); }
void PreventDefault(bool aCalledByDefaultHandler = true)
{
// Legacy mouse events shouldn't be prevented on ePointerDown by default
// handlers.
MOZ_RELEASE_ASSERT(!aCalledByDefaultHandler || mMessage != ePointerDown);
mFlags.PreventDefault(aCalledByDefaultHandler);
}
void PreventDefaultBeforeDispatch() { mFlags.PreventDefaultBeforeDispatch(); }
bool DefaultPrevented() const { return mFlags.DefaultPrevented(); }
bool DefaultPreventedByContent() const
{
return mFlags.DefaultPreventedByContent();
}
bool IsTrusted() const { return mFlags.IsTrusted(); }
bool PropagationStopped() const { return mFlags.PropagationStopped(); }
/**
* 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 is a native event deliverer event for plugin.
*/
bool IsNativeEventDelivererForPlugin() 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 the event mMessage is one of key events.
*/
bool HasKeyEventMessage() const;
/**
* Returns true if the event mMessage is one of composition events or text
* event.
*/
bool HasIMEEventMessage() const;
/**
* Returns true if the event mMessage is one of plugin activation events.
*/
bool HasPluginActivationEventMessage() const;
/**
* Returns true if the event is native event deliverer event for plugin and
* it should be retarted to focused document.
*/
bool IsRetargetedNativeEventDelivererForPlugin() const;
/**
* Returns true if the event is native event deliverer event for plugin and
* it should NOT be retarted to focused document.
*/
bool IsNonRetargetedNativeEventDelivererForPlugin() 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;
/**
* Initialize mComposed
*/
void SetDefaultComposed()
{
switch (mClass) {
case eCompositionEventClass:
mFlags.mComposed = mMessage == eCompositionStart ||
mMessage == eCompositionUpdate ||
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;
break;
case eFocusEventClass:
mFlags.mComposed = mMessage == eBlur || mMessage == eFocus;
break;
case eKeyboardEventClass:
mFlags.mComposed = mMessage == eKeyDown || mMessage == eKeyUp ||
mMessage == eKeyPress;
break;
case eMouseEventClass:
mFlags.mComposed = mMessage == eMouseClick ||
mMessage == eMouseDoubleClick ||
mMessage == eMouseDown || mMessage == eMouseUp ||
mMessage == eMouseEnter || mMessage == eMouseLeave ||
mMessage == eMouseOver || mMessage == eMouseOut ||
mMessage == eMouseMove || mMessage == eContextMenu;
break;
case ePointerEventClass:
// All pointer events are composed
mFlags.mComposed = mMessage == ePointerDown ||
mMessage == ePointerMove || mMessage == ePointerUp ||
mMessage == ePointerCancel ||
mMessage == ePointerOver ||
mMessage == ePointerOut ||
mMessage == ePointerEnter ||
mMessage == ePointerLeave ||
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;
default:
mFlags.mComposed = false;
break;
}
}
void SetComposed(const nsAString& aEventTypeArg)
{
mFlags.mComposed = // composition events
aEventTypeArg.EqualsLiteral("compositionstart") ||
aEventTypeArg.EqualsLiteral("compositionupdate") ||
aEventTypeArg.EqualsLiteral("compositionend") ||
// 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;
}
};
/******************************************************************************
* mozilla::NativeEventData
*
* WidgetGUIEvent's mPluginEvent member used to be a void* pointer,
* used to reference external, OS-specific data structures.
*
* That void* pointer wasn't serializable by itself, causing
* certain plugin events not to function in e10s. See bug 586656.
*
* To make this serializable, we changed this void* pointer into
* a proper buffer, and copy these external data structures into this
* buffer.
*
* That buffer is NativeEventData::mBuffer below.
*
* We wrap this in that NativeEventData class providing operators to
* be compatible with existing code that was written around
* the old void* field.
******************************************************************************/
class NativeEventData final
{
nsTArray<uint8_t> mBuffer;
friend struct IPC::ParamTraits<mozilla::NativeEventData>;
public:
explicit operator bool() const
{
return !mBuffer.IsEmpty();
}
template<typename T>
explicit operator const T*() const
{
return mBuffer.IsEmpty()
? nullptr
: reinterpret_cast<const T*>(mBuffer.Elements());
}
template <typename T>
void Copy(const T& other)
{
static_assert(!mozilla::IsPointer<T>::value, "Don't want a pointer!");
mBuffer.SetLength(sizeof(T));
memcpy(mBuffer.Elements(), &other, mBuffer.Length());
}
void Clear()
{
mBuffer.Clear();
}
};
/******************************************************************************
* mozilla::WidgetGUIEvent
******************************************************************************/
class WidgetGUIEvent : public WidgetEvent
{
protected:
WidgetGUIEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
EventClassID aEventClassID)
: WidgetEvent(aIsTrusted, aMessage, aEventClassID)
, mWidget(aWidget)
{
}
WidgetGUIEvent()
{
}
public:
virtual WidgetGUIEvent* AsGUIEvent() override { return this; }
WidgetGUIEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget)
: WidgetEvent(aIsTrusted, aMessage, eGUIEventClass)
, 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);
result->AssignGUIEventData(*this, true);
result->mFlags = mFlags;
return result;
}
// Originator of the event
nsCOMPtr<nsIWidget> mWidget;
/*
* Ideally though, we wouldn't allow arbitrary reinterpret_cast'ing here;
* instead, we would at least store type information here so that
* this class can't be used to reinterpret one structure type into another.
* We can also wonder if it would be possible to properly extend
* WidgetGUIEvent and other Event classes to remove the need for this
* mPluginEvent field.
*/
typedef NativeEventData PluginEvent;
// Event for NPAPI plugin
PluginEvent mPluginEvent;
void AssignGUIEventData(const WidgetGUIEvent& aEvent, bool aCopyTargets)
{
AssignEventData(aEvent, aCopyTargets);
// widget should be initialized with the constructor.
mPluginEvent = aEvent.mPluginEvent;
}
};
/******************************************************************************
* 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_OS = 0x1000
};
/******************************************************************************
* 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 (aModifiers & MODIFIER_OS) {
MaybeAppendSeparator();
AppendLiteral(NS_DOM_KEYNAME_OS);
}
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)
: WidgetGUIEvent(aIsTrusted, aMessage, aWidget, aEventClassID)
, mModifiers(0)
{
}
WidgetInputEvent()
: mModifiers(0)
{
}
public:
virtual WidgetInputEvent* AsInputEvent() override { return this; }
WidgetInputEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget)
: WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eInputEventClass)
, 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);
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 (or, on Mac, the Command key)
bool IsMeta() const
{
return ((mModifiers & MODIFIER_META) != 0);
}
// true indicates the win key is down on Windows. Or the Super or Hyper key
// is down on Linux.
bool IsOS() const
{
return ((mModifiers & MODIFIER_OS) != 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)
: WidgetGUIEvent(aIsTrusted, aMessage, aWidget, aEventClassID)
, mDetail(0)
, mCausedByUntrustedEvent(false)
{
}
InternalUIEvent(bool aIsTrusted, EventMessage aMessage,
EventClassID aEventClassID)
: WidgetGUIEvent(aIsTrusted, aMessage, nullptr, aEventClassID)
, 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)
: WidgetGUIEvent(aIsTrusted, aMessage, nullptr, eUIEventClass)
, 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);
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__