1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef mozilla_BasicEvents_h__
7 #define mozilla_BasicEvents_h__
8 
9 #include <stdint.h>
10 #include <type_traits>
11 
12 #include "mozilla/EventForwards.h"
13 #include "mozilla/TimeStamp.h"
14 #include "mozilla/dom/EventTarget.h"
15 #include "mozilla/layers/LayersTypes.h"
16 #include "nsCOMPtr.h"
17 #include "nsAtom.h"
18 #include "nsISupportsImpl.h"
19 #include "nsIWidget.h"
20 #include "nsString.h"
21 #include "Units.h"
22 
23 #ifdef DEBUG
24 #  include "nsXULAppAPI.h"
25 #endif  // #ifdef DEBUG
26 
27 class nsIPrincipal;
28 
29 namespace IPC {
30 template <typename T>
31 struct ParamTraits;
32 }  // namespace IPC
33 
34 namespace mozilla {
35 
36 class EventTargetChainItem;
37 
38 enum class CrossProcessForwarding {
39   // eStop prevents the event to be sent to remote process.
40   eStop,
41   // eAllow keeps current state of the event whether it's sent to remote
42   // process.  In other words, eAllow does NOT mean that making the event
43   // sent to remote process when IsCrossProcessForwardingStopped() returns
44   // true.
45   eAllow,
46 };
47 
48 /******************************************************************************
49  * mozilla::BaseEventFlags
50  *
51  * BaseEventFlags must be a POD struct for safe to use memcpy (including
52  * in ParamTraits<BaseEventFlags>).  So don't make virtual methods, constructor,
53  * destructor and operators.
54  * This is necessary for VC which is NOT C++0x compiler.
55  ******************************************************************************/
56 
57 struct BaseEventFlags {
58  public:
59   // If mIsTrusted is true, the event is a trusted event.  Otherwise, it's
60   // an untrusted event.
61   bool mIsTrusted : 1;
62   // If mInBubblingPhase is true, the event is in bubbling phase or target
63   // phase.
64   bool mInBubblingPhase : 1;
65   // If mInCapturePhase is true, the event is in capture phase or target phase.
66   bool mInCapturePhase : 1;
67   // If mInSystemGroup is true, the event is being dispatched in system group.
68   bool mInSystemGroup : 1;
69   // If mCancelable is true, the event can be consumed.  I.e., calling
70   // dom::Event::PreventDefault() can prevent the default action.
71   bool mCancelable : 1;
72   // If mBubbles is true, the event can bubble.  Otherwise, cannot be handled
73   // in bubbling phase.
74   bool mBubbles : 1;
75   // If mPropagationStopped is true, dom::Event::StopPropagation() or
76   // dom::Event::StopImmediatePropagation() has been called.
77   bool mPropagationStopped : 1;
78   // If mImmediatePropagationStopped is true,
79   // dom::Event::StopImmediatePropagation() has been called.
80   // Note that mPropagationStopped must be true when this is true.
81   bool mImmediatePropagationStopped : 1;
82   // If mDefaultPrevented is true, the event has been consumed.
83   // E.g., dom::Event::PreventDefault() has been called or
84   // the default action has been performed.
85   bool mDefaultPrevented : 1;
86   // If mDefaultPreventedByContent is true, the event has been
87   // consumed by content.
88   // Note that mDefaultPrevented must be true when this is true.
89   bool mDefaultPreventedByContent : 1;
90   // If mDefaultPreventedByChrome is true, the event has been
91   // consumed by chrome.
92   // Note that mDefaultPrevented must be true when this is true.
93   bool mDefaultPreventedByChrome : 1;
94   // mMultipleActionsPrevented may be used when default handling don't want to
95   // be prevented, but only one of the event targets should handle the event.
96   // For example, when a <label> element is in another <label> element and
97   // the first <label> element is clicked, that one may set this true.
98   // Then, the second <label> element won't handle the event.
99   bool mMultipleActionsPrevented : 1;
100   // Similar to above but expected to be used during PreHandleEvent phase.
101   bool mMultiplePreActionsPrevented : 1;
102   // If mIsBeingDispatched is true, the DOM event created from the event is
103   // dispatching into the DOM tree and not completed.
104   bool mIsBeingDispatched : 1;
105   // If mDispatchedAtLeastOnce is true, the event has been dispatched
106   // as a DOM event and the dispatch has been completed in the process.
107   // So, this is false even if the event has already been dispatched
108   // in another process.
109   bool mDispatchedAtLeastOnce : 1;
110   // If mIsSynthesizedForTests is true, the event has been synthesized for
111   // automated tests or something hacky approach of an add-on.
112   bool mIsSynthesizedForTests : 1;
113   // If mExceptionWasRaised is true, one of the event handlers has raised an
114   // exception.
115   bool mExceptionWasRaised : 1;
116   // If mRetargetToNonNativeAnonymous is true and the target is in a non-native
117   // native anonymous subtree, the event target is set to mOriginalTarget.
118   bool mRetargetToNonNativeAnonymous : 1;
119   // If mNoContentDispatch is true, the event is never dispatched to the
120   // event handlers which are added to the contents, onfoo attributes and
121   // properties.  Note that this flag is ignored when
122   // EventChainPreVisitor::mForceContentDispatch is set true.  For exapmle,
123   // window and document object sets it true.  Therefore, web applications
124   // can handle the event if they add event listeners to the window or the
125   // document.
126   // XXX This is an ancient and broken feature, don't use this for new bug
127   //     as far as possible.
128   bool mNoContentDispatch : 1;
129   // If mOnlyChromeDispatch is true, the event is dispatched to only chrome.
130   bool mOnlyChromeDispatch : 1;
131   // Indicates if the key combination is reserved by chrome.  This is set by
132   // MarkAsReservedByChrome().
133   bool mIsReservedByChrome : 1;
134   // If mOnlySystemGroupDispatchInContent is true, event listeners added to
135   // the default group for non-chrome EventTarget won't be called.
136   // Be aware, if this is true, EventDispatcher needs to check if each event
137   // listener is added to chrome node, so, don't set this to true for the
138   // events which are fired a lot of times like eMouseMove.
139   bool mOnlySystemGroupDispatchInContent : 1;
140   // If mOnlySystemGroupDispatch is true, the event will be dispatched only to
141   // event listeners added in the system group.
142   bool mOnlySystemGroupDispatch : 1;
143   // The event's action will be handled by APZ. The main thread should not
144   // perform its associated action.
145   bool mHandledByAPZ : 1;
146   // True if the event is currently being handled by an event listener that
147   // was registered as a passive listener.
148   bool mInPassiveListener : 1;
149   // If mComposed is true, the event fired by nodes in shadow DOM can cross the
150   // boundary of shadow DOM and light DOM.
151   bool mComposed : 1;
152   // Similar to mComposed. Set it to true to allow events cross the boundary
153   // between native non-anonymous content and native anonymouse content
154   bool mComposedInNativeAnonymousContent : 1;
155   // Set to true for events which are suppressed or delayed so that later a
156   // DelayedEvent of it is dispatched. This is used when parent side process
157   // the key event after content side, and may drop the event if the event
158   // was suppressed or delayed in contents side.
159   // It is also set to true for the events (in a DelayedInputEvent), which will
160   // be dispatched afterwards.
161   bool mIsSuppressedOrDelayed : 1;
162   // Certain mouse events can be marked as positionless to return 0 from
163   // coordinate related getters.
164   bool mIsPositionless : 1;
165 
166   // Flags managing state of propagation between processes.
167   // Note the the following flags shouldn't be referred directly.  Use utility
168   // methods instead.
169 
170   // If mNoRemoteProcessDispatch is true, the event is not allowed to be sent
171   // to remote process.
172   bool mNoRemoteProcessDispatch : 1;
173   // If mWantReplyFromContentProcess is true, the event will be redispatched
174   // in the parent process after the content process has handled it. Useful
175   // for when the parent process need the know first how the event was used
176   // by content before handling it itself.
177   bool mWantReplyFromContentProcess : 1;
178   // If mPostedToRemoteProcess is true, the event has been posted to the
179   // remote process (but it's not handled yet if it's not a duplicated event
180   // instance).
181   bool mPostedToRemoteProcess : 1;
182   // If mCameFromAnotherProcess is true, the event came from another process.
183   bool mCameFromAnotherProcess : 1;
184 
185   // At lease one of the event in the event path had non privileged click
186   // listener.
187   bool mHadNonPrivilegedClickListeners : 1;
188 
189   // If the event is being handled in target phase, returns true.
InTargetPhaseBaseEventFlags190   inline bool InTargetPhase() const {
191     return (mInBubblingPhase && mInCapturePhase);
192   }
193 
194   /**
195    * Helper methods for methods of DOM Event.
196    */
StopPropagationBaseEventFlags197   inline void StopPropagation() { mPropagationStopped = true; }
StopImmediatePropagationBaseEventFlags198   inline void StopImmediatePropagation() {
199     StopPropagation();
200     mImmediatePropagationStopped = true;
201   }
202   inline void PreventDefault(bool aCalledByDefaultHandler = true) {
203     if (!mCancelable) {
204       return;
205     }
206     mDefaultPrevented = true;
207     // Note that even if preventDefault() has already been called by chrome,
208     // a call of preventDefault() by content needs to overwrite
209     // mDefaultPreventedByContent to true because in such case, defaultPrevented
210     // must be true when web apps check it after they call preventDefault().
211     if (aCalledByDefaultHandler) {
212       StopCrossProcessForwarding();
213       mDefaultPreventedByChrome = true;
214     } else {
215       mDefaultPreventedByContent = true;
216     }
217   }
218   // This should be used only before dispatching events into the DOM tree.
PreventDefaultBeforeDispatchBaseEventFlags219   inline void PreventDefaultBeforeDispatch(
220       CrossProcessForwarding aCrossProcessForwarding) {
221     if (!mCancelable) {
222       return;
223     }
224     mDefaultPrevented = true;
225     if (aCrossProcessForwarding == CrossProcessForwarding::eStop) {
226       StopCrossProcessForwarding();
227     }
228   }
DefaultPreventedBaseEventFlags229   inline bool DefaultPrevented() const { return mDefaultPrevented; }
DefaultPreventedByContentBaseEventFlags230   inline bool DefaultPreventedByContent() const {
231     MOZ_ASSERT(!mDefaultPreventedByContent || DefaultPrevented());
232     return mDefaultPreventedByContent;
233   }
IsTrustedBaseEventFlags234   inline bool IsTrusted() const { return mIsTrusted; }
PropagationStoppedBaseEventFlags235   inline bool PropagationStopped() const { return mPropagationStopped; }
236 
237   // Helper methods to access flags managing state of propagation between
238   // processes.
239 
240   /**
241    * Prevent to be dispatched to remote process.
242    */
StopCrossProcessForwardingBaseEventFlags243   inline void StopCrossProcessForwarding() {
244     MOZ_ASSERT(!mPostedToRemoteProcess);
245     mNoRemoteProcessDispatch = true;
246     mWantReplyFromContentProcess = false;
247   }
248   /**
249    * Return true if the event shouldn't be dispatched to remote process.
250    */
IsCrossProcessForwardingStoppedBaseEventFlags251   inline bool IsCrossProcessForwardingStopped() const {
252     return mNoRemoteProcessDispatch;
253   }
254   /**
255    * Mark the event as waiting reply from remote process.
256    * If the caller needs to win other keyboard event handlers in chrome,
257    * the caller should call StopPropagation() too.
258    * Otherwise, if the caller just needs to know if the event is consumed by
259    * either content or chrome, it should just call this because the event
260    * may be reserved by chrome and it needs to be dispatched into the DOM
261    * tree in chrome for checking if it's reserved before being sent to any
262    * remote processes.
263    */
MarkAsWaitingReplyFromRemoteProcessBaseEventFlags264   inline void MarkAsWaitingReplyFromRemoteProcess() {
265     MOZ_ASSERT(!mPostedToRemoteProcess);
266     mNoRemoteProcessDispatch = false;
267     mWantReplyFromContentProcess = true;
268   }
269   /**
270    * Reset "waiting reply from remote process" state.  This is useful when
271    * you dispatch a copy of an event coming from different process.
272    */
ResetWaitingReplyFromRemoteProcessStateBaseEventFlags273   inline void ResetWaitingReplyFromRemoteProcessState() {
274     if (IsWaitingReplyFromRemoteProcess()) {
275       // FYI: mWantReplyFromContentProcess is also used for indicating
276       //      "handled in remote process" state.  Therefore, only when
277       //      IsWaitingReplyFromRemoteProcess() returns true, this should
278       //      reset the flag.
279       mWantReplyFromContentProcess = false;
280     }
281   }
282   /**
283    * Return true if the event handler should wait reply event.  I.e., if this
284    * returns true, any event handler should do nothing with the event.
285    */
IsWaitingReplyFromRemoteProcessBaseEventFlags286   inline bool IsWaitingReplyFromRemoteProcess() const {
287     return !mNoRemoteProcessDispatch && mWantReplyFromContentProcess;
288   }
289   /**
290    * Mark the event as already handled in the remote process.  This should be
291    * called when initializing reply events.
292    */
MarkAsHandledInRemoteProcessBaseEventFlags293   inline void MarkAsHandledInRemoteProcess() {
294     mNoRemoteProcessDispatch = true;
295     mWantReplyFromContentProcess = true;
296     mPostedToRemoteProcess = false;
297   }
298   /**
299    * Return true if the event has already been handled in the remote process.
300    */
IsHandledInRemoteProcessBaseEventFlags301   inline bool IsHandledInRemoteProcess() const {
302     return mNoRemoteProcessDispatch && mWantReplyFromContentProcess;
303   }
304   /**
305    * Return true if the event should be sent back to its parent process.
306    */
WantReplyFromContentProcessBaseEventFlags307   inline bool WantReplyFromContentProcess() const {
308     MOZ_ASSERT(!XRE_IsParentProcess());
309     return IsWaitingReplyFromRemoteProcess();
310   }
311   /**
312    * Mark the event has already posted to a remote process.
313    */
MarkAsPostedToRemoteProcessBaseEventFlags314   inline void MarkAsPostedToRemoteProcess() {
315     MOZ_ASSERT(!IsCrossProcessForwardingStopped());
316     mPostedToRemoteProcess = true;
317   }
318   /**
319    * Reset the cross process dispatching state.  This should be used when a
320    * process receives the event because the state is in the sender.
321    */
ResetCrossProcessDispatchingStateBaseEventFlags322   inline void ResetCrossProcessDispatchingState() {
323     MOZ_ASSERT(!IsCrossProcessForwardingStopped());
324     mPostedToRemoteProcess = false;
325     // Ignore propagation state in the different process if it's marked as
326     // "waiting reply from remote process" because the process needs to
327     // stop propagation in the process until receiving a reply event.
328     if (IsWaitingReplyFromRemoteProcess()) {
329       mPropagationStopped = mImmediatePropagationStopped = false;
330     }
331     // mDispatchedAtLeastOnce indicates the state in current process.
332     mDispatchedAtLeastOnce = false;
333   }
334   /**
335    * Return true if the event has been posted to a remote process.
336    * Note that MarkAsPostedToRemoteProcess() is called by
337    * ParamTraits<mozilla::WidgetEvent>.  Therefore, it *might* be possible
338    * that posting the event failed even if this returns true.  But that must
339    * really rare.  If that'd be problem for you, you should unmark this in
340    * BrowserParent or somewhere.
341    */
HasBeenPostedToRemoteProcessBaseEventFlags342   inline bool HasBeenPostedToRemoteProcess() const {
343     return mPostedToRemoteProcess;
344   }
345   /**
346    * Return true if the event came from another process.
347    */
CameFromAnotherProcessBaseEventFlags348   inline bool CameFromAnotherProcess() const { return mCameFromAnotherProcess; }
349   /**
350    * Mark the event as coming from another process.
351    */
MarkAsComingFromAnotherProcessBaseEventFlags352   inline void MarkAsComingFromAnotherProcess() {
353     mCameFromAnotherProcess = true;
354   }
355   /**
356    * Mark the event is reserved by chrome.  I.e., shouldn't be dispatched to
357    * content because it shouldn't be cancelable.
358    */
MarkAsReservedByChromeBaseEventFlags359   inline void MarkAsReservedByChrome() {
360     MOZ_ASSERT(!mPostedToRemoteProcess);
361     mIsReservedByChrome = true;
362     // For reserved commands (such as Open New Tab), we don't need to wait for
363     // the content to answer, neither to give a chance for content to override
364     // its behavior.
365     StopCrossProcessForwarding();
366     // If the event is reserved by chrome, we shouldn't expose the event to
367     // web contents because such events shouldn't be cancelable.  So, it's not
368     // good behavior to fire such events but to ignore the defaultPrevented
369     // attribute value in chrome.
370     mOnlySystemGroupDispatchInContent = true;
371   }
372   /**
373    * Return true if the event is reserved by chrome.
374    */
IsReservedByChromeBaseEventFlags375   inline bool IsReservedByChrome() const {
376     MOZ_ASSERT(!mIsReservedByChrome || (IsCrossProcessForwardingStopped() &&
377                                         mOnlySystemGroupDispatchInContent));
378     return mIsReservedByChrome;
379   }
380 
ClearBaseEventFlags381   inline void Clear() { SetRawFlags(0); }
382   // Get if either the instance's bit or the aOther's bit is true, the
383   // instance's bit becomes true.  In other words, this works like:
384   // eventFlags |= aOther;
UnionBaseEventFlags385   inline void Union(const BaseEventFlags& aOther) {
386     RawFlags rawFlags = GetRawFlags() | aOther.GetRawFlags();
387     SetRawFlags(rawFlags);
388   }
389 
390  private:
391   typedef uint64_t RawFlags;
392 
SetRawFlagsBaseEventFlags393   inline void SetRawFlags(RawFlags aRawFlags) {
394     static_assert(sizeof(BaseEventFlags) <= sizeof(RawFlags),
395                   "mozilla::EventFlags must not be bigger than the RawFlags");
396     memcpy(this, &aRawFlags, sizeof(BaseEventFlags));
397   }
GetRawFlagsBaseEventFlags398   inline RawFlags GetRawFlags() const {
399     RawFlags result = 0;
400     memcpy(&result, this, sizeof(BaseEventFlags));
401     return result;
402   }
403 };
404 
405 /******************************************************************************
406  * mozilla::EventFlags
407  ******************************************************************************/
408 
409 struct EventFlags : public BaseEventFlags {
EventFlagsEventFlags410   EventFlags() { Clear(); }
411 };
412 
413 /******************************************************************************
414  * mozilla::WidgetEventTime
415  ******************************************************************************/
416 
417 class WidgetEventTime {
418  public:
419   // Elapsed time, in milliseconds, from a platform-specific zero time
420   // to the time the message was created
421   uint64_t mTime;
422   // Timestamp when the message was created. Set in parallel to 'time' until we
423   // determine if it is safe to drop 'time' (see bug 77992).
424   TimeStamp mTimeStamp;
425 
WidgetEventTime()426   WidgetEventTime() : mTime(0), mTimeStamp(TimeStamp::Now()) {}
427 
WidgetEventTime(uint64_t aTime,TimeStamp aTimeStamp)428   WidgetEventTime(uint64_t aTime, TimeStamp aTimeStamp)
429       : mTime(aTime), mTimeStamp(aTimeStamp) {}
430 
AssignEventTime(const WidgetEventTime & aOther)431   void AssignEventTime(const WidgetEventTime& aOther) {
432     mTime = aOther.mTime;
433     mTimeStamp = aOther.mTimeStamp;
434   }
435 };
436 
437 /******************************************************************************
438  * mozilla::WidgetEvent
439  ******************************************************************************/
440 
441 class WidgetEvent : public WidgetEventTime {
442  private:
SetDefaultCancelableAndBubbles()443   void SetDefaultCancelableAndBubbles() {
444     switch (mClass) {
445       case eEditorInputEventClass:
446         mFlags.mCancelable = false;
447         mFlags.mBubbles = mFlags.mIsTrusted;
448         break;
449       case eMouseEventClass:
450         mFlags.mCancelable =
451             (mMessage != eMouseEnter && mMessage != eMouseLeave);
452         mFlags.mBubbles = (mMessage != eMouseEnter && mMessage != eMouseLeave);
453         break;
454       case ePointerEventClass:
455         mFlags.mCancelable =
456             (mMessage != ePointerEnter && mMessage != ePointerLeave &&
457              mMessage != ePointerCancel && mMessage != ePointerGotCapture &&
458              mMessage != ePointerLostCapture);
459         mFlags.mBubbles =
460             (mMessage != ePointerEnter && mMessage != ePointerLeave);
461         break;
462       case eDragEventClass:
463         mFlags.mCancelable = (mMessage != eDragExit && mMessage != eDragLeave &&
464                               mMessage != eDragEnd);
465         mFlags.mBubbles = true;
466         break;
467       case eSMILTimeEventClass:
468         mFlags.mCancelable = false;
469         mFlags.mBubbles = false;
470         break;
471       case eTransitionEventClass:
472       case eAnimationEventClass:
473         mFlags.mCancelable = false;
474         mFlags.mBubbles = true;
475         break;
476       case eCompositionEventClass:
477         // XXX compositionstart is cancelable in draft of DOM3 Events.
478         //     However, it doesn't make sense for us, we cannot cancel
479         //     composition when we send compositionstart event.
480         mFlags.mCancelable = false;
481         mFlags.mBubbles = true;
482         break;
483       default:
484         if (mMessage == eResize || mMessage == eMozVisualResize ||
485             mMessage == eMozVisualScroll || mMessage == eEditorInput ||
486             mMessage == eFormSelect) {
487           mFlags.mCancelable = false;
488         } else {
489           mFlags.mCancelable = true;
490         }
491         mFlags.mBubbles = true;
492         break;
493     }
494   }
495 
496  protected:
WidgetEvent(bool aIsTrusted,EventMessage aMessage,EventClassID aEventClassID)497   WidgetEvent(bool aIsTrusted, EventMessage aMessage,
498               EventClassID aEventClassID)
499       : WidgetEventTime(),
500         mClass(aEventClassID),
501         mMessage(aMessage),
502         mRefPoint(0, 0),
503         mLastRefPoint(0, 0),
504         mFocusSequenceNumber(0),
505         mSpecifiedEventType(nullptr),
506         mPath(nullptr),
507         mLayersId(layers::LayersId{0}) {
508     MOZ_COUNT_CTOR(WidgetEvent);
509     mFlags.Clear();
510     mFlags.mIsTrusted = aIsTrusted;
511     SetDefaultCancelableAndBubbles();
512     SetDefaultComposed();
513     SetDefaultComposedInNativeAnonymousContent();
514   }
515 
WidgetEvent()516   WidgetEvent() : WidgetEventTime(), mPath(nullptr) {
517     MOZ_COUNT_CTOR(WidgetEvent);
518   }
519 
520  public:
WidgetEvent(bool aIsTrusted,EventMessage aMessage)521   WidgetEvent(bool aIsTrusted, EventMessage aMessage)
522       : WidgetEvent(aIsTrusted, aMessage, eBasicEventClass) {}
523 
524   MOZ_COUNTED_DTOR_VIRTUAL(WidgetEvent)
525 
WidgetEvent(const WidgetEvent & aOther)526   WidgetEvent(const WidgetEvent& aOther) : WidgetEventTime() {
527     MOZ_COUNT_CTOR(WidgetEvent);
528     *this = aOther;
529   }
530   WidgetEvent& operator=(const WidgetEvent& aOther) = default;
531 
WidgetEvent(WidgetEvent && aOther)532   WidgetEvent(WidgetEvent&& aOther)
533       : WidgetEventTime(std::move(aOther)),
534         mClass(aOther.mClass),
535         mMessage(aOther.mMessage),
536         mRefPoint(std::move(aOther.mRefPoint)),
537         mLastRefPoint(std::move(aOther.mLastRefPoint)),
538         mFocusSequenceNumber(aOther.mFocusSequenceNumber),
539         mFlags(std::move(aOther.mFlags)),
540         mSpecifiedEventType(std::move(aOther.mSpecifiedEventType)),
541         mSpecifiedEventTypeString(std::move(aOther.mSpecifiedEventTypeString)),
542         mTarget(std::move(aOther.mTarget)),
543         mCurrentTarget(std::move(aOther.mCurrentTarget)),
544         mOriginalTarget(std::move(aOther.mOriginalTarget)),
545         mRelatedTarget(std::move(aOther.mRelatedTarget)),
546         mOriginalRelatedTarget(std::move(aOther.mOriginalRelatedTarget)),
547         mPath(std::move(aOther.mPath)) {
548     MOZ_COUNT_CTOR(WidgetEvent);
549   }
550   WidgetEvent& operator=(WidgetEvent&& aOther) = default;
551 
Duplicate()552   virtual WidgetEvent* Duplicate() const {
553     MOZ_ASSERT(mClass == eBasicEventClass,
554                "Duplicate() must be overridden by sub class");
555     WidgetEvent* result = new WidgetEvent(false, mMessage);
556     result->AssignEventData(*this, true);
557     result->mFlags = mFlags;
558     return result;
559   }
560 
561   EventClassID mClass;
562   EventMessage mMessage;
563   // Relative to the widget of the event, or if there is no widget then it is
564   // in screen coordinates. Not modified by layout code.
565   // This is in visual coordinates, i.e. the correct RelativeTo value that
566   // expresses what this is relative to is `{viewportFrame, Visual}`, where
567   // `viewportFrame` is the viewport frame of the widget's root document.
568   LayoutDeviceIntPoint mRefPoint;
569   // The previous mRefPoint, if known, used to calculate mouse movement deltas.
570   LayoutDeviceIntPoint mLastRefPoint;
571   // The sequence number of the last potentially focus changing event handled
572   // by APZ. This is used to track when that event has been processed by
573   // content, and focus can be reconfirmed for async keyboard scrolling.
574   uint64_t mFocusSequenceNumber;
575   // See BaseEventFlags definition for the detail.
576   BaseEventFlags mFlags;
577 
578   // If JS creates an event with unknown event type or known event type but
579   // for different event interface, the event type is stored to this.
580   // NOTE: This is always used if the instance is a WidgetCommandEvent instance
581   //       or "input" event is dispatched with dom::Event class.
582   RefPtr<nsAtom> mSpecifiedEventType;
583 
584   // nsAtom isn't available on non-main thread due to unsafe.  Therefore,
585   // mSpecifiedEventTypeString is used instead of mSpecifiedEventType if
586   // the event is created in non-main thread.
587   nsString mSpecifiedEventTypeString;
588 
589   // Event targets, needed by DOM Events
590   // Note that when you need event target for DOM event, you should use
591   // Get*DOMEventTarget() instead of accessing these members directly.
592   nsCOMPtr<dom::EventTarget> mTarget;
593   nsCOMPtr<dom::EventTarget> mCurrentTarget;
594   nsCOMPtr<dom::EventTarget> mOriginalTarget;
595 
596   /// The possible related target
597   nsCOMPtr<dom::EventTarget> mRelatedTarget;
598   nsCOMPtr<dom::EventTarget> mOriginalRelatedTarget;
599 
600   nsTArray<EventTargetChainItem>* mPath;
601 
602   // The LayersId of the content process that this event should be
603   // dispatched to. This field is only used in the chrome process
604   // and doesn't get remoted to child processes.
605   layers::LayersId mLayersId;
606 
607   dom::EventTarget* GetDOMEventTarget() const;
608   dom::EventTarget* GetCurrentDOMEventTarget() const;
609   dom::EventTarget* GetOriginalDOMEventTarget() const;
610 
AssignEventData(const WidgetEvent & aEvent,bool aCopyTargets)611   void AssignEventData(const WidgetEvent& aEvent, bool aCopyTargets) {
612     // mClass should be initialized with the constructor.
613     // mMessage should be initialized with the constructor.
614     mRefPoint = aEvent.mRefPoint;
615     // mLastRefPoint doesn't need to be copied.
616     mFocusSequenceNumber = aEvent.mFocusSequenceNumber;
617     // mLayersId intentionally not copied, since it's not used within content
618     AssignEventTime(aEvent);
619     // mFlags should be copied manually if it's necessary.
620     mSpecifiedEventType = aEvent.mSpecifiedEventType;
621     // mSpecifiedEventTypeString should be copied manually if it's necessary.
622     mTarget = aCopyTargets ? aEvent.mTarget : nullptr;
623     mCurrentTarget = aCopyTargets ? aEvent.mCurrentTarget : nullptr;
624     mOriginalTarget = aCopyTargets ? aEvent.mOriginalTarget : nullptr;
625     mRelatedTarget = aCopyTargets ? aEvent.mRelatedTarget : nullptr;
626     mOriginalRelatedTarget =
627         aCopyTargets ? aEvent.mOriginalRelatedTarget : nullptr;
628   }
629 
630   /**
631    * Helper methods for methods of DOM Event.
632    */
StopPropagation()633   void StopPropagation() { mFlags.StopPropagation(); }
StopImmediatePropagation()634   void StopImmediatePropagation() { mFlags.StopImmediatePropagation(); }
635   void PreventDefault(bool aCalledByDefaultHandler = true,
636                       nsIPrincipal* aPrincipal = nullptr);
637 
PreventDefaultBeforeDispatch(CrossProcessForwarding aCrossProcessForwarding)638   void PreventDefaultBeforeDispatch(
639       CrossProcessForwarding aCrossProcessForwarding) {
640     mFlags.PreventDefaultBeforeDispatch(aCrossProcessForwarding);
641   }
DefaultPrevented()642   bool DefaultPrevented() const { return mFlags.DefaultPrevented(); }
DefaultPreventedByContent()643   bool DefaultPreventedByContent() const {
644     return mFlags.DefaultPreventedByContent();
645   }
IsTrusted()646   bool IsTrusted() const { return mFlags.IsTrusted(); }
PropagationStopped()647   bool PropagationStopped() const { return mFlags.PropagationStopped(); }
648 
649   /**
650    * Prevent to be dispatched to remote process.
651    */
StopCrossProcessForwarding()652   inline void StopCrossProcessForwarding() {
653     mFlags.StopCrossProcessForwarding();
654   }
655   /**
656    * Return true if the event shouldn't be dispatched to remote process.
657    */
IsCrossProcessForwardingStopped()658   inline bool IsCrossProcessForwardingStopped() const {
659     return mFlags.IsCrossProcessForwardingStopped();
660   }
661   /**
662    * Mark the event as waiting reply from remote process.
663    * Note that this also stops immediate propagation in current process.
664    */
MarkAsWaitingReplyFromRemoteProcess()665   inline void MarkAsWaitingReplyFromRemoteProcess() {
666     mFlags.MarkAsWaitingReplyFromRemoteProcess();
667   }
668   /**
669    * Reset "waiting reply from remote process" state.  This is useful when
670    * you dispatch a copy of an event coming from different process.
671    */
ResetWaitingReplyFromRemoteProcessState()672   inline void ResetWaitingReplyFromRemoteProcessState() {
673     mFlags.ResetWaitingReplyFromRemoteProcessState();
674   }
675   /**
676    * Return true if the event handler should wait reply event.  I.e., if this
677    * returns true, any event handler should do nothing with the event.
678    */
IsWaitingReplyFromRemoteProcess()679   inline bool IsWaitingReplyFromRemoteProcess() const {
680     return mFlags.IsWaitingReplyFromRemoteProcess();
681   }
682   /**
683    * Mark the event as already handled in the remote process.  This should be
684    * called when initializing reply events.
685    */
MarkAsHandledInRemoteProcess()686   inline void MarkAsHandledInRemoteProcess() {
687     mFlags.MarkAsHandledInRemoteProcess();
688   }
689   /**
690    * Return true if the event has already been handled in the remote process.
691    * I.e., if this returns true, the event is a reply event.
692    */
IsHandledInRemoteProcess()693   inline bool IsHandledInRemoteProcess() const {
694     return mFlags.IsHandledInRemoteProcess();
695   }
696   /**
697    * Return true if the event should be sent back to its parent process.
698    * So, usual event handlers shouldn't call this.
699    */
WantReplyFromContentProcess()700   inline bool WantReplyFromContentProcess() const {
701     return mFlags.WantReplyFromContentProcess();
702   }
703   /**
704    * Mark the event has already posted to a remote process.
705    */
MarkAsPostedToRemoteProcess()706   inline void MarkAsPostedToRemoteProcess() {
707     mFlags.MarkAsPostedToRemoteProcess();
708   }
709   /**
710    * Reset the cross process dispatching state.  This should be used when a
711    * process receives the event because the state is in the sender.
712    */
ResetCrossProcessDispatchingState()713   inline void ResetCrossProcessDispatchingState() {
714     mFlags.ResetCrossProcessDispatchingState();
715   }
716   /**
717    * Return true if the event has been posted to a remote process.
718    */
HasBeenPostedToRemoteProcess()719   inline bool HasBeenPostedToRemoteProcess() const {
720     return mFlags.HasBeenPostedToRemoteProcess();
721   }
722   /**
723    * Return true if the event came from another process.
724    */
CameFromAnotherProcess()725   inline bool CameFromAnotherProcess() const {
726     return mFlags.CameFromAnotherProcess();
727   }
728   /**
729    * Mark the event as coming from another process.
730    */
MarkAsComingFromAnotherProcess()731   inline void MarkAsComingFromAnotherProcess() {
732     mFlags.MarkAsComingFromAnotherProcess();
733   }
734   /**
735    * Mark the event is reserved by chrome.  I.e., shouldn't be dispatched to
736    * content because it shouldn't be cancelable.
737    */
MarkAsReservedByChrome()738   inline void MarkAsReservedByChrome() { mFlags.MarkAsReservedByChrome(); }
739   /**
740    * Return true if the event is reserved by chrome.
741    */
IsReservedByChrome()742   inline bool IsReservedByChrome() const { return mFlags.IsReservedByChrome(); }
743 
744   /**
745    * Utils for checking event types
746    */
747 
748   /**
749    * As*Event() returns the pointer of the instance only when the instance is
750    * the class or one of its derived class.
751    */
752 #define NS_ROOT_EVENT_CLASS(aPrefix, aName)
753 #define NS_EVENT_CLASS(aPrefix, aName) \
754   virtual aPrefix##aName* As##aName(); \
755   const aPrefix##aName* As##aName() const;
756 
757 #include "mozilla/EventClassList.h"
758 
759 #undef NS_EVENT_CLASS
760 #undef NS_ROOT_EVENT_CLASS
761 
762   /**
763    * Returns true if the event is a query content event.
764    */
765   bool IsQueryContentEvent() const;
766   /**
767    * Returns true if the event is a selection event.
768    */
769   bool IsSelectionEvent() const;
770   /**
771    * Returns true if the event is a content command event.
772    */
773   bool IsContentCommandEvent() const;
774 
775   /**
776    * Returns true if the event mMessage is one of mouse events.
777    */
778   bool HasMouseEventMessage() const;
779   /**
780    * Returns true if the event mMessage is one of drag events.
781    */
782   bool HasDragEventMessage() const;
783   /**
784    * Returns true if aMessage or mMessage is one of key events.
785    */
786   static bool IsKeyEventMessage(EventMessage aMessage);
HasKeyEventMessage()787   bool HasKeyEventMessage() const { return IsKeyEventMessage(mMessage); }
788   /**
789    * Returns true if the event mMessage is one of composition events or text
790    * event.
791    */
792   bool HasIMEEventMessage() const;
793   /**
794    * Returns true if the event mMessage is one of plugin activation events.
795    */
796   bool HasPluginActivationEventMessage() const;
797 
798   /**
799    * Returns true if the event can be sent to remote process.
800    */
801   bool CanBeSentToRemoteProcess() const;
802   /**
803    * Returns true if the original target is a remote process and the event
804    * will be posted to the remote process later.
805    */
806   bool WillBeSentToRemoteProcess() const;
807   /**
808    * Returns true if the event is related to IME handling.  It includes
809    * IME events, query content events and selection events.
810    * Be careful when you use this.
811    */
812   bool IsIMERelatedEvent() const;
813 
814   /**
815    * Whether the event should be handled by the frame of the mouse cursor
816    * position or not.  When it should be handled there (e.g., the mouse events),
817    * this returns true.
818    */
819   bool IsUsingCoordinates() const;
820   /**
821    * Whether the event should be handled by the focused DOM window in the
822    * same top level window's or not.  E.g., key events, IME related events
823    * (including the query content events, they are used in IME transaction)
824    * should be handled by the (last) focused window rather than the dispatched
825    * window.
826    *
827    * NOTE: Even if this returns true, the event isn't going to be handled by the
828    * application level active DOM window which is on another top level window.
829    * So, when the event is fired on a deactive window, the event is going to be
830    * handled by the last focused DOM window in the last focused window.
831    */
832   bool IsTargetedAtFocusedWindow() const;
833   /**
834    * Whether the event should be handled by the focused content or not.  E.g.,
835    * key events, IME related events and other input events which are not handled
836    * by the frame of the mouse cursor position.
837    *
838    * NOTE: Even if this returns true, the event isn't going to be handled by the
839    * application level active DOM window which is on another top level window.
840    * So, when the event is fired on a deactive window, the event is going to be
841    * handled by the last focused DOM element of the last focused DOM window in
842    * the last focused window.
843    */
844   bool IsTargetedAtFocusedContent() const;
845   /**
846    * Whether the event should cause a DOM event.
847    */
848   bool IsAllowedToDispatchDOMEvent() const;
849   /**
850    * Whether the event should be dispatched in system group.
851    */
852   bool IsAllowedToDispatchInSystemGroup() const;
853   /**
854    * Whether the event should be blocked for fingerprinting resistance.
855    */
856   bool IsBlockedForFingerprintingResistance() const;
857   /**
858    * Initialize mComposed
859    */
SetDefaultComposed()860   void SetDefaultComposed() {
861     switch (mClass) {
862       case eClipboardEventClass:
863         mFlags.mComposed = true;
864         break;
865       case eCompositionEventClass:
866         mFlags.mComposed =
867             mMessage == eCompositionStart || mMessage == eCompositionUpdate ||
868             mMessage == eCompositionChange || mMessage == eCompositionEnd;
869         break;
870       case eDragEventClass:
871         // All drag & drop events are composed
872         mFlags.mComposed = mMessage == eDrag || mMessage == eDragEnd ||
873                            mMessage == eDragEnter || mMessage == eDragExit ||
874                            mMessage == eDragLeave || mMessage == eDragOver ||
875                            mMessage == eDragStart || mMessage == eDrop;
876         break;
877       case eEditorInputEventClass:
878         mFlags.mComposed =
879             mMessage == eEditorInput || mMessage == eEditorBeforeInput;
880         break;
881       case eFocusEventClass:
882         mFlags.mComposed = mMessage == eBlur || mMessage == eFocus ||
883                            mMessage == eFocusOut || mMessage == eFocusIn;
884         break;
885       case eKeyboardEventClass:
886         mFlags.mComposed =
887             mMessage == eKeyDown || mMessage == eKeyUp || mMessage == eKeyPress;
888         break;
889       case eMouseEventClass:
890         mFlags.mComposed =
891             mMessage == eMouseClick || mMessage == eMouseDoubleClick ||
892             mMessage == eMouseAuxClick || mMessage == eMouseDown ||
893             mMessage == eMouseUp || mMessage == eMouseOver ||
894             mMessage == eMouseOut || mMessage == eMouseMove ||
895             mMessage == eContextMenu || mMessage == eXULPopupShowing ||
896             mMessage == eXULPopupHiding || mMessage == eXULPopupShown ||
897             mMessage == eXULPopupHidden;
898         break;
899       case ePointerEventClass:
900         // All pointer events are composed
901         mFlags.mComposed =
902             mMessage == ePointerDown || mMessage == ePointerMove ||
903             mMessage == ePointerUp || mMessage == ePointerCancel ||
904             mMessage == ePointerOver || mMessage == ePointerOut ||
905             mMessage == ePointerGotCapture || mMessage == ePointerLostCapture;
906         break;
907       case eTouchEventClass:
908         // All touch events are composed
909         mFlags.mComposed = mMessage == eTouchStart || mMessage == eTouchEnd ||
910                            mMessage == eTouchMove || mMessage == eTouchCancel;
911         break;
912       case eUIEventClass:
913         mFlags.mComposed = mMessage == eLegacyDOMFocusIn ||
914                            mMessage == eLegacyDOMFocusOut ||
915                            mMessage == eLegacyDOMActivate;
916         break;
917       case eWheelEventClass:
918         // All wheel events are composed
919         mFlags.mComposed = mMessage == eWheel;
920         break;
921       case eMouseScrollEventClass:
922         // Legacy mouse scroll events are composed too, for consistency with
923         // wheel.
924         mFlags.mComposed = mMessage == eLegacyMouseLineOrPageScroll ||
925                            mMessage == eLegacyMousePixelScroll;
926         break;
927       default:
928         mFlags.mComposed = false;
929         break;
930     }
931   }
932 
SetComposed(const nsAString & aEventTypeArg)933   void SetComposed(const nsAString& aEventTypeArg) {
934     mFlags.mComposed =  // composition events
935         aEventTypeArg.EqualsLiteral("compositionstart") ||
936         aEventTypeArg.EqualsLiteral("compositionupdate") ||
937         aEventTypeArg.EqualsLiteral("compositionend") ||
938         aEventTypeArg.EqualsLiteral("text") ||
939         // drag and drop events
940         aEventTypeArg.EqualsLiteral("dragstart") ||
941         aEventTypeArg.EqualsLiteral("drag") ||
942         aEventTypeArg.EqualsLiteral("dragenter") ||
943         aEventTypeArg.EqualsLiteral("dragexit") ||
944         aEventTypeArg.EqualsLiteral("dragleave") ||
945         aEventTypeArg.EqualsLiteral("dragover") ||
946         aEventTypeArg.EqualsLiteral("drop") ||
947         aEventTypeArg.EqualsLiteral("dropend") ||
948         // editor input events
949         aEventTypeArg.EqualsLiteral("input") ||
950         aEventTypeArg.EqualsLiteral("beforeinput") ||
951         // focus events
952         aEventTypeArg.EqualsLiteral("blur") ||
953         aEventTypeArg.EqualsLiteral("focus") ||
954         aEventTypeArg.EqualsLiteral("focusin") ||
955         aEventTypeArg.EqualsLiteral("focusout") ||
956         // keyboard events
957         aEventTypeArg.EqualsLiteral("keydown") ||
958         aEventTypeArg.EqualsLiteral("keyup") ||
959         aEventTypeArg.EqualsLiteral("keypress") ||
960         // mouse events
961         aEventTypeArg.EqualsLiteral("click") ||
962         aEventTypeArg.EqualsLiteral("dblclick") ||
963         aEventTypeArg.EqualsLiteral("mousedown") ||
964         aEventTypeArg.EqualsLiteral("mouseup") ||
965         aEventTypeArg.EqualsLiteral("mouseenter") ||
966         aEventTypeArg.EqualsLiteral("mouseleave") ||
967         aEventTypeArg.EqualsLiteral("mouseover") ||
968         aEventTypeArg.EqualsLiteral("mouseout") ||
969         aEventTypeArg.EqualsLiteral("mousemove") ||
970         aEventTypeArg.EqualsLiteral("contextmenu") ||
971         // pointer events
972         aEventTypeArg.EqualsLiteral("pointerdown") ||
973         aEventTypeArg.EqualsLiteral("pointermove") ||
974         aEventTypeArg.EqualsLiteral("pointerup") ||
975         aEventTypeArg.EqualsLiteral("pointercancel") ||
976         aEventTypeArg.EqualsLiteral("pointerover") ||
977         aEventTypeArg.EqualsLiteral("pointerout") ||
978         aEventTypeArg.EqualsLiteral("pointerenter") ||
979         aEventTypeArg.EqualsLiteral("pointerleave") ||
980         aEventTypeArg.EqualsLiteral("gotpointercapture") ||
981         aEventTypeArg.EqualsLiteral("lostpointercapture") ||
982         // touch events
983         aEventTypeArg.EqualsLiteral("touchstart") ||
984         aEventTypeArg.EqualsLiteral("touchend") ||
985         aEventTypeArg.EqualsLiteral("touchmove") ||
986         aEventTypeArg.EqualsLiteral("touchcancel") ||
987         // UI legacy events
988         aEventTypeArg.EqualsLiteral("DOMFocusIn") ||
989         aEventTypeArg.EqualsLiteral("DOMFocusOut") ||
990         aEventTypeArg.EqualsLiteral("DOMActivate") ||
991         // wheel events
992         aEventTypeArg.EqualsLiteral("wheel");
993   }
994 
SetComposed(bool aComposed)995   void SetComposed(bool aComposed) { mFlags.mComposed = aComposed; }
996 
SetDefaultComposedInNativeAnonymousContent()997   void SetDefaultComposedInNativeAnonymousContent() {
998     // For compatibility concerns, we set mComposedInNativeAnonymousContent to
999     // false for those events we want to stop propagation.
1000     //
1001     // nsVideoFrame may create anonymous image element which fires eLoad,
1002     // eLoadStart, eLoadEnd, eLoadError. We don't want these events cross
1003     // the boundary of NAC
1004     mFlags.mComposedInNativeAnonymousContent =
1005         mMessage != eLoad && mMessage != eLoadStart && mMessage != eLoadEnd &&
1006         mMessage != eLoadError;
1007   }
1008 
1009   bool IsUserAction() const;
1010 };
1011 
1012 /******************************************************************************
1013  * mozilla::WidgetGUIEvent
1014  ******************************************************************************/
1015 
1016 class WidgetGUIEvent : public WidgetEvent {
1017  protected:
WidgetGUIEvent(bool aIsTrusted,EventMessage aMessage,nsIWidget * aWidget,EventClassID aEventClassID)1018   WidgetGUIEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
1019                  EventClassID aEventClassID)
1020       : WidgetEvent(aIsTrusted, aMessage, aEventClassID), mWidget(aWidget) {}
1021 
1022   WidgetGUIEvent() = default;
1023 
1024  public:
AsGUIEvent()1025   virtual WidgetGUIEvent* AsGUIEvent() override { return this; }
1026 
WidgetGUIEvent(bool aIsTrusted,EventMessage aMessage,nsIWidget * aWidget)1027   WidgetGUIEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget)
1028       : WidgetEvent(aIsTrusted, aMessage, eGUIEventClass), mWidget(aWidget) {}
1029 
Duplicate()1030   virtual WidgetEvent* Duplicate() const override {
1031     MOZ_ASSERT(mClass == eGUIEventClass,
1032                "Duplicate() must be overridden by sub class");
1033     // Not copying widget, it is a weak reference.
1034     WidgetGUIEvent* result = new WidgetGUIEvent(false, mMessage, nullptr);
1035     result->AssignGUIEventData(*this, true);
1036     result->mFlags = mFlags;
1037     return result;
1038   }
1039 
1040   // Originator of the event
1041   nsCOMPtr<nsIWidget> mWidget;
1042 
AssignGUIEventData(const WidgetGUIEvent & aEvent,bool aCopyTargets)1043   void AssignGUIEventData(const WidgetGUIEvent& aEvent, bool aCopyTargets) {
1044     AssignEventData(aEvent, aCopyTargets);
1045     // widget should be initialized with the constructor.
1046   }
1047 };
1048 
1049 /******************************************************************************
1050  * mozilla::Modifier
1051  *
1052  * All modifier keys should be defined here.  This is used for managing
1053  * modifier states for DOM Level 3 or later.
1054  ******************************************************************************/
1055 
1056 enum Modifier {
1057   MODIFIER_NONE = 0x0000,
1058   MODIFIER_ALT = 0x0001,
1059   MODIFIER_ALTGRAPH = 0x0002,
1060   MODIFIER_CAPSLOCK = 0x0004,
1061   MODIFIER_CONTROL = 0x0008,
1062   MODIFIER_FN = 0x0010,
1063   MODIFIER_FNLOCK = 0x0020,
1064   MODIFIER_META = 0x0040,
1065   MODIFIER_NUMLOCK = 0x0080,
1066   MODIFIER_SCROLLLOCK = 0x0100,
1067   MODIFIER_SHIFT = 0x0200,
1068   MODIFIER_SYMBOL = 0x0400,
1069   MODIFIER_SYMBOLLOCK = 0x0800,
1070   MODIFIER_OS = 0x1000
1071 };
1072 
1073 /******************************************************************************
1074  * Modifier key names.
1075  ******************************************************************************/
1076 
1077 #define NS_DOM_KEYNAME_ALT "Alt"
1078 #define NS_DOM_KEYNAME_ALTGRAPH "AltGraph"
1079 #define NS_DOM_KEYNAME_CAPSLOCK "CapsLock"
1080 #define NS_DOM_KEYNAME_CONTROL "Control"
1081 #define NS_DOM_KEYNAME_FN "Fn"
1082 #define NS_DOM_KEYNAME_FNLOCK "FnLock"
1083 #define NS_DOM_KEYNAME_META "Meta"
1084 #define NS_DOM_KEYNAME_NUMLOCK "NumLock"
1085 #define NS_DOM_KEYNAME_SCROLLLOCK "ScrollLock"
1086 #define NS_DOM_KEYNAME_SHIFT "Shift"
1087 #define NS_DOM_KEYNAME_SYMBOL "Symbol"
1088 #define NS_DOM_KEYNAME_SYMBOLLOCK "SymbolLock"
1089 #define NS_DOM_KEYNAME_OS "OS"
1090 
1091 /******************************************************************************
1092  * mozilla::Modifiers
1093  ******************************************************************************/
1094 
1095 typedef uint16_t Modifiers;
1096 
1097 class MOZ_STACK_CLASS GetModifiersName final : public nsAutoCString {
1098  public:
GetModifiersName(Modifiers aModifiers)1099   explicit GetModifiersName(Modifiers aModifiers) {
1100     if (aModifiers & MODIFIER_ALT) {
1101       AssignLiteral(NS_DOM_KEYNAME_ALT);
1102     }
1103     if (aModifiers & MODIFIER_ALTGRAPH) {
1104       MaybeAppendSeparator();
1105       AppendLiteral(NS_DOM_KEYNAME_ALTGRAPH);
1106     }
1107     if (aModifiers & MODIFIER_CAPSLOCK) {
1108       MaybeAppendSeparator();
1109       AppendLiteral(NS_DOM_KEYNAME_CAPSLOCK);
1110     }
1111     if (aModifiers & MODIFIER_CONTROL) {
1112       MaybeAppendSeparator();
1113       AppendLiteral(NS_DOM_KEYNAME_CONTROL);
1114     }
1115     if (aModifiers & MODIFIER_FN) {
1116       MaybeAppendSeparator();
1117       AppendLiteral(NS_DOM_KEYNAME_FN);
1118     }
1119     if (aModifiers & MODIFIER_FNLOCK) {
1120       MaybeAppendSeparator();
1121       AppendLiteral(NS_DOM_KEYNAME_FNLOCK);
1122     }
1123     if (aModifiers & MODIFIER_META) {
1124       MaybeAppendSeparator();
1125       AppendLiteral(NS_DOM_KEYNAME_META);
1126     }
1127     if (aModifiers & MODIFIER_NUMLOCK) {
1128       MaybeAppendSeparator();
1129       AppendLiteral(NS_DOM_KEYNAME_NUMLOCK);
1130     }
1131     if (aModifiers & MODIFIER_SCROLLLOCK) {
1132       MaybeAppendSeparator();
1133       AppendLiteral(NS_DOM_KEYNAME_SCROLLLOCK);
1134     }
1135     if (aModifiers & MODIFIER_SHIFT) {
1136       MaybeAppendSeparator();
1137       AppendLiteral(NS_DOM_KEYNAME_SHIFT);
1138     }
1139     if (aModifiers & MODIFIER_SYMBOL) {
1140       MaybeAppendSeparator();
1141       AppendLiteral(NS_DOM_KEYNAME_SYMBOL);
1142     }
1143     if (aModifiers & MODIFIER_SYMBOLLOCK) {
1144       MaybeAppendSeparator();
1145       AppendLiteral(NS_DOM_KEYNAME_SYMBOLLOCK);
1146     }
1147     if (aModifiers & MODIFIER_OS) {
1148       MaybeAppendSeparator();
1149       AppendLiteral(NS_DOM_KEYNAME_OS);
1150     }
1151     if (IsEmpty()) {
1152       AssignLiteral("none");
1153     }
1154   }
1155 
1156  private:
MaybeAppendSeparator()1157   void MaybeAppendSeparator() {
1158     if (!IsEmpty()) {
1159       AppendLiteral(" | ");
1160     }
1161   }
1162 };
1163 
1164 /******************************************************************************
1165  * mozilla::WidgetInputEvent
1166  ******************************************************************************/
1167 
1168 class WidgetInputEvent : public WidgetGUIEvent {
1169  protected:
WidgetInputEvent(bool aIsTrusted,EventMessage aMessage,nsIWidget * aWidget,EventClassID aEventClassID)1170   WidgetInputEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
1171                    EventClassID aEventClassID)
1172       : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, aEventClassID),
1173         mModifiers(0) {}
1174 
WidgetInputEvent()1175   WidgetInputEvent() : mModifiers(0) {}
1176 
1177  public:
AsInputEvent()1178   virtual WidgetInputEvent* AsInputEvent() override { return this; }
1179 
WidgetInputEvent(bool aIsTrusted,EventMessage aMessage,nsIWidget * aWidget)1180   WidgetInputEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget)
1181       : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eInputEventClass),
1182         mModifiers(0) {}
1183 
Duplicate()1184   virtual WidgetEvent* Duplicate() const override {
1185     MOZ_ASSERT(mClass == eInputEventClass,
1186                "Duplicate() must be overridden by sub class");
1187     // Not copying widget, it is a weak reference.
1188     WidgetInputEvent* result = new WidgetInputEvent(false, mMessage, nullptr);
1189     result->AssignInputEventData(*this, true);
1190     result->mFlags = mFlags;
1191     return result;
1192   }
1193 
1194   /**
1195    * Returns a modifier of "Accel" virtual modifier which is used for shortcut
1196    * key.
1197    */
1198   static Modifier AccelModifier();
1199 
1200   /**
1201    * GetModifier() returns a modifier flag which is activated by aDOMKeyName.
1202    */
1203   static Modifier GetModifier(const nsAString& aDOMKeyName);
1204 
1205   // true indicates the accel key on the environment is down
IsAccel()1206   bool IsAccel() const { return ((mModifiers & AccelModifier()) != 0); }
1207 
1208   // true indicates the shift key is down
IsShift()1209   bool IsShift() const { return ((mModifiers & MODIFIER_SHIFT) != 0); }
1210   // true indicates the control key is down
IsControl()1211   bool IsControl() const { return ((mModifiers & MODIFIER_CONTROL) != 0); }
1212   // true indicates the alt key is down
IsAlt()1213   bool IsAlt() const { return ((mModifiers & MODIFIER_ALT) != 0); }
1214   // true indicates the meta key is down (or, on Mac, the Command key)
IsMeta()1215   bool IsMeta() const { return ((mModifiers & MODIFIER_META) != 0); }
1216   // true indicates the win key is down on Windows. Or the Super or Hyper key
1217   // is down on Linux.
IsOS()1218   bool IsOS() const { return ((mModifiers & MODIFIER_OS) != 0); }
1219   // true indicates the alt graph key is down
1220   // NOTE: on Mac, the option key press causes both IsAlt() and IsAltGrpah()
1221   //       return true.
IsAltGraph()1222   bool IsAltGraph() const { return ((mModifiers & MODIFIER_ALTGRAPH) != 0); }
1223   // true indicates the CapLock LED is turn on.
IsCapsLocked()1224   bool IsCapsLocked() const { return ((mModifiers & MODIFIER_CAPSLOCK) != 0); }
1225   // true indicates the NumLock LED is turn on.
IsNumLocked()1226   bool IsNumLocked() const { return ((mModifiers & MODIFIER_NUMLOCK) != 0); }
1227   // true indicates the ScrollLock LED is turn on.
IsScrollLocked()1228   bool IsScrollLocked() const {
1229     return ((mModifiers & MODIFIER_SCROLLLOCK) != 0);
1230   }
1231 
1232   // true indicates the Fn key is down, but this is not supported by native
1233   // key event on any platform.
IsFn()1234   bool IsFn() const { return ((mModifiers & MODIFIER_FN) != 0); }
1235   // true indicates the FnLock LED is turn on, but we don't know such
1236   // keyboards nor platforms.
IsFnLocked()1237   bool IsFnLocked() const { return ((mModifiers & MODIFIER_FNLOCK) != 0); }
1238   // true indicates the Symbol is down, but this is not supported by native
1239   // key event on any platforms.
IsSymbol()1240   bool IsSymbol() const { return ((mModifiers & MODIFIER_SYMBOL) != 0); }
1241   // true indicates the SymbolLock LED is turn on, but we don't know such
1242   // keyboards nor platforms.
IsSymbolLocked()1243   bool IsSymbolLocked() const {
1244     return ((mModifiers & MODIFIER_SYMBOLLOCK) != 0);
1245   }
1246 
InitBasicModifiers(bool aCtrlKey,bool aAltKey,bool aShiftKey,bool aMetaKey)1247   void InitBasicModifiers(bool aCtrlKey, bool aAltKey, bool aShiftKey,
1248                           bool aMetaKey) {
1249     mModifiers = 0;
1250     if (aCtrlKey) {
1251       mModifiers |= MODIFIER_CONTROL;
1252     }
1253     if (aAltKey) {
1254       mModifiers |= MODIFIER_ALT;
1255     }
1256     if (aShiftKey) {
1257       mModifiers |= MODIFIER_SHIFT;
1258     }
1259     if (aMetaKey) {
1260       mModifiers |= MODIFIER_META;
1261     }
1262   }
1263 
1264   Modifiers mModifiers;
1265 
AssignInputEventData(const WidgetInputEvent & aEvent,bool aCopyTargets)1266   void AssignInputEventData(const WidgetInputEvent& aEvent, bool aCopyTargets) {
1267     AssignGUIEventData(aEvent, aCopyTargets);
1268 
1269     mModifiers = aEvent.mModifiers;
1270   }
1271 };
1272 
1273 /******************************************************************************
1274  * mozilla::InternalUIEvent
1275  *
1276  * XXX Why this inherits WidgetGUIEvent rather than WidgetEvent?
1277  ******************************************************************************/
1278 
1279 class InternalUIEvent : public WidgetGUIEvent {
1280  protected:
InternalUIEvent()1281   InternalUIEvent() : mDetail(0), mCausedByUntrustedEvent(false) {}
1282 
InternalUIEvent(bool aIsTrusted,EventMessage aMessage,nsIWidget * aWidget,EventClassID aEventClassID)1283   InternalUIEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
1284                   EventClassID aEventClassID)
1285       : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, aEventClassID),
1286         mDetail(0),
1287         mCausedByUntrustedEvent(false) {}
1288 
InternalUIEvent(bool aIsTrusted,EventMessage aMessage,EventClassID aEventClassID)1289   InternalUIEvent(bool aIsTrusted, EventMessage aMessage,
1290                   EventClassID aEventClassID)
1291       : WidgetGUIEvent(aIsTrusted, aMessage, nullptr, aEventClassID),
1292         mDetail(0),
1293         mCausedByUntrustedEvent(false) {}
1294 
1295  public:
AsUIEvent()1296   virtual InternalUIEvent* AsUIEvent() override { return this; }
1297 
1298   /**
1299    * If the UIEvent is caused by another event (e.g., click event),
1300    * aEventCausesThisEvent should be the event.  If there is no such event,
1301    * this should be nullptr.
1302    */
InternalUIEvent(bool aIsTrusted,EventMessage aMessage,const WidgetEvent * aEventCausesThisEvent)1303   InternalUIEvent(bool aIsTrusted, EventMessage aMessage,
1304                   const WidgetEvent* aEventCausesThisEvent)
1305       : WidgetGUIEvent(aIsTrusted, aMessage, nullptr, eUIEventClass),
1306         mDetail(0),
1307         mCausedByUntrustedEvent(aEventCausesThisEvent &&
1308                                 !aEventCausesThisEvent->IsTrusted()) {}
1309 
Duplicate()1310   virtual WidgetEvent* Duplicate() const override {
1311     MOZ_ASSERT(mClass == eUIEventClass,
1312                "Duplicate() must be overridden by sub class");
1313     InternalUIEvent* result = new InternalUIEvent(false, mMessage, nullptr);
1314     result->AssignUIEventData(*this, true);
1315     result->mFlags = mFlags;
1316     return result;
1317   }
1318 
1319   int32_t mDetail;
1320   // mCausedByUntrustedEvent is true if the event is caused by untrusted event.
1321   bool mCausedByUntrustedEvent;
1322 
1323   // If you check the event is a trusted event and NOT caused by an untrusted
1324   // event, IsTrustable() returns what you expected.
IsTrustable()1325   bool IsTrustable() const { return IsTrusted() && !mCausedByUntrustedEvent; }
1326 
AssignUIEventData(const InternalUIEvent & aEvent,bool aCopyTargets)1327   void AssignUIEventData(const InternalUIEvent& aEvent, bool aCopyTargets) {
1328     AssignGUIEventData(aEvent, aCopyTargets);
1329 
1330     mDetail = aEvent.mDetail;
1331     mCausedByUntrustedEvent = aEvent.mCausedByUntrustedEvent;
1332   }
1333 };
1334 
1335 }  // namespace mozilla
1336 
1337 #endif  // mozilla_BasicEvents_h__
1338