Backed out changeset 2fc34d798e24 (bug 1917771) for causing failures at baseline...
[gecko.git] / dom / events / Event.cpp
blob44f9872443c11c367947e1e0ff5b28946d467313
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"
38 #include "nsCOMPtr.h"
39 #include "nsDeviceContext.h"
40 #include "nsError.h"
41 #include "nsGlobalWindowInner.h"
42 #include "nsIFrame.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) {
63 SetOwner(aOwner);
64 mIsMainThreadEvent = NS_IsMainThread();
65 if (mIsMainThreadEvent) {
66 mRefCnt.SetIsOnMainThread();
69 mPrivateDataDuplicated = false;
70 mWantsPopupControlCheck = false;
72 if (aEvent) {
73 mEvent = aEvent;
74 mEventIsInternal = false;
75 } else {
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)
89 ...
91 ...
92 if (aEvent) {
93 mEventIsInternal = false;
95 else {
96 mEventIsInternal = true;
98 ...
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);
114 } else {
115 mExplicitOriginalTarget = nullptr;
120 Event::~Event() {
121 NS_ASSERT_OWNINGTHREAD(Event);
123 if (mEventIsInternal && mEvent) {
124 delete 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)
132 NS_INTERFACE_MAP_END
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;
150 break;
152 case eClipboardEventClass:
153 tmp->mEvent->AsClipboardEvent()->mClipboardData = nullptr;
154 break;
155 case eEditorInputEventClass: {
156 InternalEditorInputEvent* inputEvent =
157 tmp->mEvent->AsEditorInputEvent();
158 inputEvent->mDataTransfer = nullptr;
159 inputEvent->mTargetRanges.Clear();
160 break;
162 case eMutationEventClass:
163 tmp->mEvent->AsMutationEvent()->mRelatedNode = nullptr;
164 break;
165 default:
166 break;
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);
191 break;
193 case eClipboardEventClass:
194 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mClipboardData");
195 cb.NoteXPCOMChild(tmp->mEvent->AsClipboardEvent()->mClipboardData);
196 break;
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);
202 break;
203 case eMutationEventClass:
204 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedNode");
205 cb.NoteXPCOMChild(tmp->mEvent->AsMutationEvent()->mRelatedNode);
206 break;
207 default:
208 break;
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);
227 p->Unlink(supports);
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();
248 if (!eventTarget) {
249 return nullptr;
252 nsIGlobalObject* global = eventTarget->GetOwnerGlobal();
253 if (!global) {
254 return nullptr;
257 nsPIDOMWindowInner* win = global->GetAsInnerWindow();
258 if (!win) {
259 return nullptr;
262 nsCOMPtr<Document> doc;
263 doc = win->GetExtantDoc();
265 return doc.forget();
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() {
280 if (!mPresContext) {
281 return nullptr;
284 // Get the mTarget frame (have to get the ESM first)
285 nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
286 if (!targetFrame) {
287 return nullptr;
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;
300 return GetTarget();
303 EventTarget* Event::GetOriginalTarget() const {
304 return mEvent->GetOriginalDOMEventTarget();
307 EventTarget* Event::GetComposedTarget() const {
308 EventTarget* et = GetOriginalTarget();
309 nsIContent* content = nsIContent::FromEventTargetOrNull(et);
310 if (!content) {
311 return 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()) {
323 return false;
325 if (EventTarget* currentTarget = GetCurrentTarget();
326 NS_WARN_IF(!currentTarget) || !currentTarget->IsRootWindow()) {
327 return false;
329 EventTarget* et = GetOriginalTarget();
330 if (NS_WARN_IF(!et)) {
331 return false;
333 nsIGlobalObject* global = et->GetOwnerGlobal();
334 if (NS_WARN_IF(!global)) {
335 return false;
337 nsPIDOMWindowInner* win = global->GetAsInnerWindow();
338 if (NS_WARN_IF(!win)) {
339 return false;
341 BrowsingContext* bc = win->GetBrowsingContext();
342 if (NS_WARN_IF(!bc)) {
343 return false;
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;
355 if (aGlobal) {
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);
365 return trusted;
368 // static
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);
377 // static
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);
386 return e.forget();
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) {
431 return;
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,
441 false, params);
445 return;
448 mEvent->PreventDefault(aCalledByDefaultHandler, aPrincipal);
450 if (!IsTrusted()) {
451 return;
454 if (mEvent->mClass == eDragEventClass) {
455 UpdateDefaultPreventedOnContentForDragEvent();
459 void Event::UpdateDefaultPreventedOnContentForDragEvent() {
460 WidgetDragEvent* dragEvent = mEvent->AsDragEvent();
461 if (!dragEvent) {
462 return;
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
472 ? mEvent->mTarget
473 : mEvent->mCurrentTarget;
475 nsINode* node = nsINode::FromEventTargetOrNull(target);
476 if (node) {
477 principal = node->NodePrincipal();
478 } else {
479 nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(target);
480 if (sop) {
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();
506 } else {
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;
517 if (relatedTarget) {
518 nsIContent* content = nsIContent::FromEventTarget(relatedTarget);
519 if (content && content->ChromeOnlyAccess() &&
520 !nsContentUtils::CanAccessNativeAnon()) {
521 content = content->FindFirstNonChromeOnlyAccessContent();
522 relatedTarget = content;
525 if (relatedTarget) {
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);
539 if (IsTrusted()) {
540 // Ensure the caller is permitted to dispatch trusted DOM events.
541 if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
542 SetTrusted(false);
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) {
569 return;
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; }
584 // static
585 Maybe<CSSIntPoint> Event::GetScreenCoords(nsPresContext* aPresContext,
586 WidgetEvent* aEvent,
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)) {
599 return Nothing();
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(
617 floatPoint);
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));
630 // static
631 CSSIntPoint Event::GetPageCoords(nsPresContext* aPresContext,
632 WidgetEvent* aEvent,
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());
646 return pagePoint;
649 // static
650 CSSIntPoint Event::GetClientCoords(nsPresContext* aPresContext,
651 WidgetEvent* aEvent,
652 LayoutDeviceIntPoint aPoint,
653 CSSIntPoint aDefaultPoint) {
654 if (PointerLockManager::IsLocked()) {
655 return EventStateManager::sLastClientPoint;
658 if (!aEvent ||
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();
671 if (!presShell) {
672 return CSSIntPoint(0, 0);
674 nsIFrame* rootFrame = presShell->GetRootFrame();
675 if (!rootFrame) {
676 return CSSIntPoint(0, 0);
678 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
679 aEvent, aPoint, RelativeTo{rootFrame});
681 return CSSIntPoint::FromAppUnitsRounded(pt);
684 // static
685 CSSIntPoint Event::GetOffsetCoords(nsPresContext* aPresContext,
686 WidgetEvent* aEvent,
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();
697 if (!presShell) {
698 return CSSIntPoint();
700 presShell->FlushPendingNotifications(FlushType::Layout);
701 nsIFrame* frame = content->GetPrimaryFrame();
702 if (!frame) {
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
707 // unfortunate.
708 if (frame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT) &&
709 StaticPrefs::dom_events_offset_in_svg_relative_to_svg_root()) {
710 frame = SVGUtils::GetOuterSVGFrame(frame);
711 if (!frame) {
712 return CSSIntPoint();
715 nsIFrame* rootFrame = presShell->GetRootFrame();
716 if (!rootFrame) {
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).
732 // static
733 const char16_t* Event::GetEventName(EventMessage aEventType) {
734 switch (aEventType) {
735 #define MESSAGE_TO_EVENT(name_, _message, _type, _struct) \
736 case _message: \
737 return u"" #name_;
738 #include "mozilla/EventNameList.h"
739 #undef MESSAGE_TO_EVENT
740 default:
741 break;
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.)
748 return nullptr;
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()) {
756 return false;
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) {
771 if (!aReturnValue) {
772 PreventDefaultInternal(aCallerType == CallerType::System);
776 double Event::TimeStamp() {
777 if (mEvent->mTimeStamp.IsNull()) {
778 return 0.0;
781 if (mIsMainThreadEvent) {
782 if (NS_WARN_IF(!mOwner)) {
783 return 0.0;
786 nsPIDOMWindowInner* win = mOwner->GetAsInnerWindow();
787 if (NS_WARN_IF(!win)) {
788 return 0.0;
791 Performance* perf = win->GetPerformance();
792 if (NS_WARN_IF(!perf)) {
793 return 0.0;
796 double ret =
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);
820 nsString type;
821 GetType(type);
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) {
833 nsString type;
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);
849 SetTrusted(trusted);
850 SetComposed(composed);
852 return true;
855 void Event::SetOwner(EventTarget* aOwner) {
856 mOwner = nullptr;
858 if (!aOwner) {
859 return;
862 if (nsINode* n = aOwner->GetAsNode()) {
863 mOwner = n->OwnerDoc()->GetScopeObject();
864 return;
867 if (nsPIDOMWindowInner* w = aOwner->GetAsInnerWindow()) {
868 mOwner = w->AsGlobal();
869 return;
872 nsCOMPtr<DOMEventTargetHelper> eth = do_QueryInterface(aOwner);
873 if (eth) {
874 mOwner = eth->GetParentObject();
875 return;
878 #ifdef DEBUG
879 nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(aOwner);
880 MOZ_ASSERT(root, "Unexpected EventTarget!");
881 #endif
884 void Event::GetWidgetEventType(WidgetEvent* aEvent, nsAString& aType) {
885 if (!aEvent->mSpecifiedEventTypeString.IsEmpty()) {
886 aType = aEvent->mSpecifiedEventTypeString;
887 return;
890 const char16_t* name = GetEventName(aEvent->mMessage);
892 if (name) {
893 aType.AssignLiteral(name, nsString::char_traits::length(name));
894 return;
895 } else if (aEvent->mMessage == eUnidentifiedEvent &&
896 aEvent->mSpecifiedEventType) {
897 // Remove "on"
898 aType = Substring(nsDependentAtomString(aEvent->mSpecifiedEventType), 2);
899 aEvent->mSpecifiedEventTypeString = aType;
900 return;
903 aType.Truncate();
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);
920 return it.forget();