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/TextEvents.h"
25 #include "mozilla/TouchEvents.h"
26 #include "mozilla/ViewportUtils.h"
27 #include "mozilla/dom/Document.h"
28 #include "mozilla/dom/DocumentInlines.h"
29 #include "mozilla/dom/Event.h"
30 #include "mozilla/dom/ShadowRoot.h"
31 #include "mozilla/dom/WorkerScope.h"
32 #include "mozilla/StaticPrefs_dom.h"
33 #include "mozilla/SVGUtils.h"
34 #include "mozilla/SVGOuterSVGFrame.h"
35 #include "nsContentUtils.h"
37 #include "nsDeviceContext.h"
39 #include "nsGlobalWindowInner.h"
41 #include "nsIContent.h"
42 #include "nsIContentInlines.h"
43 #include "nsIScrollableFrame.h"
44 #include "nsJSEnvironment.h"
45 #include "nsLayoutUtils.h"
46 #include "nsPIWindowRoot.h"
47 #include "nsRFPService.h"
49 namespace mozilla::dom
{
51 Event::Event(EventTarget
* aOwner
, nsPresContext
* aPresContext
,
52 WidgetEvent
* aEvent
) {
53 ConstructorInit(aOwner
, aPresContext
, aEvent
);
56 Event::Event(nsPIDOMWindowInner
* aParent
) {
57 ConstructorInit(nsGlobalWindowInner::Cast(aParent
), nullptr, nullptr);
60 void Event::ConstructorInit(EventTarget
* aOwner
, nsPresContext
* aPresContext
,
61 WidgetEvent
* aEvent
) {
63 mIsMainThreadEvent
= NS_IsMainThread();
64 if (mIsMainThreadEvent
) {
65 mRefCnt
.SetIsOnMainThread();
68 mPrivateDataDuplicated
= false;
69 mWantsPopupControlCheck
= false;
73 mEventIsInternal
= false;
75 mEventIsInternal
= true;
77 A derived class might want to allocate its own type of aEvent
78 (derived from WidgetEvent). To do this, it should take care to pass
79 a non-nullptr aEvent to this ctor, e.g.:
81 FooEvent::FooEvent(..., WidgetEvent* aEvent)
82 : Event(..., aEvent ? aEvent : new WidgetEvent())
84 Then, to override the mEventIsInternal assignments done by the
85 base ctor, it should do this in its own ctor:
87 FooEvent::FooEvent(..., WidgetEvent* aEvent)
92 mEventIsInternal = false;
95 mEventIsInternal = true;
100 mEvent
= new WidgetEvent(false, eVoidEvent
);
103 InitPresContextData(aPresContext
);
106 void Event::InitPresContextData(nsPresContext
* aPresContext
) {
107 mPresContext
= aPresContext
;
108 // Get the explicit original target (if it's anonymous make it null)
110 nsCOMPtr
<nsIContent
> content
= GetTargetFromFrame();
111 if (content
&& !content
->IsInNativeAnonymousSubtree()) {
112 mExplicitOriginalTarget
= std::move(content
);
114 mExplicitOriginalTarget
= nullptr;
120 NS_ASSERT_OWNINGTHREAD(Event
);
122 if (mEventIsInternal
&& mEvent
) {
127 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Event
)
128 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
129 NS_INTERFACE_MAP_ENTRY(nsISupports
)
130 NS_INTERFACE_MAP_ENTRY(Event
)
133 NS_IMPL_CYCLE_COLLECTING_ADDREF(Event
)
134 NS_IMPL_CYCLE_COLLECTING_RELEASE(Event
)
136 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(Event
)
138 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event
)
139 if (tmp
->mEventIsInternal
) {
140 tmp
->mEvent
->mTarget
= nullptr;
141 tmp
->mEvent
->mCurrentTarget
= nullptr;
142 tmp
->mEvent
->mOriginalTarget
= nullptr;
143 tmp
->mEvent
->mRelatedTarget
= nullptr;
144 tmp
->mEvent
->mOriginalRelatedTarget
= nullptr;
145 switch (tmp
->mEvent
->mClass
) {
146 case eDragEventClass
: {
147 WidgetDragEvent
* dragEvent
= tmp
->mEvent
->AsDragEvent();
148 dragEvent
->mDataTransfer
= nullptr;
151 case eClipboardEventClass
:
152 tmp
->mEvent
->AsClipboardEvent()->mClipboardData
= nullptr;
154 case eEditorInputEventClass
: {
155 InternalEditorInputEvent
* inputEvent
=
156 tmp
->mEvent
->AsEditorInputEvent();
157 inputEvent
->mDataTransfer
= nullptr;
158 inputEvent
->mTargetRanges
.Clear();
161 case eMutationEventClass
:
162 tmp
->mEvent
->AsMutationEvent()->mRelatedNode
= nullptr;
168 if (WidgetMouseEvent
* mouseEvent
= tmp
->mEvent
->AsMouseEvent()) {
169 mouseEvent
->mClickTarget
= nullptr;
172 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext
);
173 NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget
);
174 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner
);
175 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
176 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
178 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event
)
179 if (tmp
->mEventIsInternal
) {
180 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mTarget
)
181 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mCurrentTarget
)
182 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mOriginalTarget
)
183 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mRelatedTarget
)
184 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent
->mOriginalRelatedTarget
);
185 switch (tmp
->mEvent
->mClass
) {
186 case eDragEventClass
: {
187 WidgetDragEvent
* dragEvent
= tmp
->mEvent
->AsDragEvent();
188 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mDataTransfer");
189 cb
.NoteXPCOMChild(dragEvent
->mDataTransfer
);
192 case eClipboardEventClass
:
193 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mClipboardData");
194 cb
.NoteXPCOMChild(tmp
->mEvent
->AsClipboardEvent()->mClipboardData
);
196 case eEditorInputEventClass
:
197 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mDataTransfer");
198 cb
.NoteXPCOMChild(tmp
->mEvent
->AsEditorInputEvent()->mDataTransfer
);
199 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
200 mEvent
->AsEditorInputEvent()->mTargetRanges
);
202 case eMutationEventClass
:
203 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mRelatedNode");
204 cb
.NoteXPCOMChild(tmp
->mEvent
->AsMutationEvent()->mRelatedNode
);
210 if (WidgetMouseEvent
* mouseEvent
= tmp
->mEvent
->AsMouseEvent()) {
211 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mEvent->mClickTarget");
212 cb
.NoteXPCOMChild(mouseEvent
->mClickTarget
);
215 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext
)
216 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget
)
217 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner
)
218 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
220 JSObject
* Event::WrapObject(JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
221 return WrapObjectInternal(aCx
, aGivenProto
);
224 JSObject
* Event::WrapObjectInternal(JSContext
* aCx
,
225 JS::Handle
<JSObject
*> aGivenProto
) {
226 return Event_Binding::Wrap(aCx
, this, aGivenProto
);
229 void Event::GetType(nsAString
& aType
) const {
230 GetWidgetEventType(mEvent
, aType
);
233 EventTarget
* Event::GetTarget() const { return mEvent
->GetDOMEventTarget(); }
235 already_AddRefed
<Document
> Event::GetDocument() const {
236 nsCOMPtr
<EventTarget
> eventTarget
= GetTarget();
242 nsIGlobalObject
* global
= eventTarget
->GetOwnerGlobal();
247 nsPIDOMWindowInner
* win
= global
->GetAsInnerWindow();
252 nsCOMPtr
<Document
> doc
;
253 doc
= win
->GetExtantDoc();
258 EventTarget
* Event::GetCurrentTarget() const {
259 return mEvent
->GetCurrentDOMEventTarget();
262 void Event::ComposedPath(nsTArray
<RefPtr
<EventTarget
>>& aPath
) {
263 EventDispatcher::GetComposedPathFor(mEvent
, aPath
);
267 // Get the actual event target node (may have been retargeted for mouse events)
269 already_AddRefed
<nsIContent
> Event::GetTargetFromFrame() {
274 // Get the mTarget frame (have to get the ESM first)
275 nsIFrame
* targetFrame
= mPresContext
->EventStateManager()->GetEventTarget();
280 // get the real content
281 nsCOMPtr
<nsIContent
> realEventContent
;
282 targetFrame
->GetContentForEvent(mEvent
, getter_AddRefs(realEventContent
));
283 return realEventContent
.forget();
286 EventTarget
* Event::GetExplicitOriginalTarget() const {
287 if (mExplicitOriginalTarget
) {
288 return mExplicitOriginalTarget
;
293 EventTarget
* Event::GetOriginalTarget() const {
294 return mEvent
->GetOriginalDOMEventTarget();
297 EventTarget
* Event::GetComposedTarget() const {
298 EventTarget
* et
= GetOriginalTarget();
299 nsIContent
* content
= nsIContent::FromEventTargetOrNull(et
);
303 nsIContent
* nonChrome
= content
->FindFirstNonChromeOnlyAccessContent();
304 return nonChrome
? static_cast<EventTarget
*>(nonChrome
)
305 : static_cast<EventTarget
*>(content
->GetComposedDoc());
308 void Event::SetTrusted(bool aTrusted
) { mEvent
->mFlags
.mIsTrusted
= aTrusted
; }
310 bool Event::ShouldIgnoreChromeEventTargetListener() const {
311 MOZ_ASSERT(NS_IsMainThread());
312 if (!XRE_IsParentProcess()) {
315 if (EventTarget
* currentTarget
= GetCurrentTarget();
316 NS_WARN_IF(!currentTarget
) || !currentTarget
->IsRootWindow()) {
319 EventTarget
* et
= GetOriginalTarget();
320 if (NS_WARN_IF(!et
)) {
323 nsIGlobalObject
* global
= et
->GetOwnerGlobal();
324 if (NS_WARN_IF(!global
)) {
327 nsPIDOMWindowInner
* win
= global
->GetAsInnerWindow();
328 if (NS_WARN_IF(!win
)) {
331 BrowsingContext
* bc
= win
->GetBrowsingContext();
332 if (NS_WARN_IF(!bc
)) {
335 // If this is a content event on an nsWindowRoot, then we also handle this in
336 // InProcessBrowserChildMessageManager, so we can ignore this event.
337 return bc
->IsContent();
340 bool Event::Init(mozilla::dom::EventTarget
* aGlobal
) {
341 if (!mIsMainThreadEvent
) {
342 return IsCurrentThreadRunningChromeWorker();
344 bool trusted
= false;
346 if (nsPIDOMWindowInner
* w
= aGlobal
->GetAsInnerWindow()) {
347 if (Document
* d
= w
->GetExtantDoc()) {
348 trusted
= nsContentUtils::IsChromeDoc(d
);
349 if (nsPresContext
* presContext
= d
->GetPresContext()) {
350 InitPresContextData(presContext
);
359 already_AddRefed
<Event
> Event::Constructor(const GlobalObject
& aGlobal
,
360 const nsAString
& aType
,
361 const EventInit
& aParam
) {
362 nsCOMPtr
<mozilla::dom::EventTarget
> t
=
363 do_QueryInterface(aGlobal
.GetAsSupports());
364 return Constructor(t
, aType
, aParam
);
368 already_AddRefed
<Event
> Event::Constructor(EventTarget
* aEventTarget
,
369 const nsAString
& aType
,
370 const EventInit
& aParam
) {
371 RefPtr
<Event
> e
= new Event(aEventTarget
, nullptr, nullptr);
372 bool trusted
= e
->Init(aEventTarget
);
373 e
->InitEvent(aType
, aParam
.mBubbles
, aParam
.mCancelable
);
374 e
->SetTrusted(trusted
);
375 e
->SetComposed(aParam
.mComposed
);
379 uint16_t Event::EventPhase() const {
380 if ((mEvent
->mCurrentTarget
&& mEvent
->mCurrentTarget
== mEvent
->mTarget
) ||
381 mEvent
->mFlags
.mInTargetPhase
) {
382 return Event_Binding::AT_TARGET
;
384 if (mEvent
->mFlags
.mInCapturePhase
) {
385 return Event_Binding::CAPTURING_PHASE
;
387 if (mEvent
->mFlags
.mInBubblingPhase
) {
388 return Event_Binding::BUBBLING_PHASE
;
390 return Event_Binding::NONE
;
393 void Event::StopPropagation() { mEvent
->StopPropagation(); }
395 void Event::StopImmediatePropagation() { mEvent
->StopImmediatePropagation(); }
397 void Event::StopCrossProcessForwarding() {
398 mEvent
->StopCrossProcessForwarding();
401 void Event::PreventDefault() {
402 // This method is called only from C++ code which must handle default action
403 // of this event. So, pass true always.
404 PreventDefaultInternal(true);
407 void Event::PreventDefault(JSContext
* aCx
, CallerType aCallerType
) {
408 // Note that at handling default action, another event may be dispatched.
409 // Then, JS in content mey be call preventDefault()
410 // even in the event is in system event group. Therefore, don't refer
411 // mInSystemGroup here.
412 nsIPrincipal
* principal
=
413 mIsMainThreadEvent
? nsContentUtils::SubjectPrincipal(aCx
) : nullptr;
415 PreventDefaultInternal(aCallerType
== CallerType::System
, principal
);
418 void Event::PreventDefaultInternal(bool aCalledByDefaultHandler
,
419 nsIPrincipal
* aPrincipal
) {
420 if (!mEvent
->mFlags
.mCancelable
) {
423 if (mEvent
->mFlags
.mInPassiveListener
) {
424 if (nsPIDOMWindowInner
* win
= mOwner
->GetAsInnerWindow()) {
425 if (Document
* doc
= win
->GetExtantDoc()) {
426 if (!doc
->HasWarnedAbout(
427 Document::ePreventDefaultFromPassiveListener
)) {
428 AutoTArray
<nsString
, 1> params
;
429 GetType(*params
.AppendElement());
430 doc
->WarnOnceAbout(Document::ePreventDefaultFromPassiveListener
,
438 mEvent
->PreventDefault(aCalledByDefaultHandler
, aPrincipal
);
444 if (mEvent
->mClass
== eDragEventClass
) {
445 UpdateDefaultPreventedOnContentForDragEvent();
449 void Event::UpdateDefaultPreventedOnContentForDragEvent() {
450 WidgetDragEvent
* dragEvent
= mEvent
->AsDragEvent();
455 nsIPrincipal
* principal
= nullptr;
456 // Since we now have HTMLEditorEventListener registered on nsWindowRoot,
457 // mCurrentTarget could be nsWindowRoot, so we need to use
458 // mTarget if that's the case.
459 MOZ_ASSERT_IF(dragEvent
->mInHTMLEditorEventListener
,
460 mEvent
->mCurrentTarget
->IsRootWindow());
461 EventTarget
* target
= dragEvent
->mInHTMLEditorEventListener
463 : mEvent
->mCurrentTarget
;
465 nsINode
* node
= nsINode::FromEventTargetOrNull(target
);
467 principal
= node
->NodePrincipal();
469 nsCOMPtr
<nsIScriptObjectPrincipal
> sop
= do_QueryInterface(target
);
471 principal
= sop
->GetPrincipal();
474 if (principal
&& !principal
->IsSystemPrincipal()) {
475 dragEvent
->mDefaultPreventedOnContent
= true;
479 void Event::SetEventType(const nsAString
& aEventTypeArg
) {
480 mEvent
->mSpecifiedEventTypeString
.Truncate();
481 if (mIsMainThreadEvent
) {
482 mEvent
->mSpecifiedEventType
= nsContentUtils::GetEventMessageAndAtom(
483 aEventTypeArg
, mEvent
->mClass
, &(mEvent
->mMessage
));
484 mEvent
->SetDefaultComposed();
486 mEvent
->mSpecifiedEventType
= NS_Atomize(u
"on"_ns
+ aEventTypeArg
);
487 mEvent
->mMessage
= eUnidentifiedEvent
;
488 mEvent
->SetComposed(aEventTypeArg
);
490 mEvent
->SetDefaultComposedInNativeAnonymousContent();
493 already_AddRefed
<EventTarget
> Event::EnsureWebAccessibleRelatedTarget(
494 EventTarget
* aRelatedTarget
) {
495 nsCOMPtr
<EventTarget
> relatedTarget
= aRelatedTarget
;
497 nsIContent
* content
= nsIContent::FromEventTarget(relatedTarget
);
498 if (content
&& content
->ChromeOnlyAccess() &&
499 !nsContentUtils::CanAccessNativeAnon()) {
500 content
= content
->FindFirstNonChromeOnlyAccessContent();
501 relatedTarget
= content
;
505 relatedTarget
= relatedTarget
->GetTargetForDOMEvent();
508 return relatedTarget
.forget();
511 void Event::InitEvent(const nsAString
& aEventTypeArg
,
512 mozilla::CanBubble aCanBubbleArg
,
513 mozilla::Cancelable aCancelableArg
,
514 mozilla::Composed aComposedArg
) {
515 // Make sure this event isn't already being dispatched.
516 NS_ENSURE_TRUE_VOID(!mEvent
->mFlags
.mIsBeingDispatched
);
519 // Ensure the caller is permitted to dispatch trusted DOM events.
520 if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
525 SetEventType(aEventTypeArg
);
527 mEvent
->mFlags
.mBubbles
= aCanBubbleArg
== CanBubble::eYes
;
528 mEvent
->mFlags
.mCancelable
= aCancelableArg
== Cancelable::eYes
;
529 if (aComposedArg
!= Composed::eDefault
) {
530 mEvent
->mFlags
.mComposed
= aComposedArg
== Composed::eYes
;
533 mEvent
->mFlags
.mDefaultPrevented
= false;
534 mEvent
->mFlags
.mDefaultPreventedByContent
= false;
535 mEvent
->mFlags
.mDefaultPreventedByChrome
= false;
536 mEvent
->mFlags
.mPropagationStopped
= false;
537 mEvent
->mFlags
.mImmediatePropagationStopped
= false;
539 // Clearing the old targets, so that the event is targeted correctly when
540 // re-dispatching it.
541 mEvent
->mTarget
= nullptr;
542 mEvent
->mOriginalTarget
= nullptr;
545 void Event::DuplicatePrivateData() {
546 NS_ASSERTION(mEvent
, "No WidgetEvent for Event duplication!");
547 if (mEventIsInternal
) {
551 mEvent
= mEvent
->Duplicate();
552 mPresContext
= nullptr;
553 mEventIsInternal
= true;
554 mPrivateDataDuplicated
= true;
557 void Event::SetTarget(EventTarget
* aTarget
) { mEvent
->mTarget
= aTarget
; }
559 bool Event::IsDispatchStopped() { return mEvent
->PropagationStopped(); }
561 WidgetEvent
* Event::WidgetEventPtr() { return mEvent
; }
564 Maybe
<CSSIntPoint
> Event::GetScreenCoords(nsPresContext
* aPresContext
,
566 LayoutDeviceIntPoint aPoint
) {
567 if (PointerLockManager::IsLocked()) {
568 return Some(EventStateManager::sLastScreenPoint
);
571 if (!aEvent
|| (aEvent
->mClass
!= eMouseEventClass
&&
572 aEvent
->mClass
!= eMouseScrollEventClass
&&
573 aEvent
->mClass
!= eWheelEventClass
&&
574 aEvent
->mClass
!= ePointerEventClass
&&
575 aEvent
->mClass
!= eTouchEventClass
&&
576 aEvent
->mClass
!= eDragEventClass
&&
577 aEvent
->mClass
!= eSimpleGestureEventClass
)) {
581 // Doing a straight conversion from LayoutDeviceIntPoint to CSSIntPoint
582 // seem incorrect, but it is needed to maintain legacy functionality.
583 WidgetGUIEvent
* guiEvent
= aEvent
->AsGUIEvent();
584 if (!aPresContext
|| !(guiEvent
&& guiEvent
->mWidget
)) {
585 return Some(CSSIntPoint(aPoint
.x
, aPoint
.y
));
588 // (Potentially) transform the point from the coordinate space of an
589 // out-of-process iframe to the coordinate space of the native
590 // window. The transform can only be applied to a point whose components
591 // are floating-point values, so convert the integer point first, then
592 // transform, and then round the result back to an integer point.
593 LayoutDevicePoint
floatPoint(aPoint
);
594 LayoutDevicePoint topLevelPoint
=
595 guiEvent
->mWidget
->WidgetToTopLevelWidgetTransform().TransformPoint(
597 LayoutDeviceIntPoint rounded
= RoundedToInt(topLevelPoint
);
599 nsPoint pt
= LayoutDevicePixel::ToAppUnits(
600 rounded
, aPresContext
->DeviceContext()->AppUnitsPerDevPixel());
602 pt
+= LayoutDevicePixel::ToAppUnits(
603 guiEvent
->mWidget
->TopLevelWidgetToScreenOffset(),
604 aPresContext
->DeviceContext()->AppUnitsPerDevPixel());
606 return Some(CSSPixel::FromAppUnitsRounded(pt
));
610 CSSIntPoint
Event::GetPageCoords(nsPresContext
* aPresContext
,
612 LayoutDeviceIntPoint aPoint
,
613 CSSIntPoint aDefaultPoint
) {
614 CSSIntPoint pagePoint
=
615 Event::GetClientCoords(aPresContext
, aEvent
, aPoint
, aDefaultPoint
);
617 // If there is some scrolling, add scroll info to client point.
618 if (aPresContext
&& aPresContext
->GetPresShell()) {
619 PresShell
* presShell
= aPresContext
->PresShell();
620 nsIScrollableFrame
* scrollframe
=
621 presShell
->GetRootScrollFrameAsScrollable();
624 CSSIntPoint::FromAppUnitsRounded(scrollframe
->GetScrollPosition());
632 CSSIntPoint
Event::GetClientCoords(nsPresContext
* aPresContext
,
634 LayoutDeviceIntPoint aPoint
,
635 CSSIntPoint aDefaultPoint
) {
636 if (PointerLockManager::IsLocked()) {
637 return EventStateManager::sLastClientPoint
;
641 (aEvent
->mClass
!= eMouseEventClass
&&
642 aEvent
->mClass
!= eMouseScrollEventClass
&&
643 aEvent
->mClass
!= eWheelEventClass
&&
644 aEvent
->mClass
!= eTouchEventClass
&&
645 aEvent
->mClass
!= eDragEventClass
&&
646 aEvent
->mClass
!= ePointerEventClass
&&
647 aEvent
->mClass
!= eSimpleGestureEventClass
) ||
648 !aPresContext
|| !aEvent
->AsGUIEvent()->mWidget
) {
649 return aDefaultPoint
;
652 PresShell
* presShell
= aPresContext
->GetPresShell();
654 return CSSIntPoint(0, 0);
656 nsIFrame
* rootFrame
= presShell
->GetRootFrame();
658 return CSSIntPoint(0, 0);
660 nsPoint pt
= nsLayoutUtils::GetEventCoordinatesRelativeTo(
661 aEvent
, aPoint
, RelativeTo
{rootFrame
});
663 return CSSIntPoint::FromAppUnitsRounded(pt
);
667 CSSIntPoint
Event::GetOffsetCoords(nsPresContext
* aPresContext
,
669 LayoutDeviceIntPoint aPoint
,
670 CSSIntPoint aDefaultPoint
) {
671 if (!aEvent
->mTarget
) {
672 return GetPageCoords(aPresContext
, aEvent
, aPoint
, aDefaultPoint
);
674 nsCOMPtr
<nsIContent
> content
= nsIContent::FromEventTarget(aEvent
->mTarget
);
675 if (!content
|| !aPresContext
) {
676 return CSSIntPoint();
678 RefPtr
<PresShell
> presShell
= aPresContext
->GetPresShell();
680 return CSSIntPoint();
682 presShell
->FlushPendingNotifications(FlushType::Layout
);
683 nsIFrame
* frame
= content
->GetPrimaryFrame();
685 return CSSIntPoint();
687 // For compat, see https://github.com/w3c/csswg-drafts/issues/1508. In SVG we
688 // just return the coordinates of the outer SVG box. This is all kinda
690 if (frame
->HasAnyStateBits(NS_FRAME_SVG_LAYOUT
) &&
691 StaticPrefs::dom_events_offset_in_svg_relative_to_svg_root()) {
692 frame
= SVGUtils::GetOuterSVGFrame(frame
);
694 return CSSIntPoint();
697 nsIFrame
* rootFrame
= presShell
->GetRootFrame();
699 return CSSIntPoint();
701 CSSIntPoint clientCoords
=
702 GetClientCoords(aPresContext
, aEvent
, aPoint
, aDefaultPoint
);
703 nsPoint pt
= CSSPixel::ToAppUnits(clientCoords
);
704 if (nsLayoutUtils::TransformPoint(RelativeTo
{rootFrame
}, RelativeTo
{frame
},
705 pt
) == nsLayoutUtils::TRANSFORM_SUCCEEDED
) {
706 pt
-= frame
->GetPaddingRectRelativeToSelf().TopLeft();
707 return CSSPixel::FromAppUnitsRounded(pt
);
709 return CSSIntPoint();
712 // To be called ONLY by Event::GetType (which has the additional
713 // logic for handling user-defined events).
715 const char16_t
* Event::GetEventName(EventMessage aEventType
) {
716 switch (aEventType
) {
717 #define MESSAGE_TO_EVENT(name_, _message, _type, _struct) \
720 #include "mozilla/EventNameList.h"
721 #undef MESSAGE_TO_EVENT
725 // XXXldb We can hit this case for WidgetEvent objects that we didn't
726 // create and that are not user defined events since this function and
727 // SetEventType are incomplete. (But fixing that requires fixing the
728 // arrays in nsEventListenerManager too, since the events for which
729 // this is a problem generally *are* created by Event.)
733 bool Event::DefaultPrevented(CallerType aCallerType
) const {
734 NS_ENSURE_TRUE(mEvent
, false);
736 // If preventDefault() has never been called, just return false.
737 if (!mEvent
->DefaultPrevented()) {
741 // If preventDefault() has been called by content, return true. Otherwise,
742 // i.e., preventDefault() has been called by chrome, return true only when
743 // this is called by chrome.
744 return mEvent
->DefaultPreventedByContent() ||
745 aCallerType
== CallerType::System
;
748 bool Event::ReturnValue(CallerType aCallerType
) const {
749 return !DefaultPrevented(aCallerType
);
752 void Event::SetReturnValue(bool aReturnValue
, CallerType aCallerType
) {
754 PreventDefaultInternal(aCallerType
== CallerType::System
);
758 double Event::TimeStamp() {
759 if (mEvent
->mTimeStamp
.IsNull()) {
763 if (mIsMainThreadEvent
) {
764 if (NS_WARN_IF(!mOwner
)) {
768 nsPIDOMWindowInner
* win
= mOwner
->GetAsInnerWindow();
769 if (NS_WARN_IF(!win
)) {
773 Performance
* perf
= win
->GetPerformance();
774 if (NS_WARN_IF(!perf
)) {
779 perf
->GetDOMTiming()->TimeStampToDOMHighRes(mEvent
->mTimeStamp
);
780 MOZ_ASSERT(mOwner
->PrincipalOrNull());
782 return nsRFPService::ReduceTimePrecisionAsMSecs(
783 ret
, perf
->GetRandomTimelineSeed(), perf
->GetRTPCallerType());
786 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
787 MOZ_ASSERT(workerPrivate
);
789 double ret
= workerPrivate
->TimeStampToDOMHighRes(mEvent
->mTimeStamp
);
791 return nsRFPService::ReduceTimePrecisionAsMSecs(
792 ret
, workerPrivate
->GetRandomTimelineSeed(),
793 workerPrivate
->GlobalScope()->GetRTPCallerType());
796 void Event::Serialize(IPC::MessageWriter
* aWriter
,
797 bool aSerializeInterfaceType
) {
798 if (aSerializeInterfaceType
) {
799 IPC::WriteParam(aWriter
, u
"event"_ns
);
804 IPC::WriteParam(aWriter
, type
);
806 IPC::WriteParam(aWriter
, Bubbles());
807 IPC::WriteParam(aWriter
, Cancelable());
808 IPC::WriteParam(aWriter
, IsTrusted());
809 IPC::WriteParam(aWriter
, Composed());
811 // No timestamp serialization for now!
814 bool Event::Deserialize(IPC::MessageReader
* aReader
) {
816 NS_ENSURE_TRUE(IPC::ReadParam(aReader
, &type
), false);
818 bool bubbles
= false;
819 NS_ENSURE_TRUE(IPC::ReadParam(aReader
, &bubbles
), false);
821 bool cancelable
= false;
822 NS_ENSURE_TRUE(IPC::ReadParam(aReader
, &cancelable
), false);
824 bool trusted
= false;
825 NS_ENSURE_TRUE(IPC::ReadParam(aReader
, &trusted
), false);
827 bool composed
= false;
828 NS_ENSURE_TRUE(IPC::ReadParam(aReader
, &composed
), false);
830 InitEvent(type
, bubbles
, cancelable
);
832 SetComposed(composed
);
837 void Event::SetOwner(EventTarget
* aOwner
) {
844 if (nsINode
* n
= aOwner
->GetAsNode()) {
845 mOwner
= n
->OwnerDoc()->GetScopeObject();
849 if (nsPIDOMWindowInner
* w
= aOwner
->GetAsInnerWindow()) {
850 mOwner
= w
->AsGlobal();
854 nsCOMPtr
<DOMEventTargetHelper
> eth
= do_QueryInterface(aOwner
);
856 mOwner
= eth
->GetParentObject();
861 nsCOMPtr
<nsPIWindowRoot
> root
= do_QueryInterface(aOwner
);
862 MOZ_ASSERT(root
, "Unexpected EventTarget!");
866 void Event::GetWidgetEventType(WidgetEvent
* aEvent
, nsAString
& aType
) {
867 if (!aEvent
->mSpecifiedEventTypeString
.IsEmpty()) {
868 aType
= aEvent
->mSpecifiedEventTypeString
;
872 const char16_t
* name
= GetEventName(aEvent
->mMessage
);
875 aType
.AssignLiteral(name
, nsString::char_traits::length(name
));
877 } else if (aEvent
->mMessage
== eUnidentifiedEvent
&&
878 aEvent
->mSpecifiedEventType
) {
880 aType
= Substring(nsDependentAtomString(aEvent
->mSpecifiedEventType
), 2);
881 aEvent
->mSpecifiedEventTypeString
= aType
;
888 bool Event::IsDragExitEnabled(JSContext
* aCx
, JSObject
* aGlobal
) {
889 return StaticPrefs::dom_event_dragexit_enabled() ||
890 nsContentUtils::IsSystemCaller(aCx
);
893 } // namespace mozilla::dom
895 using namespace mozilla
;
896 using namespace mozilla::dom
;
898 already_AddRefed
<Event
> NS_NewDOMEvent(EventTarget
* aOwner
,
899 nsPresContext
* aPresContext
,
900 WidgetEvent
* aEvent
) {
901 RefPtr
<Event
> it
= new Event(aOwner
, aPresContext
, aEvent
);