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/. */
7 #include "AccessCheck.h"
8 #include "base/basictypes.h"
9 #include "ipc/IPCMessageUtils.h"
10 #include "mozilla/EventDispatcher.h"
11 #include "mozilla/BasePrincipal.h"
12 #include "mozilla/ContentEvents.h"
13 #include "mozilla/DOMEventTargetHelper.h"
14 #include "mozilla/EventStateManager.h"
15 #include "mozilla/InternalMutationEvent.h"
16 #include "mozilla/dom/Performance.h"
17 #include "mozilla/dom/WorkerPrivate.h"
18 #include "mozilla/MiscEvents.h"
19 #include "mozilla/MouseEvents.h"
20 #include "mozilla/PointerLockManager.h"
21 #include "mozilla/Preferences.h"
22 #include "mozilla/PresShell.h"
23 #include "mozilla/TextEvents.h"
24 #include "mozilla/TouchEvents.h"
25 #include "mozilla/ViewportUtils.h"
26 #include "mozilla/dom/Document.h"
27 #include "mozilla/dom/DocumentInlines.h"
28 #include "mozilla/dom/Event.h"
29 #include "mozilla/dom/ShadowRoot.h"
30 #include "mozilla/StaticPrefs_dom.h"
31 #include "mozilla/SVGUtils.h"
32 #include "mozilla/SVGOuterSVGFrame.h"
33 #include "nsContentUtils.h"
35 #include "nsDeviceContext.h"
37 #include "nsGlobalWindow.h"
39 #include "nsIContent.h"
40 #include "nsIContentInlines.h"
41 #include "nsIScrollableFrame.h"
42 #include "nsJSEnvironment.h"
43 #include "nsLayoutUtils.h"
44 #include "nsPIWindowRoot.h"
45 #include "nsRFPService.h"
47 namespace mozilla::dom
{
49 Event::Event(EventTarget
* aOwner
, nsPresContext
* aPresContext
,
50 WidgetEvent
* aEvent
) {
51 ConstructorInit(aOwner
, aPresContext
, aEvent
);
54 Event::Event(nsPIDOMWindowInner
* aParent
) {
55 ConstructorInit(nsGlobalWindowInner::Cast(aParent
), nullptr, nullptr);
58 void Event::ConstructorInit(EventTarget
* aOwner
, nsPresContext
* aPresContext
,
59 WidgetEvent
* aEvent
) {
61 mIsMainThreadEvent
= NS_IsMainThread();
63 mPrivateDataDuplicated
= false;
64 mWantsPopupControlCheck
= false;
68 mEventIsInternal
= false;
70 mEventIsInternal
= true;
72 A derived class might want to allocate its own type of aEvent
73 (derived from WidgetEvent). To do this, it should take care to pass
74 a non-nullptr aEvent to this ctor, e.g.:
76 FooEvent::FooEvent(..., WidgetEvent* aEvent)
77 : Event(..., aEvent ? aEvent : new WidgetEvent())
79 Then, to override the mEventIsInternal assignments done by the
80 base ctor, it should do this in its own ctor:
82 FooEvent::FooEvent(..., WidgetEvent* aEvent)
87 mEventIsInternal = false;
90 mEventIsInternal = true;
95 mEvent
= new WidgetEvent(false, eVoidEvent
);
96 mEvent
->mTime
= PR_Now();
99 InitPresContextData(aPresContext
);
102 void Event::InitPresContextData(nsPresContext
* aPresContext
) {
103 mPresContext
= aPresContext
;
104 // Get the explicit original target (if it's anonymous make it null)
106 nsCOMPtr
<nsIContent
> content
= GetTargetFromFrame();
107 mExplicitOriginalTarget
= content
;
108 if (content
&& content
->IsInNativeAnonymousSubtree()) {
109 mExplicitOriginalTarget
= nullptr;
115 NS_ASSERT_OWNINGTHREAD(Event
);
117 if (mEventIsInternal
&& mEvent
) {
122 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Event
)
123 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
124 NS_INTERFACE_MAP_ENTRY(nsISupports
)
125 NS_INTERFACE_MAP_ENTRY(Event
)
128 NS_IMPL_CYCLE_COLLECTING_ADDREF(Event
)
129 NS_IMPL_CYCLE_COLLECTING_RELEASE(Event
)
131 NS_IMPL_CYCLE_COLLECTION_CLASS(Event
)
133 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Event
)
134 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
135 NS_IMPL_CYCLE_COLLECTION_TRACE_END
137 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event
)
138 if (tmp
->mEventIsInternal
) {
139 tmp
->mEvent
->mTarget
= nullptr;
140 tmp
->mEvent
->mCurrentTarget
= nullptr;
141 tmp
->mEvent
->mOriginalTarget
= nullptr;
142 tmp
->mEvent
->mRelatedTarget
= nullptr;
143 tmp
->mEvent
->mOriginalRelatedTarget
= nullptr;
144 switch (tmp
->mEvent
->mClass
) {
145 case eDragEventClass
: {
146 WidgetDragEvent
* dragEvent
= tmp
->mEvent
->AsDragEvent();
147 dragEvent
->mDataTransfer
= nullptr;
150 case eClipboardEventClass
:
151 tmp
->mEvent
->AsClipboardEvent()->mClipboardData
= nullptr;
153 case eEditorInputEventClass
: {
154 InternalEditorInputEvent
* inputEvent
=
155 tmp
->mEvent
->AsEditorInputEvent();
156 inputEvent
->mDataTransfer
= nullptr;
157 inputEvent
->mTargetRanges
.Clear();
160 case eMutationEventClass
:
161 tmp
->mEvent
->AsMutationEvent()->mRelatedNode
= nullptr;
167 if (WidgetMouseEvent
* mouseEvent
= tmp
->mEvent
->AsMouseEvent()) {
168 mouseEvent
->mClickTarget
= nullptr;
171 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext
);
172 NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget
);
173 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner
);
174 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
175 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
177 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event
)
178 if (tmp
->mEventIsInternal
) {
179 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mTarget
)
180 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mCurrentTarget
)
181 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mOriginalTarget
)
182 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mRelatedTarget
)
183 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mOriginalRelatedTarget
);
184 switch (tmp
->mEvent
->mClass
) {
185 case eDragEventClass
: {
186 WidgetDragEvent
* dragEvent
= tmp
->mEvent
->AsDragEvent();
187 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mDataTransfer");
188 cb
.NoteXPCOMChild(dragEvent
->mDataTransfer
);
191 case eClipboardEventClass
:
192 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mClipboardData");
193 cb
.NoteXPCOMChild(tmp
->mEvent
->AsClipboardEvent()->mClipboardData
);
195 case eEditorInputEventClass
:
196 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mDataTransfer");
197 cb
.NoteXPCOMChild(tmp
->mEvent
->AsEditorInputEvent()->mDataTransfer
);
198 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
199 mEvent
->AsEditorInputEvent()->mTargetRanges
);
201 case eMutationEventClass
:
202 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mRelatedNode");
203 cb
.NoteXPCOMChild(tmp
->mEvent
->AsMutationEvent()->mRelatedNode
);
209 if (WidgetMouseEvent
* mouseEvent
= tmp
->mEvent
->AsMouseEvent()) {
210 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mClickTarget");
211 cb
.NoteXPCOMChild(mouseEvent
->mClickTarget
);
214 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext
)
215 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget
)
216 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner
)
217 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
219 JSObject
* Event::WrapObject(JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
220 return WrapObjectInternal(aCx
, aGivenProto
);
223 JSObject
* Event::WrapObjectInternal(JSContext
* aCx
,
224 JS::Handle
<JSObject
*> aGivenProto
) {
225 return Event_Binding::Wrap(aCx
, this, aGivenProto
);
228 void Event::GetType(nsAString
& aType
) const {
229 GetWidgetEventType(mEvent
, aType
);
232 EventTarget
* Event::GetTarget() const { return mEvent
->GetDOMEventTarget(); }
234 already_AddRefed
<Document
> Event::GetDocument() const {
235 nsCOMPtr
<EventTarget
> eventTarget
= GetTarget();
241 nsCOMPtr
<nsPIDOMWindowInner
> win
=
242 do_QueryInterface(eventTarget
->GetOwnerGlobal());
248 nsCOMPtr
<Document
> doc
;
249 doc
= win
->GetExtantDoc();
254 EventTarget
* Event::GetCurrentTarget() const {
255 return mEvent
->GetCurrentDOMEventTarget();
258 void Event::ComposedPath(nsTArray
<RefPtr
<EventTarget
>>& aPath
) {
259 EventDispatcher::GetComposedPathFor(mEvent
, aPath
);
263 // Get the actual event target node (may have been retargeted for mouse events)
265 already_AddRefed
<nsIContent
> Event::GetTargetFromFrame() {
270 // Get the mTarget frame (have to get the ESM first)
271 nsIFrame
* targetFrame
= mPresContext
->EventStateManager()->GetEventTarget();
276 // get the real content
277 nsCOMPtr
<nsIContent
> realEventContent
;
278 targetFrame
->GetContentForEvent(mEvent
, getter_AddRefs(realEventContent
));
279 return realEventContent
.forget();
282 EventTarget
* Event::GetExplicitOriginalTarget() const {
283 if (mExplicitOriginalTarget
) {
284 return mExplicitOriginalTarget
;
289 EventTarget
* Event::GetOriginalTarget() const {
290 return mEvent
->GetOriginalDOMEventTarget();
293 EventTarget
* Event::GetComposedTarget() const {
294 EventTarget
* et
= GetOriginalTarget();
295 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(et
);
299 nsIContent
* nonChrome
= content
->FindFirstNonChromeOnlyAccessContent();
300 return nonChrome
? static_cast<EventTarget
*>(nonChrome
)
301 : static_cast<EventTarget
*>(content
->GetComposedDoc());
304 void Event::SetTrusted(bool aTrusted
) { mEvent
->mFlags
.mIsTrusted
= aTrusted
; }
306 bool Event::Init(mozilla::dom::EventTarget
* aGlobal
) {
307 if (!mIsMainThreadEvent
) {
308 return IsCurrentThreadRunningChromeWorker();
310 bool trusted
= false;
311 nsCOMPtr
<nsPIDOMWindowInner
> w
= do_QueryInterface(aGlobal
);
313 nsCOMPtr
<Document
> d
= w
->GetExtantDoc();
315 trusted
= nsContentUtils::IsChromeDoc(d
);
316 nsPresContext
* presContext
= d
->GetPresContext();
318 InitPresContextData(presContext
);
326 already_AddRefed
<Event
> Event::Constructor(const GlobalObject
& aGlobal
,
327 const nsAString
& aType
,
328 const EventInit
& aParam
) {
329 nsCOMPtr
<mozilla::dom::EventTarget
> t
=
330 do_QueryInterface(aGlobal
.GetAsSupports());
331 return Constructor(t
, aType
, aParam
);
335 already_AddRefed
<Event
> Event::Constructor(EventTarget
* aEventTarget
,
336 const nsAString
& aType
,
337 const EventInit
& aParam
) {
338 RefPtr
<Event
> e
= new Event(aEventTarget
, nullptr, nullptr);
339 bool trusted
= e
->Init(aEventTarget
);
340 e
->InitEvent(aType
, aParam
.mBubbles
, aParam
.mCancelable
);
341 e
->SetTrusted(trusted
);
342 e
->SetComposed(aParam
.mComposed
);
346 uint16_t Event::EventPhase() const {
347 // Note, remember to check that this works also
348 // if or when Bug 235441 is fixed.
349 if ((mEvent
->mCurrentTarget
&& mEvent
->mCurrentTarget
== mEvent
->mTarget
) ||
350 mEvent
->mFlags
.InTargetPhase()) {
351 return Event_Binding::AT_TARGET
;
353 if (mEvent
->mFlags
.mInCapturePhase
) {
354 return Event_Binding::CAPTURING_PHASE
;
356 if (mEvent
->mFlags
.mInBubblingPhase
) {
357 return Event_Binding::BUBBLING_PHASE
;
359 return Event_Binding::NONE
;
362 void Event::StopPropagation() { mEvent
->StopPropagation(); }
364 void Event::StopImmediatePropagation() { mEvent
->StopImmediatePropagation(); }
366 void Event::StopCrossProcessForwarding() {
367 mEvent
->StopCrossProcessForwarding();
370 void Event::PreventDefault() {
371 // This method is called only from C++ code which must handle default action
372 // of this event. So, pass true always.
373 PreventDefaultInternal(true);
376 void Event::PreventDefault(JSContext
* aCx
, CallerType aCallerType
) {
377 // Note that at handling default action, another event may be dispatched.
378 // Then, JS in content mey be call preventDefault()
379 // even in the event is in system event group. Therefore, don't refer
380 // mInSystemGroup here.
381 nsIPrincipal
* principal
=
382 mIsMainThreadEvent
? nsContentUtils::SubjectPrincipal(aCx
) : nullptr;
384 PreventDefaultInternal(aCallerType
== CallerType::System
, principal
);
387 void Event::PreventDefaultInternal(bool aCalledByDefaultHandler
,
388 nsIPrincipal
* aPrincipal
) {
389 if (!mEvent
->mFlags
.mCancelable
) {
392 if (mEvent
->mFlags
.mInPassiveListener
) {
393 nsCOMPtr
<nsPIDOMWindowInner
> win(do_QueryInterface(mOwner
));
395 if (Document
* doc
= win
->GetExtantDoc()) {
396 AutoTArray
<nsString
, 1> params
;
397 GetType(*params
.AppendElement());
398 doc
->WarnOnceAbout(Document::ePreventDefaultFromPassiveListener
, false,
405 mEvent
->PreventDefault(aCalledByDefaultHandler
, aPrincipal
);
411 WidgetDragEvent
* dragEvent
= mEvent
->AsDragEvent();
416 nsIPrincipal
* principal
= nullptr;
417 nsCOMPtr
<nsINode
> node
= do_QueryInterface(mEvent
->mCurrentTarget
);
419 principal
= node
->NodePrincipal();
421 nsCOMPtr
<nsIScriptObjectPrincipal
> sop
=
422 do_QueryInterface(mEvent
->mCurrentTarget
);
424 principal
= sop
->GetPrincipal();
427 if (principal
&& !principal
->IsSystemPrincipal()) {
428 dragEvent
->mDefaultPreventedOnContent
= true;
432 void Event::SetEventType(const nsAString
& aEventTypeArg
) {
433 mEvent
->mSpecifiedEventTypeString
.Truncate();
434 if (mIsMainThreadEvent
) {
435 mEvent
->mSpecifiedEventType
= nsContentUtils::GetEventMessageAndAtom(
436 aEventTypeArg
, mEvent
->mClass
, &(mEvent
->mMessage
));
437 mEvent
->SetDefaultComposed();
439 mEvent
->mSpecifiedEventType
= NS_Atomize(u
"on"_ns
+ aEventTypeArg
);
440 mEvent
->mMessage
= eUnidentifiedEvent
;
441 mEvent
->SetComposed(aEventTypeArg
);
443 mEvent
->SetDefaultComposedInNativeAnonymousContent();
446 already_AddRefed
<EventTarget
> Event::EnsureWebAccessibleRelatedTarget(
447 EventTarget
* aRelatedTarget
) {
448 nsCOMPtr
<EventTarget
> relatedTarget
= aRelatedTarget
;
450 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(relatedTarget
);
452 if (content
&& content
->ChromeOnlyAccess() &&
453 !nsContentUtils::CanAccessNativeAnon()) {
454 content
= content
->FindFirstNonChromeOnlyAccessContent();
455 relatedTarget
= content
;
459 relatedTarget
= relatedTarget
->GetTargetForDOMEvent();
462 return relatedTarget
.forget();
465 void Event::InitEvent(const nsAString
& aEventTypeArg
,
466 mozilla::CanBubble aCanBubbleArg
,
467 mozilla::Cancelable aCancelableArg
,
468 mozilla::Composed aComposedArg
) {
469 // Make sure this event isn't already being dispatched.
470 NS_ENSURE_TRUE_VOID(!mEvent
->mFlags
.mIsBeingDispatched
);
473 // Ensure the caller is permitted to dispatch trusted DOM events.
474 if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
479 SetEventType(aEventTypeArg
);
481 mEvent
->mFlags
.mBubbles
= aCanBubbleArg
== CanBubble::eYes
;
482 mEvent
->mFlags
.mCancelable
= aCancelableArg
== Cancelable::eYes
;
483 if (aComposedArg
!= Composed::eDefault
) {
484 mEvent
->mFlags
.mComposed
= aComposedArg
== Composed::eYes
;
487 mEvent
->mFlags
.mDefaultPrevented
= false;
488 mEvent
->mFlags
.mDefaultPreventedByContent
= false;
489 mEvent
->mFlags
.mDefaultPreventedByChrome
= false;
490 mEvent
->mFlags
.mPropagationStopped
= false;
491 mEvent
->mFlags
.mImmediatePropagationStopped
= false;
493 // Clearing the old targets, so that the event is targeted correctly when
494 // re-dispatching it.
495 mEvent
->mTarget
= nullptr;
496 mEvent
->mOriginalTarget
= nullptr;
499 void Event::DuplicatePrivateData() {
500 NS_ASSERTION(mEvent
, "No WidgetEvent for Event duplication!");
501 if (mEventIsInternal
) {
505 mEvent
= mEvent
->Duplicate();
506 mPresContext
= nullptr;
507 mEventIsInternal
= true;
508 mPrivateDataDuplicated
= true;
511 void Event::SetTarget(EventTarget
* aTarget
) { mEvent
->mTarget
= aTarget
; }
513 bool Event::IsDispatchStopped() { return mEvent
->PropagationStopped(); }
515 WidgetEvent
* Event::WidgetEventPtr() { return mEvent
; }
518 CSSIntPoint
Event::GetScreenCoords(nsPresContext
* aPresContext
,
520 LayoutDeviceIntPoint aPoint
) {
521 if (PointerLockManager::IsLocked()) {
522 return EventStateManager::sLastScreenPoint
;
525 if (!aEvent
|| (aEvent
->mClass
!= eMouseEventClass
&&
526 aEvent
->mClass
!= eMouseScrollEventClass
&&
527 aEvent
->mClass
!= eWheelEventClass
&&
528 aEvent
->mClass
!= ePointerEventClass
&&
529 aEvent
->mClass
!= eTouchEventClass
&&
530 aEvent
->mClass
!= eDragEventClass
&&
531 aEvent
->mClass
!= eSimpleGestureEventClass
)) {
532 return CSSIntPoint(0, 0);
535 // Doing a straight conversion from LayoutDeviceIntPoint to CSSIntPoint
536 // seem incorrect, but it is needed to maintain legacy functionality.
537 WidgetGUIEvent
* guiEvent
= aEvent
->AsGUIEvent();
538 if (!aPresContext
|| !(guiEvent
&& guiEvent
->mWidget
)) {
539 return CSSIntPoint(aPoint
.x
, aPoint
.y
);
542 // (Potentially) transform the point from the coordinate space of an
543 // out-of-process iframe to the coordinate space of the native
544 // window. The transform can only be applied to a point whose components
545 // are floating-point values, so convert the integer point first, then
546 // transform, and then round the result back to an integer point.
547 LayoutDevicePoint
floatPoint(aPoint
);
548 LayoutDevicePoint topLevelPoint
=
549 guiEvent
->mWidget
->WidgetToTopLevelWidgetTransform().TransformPoint(
551 LayoutDeviceIntPoint rounded
= RoundedToInt(topLevelPoint
);
553 nsPoint pt
= LayoutDevicePixel::ToAppUnits(
555 aPresContext
->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
557 pt
+= LayoutDevicePixel::ToAppUnits(
558 guiEvent
->mWidget
->TopLevelWidgetToScreenOffset(),
559 aPresContext
->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
561 return CSSPixel::FromAppUnitsRounded(pt
);
565 CSSIntPoint
Event::GetPageCoords(nsPresContext
* aPresContext
,
567 LayoutDeviceIntPoint aPoint
,
568 CSSIntPoint aDefaultPoint
) {
569 CSSIntPoint pagePoint
=
570 Event::GetClientCoords(aPresContext
, aEvent
, aPoint
, aDefaultPoint
);
572 // If there is some scrolling, add scroll info to client point.
573 if (aPresContext
&& aPresContext
->GetPresShell()) {
574 PresShell
* presShell
= aPresContext
->PresShell();
575 nsIScrollableFrame
* scrollframe
=
576 presShell
->GetRootScrollFrameAsScrollable();
579 CSSIntPoint::FromAppUnitsRounded(scrollframe
->GetScrollPosition());
587 CSSIntPoint
Event::GetClientCoords(nsPresContext
* aPresContext
,
589 LayoutDeviceIntPoint aPoint
,
590 CSSIntPoint aDefaultPoint
) {
591 if (PointerLockManager::IsLocked()) {
592 return EventStateManager::sLastClientPoint
;
596 (aEvent
->mClass
!= eMouseEventClass
&&
597 aEvent
->mClass
!= eMouseScrollEventClass
&&
598 aEvent
->mClass
!= eWheelEventClass
&&
599 aEvent
->mClass
!= eTouchEventClass
&&
600 aEvent
->mClass
!= eDragEventClass
&&
601 aEvent
->mClass
!= ePointerEventClass
&&
602 aEvent
->mClass
!= eSimpleGestureEventClass
) ||
603 !aPresContext
|| !aEvent
->AsGUIEvent()->mWidget
) {
604 return aDefaultPoint
;
607 PresShell
* presShell
= aPresContext
->GetPresShell();
609 return CSSIntPoint(0, 0);
611 nsIFrame
* rootFrame
= presShell
->GetRootFrame();
613 return CSSIntPoint(0, 0);
615 nsPoint pt
= nsLayoutUtils::GetEventCoordinatesRelativeTo(
616 aEvent
, aPoint
, RelativeTo
{rootFrame
});
618 return CSSIntPoint::FromAppUnitsRounded(pt
);
622 CSSIntPoint
Event::GetOffsetCoords(nsPresContext
* aPresContext
,
624 LayoutDeviceIntPoint aPoint
,
625 CSSIntPoint aDefaultPoint
) {
626 if (!aEvent
->mTarget
) {
627 return GetPageCoords(aPresContext
, aEvent
, aPoint
, aDefaultPoint
);
629 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(aEvent
->mTarget
);
630 if (!content
|| !aPresContext
) {
631 return CSSIntPoint();
633 RefPtr
<PresShell
> presShell
= aPresContext
->GetPresShell();
635 return CSSIntPoint();
637 presShell
->FlushPendingNotifications(FlushType::Layout
);
638 nsIFrame
* frame
= content
->GetPrimaryFrame();
640 return CSSIntPoint();
642 // For compat, see https://github.com/w3c/csswg-drafts/issues/1508. In SVG we
643 // just return the coordinates of the outer SVG box. This is all kinda
645 if (frame
->HasAnyStateBits(NS_FRAME_SVG_LAYOUT
) &&
646 StaticPrefs::dom_events_offset_in_svg_relative_to_svg_root()) {
647 frame
= SVGUtils::GetOuterSVGFrame(frame
);
649 return CSSIntPoint();
652 nsIFrame
* rootFrame
= presShell
->GetRootFrame();
654 return CSSIntPoint();
656 CSSIntPoint clientCoords
=
657 GetClientCoords(aPresContext
, aEvent
, aPoint
, aDefaultPoint
);
658 nsPoint pt
= CSSPixel::ToAppUnits(clientCoords
);
659 if (nsLayoutUtils::TransformPoint(RelativeTo
{rootFrame
}, RelativeTo
{frame
},
660 pt
) == nsLayoutUtils::TRANSFORM_SUCCEEDED
) {
661 pt
-= frame
->GetPaddingRectRelativeToSelf().TopLeft();
662 return CSSPixel::FromAppUnitsRounded(pt
);
664 return CSSIntPoint();
667 // To be called ONLY by Event::GetType (which has the additional
668 // logic for handling user-defined events).
670 const char16_t
* Event::GetEventName(EventMessage aEventType
) {
671 switch (aEventType
) {
672 #define MESSAGE_TO_EVENT(name_, _message, _type, _struct) \
675 #include "mozilla/EventNameList.h"
676 #undef MESSAGE_TO_EVENT
680 // XXXldb We can hit this case for WidgetEvent objects that we didn't
681 // create and that are not user defined events since this function and
682 // SetEventType are incomplete. (But fixing that requires fixing the
683 // arrays in nsEventListenerManager too, since the events for which
684 // this is a problem generally *are* created by Event.)
688 bool Event::DefaultPrevented(CallerType aCallerType
) const {
689 NS_ENSURE_TRUE(mEvent
, false);
691 // If preventDefault() has never been called, just return false.
692 if (!mEvent
->DefaultPrevented()) {
696 // If preventDefault() has been called by content, return true. Otherwise,
697 // i.e., preventDefault() has been called by chrome, return true only when
698 // this is called by chrome.
699 return mEvent
->DefaultPreventedByContent() ||
700 aCallerType
== CallerType::System
;
703 bool Event::ReturnValue(CallerType aCallerType
) const {
704 return !DefaultPrevented(aCallerType
);
707 void Event::SetReturnValue(bool aReturnValue
, CallerType aCallerType
) {
709 PreventDefaultInternal(aCallerType
== CallerType::System
);
713 double Event::TimeStamp() {
714 if (mEvent
->mTimeStamp
.IsNull()) {
718 if (mIsMainThreadEvent
) {
719 if (NS_WARN_IF(!mOwner
)) {
723 nsCOMPtr
<nsPIDOMWindowInner
> win
= do_QueryInterface(mOwner
);
724 if (NS_WARN_IF(!win
)) {
728 Performance
* perf
= win
->GetPerformance();
729 if (NS_WARN_IF(!perf
)) {
734 perf
->GetDOMTiming()->TimeStampToDOMHighRes(mEvent
->mTimeStamp
);
735 MOZ_ASSERT(mOwner
->PrincipalOrNull());
737 return nsRFPService::ReduceTimePrecisionAsMSecs(
738 ret
, perf
->GetRandomTimelineSeed(),
739 mOwner
->PrincipalOrNull()->IsSystemPrincipal(),
740 mOwner
->CrossOriginIsolated());
743 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
744 MOZ_ASSERT(workerPrivate
);
746 double ret
= workerPrivate
->TimeStampToDOMHighRes(mEvent
->mTimeStamp
);
748 return nsRFPService::ReduceTimePrecisionAsMSecs(
749 ret
, workerPrivate
->GetRandomTimelineSeed(),
750 workerPrivate
->UsesSystemPrincipal(),
751 workerPrivate
->CrossOriginIsolated());
754 void Event::Serialize(IPC::Message
* aMsg
, bool aSerializeInterfaceType
) {
755 if (aSerializeInterfaceType
) {
756 IPC::WriteParam(aMsg
, u
"event"_ns
);
761 IPC::WriteParam(aMsg
, type
);
763 IPC::WriteParam(aMsg
, Bubbles());
764 IPC::WriteParam(aMsg
, Cancelable());
765 IPC::WriteParam(aMsg
, IsTrusted());
766 IPC::WriteParam(aMsg
, Composed());
768 // No timestamp serialization for now!
771 bool Event::Deserialize(const IPC::Message
* aMsg
, PickleIterator
* aIter
) {
773 NS_ENSURE_TRUE(IPC::ReadParam(aMsg
, aIter
, &type
), false);
775 bool bubbles
= false;
776 NS_ENSURE_TRUE(IPC::ReadParam(aMsg
, aIter
, &bubbles
), false);
778 bool cancelable
= false;
779 NS_ENSURE_TRUE(IPC::ReadParam(aMsg
, aIter
, &cancelable
), false);
781 bool trusted
= false;
782 NS_ENSURE_TRUE(IPC::ReadParam(aMsg
, aIter
, &trusted
), false);
784 bool composed
= false;
785 NS_ENSURE_TRUE(IPC::ReadParam(aMsg
, aIter
, &composed
), false);
787 InitEvent(type
, bubbles
, cancelable
);
789 SetComposed(composed
);
794 void Event::SetOwner(EventTarget
* aOwner
) {
801 nsCOMPtr
<nsINode
> n
= do_QueryInterface(aOwner
);
803 mOwner
= n
->OwnerDoc()->GetScopeObject();
807 nsCOMPtr
<nsPIDOMWindowInner
> w
= do_QueryInterface(aOwner
);
809 mOwner
= do_QueryInterface(w
);
813 nsCOMPtr
<DOMEventTargetHelper
> eth
= do_QueryInterface(aOwner
);
815 mOwner
= eth
->GetParentObject();
820 nsCOMPtr
<nsPIWindowRoot
> root
= do_QueryInterface(aOwner
);
821 MOZ_ASSERT(root
, "Unexpected EventTarget!");
825 void Event::GetWidgetEventType(WidgetEvent
* aEvent
, nsAString
& aType
) {
826 if (!aEvent
->mSpecifiedEventTypeString
.IsEmpty()) {
827 aType
= aEvent
->mSpecifiedEventTypeString
;
831 const char16_t
* name
= GetEventName(aEvent
->mMessage
);
836 } else if (aEvent
->mMessage
== eUnidentifiedEvent
&&
837 aEvent
->mSpecifiedEventType
) {
839 aType
= Substring(nsDependentAtomString(aEvent
->mSpecifiedEventType
), 2);
840 aEvent
->mSpecifiedEventTypeString
= aType
;
847 bool Event::IsDragExitEnabled(JSContext
* aCx
, JSObject
* aGlobal
) {
848 return StaticPrefs::dom_event_dragexit_enabled() ||
849 nsContentUtils::IsSystemCaller(aCx
);
852 } // namespace mozilla::dom
854 using namespace mozilla
;
855 using namespace mozilla::dom
;
857 already_AddRefed
<Event
> NS_NewDOMEvent(EventTarget
* aOwner
,
858 nsPresContext
* aPresContext
,
859 WidgetEvent
* aEvent
) {
860 RefPtr
<Event
> it
= new Event(aOwner
, aPresContext
, aEvent
);