Bug 1025824 - Fix mHwcLayerMap handling r=sushil
[gecko.git] / dom / events / Event.cpp
blob0d8d1ea328f254c720951f288d18975ae4b5212d
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "AccessCheck.h"
7 #include "base/basictypes.h"
8 #include "ipc/IPCMessageUtils.h"
9 #include "mozilla/dom/Event.h"
10 #include "mozilla/ContentEvents.h"
11 #include "mozilla/DOMEventTargetHelper.h"
12 #include "mozilla/EventStateManager.h"
13 #include "mozilla/InternalMutationEvent.h"
14 #include "mozilla/MiscEvents.h"
15 #include "mozilla/MouseEvents.h"
16 #include "mozilla/Preferences.h"
17 #include "mozilla/TextEvents.h"
18 #include "mozilla/TouchEvents.h"
19 #include "nsContentUtils.h"
20 #include "nsCOMPtr.h"
21 #include "nsDeviceContext.h"
22 #include "nsError.h"
23 #include "nsGlobalWindow.h"
24 #include "nsIFrame.h"
25 #include "nsIContent.h"
26 #include "nsIDocument.h"
27 #include "nsIPresShell.h"
28 #include "nsIScrollableFrame.h"
29 #include "nsJSEnvironment.h"
30 #include "nsLayoutUtils.h"
31 #include "nsPerformance.h"
32 #include "nsPIWindowRoot.h"
33 #include "WorkerPrivate.h"
35 namespace mozilla {
36 namespace dom {
38 namespace workers {
39 extern bool IsCurrentThreadRunningChromeWorker();
40 } // namespace workers
42 static char *sPopupAllowedEvents;
44 static bool sReturnHighResTimeStamp = false;
45 static bool sReturnHighResTimeStampIsSet = false;
47 Event::Event(EventTarget* aOwner,
48 nsPresContext* aPresContext,
49 WidgetEvent* aEvent)
51 ConstructorInit(aOwner, aPresContext, aEvent);
54 Event::Event(nsPIDOMWindow* aParent)
56 ConstructorInit(static_cast<nsGlobalWindow *>(aParent), nullptr, nullptr);
59 void
60 Event::ConstructorInit(EventTarget* aOwner,
61 nsPresContext* aPresContext,
62 WidgetEvent* aEvent)
64 SetIsDOMBinding();
65 SetOwner(aOwner);
66 mIsMainThreadEvent = mOwner || NS_IsMainThread();
67 if (mIsMainThreadEvent) {
68 nsJSContext::LikelyShortLivingObjectCreated();
71 if (mIsMainThreadEvent && !sReturnHighResTimeStampIsSet) {
72 Preferences::AddBoolVarCache(&sReturnHighResTimeStamp,
73 "dom.event.highrestimestamp.enabled",
74 sReturnHighResTimeStamp);
75 sReturnHighResTimeStampIsSet = true;
78 mPrivateDataDuplicated = false;
80 if (aEvent) {
81 mEvent = aEvent;
82 mEventIsInternal = false;
84 else {
85 mEventIsInternal = true;
87 A derived class might want to allocate its own type of aEvent
88 (derived from WidgetEvent). To do this, it should take care to pass
89 a non-nullptr aEvent to this ctor, e.g.:
91 FooEvent::FooEvent(..., WidgetEvent* aEvent)
92 : Event(..., aEvent ? aEvent : new WidgetEvent())
94 Then, to override the mEventIsInternal assignments done by the
95 base ctor, it should do this in its own ctor:
97 FooEvent::FooEvent(..., WidgetEvent* aEvent)
98 ...
101 if (aEvent) {
102 mEventIsInternal = false;
104 else {
105 mEventIsInternal = true;
110 mEvent = new WidgetEvent(false, 0);
111 mEvent->time = PR_Now();
114 InitPresContextData(aPresContext);
117 void
118 Event::InitPresContextData(nsPresContext* aPresContext)
120 mPresContext = aPresContext;
121 // Get the explicit original target (if it's anonymous make it null)
123 nsCOMPtr<nsIContent> content = GetTargetFromFrame();
124 mExplicitOriginalTarget = content;
125 if (content && content->IsInAnonymousSubtree()) {
126 mExplicitOriginalTarget = nullptr;
131 Event::~Event()
133 NS_ASSERT_OWNINGTHREAD(Event);
135 if (mEventIsInternal && mEvent) {
136 delete mEvent;
140 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Event)
141 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
142 NS_INTERFACE_MAP_ENTRY(nsISupports)
143 NS_INTERFACE_MAP_ENTRY(nsIDOMEvent)
144 NS_INTERFACE_MAP_END
146 NS_IMPL_CYCLE_COLLECTING_ADDREF(Event)
147 NS_IMPL_CYCLE_COLLECTING_RELEASE(Event)
149 NS_IMPL_CYCLE_COLLECTION_CLASS(Event)
151 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Event)
152 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
153 NS_IMPL_CYCLE_COLLECTION_TRACE_END
155 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
156 if (tmp->mEventIsInternal) {
157 tmp->mEvent->target = nullptr;
158 tmp->mEvent->currentTarget = nullptr;
159 tmp->mEvent->originalTarget = nullptr;
160 switch (tmp->mEvent->eventStructType) {
161 case NS_MOUSE_EVENT:
162 case NS_MOUSE_SCROLL_EVENT:
163 case NS_WHEEL_EVENT:
164 case NS_SIMPLE_GESTURE_EVENT:
165 case NS_POINTER_EVENT:
166 tmp->mEvent->AsMouseEventBase()->relatedTarget = nullptr;
167 break;
168 case NS_DRAG_EVENT: {
169 WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
170 dragEvent->dataTransfer = nullptr;
171 dragEvent->relatedTarget = nullptr;
172 break;
174 case NS_CLIPBOARD_EVENT:
175 tmp->mEvent->AsClipboardEvent()->clipboardData = nullptr;
176 break;
177 case NS_MUTATION_EVENT:
178 tmp->mEvent->AsMutationEvent()->mRelatedNode = nullptr;
179 break;
180 case NS_FOCUS_EVENT:
181 tmp->mEvent->AsFocusEvent()->relatedTarget = nullptr;
182 break;
183 default:
184 break;
187 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext);
188 NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget);
189 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner);
190 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
191 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
193 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
194 if (tmp->mEventIsInternal) {
195 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->target)
196 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->currentTarget)
197 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->originalTarget)
198 switch (tmp->mEvent->eventStructType) {
199 case NS_MOUSE_EVENT:
200 case NS_MOUSE_SCROLL_EVENT:
201 case NS_WHEEL_EVENT:
202 case NS_SIMPLE_GESTURE_EVENT:
203 case NS_POINTER_EVENT:
204 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
205 cb.NoteXPCOMChild(tmp->mEvent->AsMouseEventBase()->relatedTarget);
206 break;
207 case NS_DRAG_EVENT: {
208 WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
209 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->dataTransfer");
210 cb.NoteXPCOMChild(dragEvent->dataTransfer);
211 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
212 cb.NoteXPCOMChild(dragEvent->relatedTarget);
213 break;
215 case NS_CLIPBOARD_EVENT:
216 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->clipboardData");
217 cb.NoteXPCOMChild(tmp->mEvent->AsClipboardEvent()->clipboardData);
218 break;
219 case NS_MUTATION_EVENT:
220 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedNode");
221 cb.NoteXPCOMChild(tmp->mEvent->AsMutationEvent()->mRelatedNode);
222 break;
223 case NS_FOCUS_EVENT:
224 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
225 cb.NoteXPCOMChild(tmp->mEvent->AsFocusEvent()->relatedTarget);
226 break;
227 default:
228 break;
231 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext)
232 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget)
233 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
234 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
235 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
237 bool
238 Event::IsChrome(JSContext* aCx) const
240 return mIsMainThreadEvent ?
241 xpc::AccessCheck::isChrome(js::GetContextCompartment(aCx)) :
242 mozilla::dom::workers::IsCurrentThreadRunningChromeWorker();
245 // nsIDOMEventInterface
246 NS_METHOD
247 Event::GetType(nsAString& aType)
249 if (!mIsMainThreadEvent || !mEvent->typeString.IsEmpty()) {
250 aType = mEvent->typeString;
251 return NS_OK;
253 const char* name = GetEventName(mEvent->message);
255 if (name) {
256 CopyASCIItoUTF16(name, aType);
257 return NS_OK;
258 } else if (mEvent->message == NS_USER_DEFINED_EVENT && mEvent->userType) {
259 aType = Substring(nsDependentAtomString(mEvent->userType), 2); // Remove "on"
260 mEvent->typeString = aType;
261 return NS_OK;
264 aType.Truncate();
265 return NS_OK;
268 static EventTarget*
269 GetDOMEventTarget(nsIDOMEventTarget* aTarget)
271 return aTarget ? aTarget->GetTargetForDOMEvent() : nullptr;
274 EventTarget*
275 Event::GetTarget() const
277 return GetDOMEventTarget(mEvent->target);
280 NS_METHOD
281 Event::GetTarget(nsIDOMEventTarget** aTarget)
283 NS_IF_ADDREF(*aTarget = GetTarget());
284 return NS_OK;
287 EventTarget*
288 Event::GetCurrentTarget() const
290 return GetDOMEventTarget(mEvent->currentTarget);
293 NS_IMETHODIMP
294 Event::GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget)
296 NS_IF_ADDREF(*aCurrentTarget = GetCurrentTarget());
297 return NS_OK;
301 // Get the actual event target node (may have been retargeted for mouse events)
303 already_AddRefed<nsIContent>
304 Event::GetTargetFromFrame()
306 if (!mPresContext) { return nullptr; }
308 // Get the target frame (have to get the ESM first)
309 nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
310 if (!targetFrame) { return nullptr; }
312 // get the real content
313 nsCOMPtr<nsIContent> realEventContent;
314 targetFrame->GetContentForEvent(mEvent, getter_AddRefs(realEventContent));
315 return realEventContent.forget();
318 EventTarget*
319 Event::GetExplicitOriginalTarget() const
321 if (mExplicitOriginalTarget) {
322 return mExplicitOriginalTarget;
324 return GetTarget();
327 NS_IMETHODIMP
328 Event::GetExplicitOriginalTarget(nsIDOMEventTarget** aRealEventTarget)
330 NS_IF_ADDREF(*aRealEventTarget = GetExplicitOriginalTarget());
331 return NS_OK;
334 EventTarget*
335 Event::GetOriginalTarget() const
337 if (mEvent->originalTarget) {
338 return GetDOMEventTarget(mEvent->originalTarget);
341 return GetTarget();
344 NS_IMETHODIMP
345 Event::GetOriginalTarget(nsIDOMEventTarget** aOriginalTarget)
347 NS_IF_ADDREF(*aOriginalTarget = GetOriginalTarget());
348 return NS_OK;
351 NS_IMETHODIMP_(void)
352 Event::SetTrusted(bool aTrusted)
354 mEvent->mFlags.mIsTrusted = aTrusted;
357 bool
358 Event::Init(mozilla::dom::EventTarget* aGlobal)
360 if (!mIsMainThreadEvent) {
361 return nsContentUtils::ThreadsafeIsCallerChrome();
363 bool trusted = false;
364 nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal);
365 if (w) {
366 nsCOMPtr<nsIDocument> d = w->GetExtantDoc();
367 if (d) {
368 trusted = nsContentUtils::IsChromeDoc(d);
369 nsIPresShell* s = d->GetShell();
370 if (s) {
371 InitPresContextData(s->GetPresContext());
375 return trusted;
378 // static
379 already_AddRefed<Event>
380 Event::Constructor(const GlobalObject& aGlobal,
381 const nsAString& aType,
382 const EventInit& aParam,
383 ErrorResult& aRv)
385 nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
386 nsRefPtr<Event> e = new Event(t, nullptr, nullptr);
387 bool trusted = e->Init(t);
388 aRv = e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
389 e->SetTrusted(trusted);
390 return e.forget();
393 uint16_t
394 Event::EventPhase() const
396 // Note, remember to check that this works also
397 // if or when Bug 235441 is fixed.
398 if ((mEvent->currentTarget &&
399 mEvent->currentTarget == mEvent->target) ||
400 mEvent->mFlags.InTargetPhase()) {
401 return nsIDOMEvent::AT_TARGET;
403 if (mEvent->mFlags.mInCapturePhase) {
404 return nsIDOMEvent::CAPTURING_PHASE;
406 if (mEvent->mFlags.mInBubblingPhase) {
407 return nsIDOMEvent::BUBBLING_PHASE;
409 return nsIDOMEvent::NONE;
412 NS_IMETHODIMP
413 Event::GetEventPhase(uint16_t* aEventPhase)
415 *aEventPhase = EventPhase();
416 return NS_OK;
419 NS_IMETHODIMP
420 Event::GetBubbles(bool* aBubbles)
422 *aBubbles = Bubbles();
423 return NS_OK;
426 NS_IMETHODIMP
427 Event::GetCancelable(bool* aCancelable)
429 *aCancelable = Cancelable();
430 return NS_OK;
433 NS_IMETHODIMP
434 Event::GetTimeStamp(uint64_t* aTimeStamp)
436 *aTimeStamp = mEvent->time;
437 return NS_OK;
440 NS_IMETHODIMP
441 Event::StopPropagation()
443 mEvent->mFlags.mPropagationStopped = true;
444 return NS_OK;
447 NS_IMETHODIMP
448 Event::StopImmediatePropagation()
450 mEvent->mFlags.mPropagationStopped = true;
451 mEvent->mFlags.mImmediatePropagationStopped = true;
452 return NS_OK;
455 NS_IMETHODIMP
456 Event::GetIsTrusted(bool* aIsTrusted)
458 *aIsTrusted = IsTrusted();
459 return NS_OK;
462 NS_IMETHODIMP
463 Event::PreventDefault()
465 // This method is called only from C++ code which must handle default action
466 // of this event. So, pass true always.
467 PreventDefaultInternal(true);
468 return NS_OK;
471 void
472 Event::PreventDefault(JSContext* aCx)
474 MOZ_ASSERT(aCx, "JS context must be specified");
476 // Note that at handling default action, another event may be dispatched.
477 // Then, JS in content mey be call preventDefault()
478 // even in the event is in system event group. Therefore, don't refer
479 // mInSystemGroup here.
480 PreventDefaultInternal(IsChrome(aCx));
483 void
484 Event::PreventDefaultInternal(bool aCalledByDefaultHandler)
486 if (!mEvent->mFlags.mCancelable) {
487 return;
490 mEvent->mFlags.mDefaultPrevented = true;
492 // Note that even if preventDefault() has already been called by chrome,
493 // a call of preventDefault() by content needs to overwrite
494 // mDefaultPreventedByContent to true because in such case, defaultPrevented
495 // must be true when web apps check it after they call preventDefault().
496 if (!aCalledByDefaultHandler) {
497 mEvent->mFlags.mDefaultPreventedByContent = true;
500 if (!IsTrusted()) {
501 return;
504 WidgetDragEvent* dragEvent = mEvent->AsDragEvent();
505 if (!dragEvent) {
506 return;
509 nsCOMPtr<nsINode> node = do_QueryInterface(mEvent->currentTarget);
510 if (!node) {
511 nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mEvent->currentTarget);
512 if (!win) {
513 return;
515 node = win->GetExtantDoc();
517 if (!nsContentUtils::IsChromeDoc(node->OwnerDoc())) {
518 dragEvent->mDefaultPreventedOnContent = true;
522 void
523 Event::SetEventType(const nsAString& aEventTypeArg)
525 if (mIsMainThreadEvent) {
526 mEvent->userType =
527 nsContentUtils::GetEventIdAndAtom(aEventTypeArg, mEvent->eventStructType,
528 &(mEvent->message));
529 } else {
530 mEvent->userType = nullptr;
531 mEvent->message = NS_USER_DEFINED_EVENT;
532 mEvent->typeString = aEventTypeArg;
536 NS_IMETHODIMP
537 Event::InitEvent(const nsAString& aEventTypeArg,
538 bool aCanBubbleArg,
539 bool aCancelableArg)
541 // Make sure this event isn't already being dispatched.
542 NS_ENSURE_TRUE(!mEvent->mFlags.mIsBeingDispatched, NS_OK);
544 if (IsTrusted()) {
545 // Ensure the caller is permitted to dispatch trusted DOM events.
546 if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
547 SetTrusted(false);
551 SetEventType(aEventTypeArg);
553 mEvent->mFlags.mBubbles = aCanBubbleArg;
554 mEvent->mFlags.mCancelable = aCancelableArg;
556 mEvent->mFlags.mDefaultPrevented = false;
558 // Clearing the old targets, so that the event is targeted correctly when
559 // re-dispatching it.
560 mEvent->target = nullptr;
561 mEvent->originalTarget = nullptr;
562 return NS_OK;
565 NS_IMETHODIMP
566 Event::DuplicatePrivateData()
568 NS_ASSERTION(mEvent, "No WidgetEvent for Event duplication!");
569 if (mEventIsInternal) {
570 return NS_OK;
573 mEvent = mEvent->Duplicate();
574 mPresContext = nullptr;
575 mEventIsInternal = true;
576 mPrivateDataDuplicated = true;
578 return NS_OK;
581 NS_IMETHODIMP
582 Event::SetTarget(nsIDOMEventTarget* aTarget)
584 #ifdef DEBUG
586 nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aTarget);
588 NS_ASSERTION(!win || !win->IsInnerWindow(),
589 "Uh, inner window set as event target!");
591 #endif
593 mEvent->target = do_QueryInterface(aTarget);
594 return NS_OK;
597 NS_IMETHODIMP_(bool)
598 Event::IsDispatchStopped()
600 return mEvent->mFlags.mPropagationStopped;
603 NS_IMETHODIMP_(WidgetEvent*)
604 Event::GetInternalNSEvent()
606 return mEvent;
609 NS_IMETHODIMP_(Event*)
610 Event::InternalDOMEvent()
612 return this;
615 // return true if eventName is contained within events, delimited by
616 // spaces
617 static bool
618 PopupAllowedForEvent(const char *eventName)
620 if (!sPopupAllowedEvents) {
621 Event::PopupAllowedEventsChanged();
623 if (!sPopupAllowedEvents) {
624 return false;
628 nsDependentCString events(sPopupAllowedEvents);
630 nsAFlatCString::const_iterator start, end;
631 nsAFlatCString::const_iterator startiter(events.BeginReading(start));
632 events.EndReading(end);
634 while (startiter != end) {
635 nsAFlatCString::const_iterator enditer(end);
637 if (!FindInReadable(nsDependentCString(eventName), startiter, enditer))
638 return false;
640 // the match is surrounded by spaces, or at a string boundary
641 if ((startiter == start || *--startiter == ' ') &&
642 (enditer == end || *enditer == ' ')) {
643 return true;
646 // Move on and see if there are other matches. (The delimitation
647 // requirement makes it pointless to begin the next search before
648 // the end of the invalid match just found.)
649 startiter = enditer;
652 return false;
655 // static
656 PopupControlState
657 Event::GetEventPopupControlState(WidgetEvent* aEvent)
659 // generally if an event handler is running, new windows are disallowed.
660 // check for exceptions:
661 PopupControlState abuse = openAbused;
663 switch(aEvent->eventStructType) {
664 case NS_EVENT :
665 // For these following events only allow popups if they're
666 // triggered while handling user input. See
667 // nsPresShell::HandleEventInternal() for details.
668 if (EventStateManager::IsHandlingUserInput()) {
669 switch(aEvent->message) {
670 case NS_FORM_SELECTED :
671 if (PopupAllowedForEvent("select")) {
672 abuse = openControlled;
674 break;
675 case NS_FORM_CHANGE :
676 if (PopupAllowedForEvent("change")) {
677 abuse = openControlled;
679 break;
682 break;
683 case NS_EDITOR_INPUT_EVENT :
684 // For this following event only allow popups if it's triggered
685 // while handling user input. See
686 // nsPresShell::HandleEventInternal() for details.
687 if (EventStateManager::IsHandlingUserInput()) {
688 switch(aEvent->message) {
689 case NS_EDITOR_INPUT:
690 if (PopupAllowedForEvent("input")) {
691 abuse = openControlled;
693 break;
696 break;
697 case NS_INPUT_EVENT :
698 // For this following event only allow popups if it's triggered
699 // while handling user input. See
700 // nsPresShell::HandleEventInternal() for details.
701 if (EventStateManager::IsHandlingUserInput()) {
702 switch(aEvent->message) {
703 case NS_FORM_CHANGE :
704 if (PopupAllowedForEvent("change")) {
705 abuse = openControlled;
707 break;
708 case NS_XUL_COMMAND:
709 abuse = openControlled;
710 break;
713 break;
714 case NS_KEY_EVENT :
715 if (aEvent->mFlags.mIsTrusted) {
716 uint32_t key = aEvent->AsKeyboardEvent()->keyCode;
717 switch(aEvent->message) {
718 case NS_KEY_PRESS :
719 // return key on focused button. see note at NS_MOUSE_CLICK.
720 if (key == nsIDOMKeyEvent::DOM_VK_RETURN) {
721 abuse = openAllowed;
722 } else if (PopupAllowedForEvent("keypress")) {
723 abuse = openControlled;
725 break;
726 case NS_KEY_UP :
727 // space key on focused button. see note at NS_MOUSE_CLICK.
728 if (key == nsIDOMKeyEvent::DOM_VK_SPACE) {
729 abuse = openAllowed;
730 } else if (PopupAllowedForEvent("keyup")) {
731 abuse = openControlled;
733 break;
734 case NS_KEY_DOWN :
735 if (PopupAllowedForEvent("keydown")) {
736 abuse = openControlled;
738 break;
741 break;
742 case NS_TOUCH_EVENT :
743 if (aEvent->mFlags.mIsTrusted) {
744 switch (aEvent->message) {
745 case NS_TOUCH_START :
746 if (PopupAllowedForEvent("touchstart")) {
747 abuse = openControlled;
749 break;
750 case NS_TOUCH_END :
751 if (PopupAllowedForEvent("touchend")) {
752 abuse = openControlled;
754 break;
757 break;
758 case NS_MOUSE_EVENT :
759 if (aEvent->mFlags.mIsTrusted &&
760 aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
761 switch(aEvent->message) {
762 case NS_MOUSE_BUTTON_UP :
763 if (PopupAllowedForEvent("mouseup")) {
764 abuse = openControlled;
766 break;
767 case NS_MOUSE_BUTTON_DOWN :
768 if (PopupAllowedForEvent("mousedown")) {
769 abuse = openControlled;
771 break;
772 case NS_MOUSE_CLICK :
773 /* Click events get special treatment because of their
774 historical status as a more legitimate event handler. If
775 click popups are enabled in the prefs, clear the popup
776 status completely. */
777 if (PopupAllowedForEvent("click")) {
778 abuse = openAllowed;
780 break;
781 case NS_MOUSE_DOUBLECLICK :
782 if (PopupAllowedForEvent("dblclick")) {
783 abuse = openControlled;
785 break;
788 break;
789 case NS_FORM_EVENT :
790 // For these following events only allow popups if they're
791 // triggered while handling user input. See
792 // nsPresShell::HandleEventInternal() for details.
793 if (EventStateManager::IsHandlingUserInput()) {
794 switch(aEvent->message) {
795 case NS_FORM_SUBMIT :
796 if (PopupAllowedForEvent("submit")) {
797 abuse = openControlled;
799 break;
800 case NS_FORM_RESET :
801 if (PopupAllowedForEvent("reset")) {
802 abuse = openControlled;
804 break;
807 break;
808 default:
809 break;
812 return abuse;
815 // static
816 void
817 Event::PopupAllowedEventsChanged()
819 if (sPopupAllowedEvents) {
820 nsMemory::Free(sPopupAllowedEvents);
823 nsAdoptingCString str = Preferences::GetCString("dom.popup_allowed_events");
825 // We'll want to do this even if str is empty to avoid looking up
826 // this pref all the time if it's not set.
827 sPopupAllowedEvents = ToNewCString(str);
830 // static
831 void
832 Event::Shutdown()
834 if (sPopupAllowedEvents) {
835 nsMemory::Free(sPopupAllowedEvents);
839 nsIntPoint
840 Event::GetScreenCoords(nsPresContext* aPresContext,
841 WidgetEvent* aEvent,
842 LayoutDeviceIntPoint aPoint)
844 if (EventStateManager::sIsPointerLocked) {
845 return EventStateManager::sLastScreenPoint;
848 if (!aEvent ||
849 (aEvent->eventStructType != NS_MOUSE_EVENT &&
850 aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
851 aEvent->eventStructType != NS_WHEEL_EVENT &&
852 aEvent->eventStructType != NS_POINTER_EVENT &&
853 aEvent->eventStructType != NS_TOUCH_EVENT &&
854 aEvent->eventStructType != NS_DRAG_EVENT &&
855 aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
856 return nsIntPoint(0, 0);
859 WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
860 if (!guiEvent->widget) {
861 return LayoutDeviceIntPoint::ToUntyped(aPoint);
864 LayoutDeviceIntPoint offset = aPoint +
865 LayoutDeviceIntPoint::FromUntyped(guiEvent->widget->WidgetToScreenOffset());
866 nscoord factor = aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
867 return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor),
868 nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor));
871 // static
872 CSSIntPoint
873 Event::GetPageCoords(nsPresContext* aPresContext,
874 WidgetEvent* aEvent,
875 LayoutDeviceIntPoint aPoint,
876 CSSIntPoint aDefaultPoint)
878 CSSIntPoint pagePoint =
879 Event::GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
881 // If there is some scrolling, add scroll info to client point.
882 if (aPresContext && aPresContext->GetPresShell()) {
883 nsIPresShell* shell = aPresContext->GetPresShell();
884 nsIScrollableFrame* scrollframe = shell->GetRootScrollFrameAsScrollable();
885 if (scrollframe) {
886 pagePoint += CSSIntPoint::FromAppUnitsRounded(scrollframe->GetScrollPosition());
890 return pagePoint;
893 // static
894 CSSIntPoint
895 Event::GetClientCoords(nsPresContext* aPresContext,
896 WidgetEvent* aEvent,
897 LayoutDeviceIntPoint aPoint,
898 CSSIntPoint aDefaultPoint)
900 if (EventStateManager::sIsPointerLocked) {
901 return EventStateManager::sLastClientPoint;
904 if (!aEvent ||
905 (aEvent->eventStructType != NS_MOUSE_EVENT &&
906 aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
907 aEvent->eventStructType != NS_WHEEL_EVENT &&
908 aEvent->eventStructType != NS_TOUCH_EVENT &&
909 aEvent->eventStructType != NS_DRAG_EVENT &&
910 aEvent->eventStructType != NS_POINTER_EVENT &&
911 aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
912 !aPresContext ||
913 !aEvent->AsGUIEvent()->widget) {
914 return aDefaultPoint;
917 nsIPresShell* shell = aPresContext->GetPresShell();
918 if (!shell) {
919 return CSSIntPoint(0, 0);
922 nsIFrame* rootFrame = shell->GetRootFrame();
923 if (!rootFrame) {
924 return CSSIntPoint(0, 0);
926 nsPoint pt =
927 nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
928 LayoutDeviceIntPoint::ToUntyped(aPoint), rootFrame);
930 return CSSIntPoint::FromAppUnitsRounded(pt);
933 // To be called ONLY by Event::GetType (which has the additional
934 // logic for handling user-defined events).
935 // static
936 const char*
937 Event::GetEventName(uint32_t aEventType)
939 switch(aEventType) {
940 #define ID_TO_EVENT(name_, _id, _type, _struct) \
941 case _id: return #name_;
942 #include "mozilla/EventNameList.h"
943 #undef ID_TO_EVENT
944 default:
945 break;
947 // XXXldb We can hit this case for WidgetEvent objects that we didn't
948 // create and that are not user defined events since this function and
949 // SetEventType are incomplete. (But fixing that requires fixing the
950 // arrays in nsEventListenerManager too, since the events for which
951 // this is a problem generally *are* created by Event.)
952 return nullptr;
955 bool
956 Event::DefaultPrevented(JSContext* aCx) const
958 MOZ_ASSERT(aCx, "JS context must be specified");
960 NS_ENSURE_TRUE(mEvent, false);
962 // If preventDefault() has never been called, just return false.
963 if (!mEvent->mFlags.mDefaultPrevented) {
964 return false;
967 // If preventDefault() has been called by content, return true. Otherwise,
968 // i.e., preventDefault() has been called by chrome, return true only when
969 // this is called by chrome.
970 return mEvent->mFlags.mDefaultPreventedByContent || IsChrome(aCx);
973 double
974 Event::TimeStamp() const
976 if (!sReturnHighResTimeStamp) {
977 return static_cast<double>(mEvent->time);
980 if (mEvent->timeStamp.IsNull()) {
981 return 0.0;
984 if (mIsMainThreadEvent) {
985 if (NS_WARN_IF(!mOwner)) {
986 return 0.0;
989 nsPerformance* perf = mOwner->GetPerformance();
990 if (NS_WARN_IF(!perf)) {
991 return 0.0;
994 return perf->GetDOMTiming()->TimeStampToDOMHighRes(mEvent->timeStamp);
997 // For dedicated workers, we should make times relative to the navigation
998 // start of the document that created the worker. We currently don't have
999 // that information handy so for now we treat shared workers and dedicated
1000 // workers alike and make times relative to the worker creation time. We can
1001 // fix this when we implement WorkerPerformance.
1002 workers::WorkerPrivate* workerPrivate =
1003 workers::GetCurrentThreadWorkerPrivate();
1004 MOZ_ASSERT(workerPrivate);
1006 TimeDuration duration =
1007 mEvent->timeStamp - workerPrivate->CreationTimeStamp();
1008 return duration.ToMilliseconds();
1011 bool
1012 Event::GetPreventDefault() const
1014 if (mOwner) {
1015 if (nsIDocument* doc = mOwner->GetExtantDoc()) {
1016 doc->WarnOnceAbout(nsIDocument::eGetPreventDefault);
1019 // GetPreventDefault() is legacy and Gecko specific method. Although,
1020 // the result should be same as defaultPrevented, we don't need to break
1021 // backward compatibility of legacy method. Let's behave traditionally.
1022 return DefaultPrevented();
1025 NS_IMETHODIMP
1026 Event::GetPreventDefault(bool* aReturn)
1028 NS_ENSURE_ARG_POINTER(aReturn);
1029 *aReturn = GetPreventDefault();
1030 return NS_OK;
1033 NS_IMETHODIMP
1034 Event::GetDefaultPrevented(bool* aReturn)
1036 NS_ENSURE_ARG_POINTER(aReturn);
1037 // This method must be called by only event handlers implemented by C++.
1038 // Then, the handlers must handle default action. So, this method don't need
1039 // to check if preventDefault() has been called by content or chrome.
1040 *aReturn = DefaultPrevented();
1041 return NS_OK;
1044 NS_IMETHODIMP_(void)
1045 Event::Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType)
1047 if (aSerializeInterfaceType) {
1048 IPC::WriteParam(aMsg, NS_LITERAL_STRING("event"));
1051 nsString type;
1052 GetType(type);
1053 IPC::WriteParam(aMsg, type);
1055 IPC::WriteParam(aMsg, Bubbles());
1056 IPC::WriteParam(aMsg, Cancelable());
1057 IPC::WriteParam(aMsg, IsTrusted());
1059 // No timestamp serialization for now!
1062 NS_IMETHODIMP_(bool)
1063 Event::Deserialize(const IPC::Message* aMsg, void** aIter)
1065 nsString type;
1066 NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &type), false);
1068 bool bubbles = false;
1069 NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &bubbles), false);
1071 bool cancelable = false;
1072 NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &cancelable), false);
1074 bool trusted = false;
1075 NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &trusted), false);
1077 nsresult rv = InitEvent(type, bubbles, cancelable);
1078 NS_ENSURE_SUCCESS(rv, false);
1079 SetTrusted(trusted);
1081 return true;
1084 NS_IMETHODIMP_(void)
1085 Event::SetOwner(mozilla::dom::EventTarget* aOwner)
1087 mOwner = nullptr;
1089 if (!aOwner) {
1090 return;
1093 nsCOMPtr<nsINode> n = do_QueryInterface(aOwner);
1094 if (n) {
1095 mOwner = do_QueryInterface(n->OwnerDoc()->GetScopeObject());
1096 return;
1099 nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aOwner);
1100 if (w) {
1101 if (w->IsOuterWindow()) {
1102 mOwner = w->GetCurrentInnerWindow();
1103 } else {
1104 mOwner.swap(w);
1106 return;
1109 nsCOMPtr<DOMEventTargetHelper> eth = do_QueryInterface(aOwner);
1110 if (eth) {
1111 mOwner = eth->GetOwner();
1112 return;
1115 #ifdef DEBUG
1116 nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(aOwner);
1117 MOZ_ASSERT(root, "Unexpected EventTarget!");
1118 #endif
1121 } // namespace dom
1122 } // namespace mozilla
1124 using namespace mozilla;
1125 using namespace mozilla::dom;
1127 nsresult
1128 NS_NewDOMEvent(nsIDOMEvent** aInstancePtrResult,
1129 EventTarget* aOwner,
1130 nsPresContext* aPresContext,
1131 WidgetEvent* aEvent)
1133 Event* it = new Event(aOwner, aPresContext, aEvent);
1134 NS_ADDREF(it);
1135 *aInstancePtrResult = static_cast<Event*>(it);
1136 return NS_OK;