Wed, 31 Dec 2014 06:09:35 +0100
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 |