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 "ipc/IPCMessageUtilsSpecializations.h"
11 #include "mozilla/EventDispatcher.h"
12 #include "mozilla/BasePrincipal.h"
13 #include "mozilla/ContentEvents.h"
14 #include "mozilla/DOMEventTargetHelper.h"
15 #include "mozilla/EventStateManager.h"
16 #include "mozilla/InternalMutationEvent.h"
17 #include "mozilla/dom/Performance.h"
18 #include "mozilla/dom/WorkerPrivate.h"
19 #include "mozilla/MiscEvents.h"
20 #include "mozilla/MouseEvents.h"
21 #include "mozilla/PointerLockManager.h"
22 #include "mozilla/Preferences.h"
23 #include "mozilla/PresShell.h"
24 #include "mozilla/StaticPrefs_dom.h"
25 #include "mozilla/TextEvents.h"
26 #include "mozilla/TouchEvents.h"
27 #include "mozilla/ViewportUtils.h"
28 #include "mozilla/dom/Document.h"
29 #include "mozilla/dom/DocumentInlines.h"
30 #include "mozilla/dom/Event.h"
31 #include "mozilla/dom/ShadowRoot.h"
32 #include "mozilla/dom/WorkerScope.h"
33 #include "mozilla/ScrollContainerFrame.h"
34 #include "mozilla/StaticPrefs_dom.h"
35 #include "mozilla/SVGUtils.h"
36 #include "mozilla/SVGOuterSVGFrame.h"
37 #include "nsContentUtils.h"
39 #include "nsDeviceContext.h"
41 #include "nsGlobalWindowInner.h"
43 #include "nsIContent.h"
44 #include "nsIContentInlines.h"
45 #include "nsJSEnvironment.h"
46 #include "nsLayoutUtils.h"
47 #include "nsPIWindowRoot.h"
48 #include "nsRFPService.h"
50 namespace mozilla::dom
{
52 Event::Event(EventTarget
* aOwner
, nsPresContext
* aPresContext
,
53 WidgetEvent
* aEvent
) {
54 ConstructorInit(aOwner
, aPresContext
, aEvent
);
57 Event::Event(nsPIDOMWindowInner
* aParent
) {
58 ConstructorInit(nsGlobalWindowInner::Cast(aParent
), nullptr, nullptr);
61 void Event::ConstructorInit(EventTarget
* aOwner
, nsPresContext
* aPresContext
,
62 WidgetEvent
* aEvent
) {
64 mIsMainThreadEvent
= NS_IsMainThread();
65 if (mIsMainThreadEvent
) {
66 mRefCnt
.SetIsOnMainThread();
69 mPrivateDataDuplicated
= false;
70 mWantsPopupControlCheck
= false;
74 mEventIsInternal
= false;
76 mEventIsInternal
= true;
78 A derived class might want to allocate its own type of aEvent
79 (derived from WidgetEvent). To do this, it should take care to pass
80 a non-nullptr aEvent to this ctor, e.g.:
82 FooEvent::FooEvent(..., WidgetEvent* aEvent)
83 : Event(..., aEvent ? aEvent : new WidgetEvent())
85 Then, to override the mEventIsInternal assignments done by the
86 base ctor, it should do this in its own ctor:
88 FooEvent::FooEvent(..., WidgetEvent* aEvent)
93 mEventIsInternal = false;
96 mEventIsInternal = true;
101 mEvent
= new WidgetEvent(false, eVoidEvent
);
104 InitPresContextData(aPresContext
);
107 void Event::InitPresContextData(nsPresContext
* aPresContext
) {
108 mPresContext
= aPresContext
;
109 // Get the explicit original target (if it's anonymous make it null)
111 nsCOMPtr
<nsIContent
> content
= GetTargetFromFrame();
112 if (content
&& !content
->IsInNativeAnonymousSubtree()) {
113 mExplicitOriginalTarget
= std::move(content
);
115 mExplicitOriginalTarget
= nullptr;
121 NS_ASSERT_OWNINGTHREAD(Event
);
123 if (mEventIsInternal
&& mEvent
) {
128 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Event
)
129 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
130 NS_INTERFACE_MAP_ENTRY(nsISupports
)
131 NS_INTERFACE_MAP_ENTRY(Event
)
134 NS_IMPL_CYCLE_COLLECTING_ADDREF(Event
)
135 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(Event
, LastRelease())
137 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(Event
)
139 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event
)
140 if (tmp
->mEventIsInternal
) {
141 tmp
->mEvent
->mTarget
= nullptr;
142 tmp
->mEvent
->mCurrentTarget
= nullptr;
143 tmp
->mEvent
->mOriginalTarget
= nullptr;
144 tmp
->mEvent
->mRelatedTarget
= nullptr;
145 tmp
->mEvent
->mOriginalRelatedTarget
= nullptr;
146 switch (tmp
->mEvent
->mClass
) {
147 case eDragEventClass
: {
148 WidgetDragEvent
* dragEvent
= tmp
->mEvent
->AsDragEvent();
149 dragEvent
->mDataTransfer
= nullptr;
152 case eClipboardEventClass
:
153 tmp
->mEvent
->AsClipboardEvent()->mClipboardData
= nullptr;
155 case eEditorInputEventClass
: {
156 InternalEditorInputEvent
* inputEvent
=
157 tmp
->mEvent
->AsEditorInputEvent();
158 inputEvent
->mDataTransfer
= nullptr;
159 inputEvent
->mTargetRanges
.Clear();
162 case eMutationEventClass
:
163 tmp
->mEvent
->AsMutationEvent()->mRelatedNode
= nullptr;
169 if (WidgetMouseEvent
* mouseEvent
= tmp
->mEvent
->AsMouseEvent()) {
170 mouseEvent
->mClickTarget
= nullptr;
173 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext
);
174 NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget
);
175 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner
);
176 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
177 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
179 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event
)
180 if (tmp
->mEventIsInternal
) {
181 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mTarget
)
182 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mCurrentTarget
)
183 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mOriginalTarget
)
184 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mRelatedTarget
)
185 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mOriginalRelatedTarget
);
186 switch (tmp
->mEvent
->mClass
) {
187 case eDragEventClass
: {
188 WidgetDragEvent
* dragEvent
= tmp
->mEvent
->AsDragEvent();
189 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mDataTransfer");
190 cb
.NoteXPCOMChild(dragEvent
->mDataTransfer
);
193 case eClipboardEventClass
:
194 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mClipboardData");
195 cb
.NoteXPCOMChild(tmp
->mEvent
->AsClipboardEvent()->mClipboardData
);
197 case eEditorInputEventClass
:
198 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mDataTransfer");
199 cb
.NoteXPCOMChild(tmp
->mEvent
->AsEditorInputEvent()->mDataTransfer
);
200 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
201 mEvent
->AsEditorInputEvent()->mTargetRanges
);
203 case eMutationEventClass
:
204 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mRelatedNode");
205 cb
.NoteXPCOMChild(tmp
->mEvent
->AsMutationEvent()->mRelatedNode
);
211 if (WidgetMouseEvent
* mouseEvent
= tmp
->mEvent
->AsMouseEvent()) {
212 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mClickTarget");
213 cb
.NoteXPCOMChild(mouseEvent
->mClickTarget
);
216 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext
)
217 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget
)
218 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner
)
219 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
221 void Event::LastRelease() {
222 nsISupports
* supports
= nullptr;
223 QueryInterface(NS_GET_IID(nsCycleCollectionISupports
),
224 reinterpret_cast<void**>(&supports
));
225 nsXPCOMCycleCollectionParticipant
* p
= nullptr;
226 CallQueryInterface(this, &p
);
230 JSObject
* Event::WrapObject(JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
231 return WrapObjectInternal(aCx
, aGivenProto
);
234 JSObject
* Event::WrapObjectInternal(JSContext
* aCx
,
235 JS::Handle
<JSObject
*> aGivenProto
) {
236 return Event_Binding::Wrap(aCx
, this, aGivenProto
);
239 void Event::GetType(nsAString
& aType
) const {
240 GetWidgetEventType(mEvent
, aType
);
243 EventTarget
* Event::GetTarget() const { return mEvent
->GetDOMEventTarget(); }
245 already_AddRefed
<Document
> Event::GetDocument() const {
246 nsCOMPtr
<EventTarget
> eventTarget
= GetTarget();
252 nsIGlobalObject
* global
= eventTarget
->GetOwnerGlobal();
257 nsPIDOMWindowInner
* win
= global
->GetAsInnerWindow();
262 nsCOMPtr
<Document
> doc
;
263 doc
= win
->GetExtantDoc();
268 EventTarget
* Event::GetCurrentTarget() const {
269 return mEvent
->GetCurrentDOMEventTarget();
272 void Event::ComposedPath(nsTArray
<RefPtr
<EventTarget
>>& aPath
) {
273 EventDispatcher::GetComposedPathFor(mEvent
, aPath
);
277 // Get the actual event target node (may have been retargeted for mouse events)
279 already_AddRefed
<nsIContent
> Event::GetTargetFromFrame() {
284 // Get the mTarget frame (have to get the ESM first)
285 nsIFrame
* targetFrame
= mPresContext
->EventStateManager()->GetEventTarget();
290 // get the real content
291 nsCOMPtr
<nsIContent
> realEventContent
;
292 targetFrame
->GetContentForEvent(mEvent
, getter_AddRefs(realEventContent
));
293 return realEventContent
.forget();
296 EventTarget
* Event::GetExplicitOriginalTarget() const {
297 if (mExplicitOriginalTarget
) {
298 return mExplicitOriginalTarget
;
303 EventTarget
* Event::GetOriginalTarget() const {
304 return mEvent
->GetOriginalDOMEventTarget();
307 EventTarget
* Event::GetComposedTarget() const {
308 EventTarget
* et
= GetOriginalTarget();
309 nsIContent
* content
= nsIContent::FromEventTargetOrNull(et
);
313 nsIContent
* nonChrome
= content
->FindFirstNonChromeOnlyAccessContent();
314 return nonChrome
? static_cast<EventTarget
*>(nonChrome
)
315 : static_cast<EventTarget
*>(content
->GetComposedDoc());
318 void Event::SetTrusted(bool aTrusted
) { mEvent
->mFlags
.mIsTrusted
= aTrusted
; }
320 bool Event::ShouldIgnoreChromeEventTargetListener() const {
321 MOZ_ASSERT(NS_IsMainThread());
322 if (!XRE_IsParentProcess()) {
325 if (EventTarget
* currentTarget
= GetCurrentTarget();
326 NS_WARN_IF(!currentTarget
) || !currentTarget
->IsRootWindow()) {
329 EventTarget
* et
= GetOriginalTarget();
330 if (NS_WARN_IF(!et
)) {
333 nsIGlobalObject
* global
= et
->GetOwnerGlobal();
334 if (NS_WARN_IF(!global
)) {
337 nsPIDOMWindowInner
* win
= global
->GetAsInnerWindow();
338 if (NS_WARN_IF(!win
)) {
341 BrowsingContext
* bc
= win
->GetBrowsingContext();
342 if (NS_WARN_IF(!bc
)) {
345 // If this is a content event on an nsWindowRoot, then we also handle this in
346 // InProcessBrowserChildMessageManager, so we can ignore this event.
347 return bc
->IsContent();
350 bool Event::Init(mozilla::dom::EventTarget
* aGlobal
) {
351 if (!mIsMainThreadEvent
) {
352 return IsCurrentThreadRunningChromeWorker();
354 bool trusted
= false;
356 if (nsPIDOMWindowInner
* w
= aGlobal
->GetAsInnerWindow()) {
357 if (Document
* d
= w
->GetExtantDoc()) {
358 trusted
= nsContentUtils::IsChromeDoc(d
);
359 if (nsPresContext
* presContext
= d
->GetPresContext()) {
360 InitPresContextData(presContext
);
369 already_AddRefed
<Event
> Event::Constructor(const GlobalObject
& aGlobal
,
370 const nsAString
& aType
,
371 const EventInit
& aParam
) {
372 nsCOMPtr
<mozilla::dom::EventTarget
> t
=
373 do_QueryInterface(aGlobal
.GetAsSupports());
374 return Constructor(t
, aType
, aParam
);
378 already_AddRefed
<Event
> Event::Constructor(EventTarget
* aEventTarget
,
379 const nsAString
& aType
,
380 const EventInit
& aParam
) {
381 RefPtr
<Event
> e
= new Event(aEventTarget
, nullptr, nullptr);
382 bool trusted
= e
->Init(aEventTarget
);
383 e
->InitEvent(aType
, aParam
.mBubbles
, aParam
.mCancelable
);
384 e
->SetTrusted(trusted
);
385 e
->SetComposed(aParam
.mComposed
);
389 uint16_t Event::EventPhase() const {
390 if ((mEvent
->mCurrentTarget
&& mEvent
->mCurrentTarget
== mEvent
->mTarget
) ||
391 mEvent
->mFlags
.mInTargetPhase
) {
392 return Event_Binding::AT_TARGET
;
394 if (mEvent
->mFlags
.mInCapturePhase
) {
395 return Event_Binding::CAPTURING_PHASE
;
397 if (mEvent
->mFlags
.mInBubblingPhase
) {
398 return Event_Binding::BUBBLING_PHASE
;
400 return Event_Binding::NONE
;
403 void Event::StopPropagation() { mEvent
->StopPropagation(); }
405 void Event::StopImmediatePropagation() { mEvent
->StopImmediatePropagation(); }
407 void Event::StopCrossProcessForwarding() {
408 mEvent
->StopCrossProcessForwarding();
411 void Event::PreventDefault() {
412 // This method is called only from C++ code which must handle default action
413 // of this event. So, pass true always.
414 PreventDefaultInternal(true);
417 void Event::PreventDefault(JSContext
* aCx
, CallerType aCallerType
) {
418 // Note that at handling default action, another event may be dispatched.
419 // Then, JS in content mey be call preventDefault()
420 // even in the event is in system event group. Therefore, don't refer
421 // mInSystemGroup here.
422 nsIPrincipal
* principal
=
423 mIsMainThreadEvent
? nsContentUtils::SubjectPrincipal(aCx
) : nullptr;
425 PreventDefaultInternal(aCallerType
== CallerType::System
, principal
);
428 void Event::PreventDefaultInternal(bool aCalledByDefaultHandler
,
429 nsIPrincipal
* aPrincipal
) {
430 if (!mEvent
->mFlags
.mCancelable
) {
433 if (mEvent
->mFlags
.mInPassiveListener
) {
434 if (nsPIDOMWindowInner
* win
= mOwner
->GetAsInnerWindow()) {
435 if (Document
* doc
= win
->GetExtantDoc()) {
436 if (!doc
->HasWarnedAbout(
437 Document::ePreventDefaultFromPassiveListener
)) {
438 AutoTArray
<nsString
, 1> params
;
439 GetType(*params
.AppendElement());
440 doc
->WarnOnceAbout(Document::ePreventDefaultFromPassiveListener
,
448 mEvent
->PreventDefault(aCalledByDefaultHandler
, aPrincipal
);
454 if (mEvent
->mClass
== eDragEventClass
) {
455 UpdateDefaultPreventedOnContentForDragEvent();
459 void Event::UpdateDefaultPreventedOnContentForDragEvent() {
460 WidgetDragEvent
* dragEvent
= mEvent
->AsDragEvent();
465 nsIPrincipal
* principal
= nullptr;
466 // Since we now have HTMLEditorEventListener registered on nsWindowRoot,
467 // mCurrentTarget could be nsWindowRoot, so we need to use
468 // mTarget if that's the case.
469 MOZ_ASSERT_IF(dragEvent
->mInHTMLEditorEventListener
,
470 mEvent
->mCurrentTarget
->IsRootWindow());
471 EventTarget
* target
= dragEvent
->mInHTMLEditorEventListener
473 : mEvent
->mCurrentTarget
;
475 nsINode
* node
= nsINode::FromEventTargetOrNull(target
);
477 principal
= node
->NodePrincipal();
479 nsCOMPtr
<nsIScriptObjectPrincipal
> sop
= do_QueryInterface(target
);
481 principal
= sop
->GetPrincipal();
484 if (principal
&& !principal
->IsSystemPrincipal()) {
485 dragEvent
->mDefaultPreventedOnContent
= true;
489 void Event::SetEventType(const nsAString
& aEventTypeArg
) {
490 mEvent
->mSpecifiedEventTypeString
.Truncate();
491 if (mIsMainThreadEvent
) {
492 EventClassID classID
= mEvent
->mClass
;
493 if (classID
== eMouseEventClass
) {
494 // Some pointer event types were changed from MouseEvent. For backward
495 // compatibility, we need to handle untrusted events of them created with
496 // MouseEvent instance in some places.
497 if (aEventTypeArg
.EqualsLiteral(u
"click") ||
498 aEventTypeArg
.EqualsLiteral(u
"auxclick") ||
499 aEventTypeArg
.EqualsLiteral(u
"contextmenu")) {
500 classID
= ePointerEventClass
;
503 mEvent
->mSpecifiedEventType
= nsContentUtils::GetEventMessageAndAtom(
504 aEventTypeArg
, classID
, &(mEvent
->mMessage
));
505 mEvent
->SetDefaultComposed();
507 mEvent
->mSpecifiedEventType
= NS_Atomize(u
"on"_ns
+ aEventTypeArg
);
508 mEvent
->mMessage
= eUnidentifiedEvent
;
509 mEvent
->SetComposed(aEventTypeArg
);
511 mEvent
->SetDefaultComposedInNativeAnonymousContent();
514 already_AddRefed
<EventTarget
> Event::EnsureWebAccessibleRelatedTarget(
515 EventTarget
* aRelatedTarget
) {
516 nsCOMPtr
<EventTarget
> relatedTarget
= aRelatedTarget
;
518 nsIContent
* content
= nsIContent::FromEventTarget(relatedTarget
);
519 if (content
&& content
->ChromeOnlyAccess() &&
520 !nsContentUtils::CanAccessNativeAnon()) {
521 content
= content
->FindFirstNonChromeOnlyAccessContent();
522 relatedTarget
= content
;
526 relatedTarget
= relatedTarget
->GetTargetForDOMEvent();
529 return relatedTarget
.forget();
532 void Event::InitEvent(const nsAString
& aEventTypeArg
,
533 mozilla::CanBubble aCanBubbleArg
,
534 mozilla::Cancelable aCancelableArg
,
535 mozilla::Composed aComposedArg
) {
536 // Make sure this event isn't already being dispatched.
537 NS_ENSURE_TRUE_VOID(!mEvent
->mFlags
.mIsBeingDispatched
);
540 // Ensure the caller is permitted to dispatch trusted DOM events.
541 if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
546 SetEventType(aEventTypeArg
);
548 mEvent
->mFlags
.mBubbles
= aCanBubbleArg
== CanBubble::eYes
;
549 mEvent
->mFlags
.mCancelable
= aCancelableArg
== Cancelable::eYes
;
550 if (aComposedArg
!= Composed::eDefault
) {
551 mEvent
->mFlags
.mComposed
= aComposedArg
== Composed::eYes
;
554 mEvent
->mFlags
.mDefaultPrevented
= false;
555 mEvent
->mFlags
.mDefaultPreventedByContent
= false;
556 mEvent
->mFlags
.mDefaultPreventedByChrome
= false;
557 mEvent
->mFlags
.mPropagationStopped
= false;
558 mEvent
->mFlags
.mImmediatePropagationStopped
= false;
560 // Clearing the old targets, so that the event is targeted correctly when
561 // re-dispatching it.
562 mEvent
->mTarget
= nullptr;
563 mEvent
->mOriginalTarget
= nullptr;
566 void Event::DuplicatePrivateData() {
567 NS_ASSERTION(mEvent
, "No WidgetEvent for Event duplication!");
568 if (mEventIsInternal
) {
572 mEvent
= mEvent
->Duplicate();
573 mPresContext
= nullptr;
574 mEventIsInternal
= true;
575 mPrivateDataDuplicated
= true;
578 void Event::SetTarget(EventTarget
* aTarget
) { mEvent
->mTarget
= aTarget
; }
580 bool Event::IsDispatchStopped() { return mEvent
->PropagationStopped(); }
582 WidgetEvent
* Event::WidgetEventPtr() { return mEvent
; }
585 Maybe
<CSSIntPoint
> Event::GetScreenCoords(nsPresContext
* aPresContext
,
587 LayoutDeviceIntPoint aPoint
) {
588 if (PointerLockManager::IsLocked()) {
589 return Some(EventStateManager::sLastScreenPoint
);
592 if (!aEvent
|| (aEvent
->mClass
!= eMouseEventClass
&&
593 aEvent
->mClass
!= eMouseScrollEventClass
&&
594 aEvent
->mClass
!= eWheelEventClass
&&
595 aEvent
->mClass
!= ePointerEventClass
&&
596 aEvent
->mClass
!= eTouchEventClass
&&
597 aEvent
->mClass
!= eDragEventClass
&&
598 aEvent
->mClass
!= eSimpleGestureEventClass
)) {
602 // Doing a straight conversion from LayoutDeviceIntPoint to CSSIntPoint
603 // seem incorrect, but it is needed to maintain legacy functionality.
604 WidgetGUIEvent
* guiEvent
= aEvent
->AsGUIEvent();
605 if (!aPresContext
|| !(guiEvent
&& guiEvent
->mWidget
)) {
606 return Some(CSSIntPoint(aPoint
.x
, aPoint
.y
));
609 // (Potentially) transform the point from the coordinate space of an
610 // out-of-process iframe to the coordinate space of the native
611 // window. The transform can only be applied to a point whose components
612 // are floating-point values, so convert the integer point first, then
613 // transform, and then round the result back to an integer point.
614 LayoutDevicePoint
floatPoint(aPoint
);
615 LayoutDevicePoint topLevelPoint
=
616 guiEvent
->mWidget
->WidgetToTopLevelWidgetTransform().TransformPoint(
618 LayoutDeviceIntPoint rounded
= RoundedToInt(topLevelPoint
);
620 nsPoint pt
= LayoutDevicePixel::ToAppUnits(
621 rounded
, aPresContext
->DeviceContext()->AppUnitsPerDevPixel());
623 pt
+= LayoutDevicePixel::ToAppUnits(
624 guiEvent
->mWidget
->TopLevelWidgetToScreenOffset(),
625 aPresContext
->DeviceContext()->AppUnitsPerDevPixel());
627 return Some(CSSPixel::FromAppUnitsRounded(pt
));
631 CSSIntPoint
Event::GetPageCoords(nsPresContext
* aPresContext
,
633 LayoutDeviceIntPoint aPoint
,
634 CSSIntPoint aDefaultPoint
) {
635 CSSIntPoint pagePoint
=
636 Event::GetClientCoords(aPresContext
, aEvent
, aPoint
, aDefaultPoint
);
638 // If there is some scrolling, add scroll info to client point.
639 if (aPresContext
&& aPresContext
->GetPresShell()) {
640 PresShell
* presShell
= aPresContext
->PresShell();
641 if (ScrollContainerFrame
* sf
= presShell
->GetRootScrollContainerFrame()) {
642 pagePoint
+= CSSIntPoint::FromAppUnitsRounded(sf
->GetScrollPosition());
650 CSSIntPoint
Event::GetClientCoords(nsPresContext
* aPresContext
,
652 LayoutDeviceIntPoint aPoint
,
653 CSSIntPoint aDefaultPoint
) {
654 if (PointerLockManager::IsLocked()) {
655 return EventStateManager::sLastClientPoint
;
659 (aEvent
->mClass
!= eMouseEventClass
&&
660 aEvent
->mClass
!= eMouseScrollEventClass
&&
661 aEvent
->mClass
!= eWheelEventClass
&&
662 aEvent
->mClass
!= eTouchEventClass
&&
663 aEvent
->mClass
!= eDragEventClass
&&
664 aEvent
->mClass
!= ePointerEventClass
&&
665 aEvent
->mClass
!= eSimpleGestureEventClass
) ||
666 !aPresContext
|| !aEvent
->AsGUIEvent()->mWidget
) {
667 return aDefaultPoint
;
670 PresShell
* presShell
= aPresContext
->GetPresShell();
672 return CSSIntPoint(0, 0);
674 nsIFrame
* rootFrame
= presShell
->GetRootFrame();
676 return CSSIntPoint(0, 0);
678 nsPoint pt
= nsLayoutUtils::GetEventCoordinatesRelativeTo(
679 aEvent
, aPoint
, RelativeTo
{rootFrame
});
681 return CSSIntPoint::FromAppUnitsRounded(pt
);
685 CSSIntPoint
Event::GetOffsetCoords(nsPresContext
* aPresContext
,
687 LayoutDeviceIntPoint aPoint
,
688 CSSIntPoint aDefaultPoint
) {
689 if (!aEvent
->mTarget
) {
690 return GetPageCoords(aPresContext
, aEvent
, aPoint
, aDefaultPoint
);
692 nsCOMPtr
<nsIContent
> content
= nsIContent::FromEventTarget(aEvent
->mTarget
);
693 if (!content
|| !aPresContext
) {
694 return CSSIntPoint();
696 RefPtr
<PresShell
> presShell
= aPresContext
->GetPresShell();
698 return CSSIntPoint();
700 presShell
->FlushPendingNotifications(FlushType::Layout
);
701 nsIFrame
* frame
= content
->GetPrimaryFrame();
703 return CSSIntPoint();
705 // For compat, see https://github.com/w3c/csswg-drafts/issues/1508. In SVG we
706 // just return the coordinates of the outer SVG box. This is all kinda
708 if (frame
->HasAnyStateBits(NS_FRAME_SVG_LAYOUT
) &&
709 StaticPrefs::dom_events_offset_in_svg_relative_to_svg_root()) {
710 frame
= SVGUtils::GetOuterSVGFrame(frame
);
712 return CSSIntPoint();
715 nsIFrame
* rootFrame
= presShell
->GetRootFrame();
717 return CSSIntPoint();
719 CSSIntPoint clientCoords
=
720 GetClientCoords(aPresContext
, aEvent
, aPoint
, aDefaultPoint
);
721 nsPoint pt
= CSSPixel::ToAppUnits(clientCoords
);
722 if (nsLayoutUtils::TransformPoint(RelativeTo
{rootFrame
}, RelativeTo
{frame
},
723 pt
) == nsLayoutUtils::TRANSFORM_SUCCEEDED
) {
724 pt
-= frame
->GetPaddingRectRelativeToSelf().TopLeft();
725 return CSSPixel::FromAppUnitsRounded(pt
);
727 return CSSIntPoint();
730 // To be called ONLY by Event::GetType (which has the additional
731 // logic for handling user-defined events).
733 const char16_t
* Event::GetEventName(EventMessage aEventType
) {
734 switch (aEventType
) {
735 #define MESSAGE_TO_EVENT(name_, _message, _type, _struct) \
738 #include "mozilla/EventNameList.h"
739 #undef MESSAGE_TO_EVENT
743 // XXXldb We can hit this case for WidgetEvent objects that we didn't
744 // create and that are not user defined events since this function and
745 // SetEventType are incomplete. (But fixing that requires fixing the
746 // arrays in nsEventListenerManager too, since the events for which
747 // this is a problem generally *are* created by Event.)
751 bool Event::DefaultPrevented(CallerType aCallerType
) const {
752 NS_ENSURE_TRUE(mEvent
, false);
754 // If preventDefault() has never been called, just return false.
755 if (!mEvent
->DefaultPrevented()) {
759 // If preventDefault() has been called by content, return true. Otherwise,
760 // i.e., preventDefault() has been called by chrome, return true only when
761 // this is called by chrome.
762 return mEvent
->DefaultPreventedByContent() ||
763 aCallerType
== CallerType::System
;
766 bool Event::ReturnValue(CallerType aCallerType
) const {
767 return !DefaultPrevented(aCallerType
);
770 void Event::SetReturnValue(bool aReturnValue
, CallerType aCallerType
) {
772 PreventDefaultInternal(aCallerType
== CallerType::System
);
776 double Event::TimeStamp() {
777 if (mEvent
->mTimeStamp
.IsNull()) {
781 if (mIsMainThreadEvent
) {
782 if (NS_WARN_IF(!mOwner
)) {
786 nsPIDOMWindowInner
* win
= mOwner
->GetAsInnerWindow();
787 if (NS_WARN_IF(!win
)) {
791 Performance
* perf
= win
->GetPerformance();
792 if (NS_WARN_IF(!perf
)) {
797 perf
->GetDOMTiming()->TimeStampToDOMHighRes(mEvent
->mTimeStamp
);
798 MOZ_ASSERT(mOwner
->PrincipalOrNull());
800 return nsRFPService::ReduceTimePrecisionAsMSecs(
801 ret
, perf
->GetRandomTimelineSeed(), perf
->GetRTPCallerType());
804 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
805 MOZ_ASSERT(workerPrivate
);
807 double ret
= workerPrivate
->TimeStampToDOMHighRes(mEvent
->mTimeStamp
);
809 return nsRFPService::ReduceTimePrecisionAsMSecs(
810 ret
, workerPrivate
->GetRandomTimelineSeed(),
811 workerPrivate
->GlobalScope()->GetRTPCallerType());
814 void Event::Serialize(IPC::MessageWriter
* aWriter
,
815 bool aSerializeInterfaceType
) {
816 if (aSerializeInterfaceType
) {
817 IPC::WriteParam(aWriter
, u
"event"_ns
);
822 IPC::WriteParam(aWriter
, type
);
824 IPC::WriteParam(aWriter
, Bubbles());
825 IPC::WriteParam(aWriter
, Cancelable());
826 IPC::WriteParam(aWriter
, IsTrusted());
827 IPC::WriteParam(aWriter
, Composed());
829 // No timestamp serialization for now!
832 bool Event::Deserialize(IPC::MessageReader
* aReader
) {
834 NS_ENSURE_TRUE(IPC::ReadParam(aReader
, &type
), false);
836 bool bubbles
= false;
837 NS_ENSURE_TRUE(IPC::ReadParam(aReader
, &bubbles
), false);
839 bool cancelable
= false;
840 NS_ENSURE_TRUE(IPC::ReadParam(aReader
, &cancelable
), false);
842 bool trusted
= false;
843 NS_ENSURE_TRUE(IPC::ReadParam(aReader
, &trusted
), false);
845 bool composed
= false;
846 NS_ENSURE_TRUE(IPC::ReadParam(aReader
, &composed
), false);
848 InitEvent(type
, bubbles
, cancelable
);
850 SetComposed(composed
);
855 void Event::SetOwner(EventTarget
* aOwner
) {
862 if (nsINode
* n
= aOwner
->GetAsNode()) {
863 mOwner
= n
->OwnerDoc()->GetScopeObject();
867 if (nsPIDOMWindowInner
* w
= aOwner
->GetAsInnerWindow()) {
868 mOwner
= w
->AsGlobal();
872 nsCOMPtr
<DOMEventTargetHelper
> eth
= do_QueryInterface(aOwner
);
874 mOwner
= eth
->GetParentObject();
879 nsCOMPtr
<nsPIWindowRoot
> root
= do_QueryInterface(aOwner
);
880 MOZ_ASSERT(root
, "Unexpected EventTarget!");
884 void Event::GetWidgetEventType(WidgetEvent
* aEvent
, nsAString
& aType
) {
885 if (!aEvent
->mSpecifiedEventTypeString
.IsEmpty()) {
886 aType
= aEvent
->mSpecifiedEventTypeString
;
890 const char16_t
* name
= GetEventName(aEvent
->mMessage
);
893 aType
.AssignLiteral(name
, nsString::char_traits::length(name
));
895 } else if (aEvent
->mMessage
== eUnidentifiedEvent
&&
896 aEvent
->mSpecifiedEventType
) {
898 aType
= Substring(nsDependentAtomString(aEvent
->mSpecifiedEventType
), 2);
899 aEvent
->mSpecifiedEventTypeString
= aType
;
906 bool Event::IsDragExitEnabled(JSContext
* aCx
, JSObject
* aGlobal
) {
907 return StaticPrefs::dom_event_dragexit_enabled() ||
908 nsContentUtils::IsSystemCaller(aCx
);
911 } // namespace mozilla::dom
913 using namespace mozilla
;
914 using namespace mozilla::dom
;
916 already_AddRefed
<Event
> NS_NewDOMEvent(EventTarget
* aOwner
,
917 nsPresContext
* aPresContext
,
918 WidgetEvent
* aEvent
) {
919 RefPtr
<Event
> it
= new Event(aOwner
, aPresContext
, aEvent
);