AsyncEventDispatcher.cpp (5621B)
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/. */ 6 7 #include "mozilla/AsyncEventDispatcher.h" 8 9 #include "mozilla/BasicEvents.h" 10 #include "mozilla/EventDispatcher.h" 11 #include "mozilla/dom/DocumentInlines.h" 12 #include "mozilla/dom/Event.h" 13 #include "mozilla/dom/EventTarget.h" 14 #include "nsContentUtils.h" 15 16 namespace mozilla { 17 18 using namespace dom; 19 20 /****************************************************************************** 21 * mozilla::AsyncEventDispatcher 22 ******************************************************************************/ 23 24 AsyncEventDispatcher::AsyncEventDispatcher(EventTarget* aTarget, 25 WidgetEvent& aEvent) 26 : CancelableRunnable("AsyncEventDispatcher"), 27 mTarget(aTarget), 28 mEventMessage(eUnidentifiedEvent) { 29 MOZ_ASSERT(mTarget); 30 RefPtr<Event> event = 31 EventDispatcher::CreateEvent(aTarget, nullptr, &aEvent, u""_ns); 32 mEvent = std::move(event); 33 mEventType.SetIsVoid(true); 34 NS_ASSERTION(mEvent, "Should never fail to create an event"); 35 mEvent->DuplicatePrivateData(); 36 mEvent->SetTrusted(aEvent.IsTrusted()); 37 } 38 39 NS_IMETHODIMP 40 AsyncEventDispatcher::Run() { 41 if (mCanceled) { 42 return NS_OK; 43 } 44 nsINode* node = nsINode::FromEventTargetOrNull(mTarget); 45 if (mCheckStillInDoc) { 46 MOZ_ASSERT(node); 47 if (!node->IsInComposedDoc()) { 48 return NS_OK; 49 } 50 } 51 mTarget->AsyncEventRunning(this); 52 if (mEventMessage != eUnidentifiedEvent) { 53 MOZ_ASSERT(mComposed == Composed::eDefault); 54 return nsContentUtils::DispatchTrustedEvent<WidgetEvent>( 55 node->OwnerDoc(), mTarget, mEventMessage, mCanBubble, Cancelable::eNo, 56 nullptr /* aDefaultAction */, mOnlyChromeDispatch); 57 } 58 // MOZ_KnownLives because this instance shouldn't be touched while running. 59 if (mEvent) { 60 DispatchEventOnTarget(MOZ_KnownLive(mTarget), MOZ_KnownLive(mEvent), 61 mOnlyChromeDispatch, mComposed); 62 } else { 63 DispatchEventOnTarget(MOZ_KnownLive(mTarget), mEventType, mCanBubble, 64 mOnlyChromeDispatch, mComposed); 65 } 66 return NS_OK; 67 } 68 69 // static 70 void AsyncEventDispatcher::DispatchEventOnTarget( 71 EventTarget* aTarget, const nsAString& aEventType, CanBubble aCanBubble, 72 ChromeOnlyDispatch aOnlyChromeDispatch, Composed aComposed) { 73 RefPtr<Event> event = NS_NewDOMEvent(aTarget, nullptr, nullptr); 74 event->InitEvent(aEventType, aCanBubble, Cancelable::eNo); 75 event->SetTrusted(true); 76 DispatchEventOnTarget(aTarget, event, aOnlyChromeDispatch, aComposed); 77 } 78 79 // static 80 void AsyncEventDispatcher::DispatchEventOnTarget( 81 EventTarget* aTarget, Event* aEvent, ChromeOnlyDispatch aOnlyChromeDispatch, 82 Composed aComposed) { 83 if (aComposed != Composed::eDefault) { 84 aEvent->WidgetEventPtr()->mFlags.mComposed = aComposed == Composed::eYes; 85 } 86 if (aOnlyChromeDispatch == ChromeOnlyDispatch::eYes) { 87 MOZ_ASSERT(aEvent->IsTrusted()); 88 aEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true; 89 } 90 aTarget->DispatchEvent(*aEvent); 91 } 92 93 nsresult AsyncEventDispatcher::Cancel() { 94 mCanceled = true; 95 return NS_OK; 96 } 97 98 nsresult AsyncEventDispatcher::PostDOMEvent() { 99 RefPtr<AsyncEventDispatcher> ensureDeletionWhenFailing = this; 100 return NS_DispatchToCurrentThread(ensureDeletionWhenFailing.forget()); 101 } 102 103 void AsyncEventDispatcher::RunDOMEventWhenSafe() { 104 RefPtr<AsyncEventDispatcher> ensureDeletionWhenFailing = this; 105 nsContentUtils::AddScriptRunner(ensureDeletionWhenFailing.forget()); 106 } 107 108 // static 109 void AsyncEventDispatcher::RunDOMEventWhenSafe( 110 EventTarget& aTarget, const nsAString& aEventType, CanBubble aCanBubble, 111 ChromeOnlyDispatch aOnlyChromeDispatch /* = ChromeOnlyDispatch::eNo */, 112 Composed aComposed /* = Composed::eDefault */) { 113 if (nsContentUtils::IsSafeToRunScript()) { 114 OwningNonNull<EventTarget> target = aTarget; 115 DispatchEventOnTarget(target, aEventType, aCanBubble, aOnlyChromeDispatch, 116 aComposed); 117 return; 118 } 119 (new AsyncEventDispatcher(&aTarget, aEventType, aCanBubble, 120 aOnlyChromeDispatch, aComposed)) 121 ->RunDOMEventWhenSafe(); 122 } 123 124 void AsyncEventDispatcher::RunDOMEventWhenSafe( 125 EventTarget& aTarget, Event& aEvent, 126 ChromeOnlyDispatch aOnlyChromeDispatch /* = ChromeOnlyDispatch::eNo */) { 127 if (nsContentUtils::IsSafeToRunScript()) { 128 DispatchEventOnTarget(&aTarget, &aEvent, aOnlyChromeDispatch, 129 Composed::eDefault); 130 return; 131 } 132 (new AsyncEventDispatcher(&aTarget, do_AddRef(&aEvent), aOnlyChromeDispatch)) 133 ->RunDOMEventWhenSafe(); 134 } 135 136 // static 137 nsresult AsyncEventDispatcher::RunDOMEventWhenSafe( 138 nsINode& aTarget, WidgetEvent& aEvent, 139 nsEventStatus* aEventStatus /* = nullptr */) { 140 if (nsContentUtils::IsSafeToRunScript()) { 141 // MOZ_KnownLive due to bug 1832202 142 nsPresContext* presContext = aTarget.OwnerDoc()->GetPresContext(); 143 return EventDispatcher::Dispatch(MOZ_KnownLive(&aTarget), 144 MOZ_KnownLive(presContext), &aEvent, 145 nullptr, aEventStatus); 146 } 147 (new AsyncEventDispatcher(&aTarget, aEvent))->RunDOMEventWhenSafe(); 148 return NS_OK; 149 } 150 151 void AsyncEventDispatcher::RequireNodeInDocument() { 152 MOZ_ASSERT(mTarget); 153 MOZ_ASSERT(mTarget->IsNode()); 154 mCheckStillInDoc = true; 155 } 156 157 } // namespace mozilla