1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/events/EventDispatcher.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,844 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsPresContext.h" 1.11 +#include "nsContentUtils.h" 1.12 +#include "nsError.h" 1.13 +#include <new> 1.14 +#include "nsIContent.h" 1.15 +#include "nsIDocument.h" 1.16 +#include "nsINode.h" 1.17 +#include "nsPIDOMWindow.h" 1.18 +#include "GeckoProfiler.h" 1.19 +#include "GeneratedEvents.h" 1.20 +#include "mozilla/ContentEvents.h" 1.21 +#include "mozilla/dom/EventTarget.h" 1.22 +#include "mozilla/dom/TouchEvent.h" 1.23 +#include "mozilla/EventDispatcher.h" 1.24 +#include "mozilla/EventListenerManager.h" 1.25 +#include "mozilla/InternalMutationEvent.h" 1.26 +#include "mozilla/MiscEvents.h" 1.27 +#include "mozilla/MouseEvents.h" 1.28 +#include "mozilla/TextEvents.h" 1.29 +#include "mozilla/TouchEvents.h" 1.30 +#include "mozilla/unused.h" 1.31 + 1.32 +namespace mozilla { 1.33 + 1.34 +using namespace dom; 1.35 + 1.36 +class ELMCreationDetector 1.37 +{ 1.38 +public: 1.39 + ELMCreationDetector() 1.40 + // We can do this optimization only in the main thread. 1.41 + : mNonMainThread(!NS_IsMainThread()) 1.42 + , mInitialCount(mNonMainThread ? 1.43 + 0 : EventListenerManager::sMainThreadCreatedCount) 1.44 + { 1.45 + } 1.46 + 1.47 + bool MayHaveNewListenerManager() 1.48 + { 1.49 + return mNonMainThread || 1.50 + mInitialCount != EventListenerManager::sMainThreadCreatedCount; 1.51 + } 1.52 + 1.53 + bool IsMainThread() 1.54 + { 1.55 + return !mNonMainThread; 1.56 + } 1.57 + 1.58 +private: 1.59 + bool mNonMainThread; 1.60 + uint32_t mInitialCount; 1.61 +}; 1.62 + 1.63 +#define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0) 1.64 +#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1) 1.65 +#define NS_TARGET_CHAIN_MAY_HAVE_MANAGER (1 << 2) 1.66 + 1.67 +// EventTargetChainItem represents a single item in the event target chain. 1.68 +class EventTargetChainItem 1.69 +{ 1.70 +private: 1.71 + EventTargetChainItem(EventTarget* aTarget); 1.72 +public: 1.73 + EventTargetChainItem() 1.74 + : mFlags(0) 1.75 + , mItemFlags(0) 1.76 + { 1.77 + } 1.78 + 1.79 + static EventTargetChainItem* Create(nsTArray<EventTargetChainItem>& aChain, 1.80 + EventTarget* aTarget, 1.81 + EventTargetChainItem* aChild = nullptr) 1.82 + { 1.83 + MOZ_ASSERT(!aChild || &aChain.ElementAt(aChain.Length() - 1) == aChild); 1.84 + return new (aChain.AppendElement()) EventTargetChainItem(aTarget); 1.85 + } 1.86 + 1.87 + static void DestroyLast(nsTArray<EventTargetChainItem>& aChain, 1.88 + EventTargetChainItem* aItem) 1.89 + { 1.90 + uint32_t lastIndex = aChain.Length() - 1; 1.91 + MOZ_ASSERT(&aChain[lastIndex] == aItem); 1.92 + aChain.RemoveElementAt(lastIndex); 1.93 + } 1.94 + 1.95 + bool IsValid() 1.96 + { 1.97 + NS_WARN_IF_FALSE(!!(mTarget), "Event target is not valid!"); 1.98 + return !!(mTarget); 1.99 + } 1.100 + 1.101 + EventTarget* GetNewTarget() 1.102 + { 1.103 + return mNewTarget; 1.104 + } 1.105 + 1.106 + void SetNewTarget(EventTarget* aNewTarget) 1.107 + { 1.108 + mNewTarget = aNewTarget; 1.109 + } 1.110 + 1.111 + void SetForceContentDispatch(bool aForce) 1.112 + { 1.113 + if (aForce) { 1.114 + mFlags |= NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH; 1.115 + } else { 1.116 + mFlags &= ~NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH; 1.117 + } 1.118 + } 1.119 + 1.120 + bool ForceContentDispatch() 1.121 + { 1.122 + return !!(mFlags & NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH); 1.123 + } 1.124 + 1.125 + void SetWantsWillHandleEvent(bool aWants) 1.126 + { 1.127 + if (aWants) { 1.128 + mFlags |= NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT; 1.129 + } else { 1.130 + mFlags &= ~NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT; 1.131 + } 1.132 + } 1.133 + 1.134 + bool WantsWillHandleEvent() 1.135 + { 1.136 + return !!(mFlags & NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT); 1.137 + } 1.138 + 1.139 + void SetMayHaveListenerManager(bool aMayHave) 1.140 + { 1.141 + if (aMayHave) { 1.142 + mFlags |= NS_TARGET_CHAIN_MAY_HAVE_MANAGER; 1.143 + } else { 1.144 + mFlags &= ~NS_TARGET_CHAIN_MAY_HAVE_MANAGER; 1.145 + } 1.146 + } 1.147 + 1.148 + bool MayHaveListenerManager() 1.149 + { 1.150 + return !!(mFlags & NS_TARGET_CHAIN_MAY_HAVE_MANAGER); 1.151 + } 1.152 + 1.153 + EventTarget* CurrentTarget() 1.154 + { 1.155 + return mTarget; 1.156 + } 1.157 + 1.158 + /** 1.159 + * Dispatches event through the event target chain. 1.160 + * Handles capture, target and bubble phases both in default 1.161 + * and system event group and calls also PostHandleEvent for each 1.162 + * item in the chain. 1.163 + */ 1.164 + static void HandleEventTargetChain(nsTArray<EventTargetChainItem>& aChain, 1.165 + EventChainPostVisitor& aVisitor, 1.166 + EventDispatchingCallback* aCallback, 1.167 + ELMCreationDetector& aCd); 1.168 + 1.169 + /** 1.170 + * Resets aVisitor object and calls PreHandleEvent. 1.171 + * Copies mItemFlags and mItemData to the current EventTargetChainItem. 1.172 + */ 1.173 + void PreHandleEvent(EventChainPreVisitor& aVisitor); 1.174 + 1.175 + /** 1.176 + * If the current item in the event target chain has an event listener 1.177 + * manager, this method calls EventListenerManager::HandleEvent(). 1.178 + */ 1.179 + void HandleEvent(EventChainPostVisitor& aVisitor, 1.180 + ELMCreationDetector& aCd) 1.181 + { 1.182 + if (WantsWillHandleEvent()) { 1.183 + mTarget->WillHandleEvent(aVisitor); 1.184 + } 1.185 + if (aVisitor.mEvent->mFlags.mPropagationStopped) { 1.186 + return; 1.187 + } 1.188 + if (!mManager) { 1.189 + if (!MayHaveListenerManager() && !aCd.MayHaveNewListenerManager()) { 1.190 + return; 1.191 + } 1.192 + mManager = mTarget->GetExistingListenerManager(); 1.193 + } 1.194 + if (mManager) { 1.195 + NS_ASSERTION(aVisitor.mEvent->currentTarget == nullptr, 1.196 + "CurrentTarget should be null!"); 1.197 + mManager->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent, 1.198 + &aVisitor.mDOMEvent, 1.199 + CurrentTarget(), 1.200 + &aVisitor.mEventStatus); 1.201 + NS_ASSERTION(aVisitor.mEvent->currentTarget == nullptr, 1.202 + "CurrentTarget should be null!"); 1.203 + } 1.204 + } 1.205 + 1.206 + /** 1.207 + * Copies mItemFlags and mItemData to aVisitor and calls PostHandleEvent. 1.208 + */ 1.209 + void PostHandleEvent(EventChainPostVisitor& aVisitor); 1.210 + 1.211 + nsCOMPtr<EventTarget> mTarget; 1.212 + uint16_t mFlags; 1.213 + uint16_t mItemFlags; 1.214 + nsCOMPtr<nsISupports> mItemData; 1.215 + // Event retargeting must happen whenever mNewTarget is non-null. 1.216 + nsCOMPtr<EventTarget> mNewTarget; 1.217 + // Cache mTarget's event listener manager. 1.218 + nsRefPtr<EventListenerManager> mManager; 1.219 +}; 1.220 + 1.221 +EventTargetChainItem::EventTargetChainItem(EventTarget* aTarget) 1.222 + : mTarget(aTarget) 1.223 + , mFlags(0) 1.224 + , mItemFlags(0) 1.225 +{ 1.226 + MOZ_ASSERT(!aTarget || mTarget == aTarget->GetTargetForEventTargetChain()); 1.227 +} 1.228 + 1.229 +void 1.230 +EventTargetChainItem::PreHandleEvent(EventChainPreVisitor& aVisitor) 1.231 +{ 1.232 + aVisitor.Reset(); 1.233 + unused << mTarget->PreHandleEvent(aVisitor); 1.234 + SetForceContentDispatch(aVisitor.mForceContentDispatch); 1.235 + SetWantsWillHandleEvent(aVisitor.mWantsWillHandleEvent); 1.236 + SetMayHaveListenerManager(aVisitor.mMayHaveListenerManager); 1.237 + mItemFlags = aVisitor.mItemFlags; 1.238 + mItemData = aVisitor.mItemData; 1.239 +} 1.240 + 1.241 +void 1.242 +EventTargetChainItem::PostHandleEvent(EventChainPostVisitor& aVisitor) 1.243 +{ 1.244 + aVisitor.mItemFlags = mItemFlags; 1.245 + aVisitor.mItemData = mItemData; 1.246 + mTarget->PostHandleEvent(aVisitor); 1.247 +} 1.248 + 1.249 +void 1.250 +EventTargetChainItem::HandleEventTargetChain( 1.251 + nsTArray<EventTargetChainItem>& aChain, 1.252 + EventChainPostVisitor& aVisitor, 1.253 + EventDispatchingCallback* aCallback, 1.254 + ELMCreationDetector& aCd) 1.255 +{ 1.256 + // Save the target so that it can be restored later. 1.257 + nsCOMPtr<EventTarget> firstTarget = aVisitor.mEvent->target; 1.258 + uint32_t chainLength = aChain.Length(); 1.259 + 1.260 + // Capture 1.261 + aVisitor.mEvent->mFlags.mInCapturePhase = true; 1.262 + aVisitor.mEvent->mFlags.mInBubblingPhase = false; 1.263 + for (uint32_t i = chainLength - 1; i > 0; --i) { 1.264 + EventTargetChainItem& item = aChain[i]; 1.265 + if ((!aVisitor.mEvent->mFlags.mNoContentDispatch || 1.266 + item.ForceContentDispatch()) && 1.267 + !aVisitor.mEvent->mFlags.mPropagationStopped) { 1.268 + item.HandleEvent(aVisitor, aCd); 1.269 + } 1.270 + 1.271 + if (item.GetNewTarget()) { 1.272 + // item is at anonymous boundary. Need to retarget for the child items. 1.273 + for (uint32_t j = i; j > 0; --j) { 1.274 + uint32_t childIndex = j - 1; 1.275 + EventTarget* newTarget = aChain[childIndex].GetNewTarget(); 1.276 + if (newTarget) { 1.277 + aVisitor.mEvent->target = newTarget; 1.278 + break; 1.279 + } 1.280 + } 1.281 + } 1.282 + } 1.283 + 1.284 + // Target 1.285 + aVisitor.mEvent->mFlags.mInBubblingPhase = true; 1.286 + EventTargetChainItem& targetItem = aChain[0]; 1.287 + if (!aVisitor.mEvent->mFlags.mPropagationStopped && 1.288 + (!aVisitor.mEvent->mFlags.mNoContentDispatch || 1.289 + targetItem.ForceContentDispatch())) { 1.290 + targetItem.HandleEvent(aVisitor, aCd); 1.291 + } 1.292 + if (aVisitor.mEvent->mFlags.mInSystemGroup) { 1.293 + targetItem.PostHandleEvent(aVisitor); 1.294 + } 1.295 + 1.296 + // Bubble 1.297 + aVisitor.mEvent->mFlags.mInCapturePhase = false; 1.298 + for (uint32_t i = 1; i < chainLength; ++i) { 1.299 + EventTargetChainItem& item = aChain[i]; 1.300 + EventTarget* newTarget = item.GetNewTarget(); 1.301 + if (newTarget) { 1.302 + // Item is at anonymous boundary. Need to retarget for the current item 1.303 + // and for parent items. 1.304 + aVisitor.mEvent->target = newTarget; 1.305 + } 1.306 + 1.307 + if (aVisitor.mEvent->mFlags.mBubbles || newTarget) { 1.308 + if ((!aVisitor.mEvent->mFlags.mNoContentDispatch || 1.309 + item.ForceContentDispatch()) && 1.310 + !aVisitor.mEvent->mFlags.mPropagationStopped) { 1.311 + item.HandleEvent(aVisitor, aCd); 1.312 + } 1.313 + if (aVisitor.mEvent->mFlags.mInSystemGroup) { 1.314 + item.PostHandleEvent(aVisitor); 1.315 + } 1.316 + } 1.317 + } 1.318 + aVisitor.mEvent->mFlags.mInBubblingPhase = false; 1.319 + 1.320 + if (!aVisitor.mEvent->mFlags.mInSystemGroup) { 1.321 + // Dispatch to the system event group. Make sure to clear the 1.322 + // STOP_DISPATCH flag since this resets for each event group. 1.323 + aVisitor.mEvent->mFlags.mPropagationStopped = false; 1.324 + aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false; 1.325 + 1.326 + // Setting back the original target of the event. 1.327 + aVisitor.mEvent->target = aVisitor.mEvent->originalTarget; 1.328 + 1.329 + // Special handling if PresShell (or some other caller) 1.330 + // used a callback object. 1.331 + if (aCallback) { 1.332 + aCallback->HandleEvent(aVisitor); 1.333 + } 1.334 + 1.335 + // Retarget for system event group (which does the default handling too). 1.336 + // Setting back the target which was used also for default event group. 1.337 + aVisitor.mEvent->target = firstTarget; 1.338 + aVisitor.mEvent->mFlags.mInSystemGroup = true; 1.339 + HandleEventTargetChain(aChain, 1.340 + aVisitor, 1.341 + aCallback, 1.342 + aCd); 1.343 + aVisitor.mEvent->mFlags.mInSystemGroup = false; 1.344 + 1.345 + // After dispatch, clear all the propagation flags so that 1.346 + // system group listeners don't affect to the event. 1.347 + aVisitor.mEvent->mFlags.mPropagationStopped = false; 1.348 + aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false; 1.349 + } 1.350 +} 1.351 + 1.352 +static nsTArray<EventTargetChainItem>* sCachedMainThreadChain = nullptr; 1.353 + 1.354 +/* static */ void 1.355 +EventDispatcher::Shutdown() 1.356 +{ 1.357 + delete sCachedMainThreadChain; 1.358 + sCachedMainThreadChain = nullptr; 1.359 +} 1.360 + 1.361 +EventTargetChainItem* 1.362 +EventTargetChainItemForChromeTarget(nsTArray<EventTargetChainItem>& aChain, 1.363 + nsINode* aNode, 1.364 + EventTargetChainItem* aChild = nullptr) 1.365 +{ 1.366 + if (!aNode->IsInDoc()) { 1.367 + return nullptr; 1.368 + } 1.369 + nsPIDOMWindow* win = aNode->OwnerDoc()->GetInnerWindow(); 1.370 + EventTarget* piTarget = win ? win->GetParentTarget() : nullptr; 1.371 + NS_ENSURE_TRUE(piTarget, nullptr); 1.372 + 1.373 + EventTargetChainItem* etci = 1.374 + EventTargetChainItem::Create(aChain, 1.375 + piTarget->GetTargetForEventTargetChain(), 1.376 + aChild); 1.377 + if (!etci->IsValid()) { 1.378 + EventTargetChainItem::DestroyLast(aChain, etci); 1.379 + return nullptr; 1.380 + } 1.381 + return etci; 1.382 +} 1.383 + 1.384 +/* static */ nsresult 1.385 +EventDispatcher::Dispatch(nsISupports* aTarget, 1.386 + nsPresContext* aPresContext, 1.387 + WidgetEvent* aEvent, 1.388 + nsIDOMEvent* aDOMEvent, 1.389 + nsEventStatus* aEventStatus, 1.390 + EventDispatchingCallback* aCallback, 1.391 + nsCOMArray<EventTarget>* aTargets) 1.392 +{ 1.393 + PROFILER_LABEL("EventDispatcher", "Dispatch"); 1.394 + NS_ASSERTION(aEvent, "Trying to dispatch without WidgetEvent!"); 1.395 + NS_ENSURE_TRUE(!aEvent->mFlags.mIsBeingDispatched, 1.396 + NS_ERROR_DOM_INVALID_STATE_ERR); 1.397 + NS_ASSERTION(!aTargets || !aEvent->message, "Wrong parameters!"); 1.398 + 1.399 + // If we're dispatching an already created DOMEvent object, make 1.400 + // sure it is initialized! 1.401 + // If aTargets is non-null, the event isn't going to be dispatched. 1.402 + NS_ENSURE_TRUE(aEvent->message || !aDOMEvent || aTargets, 1.403 + NS_ERROR_DOM_INVALID_STATE_ERR); 1.404 + 1.405 + nsCOMPtr<EventTarget> target = do_QueryInterface(aTarget); 1.406 + 1.407 + bool retargeted = false; 1.408 + 1.409 + if (aEvent->mFlags.mRetargetToNonNativeAnonymous) { 1.410 + nsCOMPtr<nsIContent> content = do_QueryInterface(target); 1.411 + if (content && content->IsInNativeAnonymousSubtree()) { 1.412 + nsCOMPtr<EventTarget> newTarget = 1.413 + do_QueryInterface(content->FindFirstNonChromeOnlyAccessContent()); 1.414 + NS_ENSURE_STATE(newTarget); 1.415 + 1.416 + aEvent->originalTarget = target; 1.417 + target = newTarget; 1.418 + retargeted = true; 1.419 + } 1.420 + } 1.421 + 1.422 + if (aEvent->mFlags.mOnlyChromeDispatch) { 1.423 + nsCOMPtr<nsINode> node = do_QueryInterface(aTarget); 1.424 + if (!node) { 1.425 + nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aTarget); 1.426 + if (win) { 1.427 + node = win->GetExtantDoc(); 1.428 + } 1.429 + } 1.430 + 1.431 + NS_ENSURE_STATE(node); 1.432 + nsIDocument* doc = node->OwnerDoc(); 1.433 + if (!nsContentUtils::IsChromeDoc(doc)) { 1.434 + nsPIDOMWindow* win = doc ? doc->GetInnerWindow() : nullptr; 1.435 + // If we can't dispatch the event to chrome, do nothing. 1.436 + EventTarget* piTarget = win ? win->GetParentTarget() : nullptr; 1.437 + NS_ENSURE_TRUE(piTarget, NS_OK); 1.438 + 1.439 + // Set the target to be the original dispatch target, 1.440 + aEvent->target = target; 1.441 + // but use chrome event handler or TabChildGlobal for event target chain. 1.442 + target = piTarget; 1.443 + } 1.444 + } 1.445 + 1.446 +#ifdef DEBUG 1.447 + if (!nsContentUtils::IsSafeToRunScript()) { 1.448 + nsresult rv = NS_ERROR_FAILURE; 1.449 + if (target->GetContextForEventHandlers(&rv) || 1.450 + NS_FAILED(rv)) { 1.451 + nsCOMPtr<nsINode> node = do_QueryInterface(target); 1.452 + if (node && nsContentUtils::IsChromeDoc(node->OwnerDoc())) { 1.453 + NS_WARNING("Fix the caller!"); 1.454 + } else { 1.455 + NS_ERROR("This is unsafe! Fix the caller!"); 1.456 + } 1.457 + } 1.458 + } 1.459 + 1.460 + if (aDOMEvent) { 1.461 + WidgetEvent* innerEvent = aDOMEvent->GetInternalNSEvent(); 1.462 + NS_ASSERTION(innerEvent == aEvent, 1.463 + "The inner event of aDOMEvent is not the same as aEvent!"); 1.464 + } 1.465 +#endif 1.466 + 1.467 + nsresult rv = NS_OK; 1.468 + bool externalDOMEvent = !!(aDOMEvent); 1.469 + 1.470 + // If we have a PresContext, make sure it doesn't die before 1.471 + // event dispatching is finished. 1.472 + nsRefPtr<nsPresContext> kungFuDeathGrip(aPresContext); 1.473 + 1.474 + ELMCreationDetector cd; 1.475 + nsTArray<EventTargetChainItem> chain; 1.476 + if (cd.IsMainThread()) { 1.477 + if (!sCachedMainThreadChain) { 1.478 + sCachedMainThreadChain = new nsTArray<EventTargetChainItem>(); 1.479 + } 1.480 + chain.SwapElements(*sCachedMainThreadChain); 1.481 + chain.SetCapacity(128); 1.482 + } 1.483 + 1.484 + // Create the event target chain item for the event target. 1.485 + EventTargetChainItem* targetEtci = 1.486 + EventTargetChainItem::Create(chain, target->GetTargetForEventTargetChain()); 1.487 + MOZ_ASSERT(&chain[0] == targetEtci); 1.488 + if (!targetEtci->IsValid()) { 1.489 + EventTargetChainItem::DestroyLast(chain, targetEtci); 1.490 + return NS_ERROR_FAILURE; 1.491 + } 1.492 + 1.493 + // Make sure that nsIDOMEvent::target and nsIDOMEvent::originalTarget 1.494 + // point to the last item in the chain. 1.495 + if (!aEvent->target) { 1.496 + // Note, CurrentTarget() points always to the object returned by 1.497 + // GetTargetForEventTargetChain(). 1.498 + aEvent->target = targetEtci->CurrentTarget(); 1.499 + } else { 1.500 + // XXX But if the target is already set, use that. This is a hack 1.501 + // for the 'load', 'beforeunload' and 'unload' events, 1.502 + // which are dispatched to |window| but have document as their target. 1.503 + // 1.504 + // Make sure that the event target points to the right object. 1.505 + aEvent->target = aEvent->target->GetTargetForEventTargetChain(); 1.506 + NS_ENSURE_STATE(aEvent->target); 1.507 + } 1.508 + 1.509 + if (retargeted) { 1.510 + aEvent->originalTarget = 1.511 + aEvent->originalTarget->GetTargetForEventTargetChain(); 1.512 + NS_ENSURE_STATE(aEvent->originalTarget); 1.513 + } 1.514 + else { 1.515 + aEvent->originalTarget = aEvent->target; 1.516 + } 1.517 + 1.518 + nsCOMPtr<nsIContent> content = do_QueryInterface(aEvent->originalTarget); 1.519 + bool isInAnon = (content && content->IsInAnonymousSubtree()); 1.520 + 1.521 + aEvent->mFlags.mIsBeingDispatched = true; 1.522 + 1.523 + // Create visitor object and start event dispatching. 1.524 + // PreHandleEvent for the original target. 1.525 + nsEventStatus status = aEventStatus ? *aEventStatus : nsEventStatus_eIgnore; 1.526 + EventChainPreVisitor preVisitor(aPresContext, aEvent, aDOMEvent, status, 1.527 + isInAnon); 1.528 + targetEtci->PreHandleEvent(preVisitor); 1.529 + 1.530 + if (!preVisitor.mCanHandle && preVisitor.mAutomaticChromeDispatch && content) { 1.531 + // Event target couldn't handle the event. Try to propagate to chrome. 1.532 + EventTargetChainItem::DestroyLast(chain, targetEtci); 1.533 + targetEtci = EventTargetChainItemForChromeTarget(chain, content); 1.534 + NS_ENSURE_STATE(targetEtci); 1.535 + MOZ_ASSERT(&chain[0] == targetEtci); 1.536 + targetEtci->PreHandleEvent(preVisitor); 1.537 + } 1.538 + if (preVisitor.mCanHandle) { 1.539 + // At least the original target can handle the event. 1.540 + // Setting the retarget to the |target| simplifies retargeting code. 1.541 + nsCOMPtr<EventTarget> t = do_QueryInterface(aEvent->target); 1.542 + targetEtci->SetNewTarget(t); 1.543 + EventTargetChainItem* topEtci = targetEtci; 1.544 + targetEtci = nullptr; 1.545 + while (preVisitor.mParentTarget) { 1.546 + EventTarget* parentTarget = preVisitor.mParentTarget; 1.547 + EventTargetChainItem* parentEtci = 1.548 + EventTargetChainItem::Create(chain, preVisitor.mParentTarget, topEtci); 1.549 + if (!parentEtci->IsValid()) { 1.550 + EventTargetChainItem::DestroyLast(chain, parentEtci); 1.551 + rv = NS_ERROR_FAILURE; 1.552 + break; 1.553 + } 1.554 + 1.555 + // Item needs event retargetting. 1.556 + if (preVisitor.mEventTargetAtParent) { 1.557 + // Need to set the target of the event 1.558 + // so that also the next retargeting works. 1.559 + preVisitor.mEvent->target = preVisitor.mEventTargetAtParent; 1.560 + parentEtci->SetNewTarget(preVisitor.mEventTargetAtParent); 1.561 + } 1.562 + 1.563 + parentEtci->PreHandleEvent(preVisitor); 1.564 + if (preVisitor.mCanHandle) { 1.565 + topEtci = parentEtci; 1.566 + } else { 1.567 + EventTargetChainItem::DestroyLast(chain, parentEtci); 1.568 + parentEtci = nullptr; 1.569 + if (preVisitor.mAutomaticChromeDispatch && content) { 1.570 + // Even if the current target can't handle the event, try to 1.571 + // propagate to chrome. 1.572 + nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget); 1.573 + if (disabledTarget) { 1.574 + parentEtci = EventTargetChainItemForChromeTarget(chain, 1.575 + disabledTarget, 1.576 + topEtci); 1.577 + if (parentEtci) { 1.578 + parentEtci->PreHandleEvent(preVisitor); 1.579 + if (preVisitor.mCanHandle) { 1.580 + chain[0].SetNewTarget(parentTarget); 1.581 + topEtci = parentEtci; 1.582 + continue; 1.583 + } 1.584 + } 1.585 + } 1.586 + } 1.587 + break; 1.588 + } 1.589 + } 1.590 + if (NS_SUCCEEDED(rv)) { 1.591 + if (aTargets) { 1.592 + aTargets->Clear(); 1.593 + aTargets->SetCapacity(chain.Length()); 1.594 + for (uint32_t i = 0; i < chain.Length(); ++i) { 1.595 + aTargets->AppendObject(chain[i].CurrentTarget()->GetTargetForDOMEvent()); 1.596 + } 1.597 + } else { 1.598 + // Event target chain is created. Handle the chain. 1.599 + EventChainPostVisitor postVisitor(preVisitor); 1.600 + EventTargetChainItem::HandleEventTargetChain(chain, postVisitor, 1.601 + aCallback, cd); 1.602 + 1.603 + preVisitor.mEventStatus = postVisitor.mEventStatus; 1.604 + // If the DOM event was created during event flow. 1.605 + if (!preVisitor.mDOMEvent && postVisitor.mDOMEvent) { 1.606 + preVisitor.mDOMEvent = postVisitor.mDOMEvent; 1.607 + } 1.608 + } 1.609 + } 1.610 + } 1.611 + 1.612 + // Note, EventTargetChainItem objects are deleted when the chain goes out of 1.613 + // the scope. 1.614 + 1.615 + aEvent->mFlags.mIsBeingDispatched = false; 1.616 + aEvent->mFlags.mDispatchedAtLeastOnce = true; 1.617 + 1.618 + if (!externalDOMEvent && preVisitor.mDOMEvent) { 1.619 + // An dom::Event was created while dispatching the event. 1.620 + // Duplicate private data if someone holds a pointer to it. 1.621 + nsrefcnt rc = 0; 1.622 + NS_RELEASE2(preVisitor.mDOMEvent, rc); 1.623 + if (preVisitor.mDOMEvent) { 1.624 + preVisitor.mDOMEvent->DuplicatePrivateData(); 1.625 + } 1.626 + } 1.627 + 1.628 + if (aEventStatus) { 1.629 + *aEventStatus = preVisitor.mEventStatus; 1.630 + } 1.631 + 1.632 + if (cd.IsMainThread() && chain.Capacity() == 128 && sCachedMainThreadChain) { 1.633 + chain.ClearAndRetainStorage(); 1.634 + chain.SwapElements(*sCachedMainThreadChain); 1.635 + } 1.636 + 1.637 + return rv; 1.638 +} 1.639 + 1.640 +/* static */ nsresult 1.641 +EventDispatcher::DispatchDOMEvent(nsISupports* aTarget, 1.642 + WidgetEvent* aEvent, 1.643 + nsIDOMEvent* aDOMEvent, 1.644 + nsPresContext* aPresContext, 1.645 + nsEventStatus* aEventStatus) 1.646 +{ 1.647 + if (aDOMEvent) { 1.648 + WidgetEvent* innerEvent = aDOMEvent->GetInternalNSEvent(); 1.649 + NS_ENSURE_TRUE(innerEvent, NS_ERROR_ILLEGAL_VALUE); 1.650 + 1.651 + bool dontResetTrusted = false; 1.652 + if (innerEvent->mFlags.mDispatchedAtLeastOnce) { 1.653 + innerEvent->target = nullptr; 1.654 + innerEvent->originalTarget = nullptr; 1.655 + } else { 1.656 + aDOMEvent->GetIsTrusted(&dontResetTrusted); 1.657 + } 1.658 + 1.659 + if (!dontResetTrusted) { 1.660 + //Check security state to determine if dispatcher is trusted 1.661 + aDOMEvent->SetTrusted(nsContentUtils::ThreadsafeIsCallerChrome()); 1.662 + } 1.663 + 1.664 + return EventDispatcher::Dispatch(aTarget, aPresContext, innerEvent, 1.665 + aDOMEvent, aEventStatus); 1.666 + } else if (aEvent) { 1.667 + return EventDispatcher::Dispatch(aTarget, aPresContext, aEvent, 1.668 + aDOMEvent, aEventStatus); 1.669 + } 1.670 + return NS_ERROR_ILLEGAL_VALUE; 1.671 +} 1.672 + 1.673 +/* static */ nsresult 1.674 +EventDispatcher::CreateEvent(EventTarget* aOwner, 1.675 + nsPresContext* aPresContext, 1.676 + WidgetEvent* aEvent, 1.677 + const nsAString& aEventType, 1.678 + nsIDOMEvent** aDOMEvent) 1.679 +{ 1.680 + *aDOMEvent = nullptr; 1.681 + 1.682 + if (aEvent) { 1.683 + switch(aEvent->eventStructType) { 1.684 + case NS_MUTATION_EVENT: 1.685 + return NS_NewDOMMutationEvent(aDOMEvent, aOwner, aPresContext, 1.686 + aEvent->AsMutationEvent()); 1.687 + case NS_GUI_EVENT: 1.688 + case NS_SCROLLPORT_EVENT: 1.689 + case NS_UI_EVENT: 1.690 + return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext, 1.691 + aEvent->AsGUIEvent()); 1.692 + case NS_SCROLLAREA_EVENT: 1.693 + return NS_NewDOMScrollAreaEvent(aDOMEvent, aOwner, aPresContext, 1.694 + aEvent->AsScrollAreaEvent()); 1.695 + case NS_KEY_EVENT: 1.696 + return NS_NewDOMKeyboardEvent(aDOMEvent, aOwner, aPresContext, 1.697 + aEvent->AsKeyboardEvent()); 1.698 + case NS_COMPOSITION_EVENT: 1.699 + return NS_NewDOMCompositionEvent(aDOMEvent, aOwner, aPresContext, 1.700 + aEvent->AsCompositionEvent()); 1.701 + case NS_MOUSE_EVENT: 1.702 + return NS_NewDOMMouseEvent(aDOMEvent, aOwner, aPresContext, 1.703 + aEvent->AsMouseEvent()); 1.704 + case NS_FOCUS_EVENT: 1.705 + return NS_NewDOMFocusEvent(aDOMEvent, aOwner, aPresContext, 1.706 + aEvent->AsFocusEvent()); 1.707 + case NS_MOUSE_SCROLL_EVENT: 1.708 + return NS_NewDOMMouseScrollEvent(aDOMEvent, aOwner, aPresContext, 1.709 + aEvent->AsMouseScrollEvent()); 1.710 + case NS_WHEEL_EVENT: 1.711 + return NS_NewDOMWheelEvent(aDOMEvent, aOwner, aPresContext, 1.712 + aEvent->AsWheelEvent()); 1.713 + case NS_EDITOR_INPUT_EVENT: 1.714 + return NS_NewDOMInputEvent(aDOMEvent, aOwner, aPresContext, 1.715 + aEvent->AsEditorInputEvent()); 1.716 + case NS_DRAG_EVENT: 1.717 + return NS_NewDOMDragEvent(aDOMEvent, aOwner, aPresContext, 1.718 + aEvent->AsDragEvent()); 1.719 + case NS_TEXT_EVENT: 1.720 + return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext, 1.721 + aEvent->AsTextEvent()); 1.722 + case NS_CLIPBOARD_EVENT: 1.723 + return NS_NewDOMClipboardEvent(aDOMEvent, aOwner, aPresContext, 1.724 + aEvent->AsClipboardEvent()); 1.725 + case NS_SVGZOOM_EVENT: 1.726 + return NS_NewDOMSVGZoomEvent(aDOMEvent, aOwner, aPresContext, 1.727 + aEvent->AsGUIEvent()); 1.728 + case NS_SMIL_TIME_EVENT: 1.729 + return NS_NewDOMTimeEvent(aDOMEvent, aOwner, aPresContext, aEvent); 1.730 + 1.731 + case NS_COMMAND_EVENT: 1.732 + return NS_NewDOMCommandEvent(aDOMEvent, aOwner, aPresContext, 1.733 + aEvent->AsCommandEvent()); 1.734 + case NS_SIMPLE_GESTURE_EVENT: 1.735 + return NS_NewDOMSimpleGestureEvent(aDOMEvent, aOwner, aPresContext, 1.736 + aEvent->AsSimpleGestureEvent()); 1.737 + case NS_POINTER_EVENT: 1.738 + return NS_NewDOMPointerEvent(aDOMEvent, aOwner, aPresContext, 1.739 + aEvent->AsPointerEvent()); 1.740 + case NS_TOUCH_EVENT: 1.741 + return NS_NewDOMTouchEvent(aDOMEvent, aOwner, aPresContext, 1.742 + aEvent->AsTouchEvent()); 1.743 + case NS_TRANSITION_EVENT: 1.744 + return NS_NewDOMTransitionEvent(aDOMEvent, aOwner, aPresContext, 1.745 + aEvent->AsTransitionEvent()); 1.746 + case NS_ANIMATION_EVENT: 1.747 + return NS_NewDOMAnimationEvent(aDOMEvent, aOwner, aPresContext, 1.748 + aEvent->AsAnimationEvent()); 1.749 + default: 1.750 + // For all other types of events, create a vanilla event object. 1.751 + return NS_NewDOMEvent(aDOMEvent, aOwner, aPresContext, aEvent); 1.752 + } 1.753 + } 1.754 + 1.755 + // And if we didn't get an event, check the type argument. 1.756 + 1.757 + if (aEventType.LowerCaseEqualsLiteral("mouseevent") || 1.758 + aEventType.LowerCaseEqualsLiteral("mouseevents") || 1.759 + aEventType.LowerCaseEqualsLiteral("popupevents")) 1.760 + return NS_NewDOMMouseEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.761 + if (aEventType.LowerCaseEqualsLiteral("mousescrollevents")) 1.762 + return NS_NewDOMMouseScrollEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.763 + if (aEventType.LowerCaseEqualsLiteral("dragevent") || 1.764 + aEventType.LowerCaseEqualsLiteral("dragevents")) 1.765 + return NS_NewDOMDragEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.766 + if (aEventType.LowerCaseEqualsLiteral("keyboardevent") || 1.767 + aEventType.LowerCaseEqualsLiteral("keyevents")) 1.768 + return NS_NewDOMKeyboardEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.769 + if (aEventType.LowerCaseEqualsLiteral("compositionevent")) 1.770 + return NS_NewDOMCompositionEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.771 + if (aEventType.LowerCaseEqualsLiteral("mutationevent") || 1.772 + aEventType.LowerCaseEqualsLiteral("mutationevents")) 1.773 + return NS_NewDOMMutationEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.774 + if (aEventType.LowerCaseEqualsLiteral("textevent") || 1.775 + aEventType.LowerCaseEqualsLiteral("textevents")) 1.776 + return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.777 + if (aEventType.LowerCaseEqualsLiteral("popupblockedevents")) 1.778 + return NS_NewDOMPopupBlockedEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.779 + if (aEventType.LowerCaseEqualsLiteral("deviceorientationevent")) 1.780 + return NS_NewDOMDeviceOrientationEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.781 + if (aEventType.LowerCaseEqualsLiteral("devicemotionevent")) 1.782 + return NS_NewDOMDeviceMotionEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.783 + if (aEventType.LowerCaseEqualsLiteral("uievent") || 1.784 + aEventType.LowerCaseEqualsLiteral("uievents")) 1.785 + return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.786 + if (aEventType.LowerCaseEqualsLiteral("event") || 1.787 + aEventType.LowerCaseEqualsLiteral("events") || 1.788 + aEventType.LowerCaseEqualsLiteral("htmlevents") || 1.789 + aEventType.LowerCaseEqualsLiteral("svgevent") || 1.790 + aEventType.LowerCaseEqualsLiteral("svgevents")) 1.791 + return NS_NewDOMEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.792 + if (aEventType.LowerCaseEqualsLiteral("svgzoomevent") || 1.793 + aEventType.LowerCaseEqualsLiteral("svgzoomevents")) 1.794 + return NS_NewDOMSVGZoomEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.795 + if (aEventType.LowerCaseEqualsLiteral("timeevent") || 1.796 + aEventType.LowerCaseEqualsLiteral("timeevents")) 1.797 + return NS_NewDOMTimeEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.798 + if (aEventType.LowerCaseEqualsLiteral("xulcommandevent") || 1.799 + aEventType.LowerCaseEqualsLiteral("xulcommandevents")) 1.800 + return NS_NewDOMXULCommandEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.801 + if (aEventType.LowerCaseEqualsLiteral("commandevent") || 1.802 + aEventType.LowerCaseEqualsLiteral("commandevents")) 1.803 + return NS_NewDOMCommandEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.804 + if (aEventType.LowerCaseEqualsLiteral("elementreplace")) 1.805 + return NS_NewDOMElementReplaceEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.806 + if (aEventType.LowerCaseEqualsLiteral("datacontainerevent") || 1.807 + aEventType.LowerCaseEqualsLiteral("datacontainerevents")) 1.808 + return NS_NewDOMDataContainerEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.809 + if (aEventType.LowerCaseEqualsLiteral("messageevent")) 1.810 + return NS_NewDOMMessageEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.811 + if (aEventType.LowerCaseEqualsLiteral("notifypaintevent")) 1.812 + return NS_NewDOMNotifyPaintEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.813 + if (aEventType.LowerCaseEqualsLiteral("simplegestureevent")) 1.814 + return NS_NewDOMSimpleGestureEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.815 + if (aEventType.LowerCaseEqualsLiteral("beforeunloadevent")) 1.816 + return NS_NewDOMBeforeUnloadEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.817 + if (aEventType.LowerCaseEqualsLiteral("pagetransition")) 1.818 + return NS_NewDOMPageTransitionEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.819 + if (aEventType.LowerCaseEqualsLiteral("domtransaction")) 1.820 + return NS_NewDOMDOMTransactionEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.821 + if (aEventType.LowerCaseEqualsLiteral("scrollareaevent")) 1.822 + return NS_NewDOMScrollAreaEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.823 + if (aEventType.LowerCaseEqualsLiteral("popstateevent")) 1.824 + return NS_NewDOMPopStateEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.825 + if (aEventType.LowerCaseEqualsLiteral("closeevent")) 1.826 + return NS_NewDOMCloseEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.827 + if (aEventType.LowerCaseEqualsLiteral("touchevent") && 1.828 + TouchEvent::PrefEnabled()) 1.829 + return NS_NewDOMTouchEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.830 + if (aEventType.LowerCaseEqualsLiteral("hashchangeevent")) 1.831 + return NS_NewDOMHashChangeEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.832 + if (aEventType.LowerCaseEqualsLiteral("customevent")) 1.833 + return NS_NewDOMCustomEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.834 + if (aEventType.LowerCaseEqualsLiteral("mozsmsevent")) 1.835 + return NS_NewDOMMozSmsEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.836 + if (aEventType.LowerCaseEqualsLiteral("mozmmsevent")) 1.837 + return NS_NewDOMMozMmsEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.838 + if (aEventType.LowerCaseEqualsLiteral("storageevent")) { 1.839 + return NS_NewDOMStorageEvent(aDOMEvent, aOwner, aPresContext, nullptr); 1.840 + } 1.841 + // NEW EVENT TYPES SHOULD NOT BE ADDED HERE; THEY SHOULD USE ONLY EVENT 1.842 + // CONSTRUCTORS 1.843 + 1.844 + return NS_ERROR_DOM_NOT_SUPPORTED_ERR; 1.845 +} 1.846 + 1.847 +} // namespace mozilla