Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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 "nsPIWindowRoot.h"
33 namespace mozilla {
34 namespace dom {
36 namespace workers {
37 extern bool IsCurrentThreadRunningChromeWorker();
38 } // namespace workers
40 static char *sPopupAllowedEvents;
42 Event::Event(EventTarget* aOwner,
43 nsPresContext* aPresContext,
44 WidgetEvent* aEvent)
45 {
46 ConstructorInit(aOwner, aPresContext, aEvent);
47 }
49 Event::Event(nsPIDOMWindow* aParent)
50 {
51 ConstructorInit(static_cast<nsGlobalWindow *>(aParent), nullptr, nullptr);
52 }
54 void
55 Event::ConstructorInit(EventTarget* aOwner,
56 nsPresContext* aPresContext,
57 WidgetEvent* aEvent)
58 {
59 SetIsDOMBinding();
60 SetOwner(aOwner);
61 mIsMainThreadEvent = mOwner || NS_IsMainThread();
62 if (mIsMainThreadEvent) {
63 nsJSContext::LikelyShortLivingObjectCreated();
64 }
66 mPrivateDataDuplicated = false;
68 if (aEvent) {
69 mEvent = aEvent;
70 mEventIsInternal = false;
71 }
72 else {
73 mEventIsInternal = true;
74 /*
75 A derived class might want to allocate its own type of aEvent
76 (derived from WidgetEvent). To do this, it should take care to pass
77 a non-nullptr aEvent to this ctor, e.g.:
79 FooEvent::FooEvent(..., WidgetEvent* aEvent)
80 : Event(..., aEvent ? aEvent : new WidgetEvent())
82 Then, to override the mEventIsInternal assignments done by the
83 base ctor, it should do this in its own ctor:
85 FooEvent::FooEvent(..., WidgetEvent* aEvent)
86 ...
87 {
88 ...
89 if (aEvent) {
90 mEventIsInternal = false;
91 }
92 else {
93 mEventIsInternal = true;
94 }
95 ...
96 }
97 */
98 mEvent = new WidgetEvent(false, 0);
99 mEvent->time = PR_Now();
100 }
102 InitPresContextData(aPresContext);
103 }
105 void
106 Event::InitPresContextData(nsPresContext* aPresContext)
107 {
108 mPresContext = aPresContext;
109 // Get the explicit original target (if it's anonymous make it null)
110 {
111 nsCOMPtr<nsIContent> content = GetTargetFromFrame();
112 mExplicitOriginalTarget = content;
113 if (content && content->IsInAnonymousSubtree()) {
114 mExplicitOriginalTarget = nullptr;
115 }
116 }
117 }
119 Event::~Event()
120 {
121 NS_ASSERT_OWNINGTHREAD(Event);
123 if (mEventIsInternal && mEvent) {
124 delete mEvent;
125 }
126 }
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(nsIDOMEvent)
132 NS_INTERFACE_MAP_END
134 NS_IMPL_CYCLE_COLLECTING_ADDREF(Event)
135 NS_IMPL_CYCLE_COLLECTING_RELEASE(Event)
137 NS_IMPL_CYCLE_COLLECTION_CLASS(Event)
139 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Event)
140 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
141 NS_IMPL_CYCLE_COLLECTION_TRACE_END
143 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
144 if (tmp->mEventIsInternal) {
145 tmp->mEvent->target = nullptr;
146 tmp->mEvent->currentTarget = nullptr;
147 tmp->mEvent->originalTarget = nullptr;
148 switch (tmp->mEvent->eventStructType) {
149 case NS_MOUSE_EVENT:
150 case NS_MOUSE_SCROLL_EVENT:
151 case NS_WHEEL_EVENT:
152 case NS_SIMPLE_GESTURE_EVENT:
153 case NS_POINTER_EVENT:
154 tmp->mEvent->AsMouseEventBase()->relatedTarget = nullptr;
155 break;
156 case NS_DRAG_EVENT: {
157 WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
158 dragEvent->dataTransfer = nullptr;
159 dragEvent->relatedTarget = nullptr;
160 break;
161 }
162 case NS_CLIPBOARD_EVENT:
163 tmp->mEvent->AsClipboardEvent()->clipboardData = nullptr;
164 break;
165 case NS_MUTATION_EVENT:
166 tmp->mEvent->AsMutationEvent()->mRelatedNode = nullptr;
167 break;
168 case NS_FOCUS_EVENT:
169 tmp->mEvent->AsFocusEvent()->relatedTarget = nullptr;
170 break;
171 default:
172 break;
173 }
174 }
175 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext);
176 NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget);
177 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner);
178 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
179 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
181 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
182 if (tmp->mEventIsInternal) {
183 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->target)
184 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->currentTarget)
185 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->originalTarget)
186 switch (tmp->mEvent->eventStructType) {
187 case NS_MOUSE_EVENT:
188 case NS_MOUSE_SCROLL_EVENT:
189 case NS_WHEEL_EVENT:
190 case NS_SIMPLE_GESTURE_EVENT:
191 case NS_POINTER_EVENT:
192 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
193 cb.NoteXPCOMChild(tmp->mEvent->AsMouseEventBase()->relatedTarget);
194 break;
195 case NS_DRAG_EVENT: {
196 WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
197 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->dataTransfer");
198 cb.NoteXPCOMChild(dragEvent->dataTransfer);
199 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
200 cb.NoteXPCOMChild(dragEvent->relatedTarget);
201 break;
202 }
203 case NS_CLIPBOARD_EVENT:
204 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->clipboardData");
205 cb.NoteXPCOMChild(tmp->mEvent->AsClipboardEvent()->clipboardData);
206 break;
207 case NS_MUTATION_EVENT:
208 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedNode");
209 cb.NoteXPCOMChild(tmp->mEvent->AsMutationEvent()->mRelatedNode);
210 break;
211 case NS_FOCUS_EVENT:
212 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
213 cb.NoteXPCOMChild(tmp->mEvent->AsFocusEvent()->relatedTarget);
214 break;
215 default:
216 break;
217 }
218 }
219 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext)
220 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget)
221 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
222 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
223 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
225 bool
226 Event::IsChrome(JSContext* aCx) const
227 {
228 return mIsMainThreadEvent ?
229 xpc::AccessCheck::isChrome(js::GetContextCompartment(aCx)) :
230 mozilla::dom::workers::IsCurrentThreadRunningChromeWorker();
231 }
233 // nsIDOMEventInterface
234 NS_METHOD
235 Event::GetType(nsAString& aType)
236 {
237 if (!mIsMainThreadEvent || !mEvent->typeString.IsEmpty()) {
238 aType = mEvent->typeString;
239 return NS_OK;
240 }
241 const char* name = GetEventName(mEvent->message);
243 if (name) {
244 CopyASCIItoUTF16(name, aType);
245 return NS_OK;
246 } else if (mEvent->message == NS_USER_DEFINED_EVENT && mEvent->userType) {
247 aType = Substring(nsDependentAtomString(mEvent->userType), 2); // Remove "on"
248 mEvent->typeString = aType;
249 return NS_OK;
250 }
252 aType.Truncate();
253 return NS_OK;
254 }
256 static EventTarget*
257 GetDOMEventTarget(nsIDOMEventTarget* aTarget)
258 {
259 return aTarget ? aTarget->GetTargetForDOMEvent() : nullptr;
260 }
262 EventTarget*
263 Event::GetTarget() const
264 {
265 return GetDOMEventTarget(mEvent->target);
266 }
268 NS_METHOD
269 Event::GetTarget(nsIDOMEventTarget** aTarget)
270 {
271 NS_IF_ADDREF(*aTarget = GetTarget());
272 return NS_OK;
273 }
275 EventTarget*
276 Event::GetCurrentTarget() const
277 {
278 return GetDOMEventTarget(mEvent->currentTarget);
279 }
281 NS_IMETHODIMP
282 Event::GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget)
283 {
284 NS_IF_ADDREF(*aCurrentTarget = GetCurrentTarget());
285 return NS_OK;
286 }
288 //
289 // Get the actual event target node (may have been retargeted for mouse events)
290 //
291 already_AddRefed<nsIContent>
292 Event::GetTargetFromFrame()
293 {
294 if (!mPresContext) { return nullptr; }
296 // Get the target frame (have to get the ESM first)
297 nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
298 if (!targetFrame) { return nullptr; }
300 // get the real content
301 nsCOMPtr<nsIContent> realEventContent;
302 targetFrame->GetContentForEvent(mEvent, getter_AddRefs(realEventContent));
303 return realEventContent.forget();
304 }
306 EventTarget*
307 Event::GetExplicitOriginalTarget() const
308 {
309 if (mExplicitOriginalTarget) {
310 return mExplicitOriginalTarget;
311 }
312 return GetTarget();
313 }
315 NS_IMETHODIMP
316 Event::GetExplicitOriginalTarget(nsIDOMEventTarget** aRealEventTarget)
317 {
318 NS_IF_ADDREF(*aRealEventTarget = GetExplicitOriginalTarget());
319 return NS_OK;
320 }
322 EventTarget*
323 Event::GetOriginalTarget() const
324 {
325 if (mEvent->originalTarget) {
326 return GetDOMEventTarget(mEvent->originalTarget);
327 }
329 return GetTarget();
330 }
332 NS_IMETHODIMP
333 Event::GetOriginalTarget(nsIDOMEventTarget** aOriginalTarget)
334 {
335 NS_IF_ADDREF(*aOriginalTarget = GetOriginalTarget());
336 return NS_OK;
337 }
339 NS_IMETHODIMP_(void)
340 Event::SetTrusted(bool aTrusted)
341 {
342 mEvent->mFlags.mIsTrusted = aTrusted;
343 }
345 bool
346 Event::Init(mozilla::dom::EventTarget* aGlobal)
347 {
348 if (!mIsMainThreadEvent) {
349 return nsContentUtils::ThreadsafeIsCallerChrome();
350 }
351 bool trusted = false;
352 nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal);
353 if (w) {
354 nsCOMPtr<nsIDocument> d = w->GetExtantDoc();
355 if (d) {
356 trusted = nsContentUtils::IsChromeDoc(d);
357 nsIPresShell* s = d->GetShell();
358 if (s) {
359 InitPresContextData(s->GetPresContext());
360 }
361 }
362 }
363 return trusted;
364 }
366 // static
367 already_AddRefed<Event>
368 Event::Constructor(const GlobalObject& aGlobal,
369 const nsAString& aType,
370 const EventInit& aParam,
371 ErrorResult& aRv)
372 {
373 nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
374 nsRefPtr<Event> e = new Event(t, nullptr, nullptr);
375 bool trusted = e->Init(t);
376 aRv = e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
377 e->SetTrusted(trusted);
378 return e.forget();
379 }
381 uint16_t
382 Event::EventPhase() const
383 {
384 // Note, remember to check that this works also
385 // if or when Bug 235441 is fixed.
386 if ((mEvent->currentTarget &&
387 mEvent->currentTarget == mEvent->target) ||
388 mEvent->mFlags.InTargetPhase()) {
389 return nsIDOMEvent::AT_TARGET;
390 }
391 if (mEvent->mFlags.mInCapturePhase) {
392 return nsIDOMEvent::CAPTURING_PHASE;
393 }
394 if (mEvent->mFlags.mInBubblingPhase) {
395 return nsIDOMEvent::BUBBLING_PHASE;
396 }
397 return nsIDOMEvent::NONE;
398 }
400 NS_IMETHODIMP
401 Event::GetEventPhase(uint16_t* aEventPhase)
402 {
403 *aEventPhase = EventPhase();
404 return NS_OK;
405 }
407 NS_IMETHODIMP
408 Event::GetBubbles(bool* aBubbles)
409 {
410 *aBubbles = Bubbles();
411 return NS_OK;
412 }
414 NS_IMETHODIMP
415 Event::GetCancelable(bool* aCancelable)
416 {
417 *aCancelable = Cancelable();
418 return NS_OK;
419 }
421 NS_IMETHODIMP
422 Event::GetTimeStamp(uint64_t* aTimeStamp)
423 {
424 *aTimeStamp = TimeStamp();
425 return NS_OK;
426 }
428 NS_IMETHODIMP
429 Event::StopPropagation()
430 {
431 mEvent->mFlags.mPropagationStopped = true;
432 return NS_OK;
433 }
435 NS_IMETHODIMP
436 Event::StopImmediatePropagation()
437 {
438 mEvent->mFlags.mPropagationStopped = true;
439 mEvent->mFlags.mImmediatePropagationStopped = true;
440 return NS_OK;
441 }
443 NS_IMETHODIMP
444 Event::GetIsTrusted(bool* aIsTrusted)
445 {
446 *aIsTrusted = IsTrusted();
447 return NS_OK;
448 }
450 NS_IMETHODIMP
451 Event::PreventDefault()
452 {
453 // This method is called only from C++ code which must handle default action
454 // of this event. So, pass true always.
455 PreventDefaultInternal(true);
456 return NS_OK;
457 }
459 void
460 Event::PreventDefault(JSContext* aCx)
461 {
462 MOZ_ASSERT(aCx, "JS context must be specified");
464 // Note that at handling default action, another event may be dispatched.
465 // Then, JS in content mey be call preventDefault()
466 // even in the event is in system event group. Therefore, don't refer
467 // mInSystemGroup here.
468 PreventDefaultInternal(IsChrome(aCx));
469 }
471 void
472 Event::PreventDefaultInternal(bool aCalledByDefaultHandler)
473 {
474 if (!mEvent->mFlags.mCancelable) {
475 return;
476 }
478 mEvent->mFlags.mDefaultPrevented = true;
480 // Note that even if preventDefault() has already been called by chrome,
481 // a call of preventDefault() by content needs to overwrite
482 // mDefaultPreventedByContent to true because in such case, defaultPrevented
483 // must be true when web apps check it after they call preventDefault().
484 if (!aCalledByDefaultHandler) {
485 mEvent->mFlags.mDefaultPreventedByContent = true;
486 }
488 if (!IsTrusted()) {
489 return;
490 }
492 WidgetDragEvent* dragEvent = mEvent->AsDragEvent();
493 if (!dragEvent) {
494 return;
495 }
497 nsCOMPtr<nsINode> node = do_QueryInterface(mEvent->currentTarget);
498 if (!node) {
499 nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mEvent->currentTarget);
500 if (!win) {
501 return;
502 }
503 node = win->GetExtantDoc();
504 }
505 if (!nsContentUtils::IsChromeDoc(node->OwnerDoc())) {
506 dragEvent->mDefaultPreventedOnContent = true;
507 }
508 }
510 void
511 Event::SetEventType(const nsAString& aEventTypeArg)
512 {
513 if (mIsMainThreadEvent) {
514 mEvent->userType =
515 nsContentUtils::GetEventIdAndAtom(aEventTypeArg, mEvent->eventStructType,
516 &(mEvent->message));
517 } else {
518 mEvent->userType = nullptr;
519 mEvent->message = NS_USER_DEFINED_EVENT;
520 mEvent->typeString = aEventTypeArg;
521 }
522 }
524 NS_IMETHODIMP
525 Event::InitEvent(const nsAString& aEventTypeArg,
526 bool aCanBubbleArg,
527 bool aCancelableArg)
528 {
529 // Make sure this event isn't already being dispatched.
530 NS_ENSURE_TRUE(!mEvent->mFlags.mIsBeingDispatched, NS_OK);
532 if (IsTrusted()) {
533 // Ensure the caller is permitted to dispatch trusted DOM events.
534 if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
535 SetTrusted(false);
536 }
537 }
539 SetEventType(aEventTypeArg);
541 mEvent->mFlags.mBubbles = aCanBubbleArg;
542 mEvent->mFlags.mCancelable = aCancelableArg;
544 mEvent->mFlags.mDefaultPrevented = false;
546 // Clearing the old targets, so that the event is targeted correctly when
547 // re-dispatching it.
548 mEvent->target = nullptr;
549 mEvent->originalTarget = nullptr;
550 return NS_OK;
551 }
553 NS_IMETHODIMP
554 Event::DuplicatePrivateData()
555 {
556 NS_ASSERTION(mEvent, "No WidgetEvent for Event duplication!");
557 if (mEventIsInternal) {
558 return NS_OK;
559 }
561 mEvent = mEvent->Duplicate();
562 mPresContext = nullptr;
563 mEventIsInternal = true;
564 mPrivateDataDuplicated = true;
566 return NS_OK;
567 }
569 NS_IMETHODIMP
570 Event::SetTarget(nsIDOMEventTarget* aTarget)
571 {
572 #ifdef DEBUG
573 {
574 nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aTarget);
576 NS_ASSERTION(!win || !win->IsInnerWindow(),
577 "Uh, inner window set as event target!");
578 }
579 #endif
581 mEvent->target = do_QueryInterface(aTarget);
582 return NS_OK;
583 }
585 NS_IMETHODIMP_(bool)
586 Event::IsDispatchStopped()
587 {
588 return mEvent->mFlags.mPropagationStopped;
589 }
591 NS_IMETHODIMP_(WidgetEvent*)
592 Event::GetInternalNSEvent()
593 {
594 return mEvent;
595 }
597 NS_IMETHODIMP_(Event*)
598 Event::InternalDOMEvent()
599 {
600 return this;
601 }
603 // return true if eventName is contained within events, delimited by
604 // spaces
605 static bool
606 PopupAllowedForEvent(const char *eventName)
607 {
608 if (!sPopupAllowedEvents) {
609 Event::PopupAllowedEventsChanged();
611 if (!sPopupAllowedEvents) {
612 return false;
613 }
614 }
616 nsDependentCString events(sPopupAllowedEvents);
618 nsAFlatCString::const_iterator start, end;
619 nsAFlatCString::const_iterator startiter(events.BeginReading(start));
620 events.EndReading(end);
622 while (startiter != end) {
623 nsAFlatCString::const_iterator enditer(end);
625 if (!FindInReadable(nsDependentCString(eventName), startiter, enditer))
626 return false;
628 // the match is surrounded by spaces, or at a string boundary
629 if ((startiter == start || *--startiter == ' ') &&
630 (enditer == end || *enditer == ' ')) {
631 return true;
632 }
634 // Move on and see if there are other matches. (The delimitation
635 // requirement makes it pointless to begin the next search before
636 // the end of the invalid match just found.)
637 startiter = enditer;
638 }
640 return false;
641 }
643 // static
644 PopupControlState
645 Event::GetEventPopupControlState(WidgetEvent* aEvent)
646 {
647 // generally if an event handler is running, new windows are disallowed.
648 // check for exceptions:
649 PopupControlState abuse = openAbused;
651 switch(aEvent->eventStructType) {
652 case NS_EVENT :
653 // For these following events only allow popups if they're
654 // triggered while handling user input. See
655 // nsPresShell::HandleEventInternal() for details.
656 if (EventStateManager::IsHandlingUserInput()) {
657 switch(aEvent->message) {
658 case NS_FORM_SELECTED :
659 if (PopupAllowedForEvent("select")) {
660 abuse = openControlled;
661 }
662 break;
663 case NS_FORM_CHANGE :
664 if (PopupAllowedForEvent("change")) {
665 abuse = openControlled;
666 }
667 break;
668 }
669 }
670 break;
671 case NS_EDITOR_INPUT_EVENT :
672 // For this following event only allow popups if it's triggered
673 // while handling user input. See
674 // nsPresShell::HandleEventInternal() for details.
675 if (EventStateManager::IsHandlingUserInput()) {
676 switch(aEvent->message) {
677 case NS_EDITOR_INPUT:
678 if (PopupAllowedForEvent("input")) {
679 abuse = openControlled;
680 }
681 break;
682 }
683 }
684 break;
685 case NS_INPUT_EVENT :
686 // For this following event only allow popups if it's triggered
687 // while handling user input. See
688 // nsPresShell::HandleEventInternal() for details.
689 if (EventStateManager::IsHandlingUserInput()) {
690 switch(aEvent->message) {
691 case NS_FORM_CHANGE :
692 if (PopupAllowedForEvent("change")) {
693 abuse = openControlled;
694 }
695 break;
696 case NS_XUL_COMMAND:
697 abuse = openControlled;
698 break;
699 }
700 }
701 break;
702 case NS_KEY_EVENT :
703 if (aEvent->mFlags.mIsTrusted) {
704 uint32_t key = aEvent->AsKeyboardEvent()->keyCode;
705 switch(aEvent->message) {
706 case NS_KEY_PRESS :
707 // return key on focused button. see note at NS_MOUSE_CLICK.
708 if (key == nsIDOMKeyEvent::DOM_VK_RETURN) {
709 abuse = openAllowed;
710 } else if (PopupAllowedForEvent("keypress")) {
711 abuse = openControlled;
712 }
713 break;
714 case NS_KEY_UP :
715 // space key on focused button. see note at NS_MOUSE_CLICK.
716 if (key == nsIDOMKeyEvent::DOM_VK_SPACE) {
717 abuse = openAllowed;
718 } else if (PopupAllowedForEvent("keyup")) {
719 abuse = openControlled;
720 }
721 break;
722 case NS_KEY_DOWN :
723 if (PopupAllowedForEvent("keydown")) {
724 abuse = openControlled;
725 }
726 break;
727 }
728 }
729 break;
730 case NS_TOUCH_EVENT :
731 if (aEvent->mFlags.mIsTrusted) {
732 switch (aEvent->message) {
733 case NS_TOUCH_START :
734 if (PopupAllowedForEvent("touchstart")) {
735 abuse = openControlled;
736 }
737 break;
738 case NS_TOUCH_END :
739 if (PopupAllowedForEvent("touchend")) {
740 abuse = openControlled;
741 }
742 break;
743 }
744 }
745 break;
746 case NS_MOUSE_EVENT :
747 if (aEvent->mFlags.mIsTrusted &&
748 aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
749 switch(aEvent->message) {
750 case NS_MOUSE_BUTTON_UP :
751 if (PopupAllowedForEvent("mouseup")) {
752 abuse = openControlled;
753 }
754 break;
755 case NS_MOUSE_BUTTON_DOWN :
756 if (PopupAllowedForEvent("mousedown")) {
757 abuse = openControlled;
758 }
759 break;
760 case NS_MOUSE_CLICK :
761 /* Click events get special treatment because of their
762 historical status as a more legitimate event handler. If
763 click popups are enabled in the prefs, clear the popup
764 status completely. */
765 if (PopupAllowedForEvent("click")) {
766 abuse = openAllowed;
767 }
768 break;
769 case NS_MOUSE_DOUBLECLICK :
770 if (PopupAllowedForEvent("dblclick")) {
771 abuse = openControlled;
772 }
773 break;
774 }
775 }
776 break;
777 case NS_FORM_EVENT :
778 // For these following events only allow popups if they're
779 // triggered while handling user input. See
780 // nsPresShell::HandleEventInternal() for details.
781 if (EventStateManager::IsHandlingUserInput()) {
782 switch(aEvent->message) {
783 case NS_FORM_SUBMIT :
784 if (PopupAllowedForEvent("submit")) {
785 abuse = openControlled;
786 }
787 break;
788 case NS_FORM_RESET :
789 if (PopupAllowedForEvent("reset")) {
790 abuse = openControlled;
791 }
792 break;
793 }
794 }
795 break;
796 default:
797 break;
798 }
800 return abuse;
801 }
803 // static
804 void
805 Event::PopupAllowedEventsChanged()
806 {
807 if (sPopupAllowedEvents) {
808 nsMemory::Free(sPopupAllowedEvents);
809 }
811 nsAdoptingCString str = Preferences::GetCString("dom.popup_allowed_events");
813 // We'll want to do this even if str is empty to avoid looking up
814 // this pref all the time if it's not set.
815 sPopupAllowedEvents = ToNewCString(str);
816 }
818 // static
819 void
820 Event::Shutdown()
821 {
822 if (sPopupAllowedEvents) {
823 nsMemory::Free(sPopupAllowedEvents);
824 }
825 }
827 nsIntPoint
828 Event::GetScreenCoords(nsPresContext* aPresContext,
829 WidgetEvent* aEvent,
830 LayoutDeviceIntPoint aPoint)
831 {
832 if (!nsContentUtils::IsCallerChrome()) {
833 // For non-chrome callers, return client coordinates instead.
834 // For some events, the result will be zero; specifically, for dragend
835 // events (there is no widget associated with dragend events, which
836 // causes GetClientX() to return zero). Since dragend is for the drag
837 // originator and not for the receiver, it is probably not widely used
838 // (receivers get a drop event). Therefore, returning 0 should not break
839 // many web pages. Also, a few years ago Firefox returned 0.
840 // See: https://bugzilla.mozilla.org/show_bug.cgi?id=466379
841 CSSIntPoint clientCoords = GetClientCoords(aPresContext, aEvent, aPoint, CSSIntPoint(0, 0));
842 return nsIntPoint(clientCoords.x, clientCoords.y);
843 }
845 if (EventStateManager::sIsPointerLocked) {
846 return EventStateManager::sLastScreenPoint;
847 }
849 if (!aEvent ||
850 (aEvent->eventStructType != NS_MOUSE_EVENT &&
851 aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
852 aEvent->eventStructType != NS_WHEEL_EVENT &&
853 aEvent->eventStructType != NS_POINTER_EVENT &&
854 aEvent->eventStructType != NS_TOUCH_EVENT &&
855 aEvent->eventStructType != NS_DRAG_EVENT &&
856 aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
857 return nsIntPoint(0, 0);
858 }
860 WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
861 if (!guiEvent->widget) {
862 return LayoutDeviceIntPoint::ToUntyped(aPoint);
863 }
865 LayoutDeviceIntPoint offset = aPoint +
866 LayoutDeviceIntPoint::FromUntyped(guiEvent->widget->WidgetToScreenOffset());
867 nscoord factor = aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
868 return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor),
869 nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor));
870 }
872 // static
873 CSSIntPoint
874 Event::GetPageCoords(nsPresContext* aPresContext,
875 WidgetEvent* aEvent,
876 LayoutDeviceIntPoint aPoint,
877 CSSIntPoint aDefaultPoint)
878 {
879 CSSIntPoint pagePoint =
880 Event::GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
882 // If there is some scrolling, add scroll info to client point.
883 if (aPresContext && aPresContext->GetPresShell()) {
884 nsIPresShell* shell = aPresContext->GetPresShell();
885 nsIScrollableFrame* scrollframe = shell->GetRootScrollFrameAsScrollable();
886 if (scrollframe) {
887 pagePoint += CSSIntPoint::FromAppUnitsRounded(scrollframe->GetScrollPosition());
888 }
889 }
891 return pagePoint;
892 }
894 // static
895 CSSIntPoint
896 Event::GetClientCoords(nsPresContext* aPresContext,
897 WidgetEvent* aEvent,
898 LayoutDeviceIntPoint aPoint,
899 CSSIntPoint aDefaultPoint)
900 {
901 if (EventStateManager::sIsPointerLocked) {
902 return EventStateManager::sLastClientPoint;
903 }
905 if (!aEvent ||
906 (aEvent->eventStructType != NS_MOUSE_EVENT &&
907 aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
908 aEvent->eventStructType != NS_WHEEL_EVENT &&
909 aEvent->eventStructType != NS_TOUCH_EVENT &&
910 aEvent->eventStructType != NS_DRAG_EVENT &&
911 aEvent->eventStructType != NS_POINTER_EVENT &&
912 aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
913 !aPresContext ||
914 !aEvent->AsGUIEvent()->widget) {
915 return aDefaultPoint;
916 }
918 nsIPresShell* shell = aPresContext->GetPresShell();
919 if (!shell) {
920 return CSSIntPoint(0, 0);
921 }
923 nsIFrame* rootFrame = shell->GetRootFrame();
924 if (!rootFrame) {
925 return CSSIntPoint(0, 0);
926 }
927 nsPoint pt =
928 nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
929 LayoutDeviceIntPoint::ToUntyped(aPoint), rootFrame);
931 return CSSIntPoint::FromAppUnitsRounded(pt);
932 }
934 // To be called ONLY by Event::GetType (which has the additional
935 // logic for handling user-defined events).
936 // static
937 const char*
938 Event::GetEventName(uint32_t aEventType)
939 {
940 switch(aEventType) {
941 #define ID_TO_EVENT(name_, _id, _type, _struct) \
942 case _id: return #name_;
943 #include "mozilla/EventNameList.h"
944 #undef ID_TO_EVENT
945 default:
946 break;
947 }
948 // XXXldb We can hit this case for WidgetEvent objects that we didn't
949 // create and that are not user defined events since this function and
950 // SetEventType are incomplete. (But fixing that requires fixing the
951 // arrays in nsEventListenerManager too, since the events for which
952 // this is a problem generally *are* created by Event.)
953 return nullptr;
954 }
956 bool
957 Event::DefaultPrevented(JSContext* aCx) const
958 {
959 MOZ_ASSERT(aCx, "JS context must be specified");
961 NS_ENSURE_TRUE(mEvent, false);
963 // If preventDefault() has never been called, just return false.
964 if (!mEvent->mFlags.mDefaultPrevented) {
965 return false;
966 }
968 // If preventDefault() has been called by content, return true. Otherwise,
969 // i.e., preventDefault() has been called by chrome, return true only when
970 // this is called by chrome.
971 return mEvent->mFlags.mDefaultPreventedByContent || IsChrome(aCx);
972 }
974 bool
975 Event::GetPreventDefault() const
976 {
977 if (mOwner) {
978 if (nsIDocument* doc = mOwner->GetExtantDoc()) {
979 doc->WarnOnceAbout(nsIDocument::eGetPreventDefault);
980 }
981 }
982 // GetPreventDefault() is legacy and Gecko specific method. Although,
983 // the result should be same as defaultPrevented, we don't need to break
984 // backward compatibility of legacy method. Let's behave traditionally.
985 return DefaultPrevented();
986 }
988 NS_IMETHODIMP
989 Event::GetPreventDefault(bool* aReturn)
990 {
991 NS_ENSURE_ARG_POINTER(aReturn);
992 *aReturn = GetPreventDefault();
993 return NS_OK;
994 }
996 NS_IMETHODIMP
997 Event::GetDefaultPrevented(bool* aReturn)
998 {
999 NS_ENSURE_ARG_POINTER(aReturn);
1000 // This method must be called by only event handlers implemented by C++.
1001 // Then, the handlers must handle default action. So, this method don't need
1002 // to check if preventDefault() has been called by content or chrome.
1003 *aReturn = DefaultPrevented();
1004 return NS_OK;
1005 }
1007 NS_IMETHODIMP_(void)
1008 Event::Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType)
1009 {
1010 if (aSerializeInterfaceType) {
1011 IPC::WriteParam(aMsg, NS_LITERAL_STRING("event"));
1012 }
1014 nsString type;
1015 GetType(type);
1016 IPC::WriteParam(aMsg, type);
1018 IPC::WriteParam(aMsg, Bubbles());
1019 IPC::WriteParam(aMsg, Cancelable());
1020 IPC::WriteParam(aMsg, IsTrusted());
1022 // No timestamp serialization for now!
1023 }
1025 NS_IMETHODIMP_(bool)
1026 Event::Deserialize(const IPC::Message* aMsg, void** aIter)
1027 {
1028 nsString type;
1029 NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &type), false);
1031 bool bubbles = false;
1032 NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &bubbles), false);
1034 bool cancelable = false;
1035 NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &cancelable), false);
1037 bool trusted = false;
1038 NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &trusted), false);
1040 nsresult rv = InitEvent(type, bubbles, cancelable);
1041 NS_ENSURE_SUCCESS(rv, false);
1042 SetTrusted(trusted);
1044 return true;
1045 }
1047 NS_IMETHODIMP_(void)
1048 Event::SetOwner(mozilla::dom::EventTarget* aOwner)
1049 {
1050 mOwner = nullptr;
1052 if (!aOwner) {
1053 return;
1054 }
1056 nsCOMPtr<nsINode> n = do_QueryInterface(aOwner);
1057 if (n) {
1058 mOwner = do_QueryInterface(n->OwnerDoc()->GetScopeObject());
1059 return;
1060 }
1062 nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aOwner);
1063 if (w) {
1064 if (w->IsOuterWindow()) {
1065 mOwner = w->GetCurrentInnerWindow();
1066 } else {
1067 mOwner.swap(w);
1068 }
1069 return;
1070 }
1072 nsCOMPtr<DOMEventTargetHelper> eth = do_QueryInterface(aOwner);
1073 if (eth) {
1074 mOwner = eth->GetOwner();
1075 return;
1076 }
1078 #ifdef DEBUG
1079 nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(aOwner);
1080 MOZ_ASSERT(root, "Unexpected EventTarget!");
1081 #endif
1082 }
1084 } // namespace dom
1085 } // namespace mozilla
1087 using namespace mozilla;
1088 using namespace mozilla::dom;
1090 nsresult
1091 NS_NewDOMEvent(nsIDOMEvent** aInstancePtrResult,
1092 EventTarget* aOwner,
1093 nsPresContext* aPresContext,
1094 WidgetEvent* aEvent)
1095 {
1096 Event* it = new Event(aOwner, aPresContext, aEvent);
1097 NS_ADDREF(it);
1098 *aInstancePtrResult = static_cast<Event*>(it);
1099 return NS_OK;
1100 }