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"
21 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(DOMEventTargetHelper
)
23 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(DOMEventTargetHelper
)
24 if (MOZ_UNLIKELY(cb
.WantDebugInfo())) {
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
);
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();
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
)
83 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMEventTargetHelper
)
84 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(DOMEventTargetHelper
,
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())) {
126 Document
* DOMEventTargetHelper::GetDocumentIfCurrent() const {
127 nsPIDOMWindowInner
* win
= GetWindowIfCurrent();
132 return win
->GetDoc();
135 bool DOMEventTargetHelper::ComputeDefaultWantsUntrusted(ErrorResult
& aRv
) {
137 nsresult rv
= WantsUntrusted(&wantsUntrusted
);
142 return wantsUntrusted
;
145 bool DOMEventTargetHelper::DispatchEvent(Event
& aEvent
, CallerType aCallerType
,
147 nsEventStatus status
= nsEventStatus_eIgnore
;
148 nsresult rv
= EventDispatcher::DispatchDOMEvent(this, nullptr, &aEvent
,
150 bool retval
= !aEvent
.DefaultPrevented(aCallerType
);
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);
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
) {
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();
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;
238 if (shouldBeKeptAlive
== mIsKeptAlive
) {
242 mIsKeptAlive
= shouldBeKeptAlive
;
250 void DOMEventTargetHelper::MaybeDontKeepAlive() {
252 mIsKeptAlive
= false;
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