Bug 1880216 - Migrate Fenix docs into Sphinx. r=owlish,geckoview-reviewers,android...
[gecko.git] / dom / events / DOMEventTargetHelper.cpp
blob2604a5a47b4a2685cf388fb024b62cadde81a498
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 "nsContentUtils.h"
8 #include "mozilla/dom/Document.h"
9 #include "mozilla/Sprintf.h"
10 #include "mozilla/dom/Event.h"
11 #include "mozilla/DOMEventTargetHelper.h"
12 #include "mozilla/EventDispatcher.h"
13 #include "mozilla/EventListenerManager.h"
14 #include "mozilla/Likely.h"
15 #include "MainThreadUtils.h"
17 namespace mozilla {
19 using namespace dom;
21 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(DOMEventTargetHelper)
23 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(DOMEventTargetHelper)
24 if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
25 char name[512];
26 nsAutoString uri;
27 if (tmp->GetOwner() && tmp->GetOwner()->GetExtantDoc()) {
28 Unused << tmp->GetOwner()->GetExtantDoc()->GetDocumentURI(uri);
31 nsXPCOMCycleCollectionParticipant* participant = nullptr;
32 CallQueryInterface(tmp, &participant);
34 SprintfLiteral(name, "%s %s", participant->ClassName(),
35 NS_ConvertUTF16toUTF8(uri).get());
36 cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
37 } else {
38 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(DOMEventTargetHelper, tmp->mRefCnt.get())
41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
42 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
44 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMEventTargetHelper)
45 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
46 if (tmp->mListenerManager) {
47 tmp->mListenerManager->Disconnect();
48 NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
50 tmp->MaybeDontKeepAlive();
51 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
53 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(DOMEventTargetHelper)
54 bool hasLiveWrapper = tmp->HasKnownLiveWrapper();
55 if (hasLiveWrapper || tmp->IsCertainlyAliveForCC()) {
56 if (tmp->mListenerManager) {
57 tmp->mListenerManager->MarkForCC();
59 if (!hasLiveWrapper && tmp->PreservingWrapper()) {
60 tmp->MarkWrapperLive();
62 return true;
64 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
66 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(DOMEventTargetHelper)
67 return tmp->HasKnownLiveWrapperAndDoesNotNeedTracing(
68 static_cast<dom::EventTarget*>(tmp));
69 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
71 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(DOMEventTargetHelper)
72 return tmp->HasKnownLiveWrapper();
73 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
75 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMEventTargetHelper)
76 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
77 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)
78 NS_INTERFACE_MAP_ENTRY(GlobalTeardownObserver)
79 NS_INTERFACE_MAP_ENTRY(dom::EventTarget)
80 NS_INTERFACE_MAP_ENTRY_CONCRETE(DOMEventTargetHelper)
81 NS_INTERFACE_MAP_END
83 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMEventTargetHelper)
84 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(DOMEventTargetHelper,
85 LastRelease())
87 DOMEventTargetHelper::DOMEventTargetHelper() = default;
89 DOMEventTargetHelper::DOMEventTargetHelper(nsPIDOMWindowInner* aWindow)
90 : GlobalTeardownObserver(aWindow ? aWindow->AsGlobal() : nullptr) {}
92 DOMEventTargetHelper::DOMEventTargetHelper(nsIGlobalObject* aGlobalObject)
93 : GlobalTeardownObserver(aGlobalObject) {}
95 DOMEventTargetHelper::DOMEventTargetHelper(DOMEventTargetHelper* aOther)
96 : GlobalTeardownObserver(aOther ? aOther->GetParentObject() : nullptr,
97 aOther ? aOther->HasOrHasHadOwner() : false) {}
99 DOMEventTargetHelper::~DOMEventTargetHelper() {
100 if (mListenerManager) {
101 mListenerManager->Disconnect();
103 ReleaseWrapper(this);
106 void DOMEventTargetHelper::DisconnectFromOwner() {
107 GlobalTeardownObserver::DisconnectFromOwner();
109 // Event listeners can't be handled anymore, so we can release them here.
110 if (mListenerManager) {
111 mListenerManager->Disconnect();
112 mListenerManager = nullptr;
115 MaybeDontKeepAlive();
118 nsPIDOMWindowInner* DOMEventTargetHelper::GetWindowIfCurrent() const {
119 if (NS_FAILED(CheckCurrentGlobalCorrectness())) {
120 return nullptr;
123 return GetOwner();
126 Document* DOMEventTargetHelper::GetDocumentIfCurrent() const {
127 nsPIDOMWindowInner* win = GetWindowIfCurrent();
128 if (!win) {
129 return nullptr;
132 return win->GetDoc();
135 bool DOMEventTargetHelper::ComputeDefaultWantsUntrusted(ErrorResult& aRv) {
136 bool wantsUntrusted;
137 nsresult rv = WantsUntrusted(&wantsUntrusted);
138 if (NS_FAILED(rv)) {
139 aRv.Throw(rv);
140 return false;
142 return wantsUntrusted;
145 bool DOMEventTargetHelper::DispatchEvent(Event& aEvent, CallerType aCallerType,
146 ErrorResult& aRv) {
147 nsEventStatus status = nsEventStatus_eIgnore;
148 nsresult rv = EventDispatcher::DispatchDOMEvent(this, nullptr, &aEvent,
149 nullptr, &status);
150 bool retval = !aEvent.DefaultPrevented(aCallerType);
151 if (NS_FAILED(rv)) {
152 aRv.Throw(rv);
154 return retval;
157 nsresult DOMEventTargetHelper::DispatchTrustedEvent(
158 const nsAString& aEventName) {
159 RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
160 event->InitEvent(aEventName, false, false);
162 return DispatchTrustedEvent(event);
165 nsresult DOMEventTargetHelper::DispatchTrustedEvent(Event* event) {
166 event->SetTrusted(true);
168 ErrorResult rv;
169 DispatchEvent(*event, rv);
170 return rv.StealNSResult();
173 void DOMEventTargetHelper::GetEventTargetParent(
174 EventChainPreVisitor& aVisitor) {
175 aVisitor.mCanHandle = true;
176 aVisitor.SetParentTarget(nullptr, false);
179 nsresult DOMEventTargetHelper::PostHandleEvent(
180 EventChainPostVisitor& aVisitor) {
181 return NS_OK;
184 EventListenerManager* DOMEventTargetHelper::GetOrCreateListenerManager() {
185 if (!mListenerManager) {
186 mListenerManager = new EventListenerManager(this);
189 return mListenerManager;
192 EventListenerManager* DOMEventTargetHelper::GetExistingListenerManager() const {
193 return mListenerManager;
196 nsresult DOMEventTargetHelper::WantsUntrusted(bool* aRetVal) {
197 nsresult rv = CheckCurrentGlobalCorrectness();
198 NS_ENSURE_SUCCESS(rv, rv);
200 nsCOMPtr<Document> doc = GetDocumentIfCurrent();
201 // We can let listeners on workers to always handle all the events.
202 *aRetVal = (doc && !nsContentUtils::IsChromeDoc(doc)) || !NS_IsMainThread();
203 return rv;
206 void DOMEventTargetHelper::EventListenerAdded(nsAtom* aType) {
207 MaybeUpdateKeepAlive();
210 void DOMEventTargetHelper::EventListenerRemoved(nsAtom* aType) {
211 MaybeUpdateKeepAlive();
214 void DOMEventTargetHelper::KeepAliveIfHasListenersFor(nsAtom* aType) {
215 mKeepingAliveTypes.AppendElement(aType);
216 MaybeUpdateKeepAlive();
219 void DOMEventTargetHelper::IgnoreKeepAliveIfHasListenersFor(nsAtom* aType) {
220 mKeepingAliveTypes.RemoveElement(aType);
221 MaybeUpdateKeepAlive();
224 void DOMEventTargetHelper::MaybeUpdateKeepAlive() {
225 bool shouldBeKeptAlive = false;
227 if (NS_SUCCEEDED(CheckCurrentGlobalCorrectness())) {
228 if (!mKeepingAliveTypes.IsEmpty()) {
229 for (uint32_t i = 0; i < mKeepingAliveTypes.Length(); ++i) {
230 if (HasListenersFor(mKeepingAliveTypes[i])) {
231 shouldBeKeptAlive = true;
232 break;
238 if (shouldBeKeptAlive == mIsKeptAlive) {
239 return;
242 mIsKeptAlive = shouldBeKeptAlive;
243 if (mIsKeptAlive) {
244 AddRef();
245 } else {
246 Release();
250 void DOMEventTargetHelper::MaybeDontKeepAlive() {
251 if (mIsKeptAlive) {
252 mIsKeptAlive = false;
253 Release();
257 bool DOMEventTargetHelper::HasListenersFor(const nsAString& aType) const {
258 return mListenerManager && mListenerManager->HasListenersFor(aType);
261 bool DOMEventTargetHelper::HasListenersFor(nsAtom* aTypeWithOn) const {
262 return mListenerManager && mListenerManager->HasListenersFor(aTypeWithOn);
265 } // namespace mozilla