1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/events/DOMEventTargetHelper.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,379 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsContentUtils.h" 1.10 +#include "nsIDocument.h" 1.11 +#include "prprf.h" 1.12 +#include "nsGlobalWindow.h" 1.13 +#include "ScriptSettings.h" 1.14 +#include "mozilla/DOMEventTargetHelper.h" 1.15 +#include "mozilla/EventDispatcher.h" 1.16 +#include "mozilla/EventListenerManager.h" 1.17 +#include "mozilla/Likely.h" 1.18 + 1.19 +namespace mozilla { 1.20 + 1.21 +using namespace dom; 1.22 + 1.23 +NS_IMPL_CYCLE_COLLECTION_CLASS(DOMEventTargetHelper) 1.24 + 1.25 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMEventTargetHelper) 1.26 + NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER 1.27 +NS_IMPL_CYCLE_COLLECTION_TRACE_END 1.28 + 1.29 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(DOMEventTargetHelper) 1.30 + if (MOZ_UNLIKELY(cb.WantDebugInfo())) { 1.31 + char name[512]; 1.32 + nsAutoString uri; 1.33 + if (tmp->mOwnerWindow && tmp->mOwnerWindow->GetExtantDoc()) { 1.34 + tmp->mOwnerWindow->GetExtantDoc()->GetDocumentURI(uri); 1.35 + } 1.36 + PR_snprintf(name, sizeof(name), "DOMEventTargetHelper %s", 1.37 + NS_ConvertUTF16toUTF8(uri).get()); 1.38 + cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name); 1.39 + } else { 1.40 + NS_IMPL_CYCLE_COLLECTION_DESCRIBE(DOMEventTargetHelper, tmp->mRefCnt.get()) 1.41 + } 1.42 + 1.43 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.44 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager) 1.45 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.46 + 1.47 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMEventTargetHelper) 1.48 + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 1.49 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager) 1.50 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.51 + 1.52 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(DOMEventTargetHelper) 1.53 + if (tmp->IsBlack()) { 1.54 + if (tmp->mListenerManager) { 1.55 + tmp->mListenerManager->MarkForCC(); 1.56 + } 1.57 + return true; 1.58 + } 1.59 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END 1.60 + 1.61 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(DOMEventTargetHelper) 1.62 + return tmp->IsBlackAndDoesNotNeedTracing(tmp); 1.63 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END 1.64 + 1.65 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(DOMEventTargetHelper) 1.66 + return tmp->IsBlack(); 1.67 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END 1.68 + 1.69 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMEventTargetHelper) 1.70 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.71 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.72 + NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget) 1.73 + NS_INTERFACE_MAP_ENTRY(dom::EventTarget) 1.74 + NS_INTERFACE_MAP_ENTRY(DOMEventTargetHelper) 1.75 +NS_INTERFACE_MAP_END 1.76 + 1.77 +NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMEventTargetHelper) 1.78 +NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(DOMEventTargetHelper, 1.79 + LastRelease()) 1.80 + 1.81 +NS_IMPL_DOMTARGET_DEFAULTS(DOMEventTargetHelper) 1.82 + 1.83 +DOMEventTargetHelper::~DOMEventTargetHelper() 1.84 +{ 1.85 + if (nsPIDOMWindow* owner = GetOwner()) { 1.86 + static_cast<nsGlobalWindow*>(owner)->RemoveEventTargetObject(this); 1.87 + } 1.88 + if (mListenerManager) { 1.89 + mListenerManager->Disconnect(); 1.90 + } 1.91 + ReleaseWrapper(this); 1.92 +} 1.93 + 1.94 +void 1.95 +DOMEventTargetHelper::BindToOwner(nsPIDOMWindow* aOwner) 1.96 +{ 1.97 + MOZ_ASSERT(!aOwner || aOwner->IsInnerWindow()); 1.98 + nsCOMPtr<nsIGlobalObject> glob = do_QueryInterface(aOwner); 1.99 + BindToOwner(glob); 1.100 +} 1.101 + 1.102 +void 1.103 +DOMEventTargetHelper::BindToOwner(nsIGlobalObject* aOwner) 1.104 +{ 1.105 + if (mParentObject) { 1.106 + if (mOwnerWindow) { 1.107 + static_cast<nsGlobalWindow*>(mOwnerWindow)->RemoveEventTargetObject(this); 1.108 + mOwnerWindow = nullptr; 1.109 + } 1.110 + mParentObject = nullptr; 1.111 + mHasOrHasHadOwnerWindow = false; 1.112 + } 1.113 + if (aOwner) { 1.114 + mParentObject = aOwner; 1.115 + // Let's cache the result of this QI for fast access and off main thread usage 1.116 + mOwnerWindow = nsCOMPtr<nsPIDOMWindow>(do_QueryInterface(aOwner)).get(); 1.117 + if (mOwnerWindow) { 1.118 + mHasOrHasHadOwnerWindow = true; 1.119 + static_cast<nsGlobalWindow*>(mOwnerWindow)->AddEventTargetObject(this); 1.120 + } 1.121 + } 1.122 +} 1.123 + 1.124 +void 1.125 +DOMEventTargetHelper::BindToOwner(DOMEventTargetHelper* aOther) 1.126 +{ 1.127 + if (mOwnerWindow) { 1.128 + static_cast<nsGlobalWindow*>(mOwnerWindow)->RemoveEventTargetObject(this); 1.129 + mOwnerWindow = nullptr; 1.130 + mParentObject = nullptr; 1.131 + mHasOrHasHadOwnerWindow = false; 1.132 + } 1.133 + if (aOther) { 1.134 + mHasOrHasHadOwnerWindow = aOther->HasOrHasHadOwner(); 1.135 + if (aOther->GetParentObject()) { 1.136 + mParentObject = aOther->GetParentObject(); 1.137 + // Let's cache the result of this QI for fast access and off main thread usage 1.138 + mOwnerWindow = nsCOMPtr<nsPIDOMWindow>(do_QueryInterface(mParentObject)).get(); 1.139 + if (mOwnerWindow) { 1.140 + mHasOrHasHadOwnerWindow = true; 1.141 + static_cast<nsGlobalWindow*>(mOwnerWindow)->AddEventTargetObject(this); 1.142 + } 1.143 + } 1.144 + } 1.145 +} 1.146 + 1.147 +void 1.148 +DOMEventTargetHelper::DisconnectFromOwner() 1.149 +{ 1.150 + mOwnerWindow = nullptr; 1.151 + mParentObject = nullptr; 1.152 + // Event listeners can't be handled anymore, so we can release them here. 1.153 + if (mListenerManager) { 1.154 + mListenerManager->Disconnect(); 1.155 + mListenerManager = nullptr; 1.156 + } 1.157 +} 1.158 + 1.159 +NS_IMETHODIMP 1.160 +DOMEventTargetHelper::RemoveEventListener(const nsAString& aType, 1.161 + nsIDOMEventListener* aListener, 1.162 + bool aUseCapture) 1.163 +{ 1.164 + EventListenerManager* elm = GetExistingListenerManager(); 1.165 + if (elm) { 1.166 + elm->RemoveEventListener(aType, aListener, aUseCapture); 1.167 + } 1.168 + 1.169 + return NS_OK; 1.170 +} 1.171 + 1.172 +NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(DOMEventTargetHelper) 1.173 + 1.174 +NS_IMETHODIMP 1.175 +DOMEventTargetHelper::AddEventListener(const nsAString& aType, 1.176 + nsIDOMEventListener* aListener, 1.177 + bool aUseCapture, 1.178 + bool aWantsUntrusted, 1.179 + uint8_t aOptionalArgc) 1.180 +{ 1.181 + NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1, 1.182 + "Won't check if this is chrome, you want to set " 1.183 + "aWantsUntrusted to false or make the aWantsUntrusted " 1.184 + "explicit by making aOptionalArgc non-zero."); 1.185 + 1.186 + if (aOptionalArgc < 2) { 1.187 + nsresult rv = WantsUntrusted(&aWantsUntrusted); 1.188 + NS_ENSURE_SUCCESS(rv, rv); 1.189 + } 1.190 + 1.191 + EventListenerManager* elm = GetOrCreateListenerManager(); 1.192 + NS_ENSURE_STATE(elm); 1.193 + elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted); 1.194 + return NS_OK; 1.195 +} 1.196 + 1.197 +void 1.198 +DOMEventTargetHelper::AddEventListener(const nsAString& aType, 1.199 + EventListener* aListener, 1.200 + bool aUseCapture, 1.201 + const Nullable<bool>& aWantsUntrusted, 1.202 + ErrorResult& aRv) 1.203 +{ 1.204 + bool wantsUntrusted; 1.205 + if (aWantsUntrusted.IsNull()) { 1.206 + nsresult rv = WantsUntrusted(&wantsUntrusted); 1.207 + if (NS_FAILED(rv)) { 1.208 + aRv.Throw(rv); 1.209 + return; 1.210 + } 1.211 + } else { 1.212 + wantsUntrusted = aWantsUntrusted.Value(); 1.213 + } 1.214 + 1.215 + EventListenerManager* elm = GetOrCreateListenerManager(); 1.216 + if (!elm) { 1.217 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.218 + return; 1.219 + } 1.220 + elm->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted); 1.221 +} 1.222 + 1.223 +NS_IMETHODIMP 1.224 +DOMEventTargetHelper::AddSystemEventListener(const nsAString& aType, 1.225 + nsIDOMEventListener* aListener, 1.226 + bool aUseCapture, 1.227 + bool aWantsUntrusted, 1.228 + uint8_t aOptionalArgc) 1.229 +{ 1.230 + NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1, 1.231 + "Won't check if this is chrome, you want to set " 1.232 + "aWantsUntrusted to false or make the aWantsUntrusted " 1.233 + "explicit by making aOptionalArgc non-zero."); 1.234 + 1.235 + if (aOptionalArgc < 2) { 1.236 + nsresult rv = WantsUntrusted(&aWantsUntrusted); 1.237 + NS_ENSURE_SUCCESS(rv, rv); 1.238 + } 1.239 + 1.240 + return NS_AddSystemEventListener(this, aType, aListener, aUseCapture, 1.241 + aWantsUntrusted); 1.242 +} 1.243 + 1.244 +NS_IMETHODIMP 1.245 +DOMEventTargetHelper::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal) 1.246 +{ 1.247 + nsEventStatus status = nsEventStatus_eIgnore; 1.248 + nsresult rv = 1.249 + EventDispatcher::DispatchDOMEvent(this, nullptr, aEvent, nullptr, &status); 1.250 + 1.251 + *aRetVal = (status != nsEventStatus_eConsumeNoDefault); 1.252 + return rv; 1.253 +} 1.254 + 1.255 +nsresult 1.256 +DOMEventTargetHelper::DispatchTrustedEvent(const nsAString& aEventName) 1.257 +{ 1.258 + nsCOMPtr<nsIDOMEvent> event; 1.259 + NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr); 1.260 + nsresult rv = event->InitEvent(aEventName, false, false); 1.261 + NS_ENSURE_SUCCESS(rv, rv); 1.262 + 1.263 + return DispatchTrustedEvent(event); 1.264 +} 1.265 + 1.266 +nsresult 1.267 +DOMEventTargetHelper::DispatchTrustedEvent(nsIDOMEvent* event) 1.268 +{ 1.269 + event->SetTrusted(true); 1.270 + 1.271 + bool dummy; 1.272 + return DispatchEvent(event, &dummy); 1.273 +} 1.274 + 1.275 +nsresult 1.276 +DOMEventTargetHelper::SetEventHandler(nsIAtom* aType, 1.277 + JSContext* aCx, 1.278 + const JS::Value& aValue) 1.279 +{ 1.280 + nsRefPtr<EventHandlerNonNull> handler; 1.281 + JS::Rooted<JSObject*> callable(aCx); 1.282 + if (aValue.isObject() && 1.283 + JS_ObjectIsCallable(aCx, callable = &aValue.toObject())) { 1.284 + handler = new EventHandlerNonNull(callable, dom::GetIncumbentGlobal()); 1.285 + } 1.286 + SetEventHandler(aType, EmptyString(), handler); 1.287 + return NS_OK; 1.288 +} 1.289 + 1.290 +void 1.291 +DOMEventTargetHelper::GetEventHandler(nsIAtom* aType, 1.292 + JSContext* aCx, 1.293 + JS::Value* aValue) 1.294 +{ 1.295 + EventHandlerNonNull* handler = GetEventHandler(aType, EmptyString()); 1.296 + if (handler) { 1.297 + *aValue = JS::ObjectValue(*handler->Callable()); 1.298 + } else { 1.299 + *aValue = JS::NullValue(); 1.300 + } 1.301 +} 1.302 + 1.303 +nsresult 1.304 +DOMEventTargetHelper::PreHandleEvent(EventChainPreVisitor& aVisitor) 1.305 +{ 1.306 + aVisitor.mCanHandle = true; 1.307 + aVisitor.mParentTarget = nullptr; 1.308 + return NS_OK; 1.309 +} 1.310 + 1.311 +nsresult 1.312 +DOMEventTargetHelper::PostHandleEvent(EventChainPostVisitor& aVisitor) 1.313 +{ 1.314 + return NS_OK; 1.315 +} 1.316 + 1.317 +nsresult 1.318 +DOMEventTargetHelper::DispatchDOMEvent(WidgetEvent* aEvent, 1.319 + nsIDOMEvent* aDOMEvent, 1.320 + nsPresContext* aPresContext, 1.321 + nsEventStatus* aEventStatus) 1.322 +{ 1.323 + return EventDispatcher::DispatchDOMEvent(this, aEvent, aDOMEvent, 1.324 + aPresContext, aEventStatus); 1.325 +} 1.326 + 1.327 +EventListenerManager* 1.328 +DOMEventTargetHelper::GetOrCreateListenerManager() 1.329 +{ 1.330 + if (!mListenerManager) { 1.331 + mListenerManager = new EventListenerManager(this); 1.332 + } 1.333 + 1.334 + return mListenerManager; 1.335 +} 1.336 + 1.337 +EventListenerManager* 1.338 +DOMEventTargetHelper::GetExistingListenerManager() const 1.339 +{ 1.340 + return mListenerManager; 1.341 +} 1.342 + 1.343 +nsIScriptContext* 1.344 +DOMEventTargetHelper::GetContextForEventHandlers(nsresult* aRv) 1.345 +{ 1.346 + *aRv = CheckInnerWindowCorrectness(); 1.347 + if (NS_FAILED(*aRv)) { 1.348 + return nullptr; 1.349 + } 1.350 + nsPIDOMWindow* owner = GetOwner(); 1.351 + return owner ? static_cast<nsGlobalWindow*>(owner)->GetContextInternal() 1.352 + : nullptr; 1.353 +} 1.354 + 1.355 +nsresult 1.356 +DOMEventTargetHelper::WantsUntrusted(bool* aRetVal) 1.357 +{ 1.358 + nsresult rv; 1.359 + nsIScriptContext* context = GetContextForEventHandlers(&rv); 1.360 + NS_ENSURE_SUCCESS(rv, rv); 1.361 + nsCOMPtr<nsIDocument> doc = 1.362 + nsContentUtils::GetDocumentFromScriptContext(context); 1.363 + // We can let listeners on workers to always handle all the events. 1.364 + *aRetVal = (doc && !nsContentUtils::IsChromeDoc(doc)) || !NS_IsMainThread(); 1.365 + return rv; 1.366 +} 1.367 + 1.368 +void 1.369 +DOMEventTargetHelper::EventListenerAdded(nsIAtom* aType) 1.370 +{ 1.371 + ErrorResult rv; 1.372 + EventListenerWasAdded(Substring(nsDependentAtomString(aType), 2), rv); 1.373 +} 1.374 + 1.375 +void 1.376 +DOMEventTargetHelper::EventListenerRemoved(nsIAtom* aType) 1.377 +{ 1.378 + ErrorResult rv; 1.379 + EventListenerWasRemoved(Substring(nsDependentAtomString(aType), 2), rv); 1.380 +} 1.381 + 1.382 +} // namespace mozilla