dom/events/EventDispatcher.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: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "nsPresContext.h"
michael@0 8 #include "nsContentUtils.h"
michael@0 9 #include "nsError.h"
michael@0 10 #include <new>
michael@0 11 #include "nsIContent.h"
michael@0 12 #include "nsIDocument.h"
michael@0 13 #include "nsINode.h"
michael@0 14 #include "nsPIDOMWindow.h"
michael@0 15 #include "GeckoProfiler.h"
michael@0 16 #include "GeneratedEvents.h"
michael@0 17 #include "mozilla/ContentEvents.h"
michael@0 18 #include "mozilla/dom/EventTarget.h"
michael@0 19 #include "mozilla/dom/TouchEvent.h"
michael@0 20 #include "mozilla/EventDispatcher.h"
michael@0 21 #include "mozilla/EventListenerManager.h"
michael@0 22 #include "mozilla/InternalMutationEvent.h"
michael@0 23 #include "mozilla/MiscEvents.h"
michael@0 24 #include "mozilla/MouseEvents.h"
michael@0 25 #include "mozilla/TextEvents.h"
michael@0 26 #include "mozilla/TouchEvents.h"
michael@0 27 #include "mozilla/unused.h"
michael@0 28
michael@0 29 namespace mozilla {
michael@0 30
michael@0 31 using namespace dom;
michael@0 32
michael@0 33 class ELMCreationDetector
michael@0 34 {
michael@0 35 public:
michael@0 36 ELMCreationDetector()
michael@0 37 // We can do this optimization only in the main thread.
michael@0 38 : mNonMainThread(!NS_IsMainThread())
michael@0 39 , mInitialCount(mNonMainThread ?
michael@0 40 0 : EventListenerManager::sMainThreadCreatedCount)
michael@0 41 {
michael@0 42 }
michael@0 43
michael@0 44 bool MayHaveNewListenerManager()
michael@0 45 {
michael@0 46 return mNonMainThread ||
michael@0 47 mInitialCount != EventListenerManager::sMainThreadCreatedCount;
michael@0 48 }
michael@0 49
michael@0 50 bool IsMainThread()
michael@0 51 {
michael@0 52 return !mNonMainThread;
michael@0 53 }
michael@0 54
michael@0 55 private:
michael@0 56 bool mNonMainThread;
michael@0 57 uint32_t mInitialCount;
michael@0 58 };
michael@0 59
michael@0 60 #define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0)
michael@0 61 #define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
michael@0 62 #define NS_TARGET_CHAIN_MAY_HAVE_MANAGER (1 << 2)
michael@0 63
michael@0 64 // EventTargetChainItem represents a single item in the event target chain.
michael@0 65 class EventTargetChainItem
michael@0 66 {
michael@0 67 private:
michael@0 68 EventTargetChainItem(EventTarget* aTarget);
michael@0 69 public:
michael@0 70 EventTargetChainItem()
michael@0 71 : mFlags(0)
michael@0 72 , mItemFlags(0)
michael@0 73 {
michael@0 74 }
michael@0 75
michael@0 76 static EventTargetChainItem* Create(nsTArray<EventTargetChainItem>& aChain,
michael@0 77 EventTarget* aTarget,
michael@0 78 EventTargetChainItem* aChild = nullptr)
michael@0 79 {
michael@0 80 MOZ_ASSERT(!aChild || &aChain.ElementAt(aChain.Length() - 1) == aChild);
michael@0 81 return new (aChain.AppendElement()) EventTargetChainItem(aTarget);
michael@0 82 }
michael@0 83
michael@0 84 static void DestroyLast(nsTArray<EventTargetChainItem>& aChain,
michael@0 85 EventTargetChainItem* aItem)
michael@0 86 {
michael@0 87 uint32_t lastIndex = aChain.Length() - 1;
michael@0 88 MOZ_ASSERT(&aChain[lastIndex] == aItem);
michael@0 89 aChain.RemoveElementAt(lastIndex);
michael@0 90 }
michael@0 91
michael@0 92 bool IsValid()
michael@0 93 {
michael@0 94 NS_WARN_IF_FALSE(!!(mTarget), "Event target is not valid!");
michael@0 95 return !!(mTarget);
michael@0 96 }
michael@0 97
michael@0 98 EventTarget* GetNewTarget()
michael@0 99 {
michael@0 100 return mNewTarget;
michael@0 101 }
michael@0 102
michael@0 103 void SetNewTarget(EventTarget* aNewTarget)
michael@0 104 {
michael@0 105 mNewTarget = aNewTarget;
michael@0 106 }
michael@0 107
michael@0 108 void SetForceContentDispatch(bool aForce)
michael@0 109 {
michael@0 110 if (aForce) {
michael@0 111 mFlags |= NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH;
michael@0 112 } else {
michael@0 113 mFlags &= ~NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH;
michael@0 114 }
michael@0 115 }
michael@0 116
michael@0 117 bool ForceContentDispatch()
michael@0 118 {
michael@0 119 return !!(mFlags & NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH);
michael@0 120 }
michael@0 121
michael@0 122 void SetWantsWillHandleEvent(bool aWants)
michael@0 123 {
michael@0 124 if (aWants) {
michael@0 125 mFlags |= NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT;
michael@0 126 } else {
michael@0 127 mFlags &= ~NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT;
michael@0 128 }
michael@0 129 }
michael@0 130
michael@0 131 bool WantsWillHandleEvent()
michael@0 132 {
michael@0 133 return !!(mFlags & NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT);
michael@0 134 }
michael@0 135
michael@0 136 void SetMayHaveListenerManager(bool aMayHave)
michael@0 137 {
michael@0 138 if (aMayHave) {
michael@0 139 mFlags |= NS_TARGET_CHAIN_MAY_HAVE_MANAGER;
michael@0 140 } else {
michael@0 141 mFlags &= ~NS_TARGET_CHAIN_MAY_HAVE_MANAGER;
michael@0 142 }
michael@0 143 }
michael@0 144
michael@0 145 bool MayHaveListenerManager()
michael@0 146 {
michael@0 147 return !!(mFlags & NS_TARGET_CHAIN_MAY_HAVE_MANAGER);
michael@0 148 }
michael@0 149
michael@0 150 EventTarget* CurrentTarget()
michael@0 151 {
michael@0 152 return mTarget;
michael@0 153 }
michael@0 154
michael@0 155 /**
michael@0 156 * Dispatches event through the event target chain.
michael@0 157 * Handles capture, target and bubble phases both in default
michael@0 158 * and system event group and calls also PostHandleEvent for each
michael@0 159 * item in the chain.
michael@0 160 */
michael@0 161 static void HandleEventTargetChain(nsTArray<EventTargetChainItem>& aChain,
michael@0 162 EventChainPostVisitor& aVisitor,
michael@0 163 EventDispatchingCallback* aCallback,
michael@0 164 ELMCreationDetector& aCd);
michael@0 165
michael@0 166 /**
michael@0 167 * Resets aVisitor object and calls PreHandleEvent.
michael@0 168 * Copies mItemFlags and mItemData to the current EventTargetChainItem.
michael@0 169 */
michael@0 170 void PreHandleEvent(EventChainPreVisitor& aVisitor);
michael@0 171
michael@0 172 /**
michael@0 173 * If the current item in the event target chain has an event listener
michael@0 174 * manager, this method calls EventListenerManager::HandleEvent().
michael@0 175 */
michael@0 176 void HandleEvent(EventChainPostVisitor& aVisitor,
michael@0 177 ELMCreationDetector& aCd)
michael@0 178 {
michael@0 179 if (WantsWillHandleEvent()) {
michael@0 180 mTarget->WillHandleEvent(aVisitor);
michael@0 181 }
michael@0 182 if (aVisitor.mEvent->mFlags.mPropagationStopped) {
michael@0 183 return;
michael@0 184 }
michael@0 185 if (!mManager) {
michael@0 186 if (!MayHaveListenerManager() && !aCd.MayHaveNewListenerManager()) {
michael@0 187 return;
michael@0 188 }
michael@0 189 mManager = mTarget->GetExistingListenerManager();
michael@0 190 }
michael@0 191 if (mManager) {
michael@0 192 NS_ASSERTION(aVisitor.mEvent->currentTarget == nullptr,
michael@0 193 "CurrentTarget should be null!");
michael@0 194 mManager->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent,
michael@0 195 &aVisitor.mDOMEvent,
michael@0 196 CurrentTarget(),
michael@0 197 &aVisitor.mEventStatus);
michael@0 198 NS_ASSERTION(aVisitor.mEvent->currentTarget == nullptr,
michael@0 199 "CurrentTarget should be null!");
michael@0 200 }
michael@0 201 }
michael@0 202
michael@0 203 /**
michael@0 204 * Copies mItemFlags and mItemData to aVisitor and calls PostHandleEvent.
michael@0 205 */
michael@0 206 void PostHandleEvent(EventChainPostVisitor& aVisitor);
michael@0 207
michael@0 208 nsCOMPtr<EventTarget> mTarget;
michael@0 209 uint16_t mFlags;
michael@0 210 uint16_t mItemFlags;
michael@0 211 nsCOMPtr<nsISupports> mItemData;
michael@0 212 // Event retargeting must happen whenever mNewTarget is non-null.
michael@0 213 nsCOMPtr<EventTarget> mNewTarget;
michael@0 214 // Cache mTarget's event listener manager.
michael@0 215 nsRefPtr<EventListenerManager> mManager;
michael@0 216 };
michael@0 217
michael@0 218 EventTargetChainItem::EventTargetChainItem(EventTarget* aTarget)
michael@0 219 : mTarget(aTarget)
michael@0 220 , mFlags(0)
michael@0 221 , mItemFlags(0)
michael@0 222 {
michael@0 223 MOZ_ASSERT(!aTarget || mTarget == aTarget->GetTargetForEventTargetChain());
michael@0 224 }
michael@0 225
michael@0 226 void
michael@0 227 EventTargetChainItem::PreHandleEvent(EventChainPreVisitor& aVisitor)
michael@0 228 {
michael@0 229 aVisitor.Reset();
michael@0 230 unused << mTarget->PreHandleEvent(aVisitor);
michael@0 231 SetForceContentDispatch(aVisitor.mForceContentDispatch);
michael@0 232 SetWantsWillHandleEvent(aVisitor.mWantsWillHandleEvent);
michael@0 233 SetMayHaveListenerManager(aVisitor.mMayHaveListenerManager);
michael@0 234 mItemFlags = aVisitor.mItemFlags;
michael@0 235 mItemData = aVisitor.mItemData;
michael@0 236 }
michael@0 237
michael@0 238 void
michael@0 239 EventTargetChainItem::PostHandleEvent(EventChainPostVisitor& aVisitor)
michael@0 240 {
michael@0 241 aVisitor.mItemFlags = mItemFlags;
michael@0 242 aVisitor.mItemData = mItemData;
michael@0 243 mTarget->PostHandleEvent(aVisitor);
michael@0 244 }
michael@0 245
michael@0 246 void
michael@0 247 EventTargetChainItem::HandleEventTargetChain(
michael@0 248 nsTArray<EventTargetChainItem>& aChain,
michael@0 249 EventChainPostVisitor& aVisitor,
michael@0 250 EventDispatchingCallback* aCallback,
michael@0 251 ELMCreationDetector& aCd)
michael@0 252 {
michael@0 253 // Save the target so that it can be restored later.
michael@0 254 nsCOMPtr<EventTarget> firstTarget = aVisitor.mEvent->target;
michael@0 255 uint32_t chainLength = aChain.Length();
michael@0 256
michael@0 257 // Capture
michael@0 258 aVisitor.mEvent->mFlags.mInCapturePhase = true;
michael@0 259 aVisitor.mEvent->mFlags.mInBubblingPhase = false;
michael@0 260 for (uint32_t i = chainLength - 1; i > 0; --i) {
michael@0 261 EventTargetChainItem& item = aChain[i];
michael@0 262 if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
michael@0 263 item.ForceContentDispatch()) &&
michael@0 264 !aVisitor.mEvent->mFlags.mPropagationStopped) {
michael@0 265 item.HandleEvent(aVisitor, aCd);
michael@0 266 }
michael@0 267
michael@0 268 if (item.GetNewTarget()) {
michael@0 269 // item is at anonymous boundary. Need to retarget for the child items.
michael@0 270 for (uint32_t j = i; j > 0; --j) {
michael@0 271 uint32_t childIndex = j - 1;
michael@0 272 EventTarget* newTarget = aChain[childIndex].GetNewTarget();
michael@0 273 if (newTarget) {
michael@0 274 aVisitor.mEvent->target = newTarget;
michael@0 275 break;
michael@0 276 }
michael@0 277 }
michael@0 278 }
michael@0 279 }
michael@0 280
michael@0 281 // Target
michael@0 282 aVisitor.mEvent->mFlags.mInBubblingPhase = true;
michael@0 283 EventTargetChainItem& targetItem = aChain[0];
michael@0 284 if (!aVisitor.mEvent->mFlags.mPropagationStopped &&
michael@0 285 (!aVisitor.mEvent->mFlags.mNoContentDispatch ||
michael@0 286 targetItem.ForceContentDispatch())) {
michael@0 287 targetItem.HandleEvent(aVisitor, aCd);
michael@0 288 }
michael@0 289 if (aVisitor.mEvent->mFlags.mInSystemGroup) {
michael@0 290 targetItem.PostHandleEvent(aVisitor);
michael@0 291 }
michael@0 292
michael@0 293 // Bubble
michael@0 294 aVisitor.mEvent->mFlags.mInCapturePhase = false;
michael@0 295 for (uint32_t i = 1; i < chainLength; ++i) {
michael@0 296 EventTargetChainItem& item = aChain[i];
michael@0 297 EventTarget* newTarget = item.GetNewTarget();
michael@0 298 if (newTarget) {
michael@0 299 // Item is at anonymous boundary. Need to retarget for the current item
michael@0 300 // and for parent items.
michael@0 301 aVisitor.mEvent->target = newTarget;
michael@0 302 }
michael@0 303
michael@0 304 if (aVisitor.mEvent->mFlags.mBubbles || newTarget) {
michael@0 305 if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
michael@0 306 item.ForceContentDispatch()) &&
michael@0 307 !aVisitor.mEvent->mFlags.mPropagationStopped) {
michael@0 308 item.HandleEvent(aVisitor, aCd);
michael@0 309 }
michael@0 310 if (aVisitor.mEvent->mFlags.mInSystemGroup) {
michael@0 311 item.PostHandleEvent(aVisitor);
michael@0 312 }
michael@0 313 }
michael@0 314 }
michael@0 315 aVisitor.mEvent->mFlags.mInBubblingPhase = false;
michael@0 316
michael@0 317 if (!aVisitor.mEvent->mFlags.mInSystemGroup) {
michael@0 318 // Dispatch to the system event group. Make sure to clear the
michael@0 319 // STOP_DISPATCH flag since this resets for each event group.
michael@0 320 aVisitor.mEvent->mFlags.mPropagationStopped = false;
michael@0 321 aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false;
michael@0 322
michael@0 323 // Setting back the original target of the event.
michael@0 324 aVisitor.mEvent->target = aVisitor.mEvent->originalTarget;
michael@0 325
michael@0 326 // Special handling if PresShell (or some other caller)
michael@0 327 // used a callback object.
michael@0 328 if (aCallback) {
michael@0 329 aCallback->HandleEvent(aVisitor);
michael@0 330 }
michael@0 331
michael@0 332 // Retarget for system event group (which does the default handling too).
michael@0 333 // Setting back the target which was used also for default event group.
michael@0 334 aVisitor.mEvent->target = firstTarget;
michael@0 335 aVisitor.mEvent->mFlags.mInSystemGroup = true;
michael@0 336 HandleEventTargetChain(aChain,
michael@0 337 aVisitor,
michael@0 338 aCallback,
michael@0 339 aCd);
michael@0 340 aVisitor.mEvent->mFlags.mInSystemGroup = false;
michael@0 341
michael@0 342 // After dispatch, clear all the propagation flags so that
michael@0 343 // system group listeners don't affect to the event.
michael@0 344 aVisitor.mEvent->mFlags.mPropagationStopped = false;
michael@0 345 aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false;
michael@0 346 }
michael@0 347 }
michael@0 348
michael@0 349 static nsTArray<EventTargetChainItem>* sCachedMainThreadChain = nullptr;
michael@0 350
michael@0 351 /* static */ void
michael@0 352 EventDispatcher::Shutdown()
michael@0 353 {
michael@0 354 delete sCachedMainThreadChain;
michael@0 355 sCachedMainThreadChain = nullptr;
michael@0 356 }
michael@0 357
michael@0 358 EventTargetChainItem*
michael@0 359 EventTargetChainItemForChromeTarget(nsTArray<EventTargetChainItem>& aChain,
michael@0 360 nsINode* aNode,
michael@0 361 EventTargetChainItem* aChild = nullptr)
michael@0 362 {
michael@0 363 if (!aNode->IsInDoc()) {
michael@0 364 return nullptr;
michael@0 365 }
michael@0 366 nsPIDOMWindow* win = aNode->OwnerDoc()->GetInnerWindow();
michael@0 367 EventTarget* piTarget = win ? win->GetParentTarget() : nullptr;
michael@0 368 NS_ENSURE_TRUE(piTarget, nullptr);
michael@0 369
michael@0 370 EventTargetChainItem* etci =
michael@0 371 EventTargetChainItem::Create(aChain,
michael@0 372 piTarget->GetTargetForEventTargetChain(),
michael@0 373 aChild);
michael@0 374 if (!etci->IsValid()) {
michael@0 375 EventTargetChainItem::DestroyLast(aChain, etci);
michael@0 376 return nullptr;
michael@0 377 }
michael@0 378 return etci;
michael@0 379 }
michael@0 380
michael@0 381 /* static */ nsresult
michael@0 382 EventDispatcher::Dispatch(nsISupports* aTarget,
michael@0 383 nsPresContext* aPresContext,
michael@0 384 WidgetEvent* aEvent,
michael@0 385 nsIDOMEvent* aDOMEvent,
michael@0 386 nsEventStatus* aEventStatus,
michael@0 387 EventDispatchingCallback* aCallback,
michael@0 388 nsCOMArray<EventTarget>* aTargets)
michael@0 389 {
michael@0 390 PROFILER_LABEL("EventDispatcher", "Dispatch");
michael@0 391 NS_ASSERTION(aEvent, "Trying to dispatch without WidgetEvent!");
michael@0 392 NS_ENSURE_TRUE(!aEvent->mFlags.mIsBeingDispatched,
michael@0 393 NS_ERROR_DOM_INVALID_STATE_ERR);
michael@0 394 NS_ASSERTION(!aTargets || !aEvent->message, "Wrong parameters!");
michael@0 395
michael@0 396 // If we're dispatching an already created DOMEvent object, make
michael@0 397 // sure it is initialized!
michael@0 398 // If aTargets is non-null, the event isn't going to be dispatched.
michael@0 399 NS_ENSURE_TRUE(aEvent->message || !aDOMEvent || aTargets,
michael@0 400 NS_ERROR_DOM_INVALID_STATE_ERR);
michael@0 401
michael@0 402 nsCOMPtr<EventTarget> target = do_QueryInterface(aTarget);
michael@0 403
michael@0 404 bool retargeted = false;
michael@0 405
michael@0 406 if (aEvent->mFlags.mRetargetToNonNativeAnonymous) {
michael@0 407 nsCOMPtr<nsIContent> content = do_QueryInterface(target);
michael@0 408 if (content && content->IsInNativeAnonymousSubtree()) {
michael@0 409 nsCOMPtr<EventTarget> newTarget =
michael@0 410 do_QueryInterface(content->FindFirstNonChromeOnlyAccessContent());
michael@0 411 NS_ENSURE_STATE(newTarget);
michael@0 412
michael@0 413 aEvent->originalTarget = target;
michael@0 414 target = newTarget;
michael@0 415 retargeted = true;
michael@0 416 }
michael@0 417 }
michael@0 418
michael@0 419 if (aEvent->mFlags.mOnlyChromeDispatch) {
michael@0 420 nsCOMPtr<nsINode> node = do_QueryInterface(aTarget);
michael@0 421 if (!node) {
michael@0 422 nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aTarget);
michael@0 423 if (win) {
michael@0 424 node = win->GetExtantDoc();
michael@0 425 }
michael@0 426 }
michael@0 427
michael@0 428 NS_ENSURE_STATE(node);
michael@0 429 nsIDocument* doc = node->OwnerDoc();
michael@0 430 if (!nsContentUtils::IsChromeDoc(doc)) {
michael@0 431 nsPIDOMWindow* win = doc ? doc->GetInnerWindow() : nullptr;
michael@0 432 // If we can't dispatch the event to chrome, do nothing.
michael@0 433 EventTarget* piTarget = win ? win->GetParentTarget() : nullptr;
michael@0 434 NS_ENSURE_TRUE(piTarget, NS_OK);
michael@0 435
michael@0 436 // Set the target to be the original dispatch target,
michael@0 437 aEvent->target = target;
michael@0 438 // but use chrome event handler or TabChildGlobal for event target chain.
michael@0 439 target = piTarget;
michael@0 440 }
michael@0 441 }
michael@0 442
michael@0 443 #ifdef DEBUG
michael@0 444 if (!nsContentUtils::IsSafeToRunScript()) {
michael@0 445 nsresult rv = NS_ERROR_FAILURE;
michael@0 446 if (target->GetContextForEventHandlers(&rv) ||
michael@0 447 NS_FAILED(rv)) {
michael@0 448 nsCOMPtr<nsINode> node = do_QueryInterface(target);
michael@0 449 if (node && nsContentUtils::IsChromeDoc(node->OwnerDoc())) {
michael@0 450 NS_WARNING("Fix the caller!");
michael@0 451 } else {
michael@0 452 NS_ERROR("This is unsafe! Fix the caller!");
michael@0 453 }
michael@0 454 }
michael@0 455 }
michael@0 456
michael@0 457 if (aDOMEvent) {
michael@0 458 WidgetEvent* innerEvent = aDOMEvent->GetInternalNSEvent();
michael@0 459 NS_ASSERTION(innerEvent == aEvent,
michael@0 460 "The inner event of aDOMEvent is not the same as aEvent!");
michael@0 461 }
michael@0 462 #endif
michael@0 463
michael@0 464 nsresult rv = NS_OK;
michael@0 465 bool externalDOMEvent = !!(aDOMEvent);
michael@0 466
michael@0 467 // If we have a PresContext, make sure it doesn't die before
michael@0 468 // event dispatching is finished.
michael@0 469 nsRefPtr<nsPresContext> kungFuDeathGrip(aPresContext);
michael@0 470
michael@0 471 ELMCreationDetector cd;
michael@0 472 nsTArray<EventTargetChainItem> chain;
michael@0 473 if (cd.IsMainThread()) {
michael@0 474 if (!sCachedMainThreadChain) {
michael@0 475 sCachedMainThreadChain = new nsTArray<EventTargetChainItem>();
michael@0 476 }
michael@0 477 chain.SwapElements(*sCachedMainThreadChain);
michael@0 478 chain.SetCapacity(128);
michael@0 479 }
michael@0 480
michael@0 481 // Create the event target chain item for the event target.
michael@0 482 EventTargetChainItem* targetEtci =
michael@0 483 EventTargetChainItem::Create(chain, target->GetTargetForEventTargetChain());
michael@0 484 MOZ_ASSERT(&chain[0] == targetEtci);
michael@0 485 if (!targetEtci->IsValid()) {
michael@0 486 EventTargetChainItem::DestroyLast(chain, targetEtci);
michael@0 487 return NS_ERROR_FAILURE;
michael@0 488 }
michael@0 489
michael@0 490 // Make sure that nsIDOMEvent::target and nsIDOMEvent::originalTarget
michael@0 491 // point to the last item in the chain.
michael@0 492 if (!aEvent->target) {
michael@0 493 // Note, CurrentTarget() points always to the object returned by
michael@0 494 // GetTargetForEventTargetChain().
michael@0 495 aEvent->target = targetEtci->CurrentTarget();
michael@0 496 } else {
michael@0 497 // XXX But if the target is already set, use that. This is a hack
michael@0 498 // for the 'load', 'beforeunload' and 'unload' events,
michael@0 499 // which are dispatched to |window| but have document as their target.
michael@0 500 //
michael@0 501 // Make sure that the event target points to the right object.
michael@0 502 aEvent->target = aEvent->target->GetTargetForEventTargetChain();
michael@0 503 NS_ENSURE_STATE(aEvent->target);
michael@0 504 }
michael@0 505
michael@0 506 if (retargeted) {
michael@0 507 aEvent->originalTarget =
michael@0 508 aEvent->originalTarget->GetTargetForEventTargetChain();
michael@0 509 NS_ENSURE_STATE(aEvent->originalTarget);
michael@0 510 }
michael@0 511 else {
michael@0 512 aEvent->originalTarget = aEvent->target;
michael@0 513 }
michael@0 514
michael@0 515 nsCOMPtr<nsIContent> content = do_QueryInterface(aEvent->originalTarget);
michael@0 516 bool isInAnon = (content && content->IsInAnonymousSubtree());
michael@0 517
michael@0 518 aEvent->mFlags.mIsBeingDispatched = true;
michael@0 519
michael@0 520 // Create visitor object and start event dispatching.
michael@0 521 // PreHandleEvent for the original target.
michael@0 522 nsEventStatus status = aEventStatus ? *aEventStatus : nsEventStatus_eIgnore;
michael@0 523 EventChainPreVisitor preVisitor(aPresContext, aEvent, aDOMEvent, status,
michael@0 524 isInAnon);
michael@0 525 targetEtci->PreHandleEvent(preVisitor);
michael@0 526
michael@0 527 if (!preVisitor.mCanHandle && preVisitor.mAutomaticChromeDispatch && content) {
michael@0 528 // Event target couldn't handle the event. Try to propagate to chrome.
michael@0 529 EventTargetChainItem::DestroyLast(chain, targetEtci);
michael@0 530 targetEtci = EventTargetChainItemForChromeTarget(chain, content);
michael@0 531 NS_ENSURE_STATE(targetEtci);
michael@0 532 MOZ_ASSERT(&chain[0] == targetEtci);
michael@0 533 targetEtci->PreHandleEvent(preVisitor);
michael@0 534 }
michael@0 535 if (preVisitor.mCanHandle) {
michael@0 536 // At least the original target can handle the event.
michael@0 537 // Setting the retarget to the |target| simplifies retargeting code.
michael@0 538 nsCOMPtr<EventTarget> t = do_QueryInterface(aEvent->target);
michael@0 539 targetEtci->SetNewTarget(t);
michael@0 540 EventTargetChainItem* topEtci = targetEtci;
michael@0 541 targetEtci = nullptr;
michael@0 542 while (preVisitor.mParentTarget) {
michael@0 543 EventTarget* parentTarget = preVisitor.mParentTarget;
michael@0 544 EventTargetChainItem* parentEtci =
michael@0 545 EventTargetChainItem::Create(chain, preVisitor.mParentTarget, topEtci);
michael@0 546 if (!parentEtci->IsValid()) {
michael@0 547 EventTargetChainItem::DestroyLast(chain, parentEtci);
michael@0 548 rv = NS_ERROR_FAILURE;
michael@0 549 break;
michael@0 550 }
michael@0 551
michael@0 552 // Item needs event retargetting.
michael@0 553 if (preVisitor.mEventTargetAtParent) {
michael@0 554 // Need to set the target of the event
michael@0 555 // so that also the next retargeting works.
michael@0 556 preVisitor.mEvent->target = preVisitor.mEventTargetAtParent;
michael@0 557 parentEtci->SetNewTarget(preVisitor.mEventTargetAtParent);
michael@0 558 }
michael@0 559
michael@0 560 parentEtci->PreHandleEvent(preVisitor);
michael@0 561 if (preVisitor.mCanHandle) {
michael@0 562 topEtci = parentEtci;
michael@0 563 } else {
michael@0 564 EventTargetChainItem::DestroyLast(chain, parentEtci);
michael@0 565 parentEtci = nullptr;
michael@0 566 if (preVisitor.mAutomaticChromeDispatch && content) {
michael@0 567 // Even if the current target can't handle the event, try to
michael@0 568 // propagate to chrome.
michael@0 569 nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
michael@0 570 if (disabledTarget) {
michael@0 571 parentEtci = EventTargetChainItemForChromeTarget(chain,
michael@0 572 disabledTarget,
michael@0 573 topEtci);
michael@0 574 if (parentEtci) {
michael@0 575 parentEtci->PreHandleEvent(preVisitor);
michael@0 576 if (preVisitor.mCanHandle) {
michael@0 577 chain[0].SetNewTarget(parentTarget);
michael@0 578 topEtci = parentEtci;
michael@0 579 continue;
michael@0 580 }
michael@0 581 }
michael@0 582 }
michael@0 583 }
michael@0 584 break;
michael@0 585 }
michael@0 586 }
michael@0 587 if (NS_SUCCEEDED(rv)) {
michael@0 588 if (aTargets) {
michael@0 589 aTargets->Clear();
michael@0 590 aTargets->SetCapacity(chain.Length());
michael@0 591 for (uint32_t i = 0; i < chain.Length(); ++i) {
michael@0 592 aTargets->AppendObject(chain[i].CurrentTarget()->GetTargetForDOMEvent());
michael@0 593 }
michael@0 594 } else {
michael@0 595 // Event target chain is created. Handle the chain.
michael@0 596 EventChainPostVisitor postVisitor(preVisitor);
michael@0 597 EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
michael@0 598 aCallback, cd);
michael@0 599
michael@0 600 preVisitor.mEventStatus = postVisitor.mEventStatus;
michael@0 601 // If the DOM event was created during event flow.
michael@0 602 if (!preVisitor.mDOMEvent && postVisitor.mDOMEvent) {
michael@0 603 preVisitor.mDOMEvent = postVisitor.mDOMEvent;
michael@0 604 }
michael@0 605 }
michael@0 606 }
michael@0 607 }
michael@0 608
michael@0 609 // Note, EventTargetChainItem objects are deleted when the chain goes out of
michael@0 610 // the scope.
michael@0 611
michael@0 612 aEvent->mFlags.mIsBeingDispatched = false;
michael@0 613 aEvent->mFlags.mDispatchedAtLeastOnce = true;
michael@0 614
michael@0 615 if (!externalDOMEvent && preVisitor.mDOMEvent) {
michael@0 616 // An dom::Event was created while dispatching the event.
michael@0 617 // Duplicate private data if someone holds a pointer to it.
michael@0 618 nsrefcnt rc = 0;
michael@0 619 NS_RELEASE2(preVisitor.mDOMEvent, rc);
michael@0 620 if (preVisitor.mDOMEvent) {
michael@0 621 preVisitor.mDOMEvent->DuplicatePrivateData();
michael@0 622 }
michael@0 623 }
michael@0 624
michael@0 625 if (aEventStatus) {
michael@0 626 *aEventStatus = preVisitor.mEventStatus;
michael@0 627 }
michael@0 628
michael@0 629 if (cd.IsMainThread() && chain.Capacity() == 128 && sCachedMainThreadChain) {
michael@0 630 chain.ClearAndRetainStorage();
michael@0 631 chain.SwapElements(*sCachedMainThreadChain);
michael@0 632 }
michael@0 633
michael@0 634 return rv;
michael@0 635 }
michael@0 636
michael@0 637 /* static */ nsresult
michael@0 638 EventDispatcher::DispatchDOMEvent(nsISupports* aTarget,
michael@0 639 WidgetEvent* aEvent,
michael@0 640 nsIDOMEvent* aDOMEvent,
michael@0 641 nsPresContext* aPresContext,
michael@0 642 nsEventStatus* aEventStatus)
michael@0 643 {
michael@0 644 if (aDOMEvent) {
michael@0 645 WidgetEvent* innerEvent = aDOMEvent->GetInternalNSEvent();
michael@0 646 NS_ENSURE_TRUE(innerEvent, NS_ERROR_ILLEGAL_VALUE);
michael@0 647
michael@0 648 bool dontResetTrusted = false;
michael@0 649 if (innerEvent->mFlags.mDispatchedAtLeastOnce) {
michael@0 650 innerEvent->target = nullptr;
michael@0 651 innerEvent->originalTarget = nullptr;
michael@0 652 } else {
michael@0 653 aDOMEvent->GetIsTrusted(&dontResetTrusted);
michael@0 654 }
michael@0 655
michael@0 656 if (!dontResetTrusted) {
michael@0 657 //Check security state to determine if dispatcher is trusted
michael@0 658 aDOMEvent->SetTrusted(nsContentUtils::ThreadsafeIsCallerChrome());
michael@0 659 }
michael@0 660
michael@0 661 return EventDispatcher::Dispatch(aTarget, aPresContext, innerEvent,
michael@0 662 aDOMEvent, aEventStatus);
michael@0 663 } else if (aEvent) {
michael@0 664 return EventDispatcher::Dispatch(aTarget, aPresContext, aEvent,
michael@0 665 aDOMEvent, aEventStatus);
michael@0 666 }
michael@0 667 return NS_ERROR_ILLEGAL_VALUE;
michael@0 668 }
michael@0 669
michael@0 670 /* static */ nsresult
michael@0 671 EventDispatcher::CreateEvent(EventTarget* aOwner,
michael@0 672 nsPresContext* aPresContext,
michael@0 673 WidgetEvent* aEvent,
michael@0 674 const nsAString& aEventType,
michael@0 675 nsIDOMEvent** aDOMEvent)
michael@0 676 {
michael@0 677 *aDOMEvent = nullptr;
michael@0 678
michael@0 679 if (aEvent) {
michael@0 680 switch(aEvent->eventStructType) {
michael@0 681 case NS_MUTATION_EVENT:
michael@0 682 return NS_NewDOMMutationEvent(aDOMEvent, aOwner, aPresContext,
michael@0 683 aEvent->AsMutationEvent());
michael@0 684 case NS_GUI_EVENT:
michael@0 685 case NS_SCROLLPORT_EVENT:
michael@0 686 case NS_UI_EVENT:
michael@0 687 return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext,
michael@0 688 aEvent->AsGUIEvent());
michael@0 689 case NS_SCROLLAREA_EVENT:
michael@0 690 return NS_NewDOMScrollAreaEvent(aDOMEvent, aOwner, aPresContext,
michael@0 691 aEvent->AsScrollAreaEvent());
michael@0 692 case NS_KEY_EVENT:
michael@0 693 return NS_NewDOMKeyboardEvent(aDOMEvent, aOwner, aPresContext,
michael@0 694 aEvent->AsKeyboardEvent());
michael@0 695 case NS_COMPOSITION_EVENT:
michael@0 696 return NS_NewDOMCompositionEvent(aDOMEvent, aOwner, aPresContext,
michael@0 697 aEvent->AsCompositionEvent());
michael@0 698 case NS_MOUSE_EVENT:
michael@0 699 return NS_NewDOMMouseEvent(aDOMEvent, aOwner, aPresContext,
michael@0 700 aEvent->AsMouseEvent());
michael@0 701 case NS_FOCUS_EVENT:
michael@0 702 return NS_NewDOMFocusEvent(aDOMEvent, aOwner, aPresContext,
michael@0 703 aEvent->AsFocusEvent());
michael@0 704 case NS_MOUSE_SCROLL_EVENT:
michael@0 705 return NS_NewDOMMouseScrollEvent(aDOMEvent, aOwner, aPresContext,
michael@0 706 aEvent->AsMouseScrollEvent());
michael@0 707 case NS_WHEEL_EVENT:
michael@0 708 return NS_NewDOMWheelEvent(aDOMEvent, aOwner, aPresContext,
michael@0 709 aEvent->AsWheelEvent());
michael@0 710 case NS_EDITOR_INPUT_EVENT:
michael@0 711 return NS_NewDOMInputEvent(aDOMEvent, aOwner, aPresContext,
michael@0 712 aEvent->AsEditorInputEvent());
michael@0 713 case NS_DRAG_EVENT:
michael@0 714 return NS_NewDOMDragEvent(aDOMEvent, aOwner, aPresContext,
michael@0 715 aEvent->AsDragEvent());
michael@0 716 case NS_TEXT_EVENT:
michael@0 717 return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext,
michael@0 718 aEvent->AsTextEvent());
michael@0 719 case NS_CLIPBOARD_EVENT:
michael@0 720 return NS_NewDOMClipboardEvent(aDOMEvent, aOwner, aPresContext,
michael@0 721 aEvent->AsClipboardEvent());
michael@0 722 case NS_SVGZOOM_EVENT:
michael@0 723 return NS_NewDOMSVGZoomEvent(aDOMEvent, aOwner, aPresContext,
michael@0 724 aEvent->AsGUIEvent());
michael@0 725 case NS_SMIL_TIME_EVENT:
michael@0 726 return NS_NewDOMTimeEvent(aDOMEvent, aOwner, aPresContext, aEvent);
michael@0 727
michael@0 728 case NS_COMMAND_EVENT:
michael@0 729 return NS_NewDOMCommandEvent(aDOMEvent, aOwner, aPresContext,
michael@0 730 aEvent->AsCommandEvent());
michael@0 731 case NS_SIMPLE_GESTURE_EVENT:
michael@0 732 return NS_NewDOMSimpleGestureEvent(aDOMEvent, aOwner, aPresContext,
michael@0 733 aEvent->AsSimpleGestureEvent());
michael@0 734 case NS_POINTER_EVENT:
michael@0 735 return NS_NewDOMPointerEvent(aDOMEvent, aOwner, aPresContext,
michael@0 736 aEvent->AsPointerEvent());
michael@0 737 case NS_TOUCH_EVENT:
michael@0 738 return NS_NewDOMTouchEvent(aDOMEvent, aOwner, aPresContext,
michael@0 739 aEvent->AsTouchEvent());
michael@0 740 case NS_TRANSITION_EVENT:
michael@0 741 return NS_NewDOMTransitionEvent(aDOMEvent, aOwner, aPresContext,
michael@0 742 aEvent->AsTransitionEvent());
michael@0 743 case NS_ANIMATION_EVENT:
michael@0 744 return NS_NewDOMAnimationEvent(aDOMEvent, aOwner, aPresContext,
michael@0 745 aEvent->AsAnimationEvent());
michael@0 746 default:
michael@0 747 // For all other types of events, create a vanilla event object.
michael@0 748 return NS_NewDOMEvent(aDOMEvent, aOwner, aPresContext, aEvent);
michael@0 749 }
michael@0 750 }
michael@0 751
michael@0 752 // And if we didn't get an event, check the type argument.
michael@0 753
michael@0 754 if (aEventType.LowerCaseEqualsLiteral("mouseevent") ||
michael@0 755 aEventType.LowerCaseEqualsLiteral("mouseevents") ||
michael@0 756 aEventType.LowerCaseEqualsLiteral("popupevents"))
michael@0 757 return NS_NewDOMMouseEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 758 if (aEventType.LowerCaseEqualsLiteral("mousescrollevents"))
michael@0 759 return NS_NewDOMMouseScrollEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 760 if (aEventType.LowerCaseEqualsLiteral("dragevent") ||
michael@0 761 aEventType.LowerCaseEqualsLiteral("dragevents"))
michael@0 762 return NS_NewDOMDragEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 763 if (aEventType.LowerCaseEqualsLiteral("keyboardevent") ||
michael@0 764 aEventType.LowerCaseEqualsLiteral("keyevents"))
michael@0 765 return NS_NewDOMKeyboardEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 766 if (aEventType.LowerCaseEqualsLiteral("compositionevent"))
michael@0 767 return NS_NewDOMCompositionEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 768 if (aEventType.LowerCaseEqualsLiteral("mutationevent") ||
michael@0 769 aEventType.LowerCaseEqualsLiteral("mutationevents"))
michael@0 770 return NS_NewDOMMutationEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 771 if (aEventType.LowerCaseEqualsLiteral("textevent") ||
michael@0 772 aEventType.LowerCaseEqualsLiteral("textevents"))
michael@0 773 return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 774 if (aEventType.LowerCaseEqualsLiteral("popupblockedevents"))
michael@0 775 return NS_NewDOMPopupBlockedEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 776 if (aEventType.LowerCaseEqualsLiteral("deviceorientationevent"))
michael@0 777 return NS_NewDOMDeviceOrientationEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 778 if (aEventType.LowerCaseEqualsLiteral("devicemotionevent"))
michael@0 779 return NS_NewDOMDeviceMotionEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 780 if (aEventType.LowerCaseEqualsLiteral("uievent") ||
michael@0 781 aEventType.LowerCaseEqualsLiteral("uievents"))
michael@0 782 return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 783 if (aEventType.LowerCaseEqualsLiteral("event") ||
michael@0 784 aEventType.LowerCaseEqualsLiteral("events") ||
michael@0 785 aEventType.LowerCaseEqualsLiteral("htmlevents") ||
michael@0 786 aEventType.LowerCaseEqualsLiteral("svgevent") ||
michael@0 787 aEventType.LowerCaseEqualsLiteral("svgevents"))
michael@0 788 return NS_NewDOMEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 789 if (aEventType.LowerCaseEqualsLiteral("svgzoomevent") ||
michael@0 790 aEventType.LowerCaseEqualsLiteral("svgzoomevents"))
michael@0 791 return NS_NewDOMSVGZoomEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 792 if (aEventType.LowerCaseEqualsLiteral("timeevent") ||
michael@0 793 aEventType.LowerCaseEqualsLiteral("timeevents"))
michael@0 794 return NS_NewDOMTimeEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 795 if (aEventType.LowerCaseEqualsLiteral("xulcommandevent") ||
michael@0 796 aEventType.LowerCaseEqualsLiteral("xulcommandevents"))
michael@0 797 return NS_NewDOMXULCommandEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 798 if (aEventType.LowerCaseEqualsLiteral("commandevent") ||
michael@0 799 aEventType.LowerCaseEqualsLiteral("commandevents"))
michael@0 800 return NS_NewDOMCommandEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 801 if (aEventType.LowerCaseEqualsLiteral("elementreplace"))
michael@0 802 return NS_NewDOMElementReplaceEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 803 if (aEventType.LowerCaseEqualsLiteral("datacontainerevent") ||
michael@0 804 aEventType.LowerCaseEqualsLiteral("datacontainerevents"))
michael@0 805 return NS_NewDOMDataContainerEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 806 if (aEventType.LowerCaseEqualsLiteral("messageevent"))
michael@0 807 return NS_NewDOMMessageEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 808 if (aEventType.LowerCaseEqualsLiteral("notifypaintevent"))
michael@0 809 return NS_NewDOMNotifyPaintEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 810 if (aEventType.LowerCaseEqualsLiteral("simplegestureevent"))
michael@0 811 return NS_NewDOMSimpleGestureEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 812 if (aEventType.LowerCaseEqualsLiteral("beforeunloadevent"))
michael@0 813 return NS_NewDOMBeforeUnloadEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 814 if (aEventType.LowerCaseEqualsLiteral("pagetransition"))
michael@0 815 return NS_NewDOMPageTransitionEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 816 if (aEventType.LowerCaseEqualsLiteral("domtransaction"))
michael@0 817 return NS_NewDOMDOMTransactionEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 818 if (aEventType.LowerCaseEqualsLiteral("scrollareaevent"))
michael@0 819 return NS_NewDOMScrollAreaEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 820 if (aEventType.LowerCaseEqualsLiteral("popstateevent"))
michael@0 821 return NS_NewDOMPopStateEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 822 if (aEventType.LowerCaseEqualsLiteral("closeevent"))
michael@0 823 return NS_NewDOMCloseEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 824 if (aEventType.LowerCaseEqualsLiteral("touchevent") &&
michael@0 825 TouchEvent::PrefEnabled())
michael@0 826 return NS_NewDOMTouchEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 827 if (aEventType.LowerCaseEqualsLiteral("hashchangeevent"))
michael@0 828 return NS_NewDOMHashChangeEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 829 if (aEventType.LowerCaseEqualsLiteral("customevent"))
michael@0 830 return NS_NewDOMCustomEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 831 if (aEventType.LowerCaseEqualsLiteral("mozsmsevent"))
michael@0 832 return NS_NewDOMMozSmsEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 833 if (aEventType.LowerCaseEqualsLiteral("mozmmsevent"))
michael@0 834 return NS_NewDOMMozMmsEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 835 if (aEventType.LowerCaseEqualsLiteral("storageevent")) {
michael@0 836 return NS_NewDOMStorageEvent(aDOMEvent, aOwner, aPresContext, nullptr);
michael@0 837 }
michael@0 838 // NEW EVENT TYPES SHOULD NOT BE ADDED HERE; THEY SHOULD USE ONLY EVENT
michael@0 839 // CONSTRUCTORS
michael@0 840
michael@0 841 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
michael@0 842 }
michael@0 843
michael@0 844 } // namespace mozilla

mercurial