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.

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

mercurial