1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #ifndef mozilla_dom_Event_h_
8 #define mozilla_dom_Event_h_
9
10 #include "mozilla/Attributes.h"
11 #include "mozilla/BasicEvents.h"
12 #include "nsIDOMEvent.h"
13 #include "nsISupports.h"
14 #include "nsCOMPtr.h"
15 #include "nsPIDOMWindow.h"
16 #include "nsPoint.h"
17 #include "nsCycleCollectionParticipant.h"
18 #include "mozilla/dom/BindingDeclarations.h"
19 #include "mozilla/dom/EventBinding.h"
20 #include "nsIScriptGlobalObject.h"
21 #include "Units.h"
22 #include "js/TypeDecls.h"
23 #include "nsIGlobalObject.h"
24
25 class nsIContent;
26 class nsIDOMEventTarget;
27 class nsPresContext;
28
29 namespace mozilla {
30 namespace dom {
31
32 class BeforeUnloadEvent;
33 class EventTarget;
34 class EventMessageAutoOverride;
35 // ExtendableEvent is a ServiceWorker event that is not
36 // autogenerated since it has some extra methods.
37 class ExtendableEvent;
38 class KeyboardEvent;
39 class TimeEvent;
40 class WantsPopupControlCheck;
41 #define GENERATED_EVENT(EventClass_) class EventClass_;
42 #include "mozilla/dom/GeneratedEventList.h"
43 #undef GENERATED_EVENT
44
45 // Dummy class so we can cast through it to get from nsISupports to
46 // Event subclasses with only two non-ambiguous static casts.
47 class EventBase : public nsIDOMEvent {};
48
49 class Event : public EventBase, public nsWrapperCache {
50 public:
51 Event(EventTarget* aOwner, nsPresContext* aPresContext, WidgetEvent* aEvent);
52 explicit Event(nsPIDOMWindowInner* aWindow);
53
54 protected:
55 virtual ~Event();
56
57 private:
58 void ConstructorInit(EventTarget* aOwner, nsPresContext* aPresContext,
59 WidgetEvent* aEvent);
60
61 public:
FromSupports(nsISupports * aSupports)62 static Event* FromSupports(nsISupports* aSupports) {
63 nsIDOMEvent* event = static_cast<nsIDOMEvent*>(aSupports);
64 #ifdef DEBUG
65 {
66 nsCOMPtr<nsIDOMEvent> target_qi = do_QueryInterface(aSupports);
67
68 // If this assertion fires the QI implementation for the object in
69 // question doesn't use the nsIDOMEvent pointer as the
70 // nsISupports pointer. That must be fixed, or we'll crash...
71 MOZ_ASSERT(target_qi == event, "Uh, fix QI!");
72 }
73 #endif
74 return static_cast<Event*>(event);
75 }
76
77 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Event)78 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Event)
79
80 nsIGlobalObject* GetParentObject() { return mOwner; }
81
82 JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final;
83
84 virtual JSObject* WrapObjectInternal(JSContext* aCx,
85 JS::Handle<JSObject*> aGivenProto);
86
87 #define GENERATED_EVENT(EventClass_) \
88 virtual EventClass_* As##EventClass_() { return nullptr; }
89 #include "mozilla/dom/GeneratedEventList.h"
90 #undef GENERATED_EVENT
91
92 // ExtendableEvent is a ServiceWorker event that is not
93 // autogenerated since it has some extra methods.
AsExtendableEvent()94 virtual ExtendableEvent* AsExtendableEvent() { return nullptr; }
95
AsTimeEvent()96 virtual TimeEvent* AsTimeEvent() { return nullptr; }
97
98 // BeforeUnloadEvent is not autogenerated because it has a setter.
AsBeforeUnloadEvent()99 virtual BeforeUnloadEvent* AsBeforeUnloadEvent() { return nullptr; }
100
101 // KeyboardEvent has all sorts of non-autogeneratable bits so far.
AsKeyboardEvent()102 virtual KeyboardEvent* AsKeyboardEvent() { return nullptr; }
103
104 // nsIDOMEvent Interface
105 NS_DECL_NSIDOMEVENT
106
107 void InitPresContextData(nsPresContext* aPresContext);
108
109 // Returns true if the event should be trusted.
110 bool Init(EventTarget* aGlobal);
111
112 static PopupControlState GetEventPopupControlState(
113 WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent = nullptr);
114
115 static void PopupAllowedEventsChanged();
116
117 static void Shutdown();
118
119 static const char* GetEventName(EventMessage aEventType);
120 static CSSIntPoint GetClientCoords(nsPresContext* aPresContext,
121 WidgetEvent* aEvent,
122 LayoutDeviceIntPoint aPoint,
123 CSSIntPoint aDefaultPoint);
124 static CSSIntPoint GetPageCoords(nsPresContext* aPresContext,
125 WidgetEvent* aEvent,
126 LayoutDeviceIntPoint aPoint,
127 CSSIntPoint aDefaultPoint);
128 static CSSIntPoint GetScreenCoords(nsPresContext* aPresContext,
129 WidgetEvent* aEvent,
130 LayoutDeviceIntPoint aPoint);
131 static CSSIntPoint GetOffsetCoords(nsPresContext* aPresContext,
132 WidgetEvent* aEvent,
133 LayoutDeviceIntPoint aPoint,
134 CSSIntPoint aDefaultPoint);
135
136 static already_AddRefed<Event> Constructor(EventTarget* aEventTarget,
137 const nsAString& aType,
138 const EventInit& aParam);
139
140 static already_AddRefed<Event> Constructor(const GlobalObject& aGlobal,
141 const nsAString& aType,
142 const EventInit& aParam,
143 ErrorResult& aRv);
144
145 // Implemented as xpidl method
146 // void GetType(nsString& aRetval) {}
147
148 EventTarget* GetTarget() const;
149 static bool IsSrcElementEnabled(JSContext* /* unused */,
150 JSObject* /* unused */);
151 EventTarget* GetCurrentTarget() const;
152
153 void ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath);
154
155 uint16_t EventPhase() const;
156
157 // xpidl implementation
158 // void StopPropagation();
159
160 // xpidl implementation
161 // void StopImmediatePropagation();
162
Bubbles()163 bool Bubbles() const { return mEvent->mFlags.mBubbles; }
164
Cancelable()165 bool Cancelable() const { return mEvent->mFlags.mCancelable; }
166
Composed()167 bool Composed() const { return mEvent->mFlags.mComposed; }
168
CancelBubble()169 bool CancelBubble() const { return mEvent->PropagationStopped(); }
170
171 // xpidl implementation
172 // void PreventDefault();
173
174 // You MUST NOT call PreventDefault(JSContext*, CallerType) from C++ code. A
175 // call of this method always sets Event.defaultPrevented true for web
176 // contents. If default action handler calls this, web applications see wrong
177 // defaultPrevented value.
178 virtual void PreventDefault(JSContext* aCx, CallerType aCallerType);
179
180 // You MUST NOT call DefaultPrevented(CallerType) from C++ code. This may
181 // return false even if PreventDefault() has been called.
182 // See comments in its implementation for the details.
183 bool DefaultPrevented(CallerType aCallerType) const;
184
DefaultPrevented()185 bool DefaultPrevented() const { return mEvent->DefaultPrevented(); }
186
DefaultPreventedByChrome()187 bool DefaultPreventedByChrome() const {
188 return mEvent->mFlags.mDefaultPreventedByChrome;
189 }
190
DefaultPreventedByContent()191 bool DefaultPreventedByContent() const {
192 return mEvent->mFlags.mDefaultPreventedByContent;
193 }
194
MultipleActionsPrevented()195 bool MultipleActionsPrevented() const {
196 return mEvent->mFlags.mMultipleActionsPrevented;
197 }
198
IsTrusted()199 bool IsTrusted() const { return mEvent->IsTrusted(); }
200
IsSynthesized()201 bool IsSynthesized() const { return mEvent->mFlags.mIsSynthesizedForTests; }
202
203 double TimeStamp();
204
205 EventTarget* GetOriginalTarget() const;
206 EventTarget* GetExplicitOriginalTarget() const;
207 EventTarget* GetComposedTarget() const;
208
209 /**
210 * @param aCalledByDefaultHandler Should be true when this is called by
211 * C++ or Chrome. Otherwise, e.g., called
212 * by a call of Event.preventDefault() in
213 * content script, false.
214 */
215 void PreventDefaultInternal(bool aCalledByDefaultHandler,
216 nsIPrincipal* aPrincipal = nullptr);
217
IsMainThreadEvent()218 bool IsMainThreadEvent() { return mIsMainThreadEvent; }
219
MarkUninitialized()220 void MarkUninitialized() {
221 mEvent->mMessage = eVoidEvent;
222 mEvent->mSpecifiedEventTypeString.Truncate();
223 mEvent->mSpecifiedEventType = nullptr;
224 }
225
226 /**
227 * For WidgetEvent, return it's type in string.
228 *
229 * @param aEvent is a WidgetEvent to get its type.
230 * @param aType is a string where to return the type.
231 */
232 static void GetWidgetEventType(WidgetEvent* aEvent, nsAString& aType);
233
234 protected:
235 // Internal helper functions
236 void SetEventType(const nsAString& aEventTypeArg);
237 already_AddRefed<nsIContent> GetTargetFromFrame();
238
239 friend class EventMessageAutoOverride;
240 friend class WantsPopupControlCheck;
SetWantsPopupControlCheck(bool aCheck)241 void SetWantsPopupControlCheck(bool aCheck) {
242 mWantsPopupControlCheck = aCheck;
243 }
244
GetWantsPopupControlCheck()245 bool GetWantsPopupControlCheck() {
246 return IsTrusted() && mWantsPopupControlCheck;
247 }
248
SetComposed(bool aComposed)249 void SetComposed(bool aComposed) { mEvent->SetComposed(aComposed); }
250
251 already_AddRefed<EventTarget> EnsureWebAccessibleRelatedTarget(
252 EventTarget* aRelatedTarget);
253
254 mozilla::WidgetEvent* mEvent;
255 RefPtr<nsPresContext> mPresContext;
256 nsCOMPtr<EventTarget> mExplicitOriginalTarget;
257 nsCOMPtr<nsIGlobalObject> mOwner;
258 bool mEventIsInternal;
259 bool mPrivateDataDuplicated;
260 bool mIsMainThreadEvent;
261 // True when popup control check should rely on event.type, not
262 // WidgetEvent.mMessage.
263 bool mWantsPopupControlCheck;
264 };
265
266 /**
267 * RAII helper-class to override an event's message (i.e. its DOM-exposed
268 * type), for as long as the object is alive. Restores the original
269 * EventMessage when destructed.
270 *
271 * Notable requirements:
272 * - The original & overriding messages must be known (not eUnidentifiedEvent).
273 * - The original & overriding messages must be different.
274 * - The passed-in nsIDOMEvent must outlive this RAII helper.
275 */
276 class MOZ_RAII EventMessageAutoOverride {
277 public:
EventMessageAutoOverride(nsIDOMEvent * aEvent,EventMessage aOverridingMessage)278 explicit EventMessageAutoOverride(nsIDOMEvent* aEvent,
279 EventMessage aOverridingMessage)
280 : mEvent(aEvent->InternalDOMEvent()),
281 mOrigMessage(mEvent->mEvent->mMessage) {
282 MOZ_ASSERT(aOverridingMessage != mOrigMessage,
283 "Don't use this class if you're not actually overriding");
284 MOZ_ASSERT(aOverridingMessage != eUnidentifiedEvent,
285 "Only use this class with a valid overriding EventMessage");
286 MOZ_ASSERT(mOrigMessage != eUnidentifiedEvent &&
287 mEvent->mEvent->mSpecifiedEventTypeString.IsEmpty(),
288 "Only use this class on events whose overridden type is "
289 "known (so we can restore it properly)");
290
291 mEvent->mEvent->mMessage = aOverridingMessage;
292 }
293
~EventMessageAutoOverride()294 ~EventMessageAutoOverride() { mEvent->mEvent->mMessage = mOrigMessage; }
295
296 protected:
297 // Non-owning ref, which should be safe since we're a stack-allocated object
298 // with limited lifetime. Whoever creates us should keep mEvent alive.
299 Event* const MOZ_NON_OWNING_REF mEvent;
300 const EventMessage mOrigMessage;
301 };
302
303 class MOZ_STACK_CLASS WantsPopupControlCheck {
304 public:
WantsPopupControlCheck(nsIDOMEvent * aEvent)305 explicit WantsPopupControlCheck(nsIDOMEvent* aEvent)
306 : mEvent(aEvent->InternalDOMEvent()) {
307 mOriginalWantsPopupControlCheck = mEvent->GetWantsPopupControlCheck();
308 mEvent->SetWantsPopupControlCheck(mEvent->IsTrusted());
309 }
310
~WantsPopupControlCheck()311 ~WantsPopupControlCheck() {
312 mEvent->SetWantsPopupControlCheck(mOriginalWantsPopupControlCheck);
313 }
314
315 private:
316 Event* mEvent;
317 bool mOriginalWantsPopupControlCheck;
318 };
319
320 } // namespace dom
321 } // namespace mozilla
322
323 #define NS_FORWARD_TO_EVENT \
324 NS_FORWARD_NSIDOMEVENT(Event::) \
325 virtual void PreventDefault(JSContext* aCx, CallerType aCallerType) \
326 override { \
327 Event::PreventDefault(aCx, aCallerType); \
328 }
329
330 #define NS_FORWARD_NSIDOMEVENT_NO_SERIALIZATION_NO_DUPLICATION(_to) \
331 NS_IMETHOD GetType(nsAString& aType) override { return _to GetType(aType); } \
332 NS_IMETHOD GetTarget(nsIDOMEventTarget** aTarget) override { \
333 return _to GetTarget(aTarget); \
334 } \
335 NS_IMETHOD GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget) override { \
336 return _to GetCurrentTarget(aCurrentTarget); \
337 } \
338 NS_IMETHOD GetEventPhase(uint16_t* aEventPhase) override { \
339 return _to GetEventPhase(aEventPhase); \
340 } \
341 NS_IMETHOD GetBubbles(bool* aBubbles) override { \
342 return _to GetBubbles(aBubbles); \
343 } \
344 NS_IMETHOD GetCancelable(bool* aCancelable) override { \
345 return _to GetCancelable(aCancelable); \
346 } \
347 NS_IMETHOD GetTimeStamp(DOMTimeStamp* aTimeStamp) override { \
348 return _to GetTimeStamp(aTimeStamp); \
349 } \
350 NS_IMETHOD StopPropagation(void) override { return _to StopPropagation(); } \
351 NS_IMETHOD StopCrossProcessForwarding(void) override { \
352 return _to StopCrossProcessForwarding(); \
353 } \
354 NS_IMETHOD PreventDefault(void) override { return _to PreventDefault(); } \
355 void InitEvent(const nsAString& eventTypeArg, bool canBubbleArg, \
356 bool cancelableArg) override { \
357 _to InitEvent(eventTypeArg, canBubbleArg, cancelableArg); \
358 } \
359 NS_IMETHOD GetDefaultPrevented(bool* aDefaultPrevented) override { \
360 return _to GetDefaultPrevented(aDefaultPrevented); \
361 } \
362 NS_IMETHOD StopImmediatePropagation(void) override { \
363 return _to StopImmediatePropagation(); \
364 } \
365 NS_IMETHOD GetOriginalTarget(nsIDOMEventTarget** aOriginalTarget) override { \
366 return _to GetOriginalTarget(aOriginalTarget); \
367 } \
368 NS_IMETHOD GetExplicitOriginalTarget( \
369 nsIDOMEventTarget** aExplicitOriginalTarget) override { \
370 return _to GetExplicitOriginalTarget(aExplicitOriginalTarget); \
371 } \
372 NS_IMETHOD GetIsTrusted(bool* aIsTrusted) override { \
373 return _to GetIsTrusted(aIsTrusted); \
374 } \
375 NS_IMETHOD SetTarget(nsIDOMEventTarget* aTarget) override { \
376 return _to SetTarget(aTarget); \
377 } \
378 NS_IMETHOD_(bool) IsDispatchStopped(void) override { \
379 return _to IsDispatchStopped(); \
380 } \
381 NS_IMETHOD_(WidgetEvent*) WidgetEventPtr(void) override { \
382 return _to WidgetEventPtr(); \
383 } \
384 NS_IMETHOD_(void) SetTrusted(bool aTrusted) override { \
385 _to SetTrusted(aTrusted); \
386 } \
387 NS_IMETHOD_(void) SetOwner(EventTarget* aOwner) override { \
388 _to SetOwner(aOwner); \
389 } \
390 NS_IMETHOD_(Event*) InternalDOMEvent() override { \
391 return _to InternalDOMEvent(); \
392 } \
393 NS_IMETHOD GetCancelBubble(bool* aCancelBubble) override { \
394 return _to GetCancelBubble(aCancelBubble); \
395 } \
396 NS_IMETHOD SetCancelBubble(bool aCancelBubble) override { \
397 return _to SetCancelBubble(aCancelBubble); \
398 }
399
400 #define NS_FORWARD_TO_EVENT_NO_SERIALIZATION_NO_DUPLICATION \
401 NS_FORWARD_NSIDOMEVENT_NO_SERIALIZATION_NO_DUPLICATION(Event::) \
402 virtual void PreventDefault(JSContext* aCx, CallerType aCallerType) \
403 override { \
404 Event::PreventDefault(aCx, aCallerType); \
405 }
406
ToSupports(mozilla::dom::Event * e)407 inline nsISupports* ToSupports(mozilla::dom::Event* e) {
408 return static_cast<nsIDOMEvent*>(e);
409 }
410
ToCanonicalSupports(mozilla::dom::Event * e)411 inline nsISupports* ToCanonicalSupports(mozilla::dom::Event* e) {
412 return static_cast<nsIDOMEvent*>(e);
413 }
414
415 already_AddRefed<mozilla::dom::Event> NS_NewDOMEvent(
416 mozilla::dom::EventTarget* aOwner, nsPresContext* aPresContext,
417 mozilla::WidgetEvent* aEvent);
418
419 #endif // mozilla_dom_Event_h_
420