Bug 1892041 - Part 1: Update test262 features. r=spidermonkey-reviewers,dminor
[gecko.git] / dom / events / Event.cpp
blob64086e387f249991df6c9e4690a1e7150217fa01
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"
36 #include "nsCOMPtr.h"
37 #include "nsDeviceContext.h"
38 #include "nsError.h"
39 #include "nsGlobalWindowInner.h"
40 #include "nsIFrame.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) {
62 SetOwner(aOwner);
63 mIsMainThreadEvent = NS_IsMainThread();
64 if (mIsMainThreadEvent) {
65 mRefCnt.SetIsOnMainThread();
68 mPrivateDataDuplicated = false;
69 mWantsPopupControlCheck = false;
71 if (aEvent) {
72 mEvent = aEvent;
73 mEventIsInternal = false;
74 } else {
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)
88 ...
90 ...
91 if (aEvent) {
92 mEventIsInternal = false;
94 else {
95 mEventIsInternal = true;
97 ...
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);
113 } else {
114 mExplicitOriginalTarget = nullptr;
119 Event::~Event() {
120 NS_ASSERT_OWNINGTHREAD(Event);
122 if (mEventIsInternal && mEvent) {
123 delete 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)
131 NS_INTERFACE_MAP_END
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;
149 break;
151 case eClipboardEventClass:
152 tmp->mEvent->AsClipboardEvent()->mClipboardData = nullptr;
153 break;
154 case eEditorInputEventClass: {
155 InternalEditorInputEvent* inputEvent =
156 tmp->mEvent->AsEditorInputEvent();
157 inputEvent->mDataTransfer = nullptr;
158 inputEvent->mTargetRanges.Clear();
159 break;
161 case eMutationEventClass:
162 tmp->mEvent->AsMutationEvent()->mRelatedNode = nullptr;
163 break;
164 default:
165 break;
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);
190 break;
192 case eClipboardEventClass:
193 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mClipboardData");
194 cb.NoteXPCOMChild(tmp->mEvent->AsClipboardEvent()->mClipboardData);
195 break;
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);
201 break;
202 case eMutationEventClass:
203 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedNode");
204 cb.NoteXPCOMChild(tmp->mEvent->AsMutationEvent()->mRelatedNode);
205 break;
206 default:
207 break;
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();
238 if (!eventTarget) {
239 return nullptr;
242 nsIGlobalObject* global = eventTarget->GetOwnerGlobal();
243 if (!global) {
244 return nullptr;
247 nsPIDOMWindowInner* win = global->GetAsInnerWindow();
248 if (!win) {
249 return nullptr;
252 nsCOMPtr<Document> doc;
253 doc = win->GetExtantDoc();
255 return doc.forget();
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() {
270 if (!mPresContext) {
271 return nullptr;
274 // Get the mTarget frame (have to get the ESM first)
275 nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
276 if (!targetFrame) {
277 return nullptr;
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;
290 return GetTarget();
293 EventTarget* Event::GetOriginalTarget() const {
294 return mEvent->GetOriginalDOMEventTarget();
297 EventTarget* Event::GetComposedTarget() const {
298 EventTarget* et = GetOriginalTarget();
299 nsIContent* content = nsIContent::FromEventTargetOrNull(et);
300 if (!content) {
301 return 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()) {
313 return false;
315 if (EventTarget* currentTarget = GetCurrentTarget();
316 NS_WARN_IF(!currentTarget) || !currentTarget->IsRootWindow()) {
317 return false;
319 EventTarget* et = GetOriginalTarget();
320 if (NS_WARN_IF(!et)) {
321 return false;
323 nsIGlobalObject* global = et->GetOwnerGlobal();
324 if (NS_WARN_IF(!global)) {
325 return false;
327 nsPIDOMWindowInner* win = global->GetAsInnerWindow();
328 if (NS_WARN_IF(!win)) {
329 return false;
331 BrowsingContext* bc = win->GetBrowsingContext();
332 if (NS_WARN_IF(!bc)) {
333 return false;
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;
345 if (aGlobal) {
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);
355 return trusted;
358 // static
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);
367 // static
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);
376 return e.forget();
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) {
421 return;
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,
431 false, params);
435 return;
438 mEvent->PreventDefault(aCalledByDefaultHandler, aPrincipal);
440 if (!IsTrusted()) {
441 return;
444 if (mEvent->mClass == eDragEventClass) {
445 UpdateDefaultPreventedOnContentForDragEvent();
449 void Event::UpdateDefaultPreventedOnContentForDragEvent() {
450 WidgetDragEvent* dragEvent = mEvent->AsDragEvent();
451 if (!dragEvent) {
452 return;
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
462 ? mEvent->mTarget
463 : mEvent->mCurrentTarget;
465 nsINode* node = nsINode::FromEventTargetOrNull(target);
466 if (node) {
467 principal = node->NodePrincipal();
468 } else {
469 nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(target);
470 if (sop) {
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();
485 } else {
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;
496 if (relatedTarget) {
497 nsIContent* content = nsIContent::FromEventTarget(relatedTarget);
498 if (content && content->ChromeOnlyAccess() &&
499 !nsContentUtils::CanAccessNativeAnon()) {
500 content = content->FindFirstNonChromeOnlyAccessContent();
501 relatedTarget = content;
504 if (relatedTarget) {
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);
518 if (IsTrusted()) {
519 // Ensure the caller is permitted to dispatch trusted DOM events.
520 if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
521 SetTrusted(false);
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) {
548 return;
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; }
563 // static
564 Maybe<CSSIntPoint> Event::GetScreenCoords(nsPresContext* aPresContext,
565 WidgetEvent* aEvent,
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)) {
578 return Nothing();
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(
596 floatPoint);
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));
609 // static
610 CSSIntPoint Event::GetPageCoords(nsPresContext* aPresContext,
611 WidgetEvent* aEvent,
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();
622 if (scrollframe) {
623 pagePoint +=
624 CSSIntPoint::FromAppUnitsRounded(scrollframe->GetScrollPosition());
628 return pagePoint;
631 // static
632 CSSIntPoint Event::GetClientCoords(nsPresContext* aPresContext,
633 WidgetEvent* aEvent,
634 LayoutDeviceIntPoint aPoint,
635 CSSIntPoint aDefaultPoint) {
636 if (PointerLockManager::IsLocked()) {
637 return EventStateManager::sLastClientPoint;
640 if (!aEvent ||
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();
653 if (!presShell) {
654 return CSSIntPoint(0, 0);
656 nsIFrame* rootFrame = presShell->GetRootFrame();
657 if (!rootFrame) {
658 return CSSIntPoint(0, 0);
660 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
661 aEvent, aPoint, RelativeTo{rootFrame});
663 return CSSIntPoint::FromAppUnitsRounded(pt);
666 // static
667 CSSIntPoint Event::GetOffsetCoords(nsPresContext* aPresContext,
668 WidgetEvent* aEvent,
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();
679 if (!presShell) {
680 return CSSIntPoint();
682 presShell->FlushPendingNotifications(FlushType::Layout);
683 nsIFrame* frame = content->GetPrimaryFrame();
684 if (!frame) {
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
689 // unfortunate.
690 if (frame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT) &&
691 StaticPrefs::dom_events_offset_in_svg_relative_to_svg_root()) {
692 frame = SVGUtils::GetOuterSVGFrame(frame);
693 if (!frame) {
694 return CSSIntPoint();
697 nsIFrame* rootFrame = presShell->GetRootFrame();
698 if (!rootFrame) {
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).
714 // static
715 const char16_t* Event::GetEventName(EventMessage aEventType) {
716 switch (aEventType) {
717 #define MESSAGE_TO_EVENT(name_, _message, _type, _struct) \
718 case _message: \
719 return u"" #name_;
720 #include "mozilla/EventNameList.h"
721 #undef MESSAGE_TO_EVENT
722 default:
723 break;
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.)
730 return nullptr;
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()) {
738 return false;
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) {
753 if (!aReturnValue) {
754 PreventDefaultInternal(aCallerType == CallerType::System);
758 double Event::TimeStamp() {
759 if (mEvent->mTimeStamp.IsNull()) {
760 return 0.0;
763 if (mIsMainThreadEvent) {
764 if (NS_WARN_IF(!mOwner)) {
765 return 0.0;
768 nsPIDOMWindowInner* win = mOwner->GetAsInnerWindow();
769 if (NS_WARN_IF(!win)) {
770 return 0.0;
773 Performance* perf = win->GetPerformance();
774 if (NS_WARN_IF(!perf)) {
775 return 0.0;
778 double ret =
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);
802 nsString type;
803 GetType(type);
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) {
815 nsString type;
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);
831 SetTrusted(trusted);
832 SetComposed(composed);
834 return true;
837 void Event::SetOwner(EventTarget* aOwner) {
838 mOwner = nullptr;
840 if (!aOwner) {
841 return;
844 if (nsINode* n = aOwner->GetAsNode()) {
845 mOwner = n->OwnerDoc()->GetScopeObject();
846 return;
849 if (nsPIDOMWindowInner* w = aOwner->GetAsInnerWindow()) {
850 mOwner = w->AsGlobal();
851 return;
854 nsCOMPtr<DOMEventTargetHelper> eth = do_QueryInterface(aOwner);
855 if (eth) {
856 mOwner = eth->GetParentObject();
857 return;
860 #ifdef DEBUG
861 nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(aOwner);
862 MOZ_ASSERT(root, "Unexpected EventTarget!");
863 #endif
866 void Event::GetWidgetEventType(WidgetEvent* aEvent, nsAString& aType) {
867 if (!aEvent->mSpecifiedEventTypeString.IsEmpty()) {
868 aType = aEvent->mSpecifiedEventTypeString;
869 return;
872 const char16_t* name = GetEventName(aEvent->mMessage);
874 if (name) {
875 aType.AssignLiteral(name, nsString::char_traits::length(name));
876 return;
877 } else if (aEvent->mMessage == eUnidentifiedEvent &&
878 aEvent->mSpecifiedEventType) {
879 // Remove "on"
880 aType = Substring(nsDependentAtomString(aEvent->mSpecifiedEventType), 2);
881 aEvent->mSpecifiedEventTypeString = aType;
882 return;
885 aType.Truncate();
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);
902 return it.forget();