Merge mozilla-central to autoland on a CLOSED TREE
[gecko.git] / dom / events / Event.cpp
blobb426c9fb18f3a6b12c9030084806f22d850277c0
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 "nsGlobalWindow.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();
65 mPrivateDataDuplicated = false;
66 mWantsPopupControlCheck = false;
68 if (aEvent) {
69 mEvent = aEvent;
70 mEventIsInternal = false;
71 } else {
72 mEventIsInternal = true;
74 A derived class might want to allocate its own type of aEvent
75 (derived from WidgetEvent). To do this, it should take care to pass
76 a non-nullptr aEvent to this ctor, e.g.:
78 FooEvent::FooEvent(..., WidgetEvent* aEvent)
79 : Event(..., aEvent ? aEvent : new WidgetEvent())
81 Then, to override the mEventIsInternal assignments done by the
82 base ctor, it should do this in its own ctor:
84 FooEvent::FooEvent(..., WidgetEvent* aEvent)
85 ...
87 ...
88 if (aEvent) {
89 mEventIsInternal = false;
91 else {
92 mEventIsInternal = true;
94 ...
97 mEvent = new WidgetEvent(false, eVoidEvent);
100 InitPresContextData(aPresContext);
103 void Event::InitPresContextData(nsPresContext* aPresContext) {
104 mPresContext = aPresContext;
105 // Get the explicit original target (if it's anonymous make it null)
107 nsCOMPtr<nsIContent> content = GetTargetFromFrame();
108 if (content && !content->IsInNativeAnonymousSubtree()) {
109 mExplicitOriginalTarget = std::move(content);
110 } else {
111 mExplicitOriginalTarget = nullptr;
116 Event::~Event() {
117 NS_ASSERT_OWNINGTHREAD(Event);
119 if (mEventIsInternal && mEvent) {
120 delete mEvent;
124 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Event)
125 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
126 NS_INTERFACE_MAP_ENTRY(nsISupports)
127 NS_INTERFACE_MAP_ENTRY(Event)
128 NS_INTERFACE_MAP_END
130 NS_IMPL_CYCLE_COLLECTING_ADDREF(Event)
131 NS_IMPL_CYCLE_COLLECTING_RELEASE(Event)
133 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(Event)
135 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
136 if (tmp->mEventIsInternal) {
137 tmp->mEvent->mTarget = nullptr;
138 tmp->mEvent->mCurrentTarget = nullptr;
139 tmp->mEvent->mOriginalTarget = nullptr;
140 tmp->mEvent->mRelatedTarget = nullptr;
141 tmp->mEvent->mOriginalRelatedTarget = nullptr;
142 switch (tmp->mEvent->mClass) {
143 case eDragEventClass: {
144 WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
145 dragEvent->mDataTransfer = nullptr;
146 break;
148 case eClipboardEventClass:
149 tmp->mEvent->AsClipboardEvent()->mClipboardData = nullptr;
150 break;
151 case eEditorInputEventClass: {
152 InternalEditorInputEvent* inputEvent =
153 tmp->mEvent->AsEditorInputEvent();
154 inputEvent->mDataTransfer = nullptr;
155 inputEvent->mTargetRanges.Clear();
156 break;
158 case eMutationEventClass:
159 tmp->mEvent->AsMutationEvent()->mRelatedNode = nullptr;
160 break;
161 default:
162 break;
165 if (WidgetMouseEvent* mouseEvent = tmp->mEvent->AsMouseEvent()) {
166 mouseEvent->mClickTarget = nullptr;
169 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext);
170 NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget);
171 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner);
172 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
173 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
175 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
176 if (tmp->mEventIsInternal) {
177 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mTarget)
178 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mCurrentTarget)
179 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalTarget)
180 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mRelatedTarget)
181 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalRelatedTarget);
182 switch (tmp->mEvent->mClass) {
183 case eDragEventClass: {
184 WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
185 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mDataTransfer");
186 cb.NoteXPCOMChild(dragEvent->mDataTransfer);
187 break;
189 case eClipboardEventClass:
190 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mClipboardData");
191 cb.NoteXPCOMChild(tmp->mEvent->AsClipboardEvent()->mClipboardData);
192 break;
193 case eEditorInputEventClass:
194 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mDataTransfer");
195 cb.NoteXPCOMChild(tmp->mEvent->AsEditorInputEvent()->mDataTransfer);
196 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
197 mEvent->AsEditorInputEvent()->mTargetRanges);
198 break;
199 case eMutationEventClass:
200 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedNode");
201 cb.NoteXPCOMChild(tmp->mEvent->AsMutationEvent()->mRelatedNode);
202 break;
203 default:
204 break;
207 if (WidgetMouseEvent* mouseEvent = tmp->mEvent->AsMouseEvent()) {
208 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mClickTarget");
209 cb.NoteXPCOMChild(mouseEvent->mClickTarget);
212 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext)
213 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget)
214 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
215 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
217 JSObject* Event::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
218 return WrapObjectInternal(aCx, aGivenProto);
221 JSObject* Event::WrapObjectInternal(JSContext* aCx,
222 JS::Handle<JSObject*> aGivenProto) {
223 return Event_Binding::Wrap(aCx, this, aGivenProto);
226 void Event::GetType(nsAString& aType) const {
227 GetWidgetEventType(mEvent, aType);
230 EventTarget* Event::GetTarget() const { return mEvent->GetDOMEventTarget(); }
232 already_AddRefed<Document> Event::GetDocument() const {
233 nsCOMPtr<EventTarget> eventTarget = GetTarget();
235 if (!eventTarget) {
236 return nullptr;
239 nsCOMPtr<nsPIDOMWindowInner> win =
240 do_QueryInterface(eventTarget->GetOwnerGlobal());
242 if (!win) {
243 return nullptr;
246 nsCOMPtr<Document> doc;
247 doc = win->GetExtantDoc();
249 return doc.forget();
252 EventTarget* Event::GetCurrentTarget() const {
253 return mEvent->GetCurrentDOMEventTarget();
256 void Event::ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath) {
257 EventDispatcher::GetComposedPathFor(mEvent, aPath);
261 // Get the actual event target node (may have been retargeted for mouse events)
263 already_AddRefed<nsIContent> Event::GetTargetFromFrame() {
264 if (!mPresContext) {
265 return nullptr;
268 // Get the mTarget frame (have to get the ESM first)
269 nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
270 if (!targetFrame) {
271 return nullptr;
274 // get the real content
275 nsCOMPtr<nsIContent> realEventContent;
276 targetFrame->GetContentForEvent(mEvent, getter_AddRefs(realEventContent));
277 return realEventContent.forget();
280 EventTarget* Event::GetExplicitOriginalTarget() const {
281 if (mExplicitOriginalTarget) {
282 return mExplicitOriginalTarget;
284 return GetTarget();
287 EventTarget* Event::GetOriginalTarget() const {
288 return mEvent->GetOriginalDOMEventTarget();
291 EventTarget* Event::GetComposedTarget() const {
292 EventTarget* et = GetOriginalTarget();
293 nsCOMPtr<nsIContent> content = do_QueryInterface(et);
294 if (!content) {
295 return et;
297 nsIContent* nonChrome = content->FindFirstNonChromeOnlyAccessContent();
298 return nonChrome ? static_cast<EventTarget*>(nonChrome)
299 : static_cast<EventTarget*>(content->GetComposedDoc());
302 void Event::SetTrusted(bool aTrusted) { mEvent->mFlags.mIsTrusted = aTrusted; }
304 bool Event::ShouldIgnoreChromeEventTargetListener() const {
305 MOZ_ASSERT(NS_IsMainThread());
306 if (!XRE_IsParentProcess()) {
307 return false;
309 if (EventTarget* currentTarget = GetCurrentTarget();
310 NS_WARN_IF(!currentTarget) || !currentTarget->IsRootWindow()) {
311 return false;
313 EventTarget* et = GetOriginalTarget();
314 if (NS_WARN_IF(!et)) {
315 return false;
317 nsIGlobalObject* global = et->GetOwnerGlobal();
318 if (NS_WARN_IF(!global)) {
319 return false;
321 nsPIDOMWindowInner* win = global->AsInnerWindow();
322 if (NS_WARN_IF(!win)) {
323 return false;
325 BrowsingContext* bc = win->GetBrowsingContext();
326 if (NS_WARN_IF(!bc)) {
327 return false;
329 // If this is a content event on an nsWindowRoot, then we also handle this in
330 // InProcessBrowserChildMessageManager, so we can ignore this event.
331 return bc->IsContent();
334 bool Event::Init(mozilla::dom::EventTarget* aGlobal) {
335 if (!mIsMainThreadEvent) {
336 return IsCurrentThreadRunningChromeWorker();
338 bool trusted = false;
339 nsCOMPtr<nsPIDOMWindowInner> w = do_QueryInterface(aGlobal);
340 if (w) {
341 nsCOMPtr<Document> d = w->GetExtantDoc();
342 if (d) {
343 trusted = nsContentUtils::IsChromeDoc(d);
344 nsPresContext* presContext = d->GetPresContext();
345 if (presContext) {
346 InitPresContextData(presContext);
350 return trusted;
353 // static
354 already_AddRefed<Event> Event::Constructor(const GlobalObject& aGlobal,
355 const nsAString& aType,
356 const EventInit& aParam) {
357 nsCOMPtr<mozilla::dom::EventTarget> t =
358 do_QueryInterface(aGlobal.GetAsSupports());
359 return Constructor(t, aType, aParam);
362 // static
363 already_AddRefed<Event> Event::Constructor(EventTarget* aEventTarget,
364 const nsAString& aType,
365 const EventInit& aParam) {
366 RefPtr<Event> e = new Event(aEventTarget, nullptr, nullptr);
367 bool trusted = e->Init(aEventTarget);
368 e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
369 e->SetTrusted(trusted);
370 e->SetComposed(aParam.mComposed);
371 return e.forget();
374 uint16_t Event::EventPhase() const {
375 if ((mEvent->mCurrentTarget && mEvent->mCurrentTarget == mEvent->mTarget) ||
376 mEvent->mFlags.mInTargetPhase) {
377 return Event_Binding::AT_TARGET;
379 if (mEvent->mFlags.mInCapturePhase) {
380 return Event_Binding::CAPTURING_PHASE;
382 if (mEvent->mFlags.mInBubblingPhase) {
383 return Event_Binding::BUBBLING_PHASE;
385 return Event_Binding::NONE;
388 void Event::StopPropagation() { mEvent->StopPropagation(); }
390 void Event::StopImmediatePropagation() { mEvent->StopImmediatePropagation(); }
392 void Event::StopCrossProcessForwarding() {
393 mEvent->StopCrossProcessForwarding();
396 void Event::PreventDefault() {
397 // This method is called only from C++ code which must handle default action
398 // of this event. So, pass true always.
399 PreventDefaultInternal(true);
402 void Event::PreventDefault(JSContext* aCx, CallerType aCallerType) {
403 // Note that at handling default action, another event may be dispatched.
404 // Then, JS in content mey be call preventDefault()
405 // even in the event is in system event group. Therefore, don't refer
406 // mInSystemGroup here.
407 nsIPrincipal* principal =
408 mIsMainThreadEvent ? nsContentUtils::SubjectPrincipal(aCx) : nullptr;
410 PreventDefaultInternal(aCallerType == CallerType::System, principal);
413 void Event::PreventDefaultInternal(bool aCalledByDefaultHandler,
414 nsIPrincipal* aPrincipal) {
415 if (!mEvent->mFlags.mCancelable) {
416 return;
418 if (mEvent->mFlags.mInPassiveListener) {
419 nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(mOwner));
420 if (win) {
421 if (Document* doc = win->GetExtantDoc()) {
422 if (!doc->HasWarnedAbout(
423 Document::ePreventDefaultFromPassiveListener)) {
424 AutoTArray<nsString, 1> params;
425 GetType(*params.AppendElement());
426 doc->WarnOnceAbout(Document::ePreventDefaultFromPassiveListener,
427 false, params);
431 return;
434 mEvent->PreventDefault(aCalledByDefaultHandler, aPrincipal);
436 if (!IsTrusted()) {
437 return;
440 // If this is called by default handlers, the caller will call
441 // UpdateDefaultPreventedOnContentFor when necessary.
442 if (!aCalledByDefaultHandler) {
443 if (WidgetDragEvent* dragEvent = mEvent->AsDragEvent()) {
444 dragEvent->UpdateDefaultPreventedOnContent(dragEvent->mCurrentTarget);
449 void Event::SetEventType(const nsAString& aEventTypeArg) {
450 mEvent->mSpecifiedEventTypeString.Truncate();
451 if (mIsMainThreadEvent) {
452 mEvent->mSpecifiedEventType = nsContentUtils::GetEventMessageAndAtom(
453 aEventTypeArg, mEvent->mClass, &(mEvent->mMessage));
454 mEvent->SetDefaultComposed();
455 } else {
456 mEvent->mSpecifiedEventType = NS_Atomize(u"on"_ns + aEventTypeArg);
457 mEvent->mMessage = eUnidentifiedEvent;
458 mEvent->SetComposed(aEventTypeArg);
460 mEvent->SetDefaultComposedInNativeAnonymousContent();
463 already_AddRefed<EventTarget> Event::EnsureWebAccessibleRelatedTarget(
464 EventTarget* aRelatedTarget) {
465 nsCOMPtr<EventTarget> relatedTarget = aRelatedTarget;
466 if (relatedTarget) {
467 nsIContent* content = nsIContent::FromEventTarget(relatedTarget);
468 if (content && content->ChromeOnlyAccess() &&
469 !nsContentUtils::CanAccessNativeAnon()) {
470 content = content->FindFirstNonChromeOnlyAccessContent();
471 relatedTarget = content;
474 if (relatedTarget) {
475 relatedTarget = relatedTarget->GetTargetForDOMEvent();
478 return relatedTarget.forget();
481 void Event::InitEvent(const nsAString& aEventTypeArg,
482 mozilla::CanBubble aCanBubbleArg,
483 mozilla::Cancelable aCancelableArg,
484 mozilla::Composed aComposedArg) {
485 // Make sure this event isn't already being dispatched.
486 NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
488 if (IsTrusted()) {
489 // Ensure the caller is permitted to dispatch trusted DOM events.
490 if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
491 SetTrusted(false);
495 SetEventType(aEventTypeArg);
497 mEvent->mFlags.mBubbles = aCanBubbleArg == CanBubble::eYes;
498 mEvent->mFlags.mCancelable = aCancelableArg == Cancelable::eYes;
499 if (aComposedArg != Composed::eDefault) {
500 mEvent->mFlags.mComposed = aComposedArg == Composed::eYes;
503 mEvent->mFlags.mDefaultPrevented = false;
504 mEvent->mFlags.mDefaultPreventedByContent = false;
505 mEvent->mFlags.mDefaultPreventedByChrome = false;
506 mEvent->mFlags.mPropagationStopped = false;
507 mEvent->mFlags.mImmediatePropagationStopped = false;
509 // Clearing the old targets, so that the event is targeted correctly when
510 // re-dispatching it.
511 mEvent->mTarget = nullptr;
512 mEvent->mOriginalTarget = nullptr;
515 void Event::DuplicatePrivateData() {
516 NS_ASSERTION(mEvent, "No WidgetEvent for Event duplication!");
517 if (mEventIsInternal) {
518 return;
521 mEvent = mEvent->Duplicate();
522 mPresContext = nullptr;
523 mEventIsInternal = true;
524 mPrivateDataDuplicated = true;
527 void Event::SetTarget(EventTarget* aTarget) { mEvent->mTarget = aTarget; }
529 bool Event::IsDispatchStopped() { return mEvent->PropagationStopped(); }
531 WidgetEvent* Event::WidgetEventPtr() { return mEvent; }
533 // static
534 Maybe<CSSIntPoint> Event::GetScreenCoords(nsPresContext* aPresContext,
535 WidgetEvent* aEvent,
536 LayoutDeviceIntPoint aPoint) {
537 if (PointerLockManager::IsLocked()) {
538 return Some(EventStateManager::sLastScreenPoint);
541 if (!aEvent || (aEvent->mClass != eMouseEventClass &&
542 aEvent->mClass != eMouseScrollEventClass &&
543 aEvent->mClass != eWheelEventClass &&
544 aEvent->mClass != ePointerEventClass &&
545 aEvent->mClass != eTouchEventClass &&
546 aEvent->mClass != eDragEventClass &&
547 aEvent->mClass != eSimpleGestureEventClass)) {
548 return Nothing();
551 // Doing a straight conversion from LayoutDeviceIntPoint to CSSIntPoint
552 // seem incorrect, but it is needed to maintain legacy functionality.
553 WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
554 if (!aPresContext || !(guiEvent && guiEvent->mWidget)) {
555 return Some(CSSIntPoint(aPoint.x, aPoint.y));
558 // (Potentially) transform the point from the coordinate space of an
559 // out-of-process iframe to the coordinate space of the native
560 // window. The transform can only be applied to a point whose components
561 // are floating-point values, so convert the integer point first, then
562 // transform, and then round the result back to an integer point.
563 LayoutDevicePoint floatPoint(aPoint);
564 LayoutDevicePoint topLevelPoint =
565 guiEvent->mWidget->WidgetToTopLevelWidgetTransform().TransformPoint(
566 floatPoint);
567 LayoutDeviceIntPoint rounded = RoundedToInt(topLevelPoint);
569 nsPoint pt = LayoutDevicePixel::ToAppUnits(
570 rounded, aPresContext->DeviceContext()->AppUnitsPerDevPixel());
572 pt += LayoutDevicePixel::ToAppUnits(
573 guiEvent->mWidget->TopLevelWidgetToScreenOffset(),
574 aPresContext->DeviceContext()->AppUnitsPerDevPixel());
576 return Some(CSSPixel::FromAppUnitsRounded(pt));
579 // static
580 CSSIntPoint Event::GetPageCoords(nsPresContext* aPresContext,
581 WidgetEvent* aEvent,
582 LayoutDeviceIntPoint aPoint,
583 CSSIntPoint aDefaultPoint) {
584 CSSIntPoint pagePoint =
585 Event::GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
587 // If there is some scrolling, add scroll info to client point.
588 if (aPresContext && aPresContext->GetPresShell()) {
589 PresShell* presShell = aPresContext->PresShell();
590 nsIScrollableFrame* scrollframe =
591 presShell->GetRootScrollFrameAsScrollable();
592 if (scrollframe) {
593 pagePoint +=
594 CSSIntPoint::FromAppUnitsRounded(scrollframe->GetScrollPosition());
598 return pagePoint;
601 // static
602 CSSIntPoint Event::GetClientCoords(nsPresContext* aPresContext,
603 WidgetEvent* aEvent,
604 LayoutDeviceIntPoint aPoint,
605 CSSIntPoint aDefaultPoint) {
606 if (PointerLockManager::IsLocked()) {
607 return EventStateManager::sLastClientPoint;
610 if (!aEvent ||
611 (aEvent->mClass != eMouseEventClass &&
612 aEvent->mClass != eMouseScrollEventClass &&
613 aEvent->mClass != eWheelEventClass &&
614 aEvent->mClass != eTouchEventClass &&
615 aEvent->mClass != eDragEventClass &&
616 aEvent->mClass != ePointerEventClass &&
617 aEvent->mClass != eSimpleGestureEventClass) ||
618 !aPresContext || !aEvent->AsGUIEvent()->mWidget) {
619 return aDefaultPoint;
622 PresShell* presShell = aPresContext->GetPresShell();
623 if (!presShell) {
624 return CSSIntPoint(0, 0);
626 nsIFrame* rootFrame = presShell->GetRootFrame();
627 if (!rootFrame) {
628 return CSSIntPoint(0, 0);
630 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
631 aEvent, aPoint, RelativeTo{rootFrame});
633 return CSSIntPoint::FromAppUnitsRounded(pt);
636 // static
637 CSSIntPoint Event::GetOffsetCoords(nsPresContext* aPresContext,
638 WidgetEvent* aEvent,
639 LayoutDeviceIntPoint aPoint,
640 CSSIntPoint aDefaultPoint) {
641 if (!aEvent->mTarget) {
642 return GetPageCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
644 nsCOMPtr<nsIContent> content = nsIContent::FromEventTarget(aEvent->mTarget);
645 if (!content || !aPresContext) {
646 return CSSIntPoint();
648 RefPtr<PresShell> presShell = aPresContext->GetPresShell();
649 if (!presShell) {
650 return CSSIntPoint();
652 presShell->FlushPendingNotifications(FlushType::Layout);
653 nsIFrame* frame = content->GetPrimaryFrame();
654 if (!frame) {
655 return CSSIntPoint();
657 // For compat, see https://github.com/w3c/csswg-drafts/issues/1508. In SVG we
658 // just return the coordinates of the outer SVG box. This is all kinda
659 // unfortunate.
660 if (frame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT) &&
661 StaticPrefs::dom_events_offset_in_svg_relative_to_svg_root()) {
662 frame = SVGUtils::GetOuterSVGFrame(frame);
663 if (!frame) {
664 return CSSIntPoint();
667 nsIFrame* rootFrame = presShell->GetRootFrame();
668 if (!rootFrame) {
669 return CSSIntPoint();
671 CSSIntPoint clientCoords =
672 GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
673 nsPoint pt = CSSPixel::ToAppUnits(clientCoords);
674 if (nsLayoutUtils::TransformPoint(RelativeTo{rootFrame}, RelativeTo{frame},
675 pt) == nsLayoutUtils::TRANSFORM_SUCCEEDED) {
676 pt -= frame->GetPaddingRectRelativeToSelf().TopLeft();
677 return CSSPixel::FromAppUnitsRounded(pt);
679 return CSSIntPoint();
682 // To be called ONLY by Event::GetType (which has the additional
683 // logic for handling user-defined events).
684 // static
685 const char16_t* Event::GetEventName(EventMessage aEventType) {
686 switch (aEventType) {
687 #define MESSAGE_TO_EVENT(name_, _message, _type, _struct) \
688 case _message: \
689 return u"" #name_;
690 #include "mozilla/EventNameList.h"
691 #undef MESSAGE_TO_EVENT
692 default:
693 break;
695 // XXXldb We can hit this case for WidgetEvent objects that we didn't
696 // create and that are not user defined events since this function and
697 // SetEventType are incomplete. (But fixing that requires fixing the
698 // arrays in nsEventListenerManager too, since the events for which
699 // this is a problem generally *are* created by Event.)
700 return nullptr;
703 bool Event::DefaultPrevented(CallerType aCallerType) const {
704 NS_ENSURE_TRUE(mEvent, false);
706 // If preventDefault() has never been called, just return false.
707 if (!mEvent->DefaultPrevented()) {
708 return false;
711 // If preventDefault() has been called by content, return true. Otherwise,
712 // i.e., preventDefault() has been called by chrome, return true only when
713 // this is called by chrome.
714 return mEvent->DefaultPreventedByContent() ||
715 aCallerType == CallerType::System;
718 bool Event::ReturnValue(CallerType aCallerType) const {
719 return !DefaultPrevented(aCallerType);
722 void Event::SetReturnValue(bool aReturnValue, CallerType aCallerType) {
723 if (!aReturnValue) {
724 PreventDefaultInternal(aCallerType == CallerType::System);
728 double Event::TimeStamp() {
729 if (mEvent->mTimeStamp.IsNull()) {
730 return 0.0;
733 if (mIsMainThreadEvent) {
734 if (NS_WARN_IF(!mOwner)) {
735 return 0.0;
738 nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(mOwner);
739 if (NS_WARN_IF(!win)) {
740 return 0.0;
743 Performance* perf = win->GetPerformance();
744 if (NS_WARN_IF(!perf)) {
745 return 0.0;
748 double ret =
749 perf->GetDOMTiming()->TimeStampToDOMHighRes(mEvent->mTimeStamp);
750 MOZ_ASSERT(mOwner->PrincipalOrNull());
752 return nsRFPService::ReduceTimePrecisionAsMSecs(
753 ret, perf->GetRandomTimelineSeed(), perf->GetRTPCallerType());
756 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
757 MOZ_ASSERT(workerPrivate);
759 double ret = workerPrivate->TimeStampToDOMHighRes(mEvent->mTimeStamp);
761 return nsRFPService::ReduceTimePrecisionAsMSecs(
762 ret, workerPrivate->GetRandomTimelineSeed(),
763 workerPrivate->GlobalScope()->GetRTPCallerType());
766 void Event::Serialize(IPC::MessageWriter* aWriter,
767 bool aSerializeInterfaceType) {
768 if (aSerializeInterfaceType) {
769 IPC::WriteParam(aWriter, u"event"_ns);
772 nsString type;
773 GetType(type);
774 IPC::WriteParam(aWriter, type);
776 IPC::WriteParam(aWriter, Bubbles());
777 IPC::WriteParam(aWriter, Cancelable());
778 IPC::WriteParam(aWriter, IsTrusted());
779 IPC::WriteParam(aWriter, Composed());
781 // No timestamp serialization for now!
784 bool Event::Deserialize(IPC::MessageReader* aReader) {
785 nsString type;
786 NS_ENSURE_TRUE(IPC::ReadParam(aReader, &type), false);
788 bool bubbles = false;
789 NS_ENSURE_TRUE(IPC::ReadParam(aReader, &bubbles), false);
791 bool cancelable = false;
792 NS_ENSURE_TRUE(IPC::ReadParam(aReader, &cancelable), false);
794 bool trusted = false;
795 NS_ENSURE_TRUE(IPC::ReadParam(aReader, &trusted), false);
797 bool composed = false;
798 NS_ENSURE_TRUE(IPC::ReadParam(aReader, &composed), false);
800 InitEvent(type, bubbles, cancelable);
801 SetTrusted(trusted);
802 SetComposed(composed);
804 return true;
807 void Event::SetOwner(EventTarget* aOwner) {
808 mOwner = nullptr;
810 if (!aOwner) {
811 return;
814 if (nsINode* n = aOwner->GetAsNode()) {
815 mOwner = n->OwnerDoc()->GetScopeObject();
816 return;
819 if (nsPIDOMWindowInner* w = aOwner->GetAsWindowInner()) {
820 mOwner = w->AsGlobal();
821 return;
824 nsCOMPtr<DOMEventTargetHelper> eth = do_QueryInterface(aOwner);
825 if (eth) {
826 mOwner = eth->GetParentObject();
827 return;
830 #ifdef DEBUG
831 nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(aOwner);
832 MOZ_ASSERT(root, "Unexpected EventTarget!");
833 #endif
836 void Event::GetWidgetEventType(WidgetEvent* aEvent, nsAString& aType) {
837 if (!aEvent->mSpecifiedEventTypeString.IsEmpty()) {
838 aType = aEvent->mSpecifiedEventTypeString;
839 return;
842 const char16_t* name = GetEventName(aEvent->mMessage);
844 if (name) {
845 aType.AssignLiteral(name, nsString::char_traits::length(name));
846 return;
847 } else if (aEvent->mMessage == eUnidentifiedEvent &&
848 aEvent->mSpecifiedEventType) {
849 // Remove "on"
850 aType = Substring(nsDependentAtomString(aEvent->mSpecifiedEventType), 2);
851 aEvent->mSpecifiedEventTypeString = aType;
852 return;
855 aType.Truncate();
858 bool Event::IsDragExitEnabled(JSContext* aCx, JSObject* aGlobal) {
859 return StaticPrefs::dom_event_dragexit_enabled() ||
860 nsContentUtils::IsSystemCaller(aCx);
863 } // namespace mozilla::dom
865 using namespace mozilla;
866 using namespace mozilla::dom;
868 already_AddRefed<Event> NS_NewDOMEvent(EventTarget* aOwner,
869 nsPresContext* aPresContext,
870 WidgetEvent* aEvent) {
871 RefPtr<Event> it = new Event(aOwner, aPresContext, aEvent);
872 return it.forget();