Bug 1732219 - Add API for fetching the preview image. r=geckoview-reviewers,agi,mconley
[gecko.git] / dom / events / Event.cpp
blob2c5df5a3213080e91eb145a5371ce773ebdc181f
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 "mozilla/EventDispatcher.h"
11 #include "mozilla/BasePrincipal.h"
12 #include "mozilla/ContentEvents.h"
13 #include "mozilla/DOMEventTargetHelper.h"
14 #include "mozilla/EventStateManager.h"
15 #include "mozilla/InternalMutationEvent.h"
16 #include "mozilla/dom/Performance.h"
17 #include "mozilla/dom/WorkerPrivate.h"
18 #include "mozilla/MiscEvents.h"
19 #include "mozilla/MouseEvents.h"
20 #include "mozilla/PointerLockManager.h"
21 #include "mozilla/Preferences.h"
22 #include "mozilla/PresShell.h"
23 #include "mozilla/TextEvents.h"
24 #include "mozilla/TouchEvents.h"
25 #include "mozilla/ViewportUtils.h"
26 #include "mozilla/dom/Document.h"
27 #include "mozilla/dom/DocumentInlines.h"
28 #include "mozilla/dom/Event.h"
29 #include "mozilla/dom/ShadowRoot.h"
30 #include "mozilla/StaticPrefs_dom.h"
31 #include "mozilla/SVGUtils.h"
32 #include "mozilla/SVGOuterSVGFrame.h"
33 #include "nsContentUtils.h"
34 #include "nsCOMPtr.h"
35 #include "nsDeviceContext.h"
36 #include "nsError.h"
37 #include "nsGlobalWindow.h"
38 #include "nsIFrame.h"
39 #include "nsIContent.h"
40 #include "nsIContentInlines.h"
41 #include "nsIScrollableFrame.h"
42 #include "nsJSEnvironment.h"
43 #include "nsLayoutUtils.h"
44 #include "nsPIWindowRoot.h"
45 #include "nsRFPService.h"
47 namespace mozilla::dom {
49 Event::Event(EventTarget* aOwner, nsPresContext* aPresContext,
50 WidgetEvent* aEvent) {
51 ConstructorInit(aOwner, aPresContext, aEvent);
54 Event::Event(nsPIDOMWindowInner* aParent) {
55 ConstructorInit(nsGlobalWindowInner::Cast(aParent), nullptr, nullptr);
58 void Event::ConstructorInit(EventTarget* aOwner, nsPresContext* aPresContext,
59 WidgetEvent* aEvent) {
60 SetOwner(aOwner);
61 mIsMainThreadEvent = NS_IsMainThread();
63 mPrivateDataDuplicated = false;
64 mWantsPopupControlCheck = false;
66 if (aEvent) {
67 mEvent = aEvent;
68 mEventIsInternal = false;
69 } else {
70 mEventIsInternal = true;
72 A derived class might want to allocate its own type of aEvent
73 (derived from WidgetEvent). To do this, it should take care to pass
74 a non-nullptr aEvent to this ctor, e.g.:
76 FooEvent::FooEvent(..., WidgetEvent* aEvent)
77 : Event(..., aEvent ? aEvent : new WidgetEvent())
79 Then, to override the mEventIsInternal assignments done by the
80 base ctor, it should do this in its own ctor:
82 FooEvent::FooEvent(..., WidgetEvent* aEvent)
83 ...
85 ...
86 if (aEvent) {
87 mEventIsInternal = false;
89 else {
90 mEventIsInternal = true;
92 ...
95 mEvent = new WidgetEvent(false, eVoidEvent);
96 mEvent->mTime = PR_Now();
99 InitPresContextData(aPresContext);
102 void Event::InitPresContextData(nsPresContext* aPresContext) {
103 mPresContext = aPresContext;
104 // Get the explicit original target (if it's anonymous make it null)
106 nsCOMPtr<nsIContent> content = GetTargetFromFrame();
107 mExplicitOriginalTarget = content;
108 if (content && content->IsInNativeAnonymousSubtree()) {
109 mExplicitOriginalTarget = nullptr;
114 Event::~Event() {
115 NS_ASSERT_OWNINGTHREAD(Event);
117 if (mEventIsInternal && mEvent) {
118 delete mEvent;
122 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Event)
123 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
124 NS_INTERFACE_MAP_ENTRY(nsISupports)
125 NS_INTERFACE_MAP_ENTRY(Event)
126 NS_INTERFACE_MAP_END
128 NS_IMPL_CYCLE_COLLECTING_ADDREF(Event)
129 NS_IMPL_CYCLE_COLLECTING_RELEASE(Event)
131 NS_IMPL_CYCLE_COLLECTION_CLASS(Event)
133 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Event)
134 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
135 NS_IMPL_CYCLE_COLLECTION_TRACE_END
137 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
138 if (tmp->mEventIsInternal) {
139 tmp->mEvent->mTarget = nullptr;
140 tmp->mEvent->mCurrentTarget = nullptr;
141 tmp->mEvent->mOriginalTarget = nullptr;
142 tmp->mEvent->mRelatedTarget = nullptr;
143 tmp->mEvent->mOriginalRelatedTarget = nullptr;
144 switch (tmp->mEvent->mClass) {
145 case eDragEventClass: {
146 WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
147 dragEvent->mDataTransfer = nullptr;
148 break;
150 case eClipboardEventClass:
151 tmp->mEvent->AsClipboardEvent()->mClipboardData = nullptr;
152 break;
153 case eEditorInputEventClass: {
154 InternalEditorInputEvent* inputEvent =
155 tmp->mEvent->AsEditorInputEvent();
156 inputEvent->mDataTransfer = nullptr;
157 inputEvent->mTargetRanges.Clear();
158 break;
160 case eMutationEventClass:
161 tmp->mEvent->AsMutationEvent()->mRelatedNode = nullptr;
162 break;
163 default:
164 break;
167 if (WidgetMouseEvent* mouseEvent = tmp->mEvent->AsMouseEvent()) {
168 mouseEvent->mClickTarget = nullptr;
171 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext);
172 NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget);
173 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner);
174 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
175 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
177 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
178 if (tmp->mEventIsInternal) {
179 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mTarget)
180 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mCurrentTarget)
181 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalTarget)
182 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mRelatedTarget)
183 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalRelatedTarget);
184 switch (tmp->mEvent->mClass) {
185 case eDragEventClass: {
186 WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
187 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mDataTransfer");
188 cb.NoteXPCOMChild(dragEvent->mDataTransfer);
189 break;
191 case eClipboardEventClass:
192 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mClipboardData");
193 cb.NoteXPCOMChild(tmp->mEvent->AsClipboardEvent()->mClipboardData);
194 break;
195 case eEditorInputEventClass:
196 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mDataTransfer");
197 cb.NoteXPCOMChild(tmp->mEvent->AsEditorInputEvent()->mDataTransfer);
198 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
199 mEvent->AsEditorInputEvent()->mTargetRanges);
200 break;
201 case eMutationEventClass:
202 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedNode");
203 cb.NoteXPCOMChild(tmp->mEvent->AsMutationEvent()->mRelatedNode);
204 break;
205 default:
206 break;
209 if (WidgetMouseEvent* mouseEvent = tmp->mEvent->AsMouseEvent()) {
210 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mClickTarget");
211 cb.NoteXPCOMChild(mouseEvent->mClickTarget);
214 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext)
215 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget)
216 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
217 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
219 JSObject* Event::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
220 return WrapObjectInternal(aCx, aGivenProto);
223 JSObject* Event::WrapObjectInternal(JSContext* aCx,
224 JS::Handle<JSObject*> aGivenProto) {
225 return Event_Binding::Wrap(aCx, this, aGivenProto);
228 void Event::GetType(nsAString& aType) const {
229 GetWidgetEventType(mEvent, aType);
232 EventTarget* Event::GetTarget() const { return mEvent->GetDOMEventTarget(); }
234 already_AddRefed<Document> Event::GetDocument() const {
235 nsCOMPtr<EventTarget> eventTarget = GetTarget();
237 if (!eventTarget) {
238 return nullptr;
241 nsCOMPtr<nsPIDOMWindowInner> win =
242 do_QueryInterface(eventTarget->GetOwnerGlobal());
244 if (!win) {
245 return nullptr;
248 nsCOMPtr<Document> doc;
249 doc = win->GetExtantDoc();
251 return doc.forget();
254 EventTarget* Event::GetCurrentTarget() const {
255 return mEvent->GetCurrentDOMEventTarget();
258 void Event::ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath) {
259 EventDispatcher::GetComposedPathFor(mEvent, aPath);
263 // Get the actual event target node (may have been retargeted for mouse events)
265 already_AddRefed<nsIContent> Event::GetTargetFromFrame() {
266 if (!mPresContext) {
267 return nullptr;
270 // Get the mTarget frame (have to get the ESM first)
271 nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
272 if (!targetFrame) {
273 return nullptr;
276 // get the real content
277 nsCOMPtr<nsIContent> realEventContent;
278 targetFrame->GetContentForEvent(mEvent, getter_AddRefs(realEventContent));
279 return realEventContent.forget();
282 EventTarget* Event::GetExplicitOriginalTarget() const {
283 if (mExplicitOriginalTarget) {
284 return mExplicitOriginalTarget;
286 return GetTarget();
289 EventTarget* Event::GetOriginalTarget() const {
290 return mEvent->GetOriginalDOMEventTarget();
293 EventTarget* Event::GetComposedTarget() const {
294 EventTarget* et = GetOriginalTarget();
295 nsCOMPtr<nsIContent> content = do_QueryInterface(et);
296 if (!content) {
297 return et;
299 nsIContent* nonChrome = content->FindFirstNonChromeOnlyAccessContent();
300 return nonChrome ? static_cast<EventTarget*>(nonChrome)
301 : static_cast<EventTarget*>(content->GetComposedDoc());
304 void Event::SetTrusted(bool aTrusted) { mEvent->mFlags.mIsTrusted = aTrusted; }
306 bool Event::Init(mozilla::dom::EventTarget* aGlobal) {
307 if (!mIsMainThreadEvent) {
308 return IsCurrentThreadRunningChromeWorker();
310 bool trusted = false;
311 nsCOMPtr<nsPIDOMWindowInner> w = do_QueryInterface(aGlobal);
312 if (w) {
313 nsCOMPtr<Document> d = w->GetExtantDoc();
314 if (d) {
315 trusted = nsContentUtils::IsChromeDoc(d);
316 nsPresContext* presContext = d->GetPresContext();
317 if (presContext) {
318 InitPresContextData(presContext);
322 return trusted;
325 // static
326 already_AddRefed<Event> Event::Constructor(const GlobalObject& aGlobal,
327 const nsAString& aType,
328 const EventInit& aParam) {
329 nsCOMPtr<mozilla::dom::EventTarget> t =
330 do_QueryInterface(aGlobal.GetAsSupports());
331 return Constructor(t, aType, aParam);
334 // static
335 already_AddRefed<Event> Event::Constructor(EventTarget* aEventTarget,
336 const nsAString& aType,
337 const EventInit& aParam) {
338 RefPtr<Event> e = new Event(aEventTarget, nullptr, nullptr);
339 bool trusted = e->Init(aEventTarget);
340 e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
341 e->SetTrusted(trusted);
342 e->SetComposed(aParam.mComposed);
343 return e.forget();
346 uint16_t Event::EventPhase() const {
347 // Note, remember to check that this works also
348 // if or when Bug 235441 is fixed.
349 if ((mEvent->mCurrentTarget && mEvent->mCurrentTarget == mEvent->mTarget) ||
350 mEvent->mFlags.InTargetPhase()) {
351 return Event_Binding::AT_TARGET;
353 if (mEvent->mFlags.mInCapturePhase) {
354 return Event_Binding::CAPTURING_PHASE;
356 if (mEvent->mFlags.mInBubblingPhase) {
357 return Event_Binding::BUBBLING_PHASE;
359 return Event_Binding::NONE;
362 void Event::StopPropagation() { mEvent->StopPropagation(); }
364 void Event::StopImmediatePropagation() { mEvent->StopImmediatePropagation(); }
366 void Event::StopCrossProcessForwarding() {
367 mEvent->StopCrossProcessForwarding();
370 void Event::PreventDefault() {
371 // This method is called only from C++ code which must handle default action
372 // of this event. So, pass true always.
373 PreventDefaultInternal(true);
376 void Event::PreventDefault(JSContext* aCx, CallerType aCallerType) {
377 // Note that at handling default action, another event may be dispatched.
378 // Then, JS in content mey be call preventDefault()
379 // even in the event is in system event group. Therefore, don't refer
380 // mInSystemGroup here.
381 nsIPrincipal* principal =
382 mIsMainThreadEvent ? nsContentUtils::SubjectPrincipal(aCx) : nullptr;
384 PreventDefaultInternal(aCallerType == CallerType::System, principal);
387 void Event::PreventDefaultInternal(bool aCalledByDefaultHandler,
388 nsIPrincipal* aPrincipal) {
389 if (!mEvent->mFlags.mCancelable) {
390 return;
392 if (mEvent->mFlags.mInPassiveListener) {
393 nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(mOwner));
394 if (win) {
395 if (Document* doc = win->GetExtantDoc()) {
396 AutoTArray<nsString, 1> params;
397 GetType(*params.AppendElement());
398 doc->WarnOnceAbout(Document::ePreventDefaultFromPassiveListener, false,
399 params);
402 return;
405 mEvent->PreventDefault(aCalledByDefaultHandler, aPrincipal);
407 if (!IsTrusted()) {
408 return;
411 WidgetDragEvent* dragEvent = mEvent->AsDragEvent();
412 if (!dragEvent) {
413 return;
416 nsIPrincipal* principal = nullptr;
417 nsCOMPtr<nsINode> node = do_QueryInterface(mEvent->mCurrentTarget);
418 if (node) {
419 principal = node->NodePrincipal();
420 } else {
421 nsCOMPtr<nsIScriptObjectPrincipal> sop =
422 do_QueryInterface(mEvent->mCurrentTarget);
423 if (sop) {
424 principal = sop->GetPrincipal();
427 if (principal && !principal->IsSystemPrincipal()) {
428 dragEvent->mDefaultPreventedOnContent = true;
432 void Event::SetEventType(const nsAString& aEventTypeArg) {
433 mEvent->mSpecifiedEventTypeString.Truncate();
434 if (mIsMainThreadEvent) {
435 mEvent->mSpecifiedEventType = nsContentUtils::GetEventMessageAndAtom(
436 aEventTypeArg, mEvent->mClass, &(mEvent->mMessage));
437 mEvent->SetDefaultComposed();
438 } else {
439 mEvent->mSpecifiedEventType = NS_Atomize(u"on"_ns + aEventTypeArg);
440 mEvent->mMessage = eUnidentifiedEvent;
441 mEvent->SetComposed(aEventTypeArg);
443 mEvent->SetDefaultComposedInNativeAnonymousContent();
446 already_AddRefed<EventTarget> Event::EnsureWebAccessibleRelatedTarget(
447 EventTarget* aRelatedTarget) {
448 nsCOMPtr<EventTarget> relatedTarget = aRelatedTarget;
449 if (relatedTarget) {
450 nsCOMPtr<nsIContent> content = do_QueryInterface(relatedTarget);
452 if (content && content->ChromeOnlyAccess() &&
453 !nsContentUtils::CanAccessNativeAnon()) {
454 content = content->FindFirstNonChromeOnlyAccessContent();
455 relatedTarget = content;
458 if (relatedTarget) {
459 relatedTarget = relatedTarget->GetTargetForDOMEvent();
462 return relatedTarget.forget();
465 void Event::InitEvent(const nsAString& aEventTypeArg,
466 mozilla::CanBubble aCanBubbleArg,
467 mozilla::Cancelable aCancelableArg,
468 mozilla::Composed aComposedArg) {
469 // Make sure this event isn't already being dispatched.
470 NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
472 if (IsTrusted()) {
473 // Ensure the caller is permitted to dispatch trusted DOM events.
474 if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
475 SetTrusted(false);
479 SetEventType(aEventTypeArg);
481 mEvent->mFlags.mBubbles = aCanBubbleArg == CanBubble::eYes;
482 mEvent->mFlags.mCancelable = aCancelableArg == Cancelable::eYes;
483 if (aComposedArg != Composed::eDefault) {
484 mEvent->mFlags.mComposed = aComposedArg == Composed::eYes;
487 mEvent->mFlags.mDefaultPrevented = false;
488 mEvent->mFlags.mDefaultPreventedByContent = false;
489 mEvent->mFlags.mDefaultPreventedByChrome = false;
490 mEvent->mFlags.mPropagationStopped = false;
491 mEvent->mFlags.mImmediatePropagationStopped = false;
493 // Clearing the old targets, so that the event is targeted correctly when
494 // re-dispatching it.
495 mEvent->mTarget = nullptr;
496 mEvent->mOriginalTarget = nullptr;
499 void Event::DuplicatePrivateData() {
500 NS_ASSERTION(mEvent, "No WidgetEvent for Event duplication!");
501 if (mEventIsInternal) {
502 return;
505 mEvent = mEvent->Duplicate();
506 mPresContext = nullptr;
507 mEventIsInternal = true;
508 mPrivateDataDuplicated = true;
511 void Event::SetTarget(EventTarget* aTarget) { mEvent->mTarget = aTarget; }
513 bool Event::IsDispatchStopped() { return mEvent->PropagationStopped(); }
515 WidgetEvent* Event::WidgetEventPtr() { return mEvent; }
517 // static
518 CSSIntPoint Event::GetScreenCoords(nsPresContext* aPresContext,
519 WidgetEvent* aEvent,
520 LayoutDeviceIntPoint aPoint) {
521 if (PointerLockManager::IsLocked()) {
522 return EventStateManager::sLastScreenPoint;
525 if (!aEvent || (aEvent->mClass != eMouseEventClass &&
526 aEvent->mClass != eMouseScrollEventClass &&
527 aEvent->mClass != eWheelEventClass &&
528 aEvent->mClass != ePointerEventClass &&
529 aEvent->mClass != eTouchEventClass &&
530 aEvent->mClass != eDragEventClass &&
531 aEvent->mClass != eSimpleGestureEventClass)) {
532 return CSSIntPoint(0, 0);
535 // Doing a straight conversion from LayoutDeviceIntPoint to CSSIntPoint
536 // seem incorrect, but it is needed to maintain legacy functionality.
537 WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
538 if (!aPresContext || !(guiEvent && guiEvent->mWidget)) {
539 return CSSIntPoint(aPoint.x, aPoint.y);
542 // (Potentially) transform the point from the coordinate space of an
543 // out-of-process iframe to the coordinate space of the native
544 // window. The transform can only be applied to a point whose components
545 // are floating-point values, so convert the integer point first, then
546 // transform, and then round the result back to an integer point.
547 LayoutDevicePoint floatPoint(aPoint);
548 LayoutDevicePoint topLevelPoint =
549 guiEvent->mWidget->WidgetToTopLevelWidgetTransform().TransformPoint(
550 floatPoint);
551 LayoutDeviceIntPoint rounded = RoundedToInt(topLevelPoint);
553 nsPoint pt = LayoutDevicePixel::ToAppUnits(
554 rounded,
555 aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
557 pt += LayoutDevicePixel::ToAppUnits(
558 guiEvent->mWidget->TopLevelWidgetToScreenOffset(),
559 aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
561 return CSSPixel::FromAppUnitsRounded(pt);
564 // static
565 CSSIntPoint Event::GetPageCoords(nsPresContext* aPresContext,
566 WidgetEvent* aEvent,
567 LayoutDeviceIntPoint aPoint,
568 CSSIntPoint aDefaultPoint) {
569 CSSIntPoint pagePoint =
570 Event::GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
572 // If there is some scrolling, add scroll info to client point.
573 if (aPresContext && aPresContext->GetPresShell()) {
574 PresShell* presShell = aPresContext->PresShell();
575 nsIScrollableFrame* scrollframe =
576 presShell->GetRootScrollFrameAsScrollable();
577 if (scrollframe) {
578 pagePoint +=
579 CSSIntPoint::FromAppUnitsRounded(scrollframe->GetScrollPosition());
583 return pagePoint;
586 // static
587 CSSIntPoint Event::GetClientCoords(nsPresContext* aPresContext,
588 WidgetEvent* aEvent,
589 LayoutDeviceIntPoint aPoint,
590 CSSIntPoint aDefaultPoint) {
591 if (PointerLockManager::IsLocked()) {
592 return EventStateManager::sLastClientPoint;
595 if (!aEvent ||
596 (aEvent->mClass != eMouseEventClass &&
597 aEvent->mClass != eMouseScrollEventClass &&
598 aEvent->mClass != eWheelEventClass &&
599 aEvent->mClass != eTouchEventClass &&
600 aEvent->mClass != eDragEventClass &&
601 aEvent->mClass != ePointerEventClass &&
602 aEvent->mClass != eSimpleGestureEventClass) ||
603 !aPresContext || !aEvent->AsGUIEvent()->mWidget) {
604 return aDefaultPoint;
607 PresShell* presShell = aPresContext->GetPresShell();
608 if (!presShell) {
609 return CSSIntPoint(0, 0);
611 nsIFrame* rootFrame = presShell->GetRootFrame();
612 if (!rootFrame) {
613 return CSSIntPoint(0, 0);
615 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
616 aEvent, aPoint, RelativeTo{rootFrame});
618 return CSSIntPoint::FromAppUnitsRounded(pt);
621 // static
622 CSSIntPoint Event::GetOffsetCoords(nsPresContext* aPresContext,
623 WidgetEvent* aEvent,
624 LayoutDeviceIntPoint aPoint,
625 CSSIntPoint aDefaultPoint) {
626 if (!aEvent->mTarget) {
627 return GetPageCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
629 nsCOMPtr<nsIContent> content = do_QueryInterface(aEvent->mTarget);
630 if (!content || !aPresContext) {
631 return CSSIntPoint();
633 RefPtr<PresShell> presShell = aPresContext->GetPresShell();
634 if (!presShell) {
635 return CSSIntPoint();
637 presShell->FlushPendingNotifications(FlushType::Layout);
638 nsIFrame* frame = content->GetPrimaryFrame();
639 if (!frame) {
640 return CSSIntPoint();
642 // For compat, see https://github.com/w3c/csswg-drafts/issues/1508. In SVG we
643 // just return the coordinates of the outer SVG box. This is all kinda
644 // unfortunate.
645 if (frame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT) &&
646 StaticPrefs::dom_events_offset_in_svg_relative_to_svg_root()) {
647 frame = SVGUtils::GetOuterSVGFrame(frame);
648 if (!frame) {
649 return CSSIntPoint();
652 nsIFrame* rootFrame = presShell->GetRootFrame();
653 if (!rootFrame) {
654 return CSSIntPoint();
656 CSSIntPoint clientCoords =
657 GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
658 nsPoint pt = CSSPixel::ToAppUnits(clientCoords);
659 if (nsLayoutUtils::TransformPoint(RelativeTo{rootFrame}, RelativeTo{frame},
660 pt) == nsLayoutUtils::TRANSFORM_SUCCEEDED) {
661 pt -= frame->GetPaddingRectRelativeToSelf().TopLeft();
662 return CSSPixel::FromAppUnitsRounded(pt);
664 return CSSIntPoint();
667 // To be called ONLY by Event::GetType (which has the additional
668 // logic for handling user-defined events).
669 // static
670 const char16_t* Event::GetEventName(EventMessage aEventType) {
671 switch (aEventType) {
672 #define MESSAGE_TO_EVENT(name_, _message, _type, _struct) \
673 case _message: \
674 return u"" #name_;
675 #include "mozilla/EventNameList.h"
676 #undef MESSAGE_TO_EVENT
677 default:
678 break;
680 // XXXldb We can hit this case for WidgetEvent objects that we didn't
681 // create and that are not user defined events since this function and
682 // SetEventType are incomplete. (But fixing that requires fixing the
683 // arrays in nsEventListenerManager too, since the events for which
684 // this is a problem generally *are* created by Event.)
685 return nullptr;
688 bool Event::DefaultPrevented(CallerType aCallerType) const {
689 NS_ENSURE_TRUE(mEvent, false);
691 // If preventDefault() has never been called, just return false.
692 if (!mEvent->DefaultPrevented()) {
693 return false;
696 // If preventDefault() has been called by content, return true. Otherwise,
697 // i.e., preventDefault() has been called by chrome, return true only when
698 // this is called by chrome.
699 return mEvent->DefaultPreventedByContent() ||
700 aCallerType == CallerType::System;
703 bool Event::ReturnValue(CallerType aCallerType) const {
704 return !DefaultPrevented(aCallerType);
707 void Event::SetReturnValue(bool aReturnValue, CallerType aCallerType) {
708 if (!aReturnValue) {
709 PreventDefaultInternal(aCallerType == CallerType::System);
713 double Event::TimeStamp() {
714 if (mEvent->mTimeStamp.IsNull()) {
715 return 0.0;
718 if (mIsMainThreadEvent) {
719 if (NS_WARN_IF(!mOwner)) {
720 return 0.0;
723 nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(mOwner);
724 if (NS_WARN_IF(!win)) {
725 return 0.0;
728 Performance* perf = win->GetPerformance();
729 if (NS_WARN_IF(!perf)) {
730 return 0.0;
733 double ret =
734 perf->GetDOMTiming()->TimeStampToDOMHighRes(mEvent->mTimeStamp);
735 MOZ_ASSERT(mOwner->PrincipalOrNull());
737 return nsRFPService::ReduceTimePrecisionAsMSecs(
738 ret, perf->GetRandomTimelineSeed(),
739 mOwner->PrincipalOrNull()->IsSystemPrincipal(),
740 mOwner->CrossOriginIsolated());
743 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
744 MOZ_ASSERT(workerPrivate);
746 double ret = workerPrivate->TimeStampToDOMHighRes(mEvent->mTimeStamp);
748 return nsRFPService::ReduceTimePrecisionAsMSecs(
749 ret, workerPrivate->GetRandomTimelineSeed(),
750 workerPrivate->UsesSystemPrincipal(),
751 workerPrivate->CrossOriginIsolated());
754 void Event::Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType) {
755 if (aSerializeInterfaceType) {
756 IPC::WriteParam(aMsg, u"event"_ns);
759 nsString type;
760 GetType(type);
761 IPC::WriteParam(aMsg, type);
763 IPC::WriteParam(aMsg, Bubbles());
764 IPC::WriteParam(aMsg, Cancelable());
765 IPC::WriteParam(aMsg, IsTrusted());
766 IPC::WriteParam(aMsg, Composed());
768 // No timestamp serialization for now!
771 bool Event::Deserialize(const IPC::Message* aMsg, PickleIterator* aIter) {
772 nsString type;
773 NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &type), false);
775 bool bubbles = false;
776 NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &bubbles), false);
778 bool cancelable = false;
779 NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &cancelable), false);
781 bool trusted = false;
782 NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &trusted), false);
784 bool composed = false;
785 NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &composed), false);
787 InitEvent(type, bubbles, cancelable);
788 SetTrusted(trusted);
789 SetComposed(composed);
791 return true;
794 void Event::SetOwner(EventTarget* aOwner) {
795 mOwner = nullptr;
797 if (!aOwner) {
798 return;
801 nsCOMPtr<nsINode> n = do_QueryInterface(aOwner);
802 if (n) {
803 mOwner = n->OwnerDoc()->GetScopeObject();
804 return;
807 nsCOMPtr<nsPIDOMWindowInner> w = do_QueryInterface(aOwner);
808 if (w) {
809 mOwner = do_QueryInterface(w);
810 return;
813 nsCOMPtr<DOMEventTargetHelper> eth = do_QueryInterface(aOwner);
814 if (eth) {
815 mOwner = eth->GetParentObject();
816 return;
819 #ifdef DEBUG
820 nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(aOwner);
821 MOZ_ASSERT(root, "Unexpected EventTarget!");
822 #endif
825 void Event::GetWidgetEventType(WidgetEvent* aEvent, nsAString& aType) {
826 if (!aEvent->mSpecifiedEventTypeString.IsEmpty()) {
827 aType = aEvent->mSpecifiedEventTypeString;
828 return;
831 const char16_t* name = GetEventName(aEvent->mMessage);
833 if (name) {
834 aType.Assign(name);
835 return;
836 } else if (aEvent->mMessage == eUnidentifiedEvent &&
837 aEvent->mSpecifiedEventType) {
838 // Remove "on"
839 aType = Substring(nsDependentAtomString(aEvent->mSpecifiedEventType), 2);
840 aEvent->mSpecifiedEventTypeString = aType;
841 return;
844 aType.Truncate();
847 bool Event::IsDragExitEnabled(JSContext* aCx, JSObject* aGlobal) {
848 return StaticPrefs::dom_event_dragexit_enabled() ||
849 nsContentUtils::IsSystemCaller(aCx);
852 } // namespace mozilla::dom
854 using namespace mozilla;
855 using namespace mozilla::dom;
857 already_AddRefed<Event> NS_NewDOMEvent(EventTarget* aOwner,
858 nsPresContext* aPresContext,
859 WidgetEvent* aEvent) {
860 RefPtr<Event> it = new Event(aOwner, aPresContext, aEvent);
861 return it.forget();