dom/events/DOMEventTargetHelper.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsContentUtils.h"
michael@0 7 #include "nsIDocument.h"
michael@0 8 #include "prprf.h"
michael@0 9 #include "nsGlobalWindow.h"
michael@0 10 #include "ScriptSettings.h"
michael@0 11 #include "mozilla/DOMEventTargetHelper.h"
michael@0 12 #include "mozilla/EventDispatcher.h"
michael@0 13 #include "mozilla/EventListenerManager.h"
michael@0 14 #include "mozilla/Likely.h"
michael@0 15
michael@0 16 namespace mozilla {
michael@0 17
michael@0 18 using namespace dom;
michael@0 19
michael@0 20 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMEventTargetHelper)
michael@0 21
michael@0 22 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMEventTargetHelper)
michael@0 23 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
michael@0 24 NS_IMPL_CYCLE_COLLECTION_TRACE_END
michael@0 25
michael@0 26 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(DOMEventTargetHelper)
michael@0 27 if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
michael@0 28 char name[512];
michael@0 29 nsAutoString uri;
michael@0 30 if (tmp->mOwnerWindow && tmp->mOwnerWindow->GetExtantDoc()) {
michael@0 31 tmp->mOwnerWindow->GetExtantDoc()->GetDocumentURI(uri);
michael@0 32 }
michael@0 33 PR_snprintf(name, sizeof(name), "DOMEventTargetHelper %s",
michael@0 34 NS_ConvertUTF16toUTF8(uri).get());
michael@0 35 cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
michael@0 36 } else {
michael@0 37 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(DOMEventTargetHelper, tmp->mRefCnt.get())
michael@0 38 }
michael@0 39
michael@0 40 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
michael@0 41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
michael@0 42 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
michael@0 43
michael@0 44 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMEventTargetHelper)
michael@0 45 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
michael@0 46 NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
michael@0 47 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
michael@0 48
michael@0 49 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(DOMEventTargetHelper)
michael@0 50 if (tmp->IsBlack()) {
michael@0 51 if (tmp->mListenerManager) {
michael@0 52 tmp->mListenerManager->MarkForCC();
michael@0 53 }
michael@0 54 return true;
michael@0 55 }
michael@0 56 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
michael@0 57
michael@0 58 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(DOMEventTargetHelper)
michael@0 59 return tmp->IsBlackAndDoesNotNeedTracing(tmp);
michael@0 60 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
michael@0 61
michael@0 62 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(DOMEventTargetHelper)
michael@0 63 return tmp->IsBlack();
michael@0 64 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
michael@0 65
michael@0 66 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMEventTargetHelper)
michael@0 67 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
michael@0 68 NS_INTERFACE_MAP_ENTRY(nsISupports)
michael@0 69 NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
michael@0 70 NS_INTERFACE_MAP_ENTRY(dom::EventTarget)
michael@0 71 NS_INTERFACE_MAP_ENTRY(DOMEventTargetHelper)
michael@0 72 NS_INTERFACE_MAP_END
michael@0 73
michael@0 74 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMEventTargetHelper)
michael@0 75 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(DOMEventTargetHelper,
michael@0 76 LastRelease())
michael@0 77
michael@0 78 NS_IMPL_DOMTARGET_DEFAULTS(DOMEventTargetHelper)
michael@0 79
michael@0 80 DOMEventTargetHelper::~DOMEventTargetHelper()
michael@0 81 {
michael@0 82 if (nsPIDOMWindow* owner = GetOwner()) {
michael@0 83 static_cast<nsGlobalWindow*>(owner)->RemoveEventTargetObject(this);
michael@0 84 }
michael@0 85 if (mListenerManager) {
michael@0 86 mListenerManager->Disconnect();
michael@0 87 }
michael@0 88 ReleaseWrapper(this);
michael@0 89 }
michael@0 90
michael@0 91 void
michael@0 92 DOMEventTargetHelper::BindToOwner(nsPIDOMWindow* aOwner)
michael@0 93 {
michael@0 94 MOZ_ASSERT(!aOwner || aOwner->IsInnerWindow());
michael@0 95 nsCOMPtr<nsIGlobalObject> glob = do_QueryInterface(aOwner);
michael@0 96 BindToOwner(glob);
michael@0 97 }
michael@0 98
michael@0 99 void
michael@0 100 DOMEventTargetHelper::BindToOwner(nsIGlobalObject* aOwner)
michael@0 101 {
michael@0 102 if (mParentObject) {
michael@0 103 if (mOwnerWindow) {
michael@0 104 static_cast<nsGlobalWindow*>(mOwnerWindow)->RemoveEventTargetObject(this);
michael@0 105 mOwnerWindow = nullptr;
michael@0 106 }
michael@0 107 mParentObject = nullptr;
michael@0 108 mHasOrHasHadOwnerWindow = false;
michael@0 109 }
michael@0 110 if (aOwner) {
michael@0 111 mParentObject = aOwner;
michael@0 112 // Let's cache the result of this QI for fast access and off main thread usage
michael@0 113 mOwnerWindow = nsCOMPtr<nsPIDOMWindow>(do_QueryInterface(aOwner)).get();
michael@0 114 if (mOwnerWindow) {
michael@0 115 mHasOrHasHadOwnerWindow = true;
michael@0 116 static_cast<nsGlobalWindow*>(mOwnerWindow)->AddEventTargetObject(this);
michael@0 117 }
michael@0 118 }
michael@0 119 }
michael@0 120
michael@0 121 void
michael@0 122 DOMEventTargetHelper::BindToOwner(DOMEventTargetHelper* aOther)
michael@0 123 {
michael@0 124 if (mOwnerWindow) {
michael@0 125 static_cast<nsGlobalWindow*>(mOwnerWindow)->RemoveEventTargetObject(this);
michael@0 126 mOwnerWindow = nullptr;
michael@0 127 mParentObject = nullptr;
michael@0 128 mHasOrHasHadOwnerWindow = false;
michael@0 129 }
michael@0 130 if (aOther) {
michael@0 131 mHasOrHasHadOwnerWindow = aOther->HasOrHasHadOwner();
michael@0 132 if (aOther->GetParentObject()) {
michael@0 133 mParentObject = aOther->GetParentObject();
michael@0 134 // Let's cache the result of this QI for fast access and off main thread usage
michael@0 135 mOwnerWindow = nsCOMPtr<nsPIDOMWindow>(do_QueryInterface(mParentObject)).get();
michael@0 136 if (mOwnerWindow) {
michael@0 137 mHasOrHasHadOwnerWindow = true;
michael@0 138 static_cast<nsGlobalWindow*>(mOwnerWindow)->AddEventTargetObject(this);
michael@0 139 }
michael@0 140 }
michael@0 141 }
michael@0 142 }
michael@0 143
michael@0 144 void
michael@0 145 DOMEventTargetHelper::DisconnectFromOwner()
michael@0 146 {
michael@0 147 mOwnerWindow = nullptr;
michael@0 148 mParentObject = nullptr;
michael@0 149 // Event listeners can't be handled anymore, so we can release them here.
michael@0 150 if (mListenerManager) {
michael@0 151 mListenerManager->Disconnect();
michael@0 152 mListenerManager = nullptr;
michael@0 153 }
michael@0 154 }
michael@0 155
michael@0 156 NS_IMETHODIMP
michael@0 157 DOMEventTargetHelper::RemoveEventListener(const nsAString& aType,
michael@0 158 nsIDOMEventListener* aListener,
michael@0 159 bool aUseCapture)
michael@0 160 {
michael@0 161 EventListenerManager* elm = GetExistingListenerManager();
michael@0 162 if (elm) {
michael@0 163 elm->RemoveEventListener(aType, aListener, aUseCapture);
michael@0 164 }
michael@0 165
michael@0 166 return NS_OK;
michael@0 167 }
michael@0 168
michael@0 169 NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(DOMEventTargetHelper)
michael@0 170
michael@0 171 NS_IMETHODIMP
michael@0 172 DOMEventTargetHelper::AddEventListener(const nsAString& aType,
michael@0 173 nsIDOMEventListener* aListener,
michael@0 174 bool aUseCapture,
michael@0 175 bool aWantsUntrusted,
michael@0 176 uint8_t aOptionalArgc)
michael@0 177 {
michael@0 178 NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
michael@0 179 "Won't check if this is chrome, you want to set "
michael@0 180 "aWantsUntrusted to false or make the aWantsUntrusted "
michael@0 181 "explicit by making aOptionalArgc non-zero.");
michael@0 182
michael@0 183 if (aOptionalArgc < 2) {
michael@0 184 nsresult rv = WantsUntrusted(&aWantsUntrusted);
michael@0 185 NS_ENSURE_SUCCESS(rv, rv);
michael@0 186 }
michael@0 187
michael@0 188 EventListenerManager* elm = GetOrCreateListenerManager();
michael@0 189 NS_ENSURE_STATE(elm);
michael@0 190 elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
michael@0 191 return NS_OK;
michael@0 192 }
michael@0 193
michael@0 194 void
michael@0 195 DOMEventTargetHelper::AddEventListener(const nsAString& aType,
michael@0 196 EventListener* aListener,
michael@0 197 bool aUseCapture,
michael@0 198 const Nullable<bool>& aWantsUntrusted,
michael@0 199 ErrorResult& aRv)
michael@0 200 {
michael@0 201 bool wantsUntrusted;
michael@0 202 if (aWantsUntrusted.IsNull()) {
michael@0 203 nsresult rv = WantsUntrusted(&wantsUntrusted);
michael@0 204 if (NS_FAILED(rv)) {
michael@0 205 aRv.Throw(rv);
michael@0 206 return;
michael@0 207 }
michael@0 208 } else {
michael@0 209 wantsUntrusted = aWantsUntrusted.Value();
michael@0 210 }
michael@0 211
michael@0 212 EventListenerManager* elm = GetOrCreateListenerManager();
michael@0 213 if (!elm) {
michael@0 214 aRv.Throw(NS_ERROR_UNEXPECTED);
michael@0 215 return;
michael@0 216 }
michael@0 217 elm->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
michael@0 218 }
michael@0 219
michael@0 220 NS_IMETHODIMP
michael@0 221 DOMEventTargetHelper::AddSystemEventListener(const nsAString& aType,
michael@0 222 nsIDOMEventListener* aListener,
michael@0 223 bool aUseCapture,
michael@0 224 bool aWantsUntrusted,
michael@0 225 uint8_t aOptionalArgc)
michael@0 226 {
michael@0 227 NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
michael@0 228 "Won't check if this is chrome, you want to set "
michael@0 229 "aWantsUntrusted to false or make the aWantsUntrusted "
michael@0 230 "explicit by making aOptionalArgc non-zero.");
michael@0 231
michael@0 232 if (aOptionalArgc < 2) {
michael@0 233 nsresult rv = WantsUntrusted(&aWantsUntrusted);
michael@0 234 NS_ENSURE_SUCCESS(rv, rv);
michael@0 235 }
michael@0 236
michael@0 237 return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
michael@0 238 aWantsUntrusted);
michael@0 239 }
michael@0 240
michael@0 241 NS_IMETHODIMP
michael@0 242 DOMEventTargetHelper::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
michael@0 243 {
michael@0 244 nsEventStatus status = nsEventStatus_eIgnore;
michael@0 245 nsresult rv =
michael@0 246 EventDispatcher::DispatchDOMEvent(this, nullptr, aEvent, nullptr, &status);
michael@0 247
michael@0 248 *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
michael@0 249 return rv;
michael@0 250 }
michael@0 251
michael@0 252 nsresult
michael@0 253 DOMEventTargetHelper::DispatchTrustedEvent(const nsAString& aEventName)
michael@0 254 {
michael@0 255 nsCOMPtr<nsIDOMEvent> event;
michael@0 256 NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
michael@0 257 nsresult rv = event->InitEvent(aEventName, false, false);
michael@0 258 NS_ENSURE_SUCCESS(rv, rv);
michael@0 259
michael@0 260 return DispatchTrustedEvent(event);
michael@0 261 }
michael@0 262
michael@0 263 nsresult
michael@0 264 DOMEventTargetHelper::DispatchTrustedEvent(nsIDOMEvent* event)
michael@0 265 {
michael@0 266 event->SetTrusted(true);
michael@0 267
michael@0 268 bool dummy;
michael@0 269 return DispatchEvent(event, &dummy);
michael@0 270 }
michael@0 271
michael@0 272 nsresult
michael@0 273 DOMEventTargetHelper::SetEventHandler(nsIAtom* aType,
michael@0 274 JSContext* aCx,
michael@0 275 const JS::Value& aValue)
michael@0 276 {
michael@0 277 nsRefPtr<EventHandlerNonNull> handler;
michael@0 278 JS::Rooted<JSObject*> callable(aCx);
michael@0 279 if (aValue.isObject() &&
michael@0 280 JS_ObjectIsCallable(aCx, callable = &aValue.toObject())) {
michael@0 281 handler = new EventHandlerNonNull(callable, dom::GetIncumbentGlobal());
michael@0 282 }
michael@0 283 SetEventHandler(aType, EmptyString(), handler);
michael@0 284 return NS_OK;
michael@0 285 }
michael@0 286
michael@0 287 void
michael@0 288 DOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
michael@0 289 JSContext* aCx,
michael@0 290 JS::Value* aValue)
michael@0 291 {
michael@0 292 EventHandlerNonNull* handler = GetEventHandler(aType, EmptyString());
michael@0 293 if (handler) {
michael@0 294 *aValue = JS::ObjectValue(*handler->Callable());
michael@0 295 } else {
michael@0 296 *aValue = JS::NullValue();
michael@0 297 }
michael@0 298 }
michael@0 299
michael@0 300 nsresult
michael@0 301 DOMEventTargetHelper::PreHandleEvent(EventChainPreVisitor& aVisitor)
michael@0 302 {
michael@0 303 aVisitor.mCanHandle = true;
michael@0 304 aVisitor.mParentTarget = nullptr;
michael@0 305 return NS_OK;
michael@0 306 }
michael@0 307
michael@0 308 nsresult
michael@0 309 DOMEventTargetHelper::PostHandleEvent(EventChainPostVisitor& aVisitor)
michael@0 310 {
michael@0 311 return NS_OK;
michael@0 312 }
michael@0 313
michael@0 314 nsresult
michael@0 315 DOMEventTargetHelper::DispatchDOMEvent(WidgetEvent* aEvent,
michael@0 316 nsIDOMEvent* aDOMEvent,
michael@0 317 nsPresContext* aPresContext,
michael@0 318 nsEventStatus* aEventStatus)
michael@0 319 {
michael@0 320 return EventDispatcher::DispatchDOMEvent(this, aEvent, aDOMEvent,
michael@0 321 aPresContext, aEventStatus);
michael@0 322 }
michael@0 323
michael@0 324 EventListenerManager*
michael@0 325 DOMEventTargetHelper::GetOrCreateListenerManager()
michael@0 326 {
michael@0 327 if (!mListenerManager) {
michael@0 328 mListenerManager = new EventListenerManager(this);
michael@0 329 }
michael@0 330
michael@0 331 return mListenerManager;
michael@0 332 }
michael@0 333
michael@0 334 EventListenerManager*
michael@0 335 DOMEventTargetHelper::GetExistingListenerManager() const
michael@0 336 {
michael@0 337 return mListenerManager;
michael@0 338 }
michael@0 339
michael@0 340 nsIScriptContext*
michael@0 341 DOMEventTargetHelper::GetContextForEventHandlers(nsresult* aRv)
michael@0 342 {
michael@0 343 *aRv = CheckInnerWindowCorrectness();
michael@0 344 if (NS_FAILED(*aRv)) {
michael@0 345 return nullptr;
michael@0 346 }
michael@0 347 nsPIDOMWindow* owner = GetOwner();
michael@0 348 return owner ? static_cast<nsGlobalWindow*>(owner)->GetContextInternal()
michael@0 349 : nullptr;
michael@0 350 }
michael@0 351
michael@0 352 nsresult
michael@0 353 DOMEventTargetHelper::WantsUntrusted(bool* aRetVal)
michael@0 354 {
michael@0 355 nsresult rv;
michael@0 356 nsIScriptContext* context = GetContextForEventHandlers(&rv);
michael@0 357 NS_ENSURE_SUCCESS(rv, rv);
michael@0 358 nsCOMPtr<nsIDocument> doc =
michael@0 359 nsContentUtils::GetDocumentFromScriptContext(context);
michael@0 360 // We can let listeners on workers to always handle all the events.
michael@0 361 *aRetVal = (doc && !nsContentUtils::IsChromeDoc(doc)) || !NS_IsMainThread();
michael@0 362 return rv;
michael@0 363 }
michael@0 364
michael@0 365 void
michael@0 366 DOMEventTargetHelper::EventListenerAdded(nsIAtom* aType)
michael@0 367 {
michael@0 368 ErrorResult rv;
michael@0 369 EventListenerWasAdded(Substring(nsDependentAtomString(aType), 2), rv);
michael@0 370 }
michael@0 371
michael@0 372 void
michael@0 373 DOMEventTargetHelper::EventListenerRemoved(nsIAtom* aType)
michael@0 374 {
michael@0 375 ErrorResult rv;
michael@0 376 EventListenerWasRemoved(Substring(nsDependentAtomString(aType), 2), rv);
michael@0 377 }
michael@0 378
michael@0 379 } // namespace mozilla

mercurial