DOMEventTargetHelper.cpp (8107B)
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/DOMEventTargetHelper.h" 8 9 #include "MainThreadUtils.h" 10 #include "mozilla/EventDispatcher.h" 11 #include "mozilla/EventListenerManager.h" 12 #include "mozilla/Likely.h" 13 #include "mozilla/Sprintf.h" 14 #include "mozilla/dom/Document.h" 15 #include "mozilla/dom/Event.h" 16 #include "nsContentUtils.h" 17 #include "nsGlobalWindowInner.h" 18 19 namespace mozilla { 20 21 using namespace dom; 22 23 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(DOMEventTargetHelper) 24 25 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(DOMEventTargetHelper) 26 if (MOZ_UNLIKELY(cb.WantDebugInfo())) { 27 char name[512]; 28 nsAutoString uri; 29 if (tmp->GetOwnerWindow() && tmp->GetOwnerWindow()->GetExtantDoc()) { 30 (void)tmp->GetOwnerWindow()->GetExtantDoc()->GetDocumentURI(uri); 31 } 32 33 nsXPCOMCycleCollectionParticipant* participant = nullptr; 34 CallQueryInterface(tmp, &participant); 35 36 SprintfLiteral(name, "%s %s", participant->ClassName(), 37 NS_ConvertUTF16toUTF8(uri).get()); 38 cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name); 39 } else { 40 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(DOMEventTargetHelper, tmp->mRefCnt.get()) 41 } 42 43 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager) 44 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 45 46 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMEventTargetHelper) 47 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 48 if (tmp->mListenerManager) { 49 tmp->mListenerManager->Disconnect(); 50 NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager) 51 } 52 tmp->MaybeDontKeepAlive(); 53 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 54 55 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(DOMEventTargetHelper) 56 bool hasLiveWrapper = tmp->HasKnownLiveWrapper(); 57 if (hasLiveWrapper || tmp->IsCertainlyAliveForCC()) { 58 if (tmp->mListenerManager) { 59 tmp->mListenerManager->MarkForCC(); 60 } 61 if (!hasLiveWrapper && tmp->PreservingWrapper()) { 62 tmp->MarkWrapperLive(); 63 } 64 return true; 65 } 66 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END 67 68 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(DOMEventTargetHelper) 69 return tmp->HasKnownLiveWrapperAndDoesNotNeedTracing( 70 static_cast<dom::EventTarget*>(tmp)); 71 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END 72 73 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(DOMEventTargetHelper) 74 return tmp->HasKnownLiveWrapper(); 75 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END 76 77 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMEventTargetHelper) 78 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 79 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget) 80 NS_INTERFACE_MAP_ENTRY(dom::EventTarget) 81 NS_INTERFACE_MAP_ENTRY_CONCRETE(DOMEventTargetHelper) 82 NS_INTERFACE_MAP_END 83 84 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMEventTargetHelper) 85 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(DOMEventTargetHelper, 86 LastRelease()) 87 88 DOMEventTargetHelper::DOMEventTargetHelper() = default; 89 90 DOMEventTargetHelper::DOMEventTargetHelper(nsPIDOMWindowInner* aWindow) 91 : GlobalTeardownObserver(aWindow ? aWindow->AsGlobal() : nullptr) {} 92 93 DOMEventTargetHelper::DOMEventTargetHelper(nsIGlobalObject* aGlobalObject) 94 : GlobalTeardownObserver(aGlobalObject) {} 95 96 DOMEventTargetHelper::DOMEventTargetHelper(DOMEventTargetHelper* aOther) 97 : GlobalTeardownObserver( 98 aOther ? aOther->GetParentObject() : nullptr, 99 aOther ? aOther->HasOrHasHadOwnerWindow() : false) {} 100 101 DOMEventTargetHelper::~DOMEventTargetHelper() { 102 if (mListenerManager) { 103 mListenerManager->Disconnect(); 104 } 105 ReleaseWrapper(this); 106 } 107 108 void DOMEventTargetHelper::DisconnectFromOwner() { 109 GlobalTeardownObserver::DisconnectFromOwner(); 110 111 // Event listeners can't be handled anymore, so we can release them here. 112 if (mListenerManager) { 113 mListenerManager->Disconnect(); 114 mListenerManager = nullptr; 115 } 116 117 MaybeDontKeepAlive(); 118 } 119 120 nsPIDOMWindowOuter* DOMEventTargetHelper::GetOwnerGlobalForBindingsInternal() { 121 return nsPIDOMWindowOuter::GetFromCurrentInner(GetOwnerWindow()); 122 } 123 124 nsPIDOMWindowInner* DOMEventTargetHelper::GetWindowIfCurrent() const { 125 if (NS_FAILED(CheckCurrentGlobalCorrectness())) { 126 return nullptr; 127 } 128 return GetOwnerWindow(); 129 } 130 131 Document* DOMEventTargetHelper::GetDocumentIfCurrent() const { 132 nsPIDOMWindowInner* win = GetWindowIfCurrent(); 133 if (!win) { 134 return nullptr; 135 } 136 137 return win->GetDoc(); 138 } 139 140 bool DOMEventTargetHelper::ComputeDefaultWantsUntrusted(ErrorResult& aRv) { 141 bool wantsUntrusted; 142 nsresult rv = WantsUntrusted(&wantsUntrusted); 143 if (NS_FAILED(rv)) { 144 aRv.Throw(rv); 145 return false; 146 } 147 return wantsUntrusted; 148 } 149 150 bool DOMEventTargetHelper::DispatchEvent(Event& aEvent, CallerType aCallerType, 151 ErrorResult& aRv) { 152 nsEventStatus status = nsEventStatus_eIgnore; 153 nsresult rv = EventDispatcher::DispatchDOMEvent(this, nullptr, &aEvent, 154 nullptr, &status); 155 bool retval = !aEvent.DefaultPrevented(aCallerType); 156 if (NS_FAILED(rv)) { 157 aRv.Throw(rv); 158 } 159 return retval; 160 } 161 162 nsresult DOMEventTargetHelper::DispatchTrustedEvent( 163 const nsAString& aEventName) { 164 RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr); 165 event->InitEvent(aEventName, false, false); 166 167 return DispatchTrustedEvent(event); 168 } 169 170 nsresult DOMEventTargetHelper::DispatchTrustedEvent(Event* event) { 171 event->SetTrusted(true); 172 173 ErrorResult rv; 174 DispatchEvent(*event, rv); 175 return rv.StealNSResult(); 176 } 177 178 void DOMEventTargetHelper::GetEventTargetParent( 179 EventChainPreVisitor& aVisitor) { 180 aVisitor.mCanHandle = true; 181 aVisitor.SetParentTarget(nullptr, false); 182 } 183 184 nsresult DOMEventTargetHelper::PostHandleEvent( 185 EventChainPostVisitor& aVisitor) { 186 return NS_OK; 187 } 188 189 EventListenerManager* DOMEventTargetHelper::GetOrCreateListenerManager() { 190 if (!mListenerManager) { 191 mListenerManager = new EventListenerManager(this); 192 } 193 194 return mListenerManager; 195 } 196 197 EventListenerManager* DOMEventTargetHelper::GetExistingListenerManager() const { 198 return mListenerManager; 199 } 200 201 nsresult DOMEventTargetHelper::WantsUntrusted(bool* aRetVal) { 202 nsresult rv = CheckCurrentGlobalCorrectness(); 203 NS_ENSURE_SUCCESS(rv, rv); 204 205 nsCOMPtr<Document> doc = GetDocumentIfCurrent(); 206 // We can let listeners on workers to always handle all the events. 207 *aRetVal = (doc && !nsContentUtils::IsChromeDoc(doc)) || !NS_IsMainThread(); 208 return rv; 209 } 210 211 void DOMEventTargetHelper::EventListenerAdded(nsAtom* aType) { 212 MaybeUpdateKeepAlive(); 213 } 214 215 void DOMEventTargetHelper::EventListenerRemoved(nsAtom* aType) { 216 MaybeUpdateKeepAlive(); 217 } 218 219 void DOMEventTargetHelper::KeepAliveIfHasListenersFor(nsAtom* aType) { 220 mKeepingAliveTypes.AppendElement(aType); 221 MaybeUpdateKeepAlive(); 222 } 223 224 void DOMEventTargetHelper::IgnoreKeepAliveIfHasListenersFor(nsAtom* aType) { 225 mKeepingAliveTypes.RemoveElement(aType); 226 MaybeUpdateKeepAlive(); 227 } 228 229 void DOMEventTargetHelper::MaybeUpdateKeepAlive() { 230 bool shouldBeKeptAlive = false; 231 232 if (NS_SUCCEEDED(CheckCurrentGlobalCorrectness())) { 233 if (!mKeepingAliveTypes.IsEmpty()) { 234 for (uint32_t i = 0; i < mKeepingAliveTypes.Length(); ++i) { 235 if (HasListenersFor(mKeepingAliveTypes[i])) { 236 shouldBeKeptAlive = true; 237 break; 238 } 239 } 240 } 241 } 242 243 if (shouldBeKeptAlive == mIsKeptAlive) { 244 return; 245 } 246 247 mIsKeptAlive = shouldBeKeptAlive; 248 if (mIsKeptAlive) { 249 AddRef(); 250 } else { 251 Release(); 252 } 253 } 254 255 void DOMEventTargetHelper::MaybeDontKeepAlive() { 256 if (mIsKeptAlive) { 257 mIsKeptAlive = false; 258 Release(); 259 } 260 } 261 262 bool DOMEventTargetHelper::HasListenersFor(const nsAString& aType) const { 263 return mListenerManager && mListenerManager->HasListenersFor(aType); 264 } 265 266 bool DOMEventTargetHelper::HasListenersFor(nsAtom* aTypeWithOn) const { 267 return mListenerManager && mListenerManager->HasListenersFor(aTypeWithOn); 268 } 269 270 } // namespace mozilla