dom/events/EventListenerManager.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: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 // Microsoft's API Name hackery sucks
     7 #undef CreateEvent
     9 #include "mozilla/BasicEvents.h"
    10 #include "mozilla/EventDispatcher.h"
    11 #include "mozilla/EventListenerManager.h"
    12 #ifdef MOZ_B2G
    13 #include "mozilla/Hal.h"
    14 #endif // #ifdef MOZ_B2G
    15 #include "mozilla/HalSensor.h"
    16 #include "mozilla/InternalMutationEvent.h"
    17 #include "mozilla/JSEventHandler.h"
    18 #include "mozilla/MemoryReporting.h"
    19 #include "mozilla/dom/BindingUtils.h"
    20 #include "mozilla/dom/Element.h"
    21 #include "mozilla/dom/Event.h"
    23 #include "EventListenerService.h"
    24 #include "nsCOMArray.h"
    25 #include "nsCOMPtr.h"
    26 #include "nsContentUtils.h"
    27 #include "nsDOMCID.h"
    28 #include "nsError.h"
    29 #include "nsGkAtoms.h"
    30 #include "nsIContent.h"
    31 #include "nsIContentSecurityPolicy.h"
    32 #include "nsIDocument.h"
    33 #include "nsIDOMEventListener.h"
    34 #include "nsIScriptGlobalObject.h"
    35 #include "nsISupports.h"
    36 #include "nsIXPConnect.h"
    37 #include "nsJSUtils.h"
    38 #include "nsNameSpaceManager.h"
    39 #include "nsPIDOMWindow.h"
    40 #include "nsSandboxFlags.h"
    41 #include "xpcpublic.h"
    43 namespace mozilla {
    45 using namespace dom;
    46 using namespace hal;
    48 #define EVENT_TYPE_EQUALS(ls, type, userType, typeString, allEvents) \
    49   ((ls->mEventType == type &&                                        \
    50     (ls->mEventType != NS_USER_DEFINED_EVENT ||                      \
    51     (mIsMainThreadELM && ls->mTypeAtom == userType) ||               \
    52     (!mIsMainThreadELM && ls->mTypeString.Equals(typeString)))) ||   \
    53    (allEvents && ls->mAllEvents))
    55 static const uint32_t kAllMutationBits =
    56   NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED |
    57   NS_EVENT_BITS_MUTATION_NODEINSERTED |
    58   NS_EVENT_BITS_MUTATION_NODEREMOVED |
    59   NS_EVENT_BITS_MUTATION_NODEREMOVEDFROMDOCUMENT |
    60   NS_EVENT_BITS_MUTATION_NODEINSERTEDINTODOCUMENT |
    61   NS_EVENT_BITS_MUTATION_ATTRMODIFIED |
    62   NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED;
    64 static uint32_t
    65 MutationBitForEventType(uint32_t aEventType)
    66 {
    67   switch (aEventType) {
    68     case NS_MUTATION_SUBTREEMODIFIED:
    69       return NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED;
    70     case NS_MUTATION_NODEINSERTED:
    71       return NS_EVENT_BITS_MUTATION_NODEINSERTED;
    72     case NS_MUTATION_NODEREMOVED:
    73       return NS_EVENT_BITS_MUTATION_NODEREMOVED;
    74     case NS_MUTATION_NODEREMOVEDFROMDOCUMENT:
    75       return NS_EVENT_BITS_MUTATION_NODEREMOVEDFROMDOCUMENT;
    76     case NS_MUTATION_NODEINSERTEDINTODOCUMENT:
    77       return NS_EVENT_BITS_MUTATION_NODEINSERTEDINTODOCUMENT;
    78     case NS_MUTATION_ATTRMODIFIED:
    79       return NS_EVENT_BITS_MUTATION_ATTRMODIFIED;
    80     case NS_MUTATION_CHARACTERDATAMODIFIED:
    81       return NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED;
    82     default:
    83       break;
    84   }
    85   return 0;
    86 }
    88 uint32_t EventListenerManager::sMainThreadCreatedCount = 0;
    90 EventListenerManager::EventListenerManager(EventTarget* aTarget)
    91   : mMayHavePaintEventListener(false)
    92   , mMayHaveMutationListeners(false)
    93   , mMayHaveCapturingListeners(false)
    94   , mMayHaveSystemGroupListeners(false)
    95   , mMayHaveTouchEventListener(false)
    96   , mMayHaveMouseEnterLeaveEventListener(false)
    97   , mMayHavePointerEnterLeaveEventListener(false)
    98   , mClearingListeners(false)
    99   , mIsMainThreadELM(NS_IsMainThread())
   100   , mNoListenerForEvent(0)
   101   , mTarget(aTarget)
   102 {
   103   NS_ASSERTION(aTarget, "unexpected null pointer");
   105   if (mIsMainThreadELM) {
   106     ++sMainThreadCreatedCount;
   107   }
   108 }
   110 EventListenerManager::~EventListenerManager()
   111 {
   112   // If your code fails this assertion, a possible reason is that
   113   // a class did not call our Disconnect() manually. Note that
   114   // this class can have Disconnect called in one of two ways:
   115   // if it is part of a cycle, then in Unlink() (such a cycle
   116   // would be with one of the listeners, not mTarget which is weak).
   117   // If not part of a cycle, then Disconnect must be called manually,
   118   // typically from the destructor of the owner class (mTarget).
   119   // XXX azakai: Is there any reason to not just call Disconnect
   120   //             from right here, if not previously called?
   121   NS_ASSERTION(!mTarget, "didn't call Disconnect");
   122   RemoveAllListeners();
   123 }
   125 void
   126 EventListenerManager::RemoveAllListeners()
   127 {
   128   if (mClearingListeners) {
   129     return;
   130   }
   131   mClearingListeners = true;
   132   mListeners.Clear();
   133   mClearingListeners = false;
   134 }
   136 void
   137 EventListenerManager::Shutdown()
   138 {
   139   Event::Shutdown();
   140 }
   142 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(EventListenerManager, AddRef)
   143 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(EventListenerManager, Release)
   145 inline void
   146 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
   147                             EventListenerManager::Listener& aField,
   148                             const char* aName,
   149                             unsigned aFlags)
   150 {
   151   if (MOZ_UNLIKELY(aCallback.WantDebugInfo())) {
   152     nsAutoCString name;
   153     name.AppendASCII(aName);
   154     if (aField.mTypeAtom) {
   155       name.AppendASCII(" event=");
   156       name.Append(nsAtomCString(aField.mTypeAtom));
   157       name.AppendASCII(" listenerType=");
   158       name.AppendInt(aField.mListenerType);
   159       name.AppendASCII(" ");
   160     }
   161     CycleCollectionNoteChild(aCallback, aField.mListener.GetISupports(), name.get(),
   162                              aFlags);
   163   } else {
   164     CycleCollectionNoteChild(aCallback, aField.mListener.GetISupports(), aName,
   165                              aFlags);
   166   }
   167 }
   169 NS_IMPL_CYCLE_COLLECTION_CLASS(EventListenerManager)
   171 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(EventListenerManager)
   172   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListeners)
   173 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   175 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(EventListenerManager)
   176   tmp->Disconnect();
   177 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   180 nsPIDOMWindow*
   181 EventListenerManager::GetInnerWindowForTarget()
   182 {
   183   nsCOMPtr<nsINode> node = do_QueryInterface(mTarget);
   184   if (node) {
   185     // XXX sXBL/XBL2 issue -- do we really want the owner here?  What
   186     // if that's the XBL document?
   187     return node->OwnerDoc()->GetInnerWindow();
   188   }
   190   nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
   191   return window;
   192 }
   194 already_AddRefed<nsPIDOMWindow>
   195 EventListenerManager::GetTargetAsInnerWindow() const
   196 {
   197   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mTarget);
   198   if (!window) {
   199     return nullptr;
   200   }
   202   NS_ASSERTION(window->IsInnerWindow(), "Target should not be an outer window");
   203   return window.forget();
   204 }
   206 void
   207 EventListenerManager::AddEventListenerInternal(
   208                         const EventListenerHolder& aListenerHolder,
   209                         uint32_t aType,
   210                         nsIAtom* aTypeAtom,
   211                         const nsAString& aTypeString,
   212                         const EventListenerFlags& aFlags,
   213                         bool aHandler,
   214                         bool aAllEvents)
   215 {
   216   MOZ_ASSERT((NS_IsMainThread() && aType && aTypeAtom) || // Main thread
   217              (!NS_IsMainThread() && aType && !aTypeString.IsEmpty()) || // non-main-thread
   218              aAllEvents, "Missing type"); // all-events listener
   220   if (!aListenerHolder || mClearingListeners) {
   221     return;
   222   }
   224   // Since there is no public API to call us with an EventListenerHolder, we
   225   // know that there's an EventListenerHolder on the stack holding a strong ref
   226   // to the listener.
   228   Listener* listener;
   229   uint32_t count = mListeners.Length();
   230   for (uint32_t i = 0; i < count; i++) {
   231     listener = &mListeners.ElementAt(i);
   232     // mListener == aListenerHolder is the last one, since it can be a bit slow.
   233     if (listener->mListenerIsHandler == aHandler &&
   234         listener->mFlags == aFlags &&
   235         EVENT_TYPE_EQUALS(listener, aType, aTypeAtom, aTypeString,
   236                           aAllEvents) &&
   237         listener->mListener == aListenerHolder) {
   238       return;
   239     }
   240   }
   242   mNoListenerForEvent = NS_EVENT_NULL;
   243   mNoListenerForEventAtom = nullptr;
   245   listener = aAllEvents ? mListeners.InsertElementAt(0) :
   246                           mListeners.AppendElement();
   247   listener->mListener = aListenerHolder;
   248   MOZ_ASSERT(aType < PR_UINT16_MAX);
   249   listener->mEventType = aType;
   250   listener->mTypeString = aTypeString;
   251   listener->mTypeAtom = aTypeAtom;
   252   listener->mFlags = aFlags;
   253   listener->mListenerIsHandler = aHandler;
   254   listener->mHandlerIsString = false;
   255   listener->mAllEvents = aAllEvents;
   257   // Detect the type of event listener.
   258   nsCOMPtr<nsIXPConnectWrappedJS> wjs;
   259   if (aFlags.mListenerIsJSListener) {
   260     MOZ_ASSERT(!aListenerHolder.HasWebIDLCallback());
   261     listener->mListenerType = Listener::eJSEventListener;
   262   } else if (aListenerHolder.HasWebIDLCallback()) {
   263     listener->mListenerType = Listener::eWebIDLListener;
   264   } else if ((wjs = do_QueryInterface(aListenerHolder.GetXPCOMCallback()))) {
   265     listener->mListenerType = Listener::eWrappedJSListener;
   266   } else {
   267     listener->mListenerType = Listener::eNativeListener;
   268   }
   271   if (aFlags.mInSystemGroup) {
   272     mMayHaveSystemGroupListeners = true;
   273   }
   274   if (aFlags.mCapture) {
   275     mMayHaveCapturingListeners = true;
   276   }
   278   if (aType == NS_AFTERPAINT) {
   279     mMayHavePaintEventListener = true;
   280     nsPIDOMWindow* window = GetInnerWindowForTarget();
   281     if (window) {
   282       window->SetHasPaintEventListeners();
   283     }
   284   } else if (aType >= NS_MUTATION_START && aType <= NS_MUTATION_END) {
   285     // For mutation listeners, we need to update the global bit on the DOM window.
   286     // Otherwise we won't actually fire the mutation event.
   287     mMayHaveMutationListeners = true;
   288     // Go from our target to the nearest enclosing DOM window.
   289     nsPIDOMWindow* window = GetInnerWindowForTarget();
   290     if (window) {
   291       nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
   292       if (doc) {
   293         doc->WarnOnceAbout(nsIDocument::eMutationEvent);
   294       }
   295       // If aType is NS_MUTATION_SUBTREEMODIFIED, we need to listen all
   296       // mutations. nsContentUtils::HasMutationListeners relies on this.
   297       window->SetMutationListeners((aType == NS_MUTATION_SUBTREEMODIFIED) ?
   298                                    kAllMutationBits :
   299                                    MutationBitForEventType(aType));
   300     }
   301   } else if (aTypeAtom == nsGkAtoms::ondeviceorientation) {
   302     EnableDevice(NS_DEVICE_ORIENTATION);
   303   } else if (aTypeAtom == nsGkAtoms::ondeviceproximity || aTypeAtom == nsGkAtoms::onuserproximity) {
   304     EnableDevice(NS_DEVICE_PROXIMITY);
   305   } else if (aTypeAtom == nsGkAtoms::ondevicelight) {
   306     EnableDevice(NS_DEVICE_LIGHT);
   307   } else if (aTypeAtom == nsGkAtoms::ondevicemotion) {
   308     EnableDevice(NS_DEVICE_MOTION);
   309 #ifdef MOZ_B2G
   310   } else if (aTypeAtom == nsGkAtoms::onmoztimechange) {
   311     nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
   312     if (window) {
   313       window->EnableTimeChangeNotifications();
   314     }
   315   } else if (aTypeAtom == nsGkAtoms::onmoznetworkupload) {
   316     nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
   317     if (window) {
   318       window->EnableNetworkEvent(NS_NETWORK_UPLOAD_EVENT);
   319     }
   320   } else if (aTypeAtom == nsGkAtoms::onmoznetworkdownload) {
   321     nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
   322     if (window) {
   323       window->EnableNetworkEvent(NS_NETWORK_DOWNLOAD_EVENT);
   324     }
   325 #endif // MOZ_B2G
   326   } else if (aTypeAtom == nsGkAtoms::ontouchstart ||
   327              aTypeAtom == nsGkAtoms::ontouchend ||
   328              aTypeAtom == nsGkAtoms::ontouchmove ||
   329              aTypeAtom == nsGkAtoms::ontouchenter ||
   330              aTypeAtom == nsGkAtoms::ontouchleave ||
   331              aTypeAtom == nsGkAtoms::ontouchcancel) {
   332     mMayHaveTouchEventListener = true;
   333     nsPIDOMWindow* window = GetInnerWindowForTarget();
   334     // we don't want touchevent listeners added by scrollbars to flip this flag
   335     // so we ignore listeners created with system event flag
   336     if (window && !aFlags.mInSystemGroup) {
   337       window->SetHasTouchEventListeners();
   338     }
   339   } else if (aType >= NS_POINTER_EVENT_START && aType <= NS_POINTER_LOST_CAPTURE) {
   340     nsPIDOMWindow* window = GetInnerWindowForTarget();
   341     if (aTypeAtom == nsGkAtoms::onpointerenter ||
   342         aTypeAtom == nsGkAtoms::onpointerleave) {
   343       mMayHavePointerEnterLeaveEventListener = true;
   344       if (window) {
   345 #ifdef DEBUG
   346         nsCOMPtr<nsIDocument> d = window->GetExtantDoc();
   347         NS_WARN_IF_FALSE(!nsContentUtils::IsChromeDoc(d),
   348                          "Please do not use pointerenter/leave events in chrome. "
   349                          "They are slower than pointerover/out!");
   350 #endif
   351         window->SetHasPointerEnterLeaveEventListeners();
   352       }
   353     }
   354   } else if (aTypeAtom == nsGkAtoms::onmouseenter ||
   355              aTypeAtom == nsGkAtoms::onmouseleave) {
   356     mMayHaveMouseEnterLeaveEventListener = true;
   357     nsPIDOMWindow* window = GetInnerWindowForTarget();
   358     if (window) {
   359 #ifdef DEBUG
   360       nsCOMPtr<nsIDocument> d = window->GetExtantDoc();
   361       NS_WARN_IF_FALSE(!nsContentUtils::IsChromeDoc(d),
   362                        "Please do not use mouseenter/leave events in chrome. "
   363                        "They are slower than mouseover/out!");
   364 #endif
   365       window->SetHasMouseEnterLeaveEventListeners();
   366     }
   367 #ifdef MOZ_GAMEPAD
   368   } else if (aType >= NS_GAMEPAD_START &&
   369              aType <= NS_GAMEPAD_END) {
   370     nsPIDOMWindow* window = GetInnerWindowForTarget();
   371     if (window) {
   372       window->SetHasGamepadEventListener();
   373     }
   374 #endif
   375   }
   376   if (aTypeAtom && mTarget) {
   377     mTarget->EventListenerAdded(aTypeAtom);
   378   }
   379 }
   381 bool
   382 EventListenerManager::IsDeviceType(uint32_t aType)
   383 {
   384   switch (aType) {
   385     case NS_DEVICE_ORIENTATION:
   386     case NS_DEVICE_MOTION:
   387     case NS_DEVICE_LIGHT:
   388     case NS_DEVICE_PROXIMITY:
   389     case NS_USER_PROXIMITY:
   390       return true;
   391     default:
   392       break;
   393   }
   394   return false;
   395 }
   397 void
   398 EventListenerManager::EnableDevice(uint32_t aType)
   399 {
   400   nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
   401   if (!window) {
   402     return;
   403   }
   405   switch (aType) {
   406     case NS_DEVICE_ORIENTATION:
   407       window->EnableDeviceSensor(SENSOR_ORIENTATION);
   408       break;
   409     case NS_DEVICE_PROXIMITY:
   410     case NS_USER_PROXIMITY:
   411       window->EnableDeviceSensor(SENSOR_PROXIMITY);
   412       break;
   413     case NS_DEVICE_LIGHT:
   414       window->EnableDeviceSensor(SENSOR_LIGHT);
   415       break;
   416     case NS_DEVICE_MOTION:
   417       window->EnableDeviceSensor(SENSOR_ACCELERATION);
   418       window->EnableDeviceSensor(SENSOR_LINEAR_ACCELERATION);
   419       window->EnableDeviceSensor(SENSOR_GYROSCOPE);
   420       break;
   421     default:
   422       NS_WARNING("Enabling an unknown device sensor.");
   423       break;
   424   }
   425 }
   427 void
   428 EventListenerManager::DisableDevice(uint32_t aType)
   429 {
   430   nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
   431   if (!window) {
   432     return;
   433   }
   435   switch (aType) {
   436     case NS_DEVICE_ORIENTATION:
   437       window->DisableDeviceSensor(SENSOR_ORIENTATION);
   438       break;
   439     case NS_DEVICE_MOTION:
   440       window->DisableDeviceSensor(SENSOR_ACCELERATION);
   441       window->DisableDeviceSensor(SENSOR_LINEAR_ACCELERATION);
   442       window->DisableDeviceSensor(SENSOR_GYROSCOPE);
   443       break;
   444     case NS_DEVICE_PROXIMITY:
   445     case NS_USER_PROXIMITY:
   446       window->DisableDeviceSensor(SENSOR_PROXIMITY);
   447       break;
   448     case NS_DEVICE_LIGHT:
   449       window->DisableDeviceSensor(SENSOR_LIGHT);
   450       break;
   451     default:
   452       NS_WARNING("Disabling an unknown device sensor.");
   453       break;
   454   }
   455 }
   457 void
   458 EventListenerManager::RemoveEventListenerInternal(
   459                         const EventListenerHolder& aListenerHolder,
   460                         uint32_t aType,
   461                         nsIAtom* aUserType,
   462                         const nsAString& aTypeString,
   463                         const EventListenerFlags& aFlags,
   464                         bool aAllEvents)
   465 {
   466   if (!aListenerHolder || !aType || mClearingListeners) {
   467     return;
   468   }
   470   Listener* listener;
   472   uint32_t count = mListeners.Length();
   473   uint32_t typeCount = 0;
   474   bool deviceType = IsDeviceType(aType);
   475 #ifdef MOZ_B2G
   476   bool timeChangeEvent = (aType == NS_MOZ_TIME_CHANGE_EVENT);
   477   bool networkEvent = (aType == NS_NETWORK_UPLOAD_EVENT ||
   478                        aType == NS_NETWORK_DOWNLOAD_EVENT);
   479 #endif // MOZ_B2G
   481   for (uint32_t i = 0; i < count; ++i) {
   482     listener = &mListeners.ElementAt(i);
   483     if (EVENT_TYPE_EQUALS(listener, aType, aUserType, aTypeString,
   484                           aAllEvents)) {
   485       ++typeCount;
   486       if (listener->mListener == aListenerHolder &&
   487           listener->mFlags.EqualsIgnoringTrustness(aFlags)) {
   488         nsRefPtr<EventListenerManager> kungFuDeathGrip(this);
   489         mListeners.RemoveElementAt(i);
   490         --count;
   491         mNoListenerForEvent = NS_EVENT_NULL;
   492         mNoListenerForEventAtom = nullptr;
   493         if (mTarget && aUserType) {
   494           mTarget->EventListenerRemoved(aUserType);
   495         }
   497         if (!deviceType
   498 #ifdef MOZ_B2G
   499             && !timeChangeEvent && !networkEvent
   500 #endif // MOZ_B2G
   501             ) {
   502           return;
   503         }
   504         --typeCount;
   505       }
   506     }
   507   }
   509   if (!aAllEvents && deviceType && typeCount == 0) {
   510     DisableDevice(aType);
   511 #ifdef MOZ_B2G
   512   } else if (timeChangeEvent && typeCount == 0) {
   513     nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
   514     if (window) {
   515       window->DisableTimeChangeNotifications();
   516     }
   517   } else if (!aAllEvents && networkEvent && typeCount == 0) {
   518     nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
   519     if (window) {
   520       window->DisableNetworkEvent(aType);
   521     }
   522 #endif // MOZ_B2G
   523   }
   524 }
   526 bool
   527 EventListenerManager::ListenerCanHandle(Listener* aListener,
   528                                         WidgetEvent* aEvent)
   529 {
   530   // This is slightly different from EVENT_TYPE_EQUALS in that it returns
   531   // true even when aEvent->message == NS_USER_DEFINED_EVENT and
   532   // aListener=>mEventType != NS_USER_DEFINED_EVENT as long as the atoms are
   533   // the same
   534   if (aListener->mAllEvents) {
   535     return true;
   536   }
   537   if (aEvent->message == NS_USER_DEFINED_EVENT) {
   538     if (mIsMainThreadELM) {
   539       return aListener->mTypeAtom == aEvent->userType;
   540     }
   541     return aListener->mTypeString.Equals(aEvent->typeString);
   542   }
   543   MOZ_ASSERT(mIsMainThreadELM);
   544   return aListener->mEventType == aEvent->message;
   545 }
   547 void
   548 EventListenerManager::AddEventListenerByType(
   549                         const EventListenerHolder& aListenerHolder,
   550                         const nsAString& aType,
   551                         const EventListenerFlags& aFlags)
   552 {
   553   nsCOMPtr<nsIAtom> atom =
   554     mIsMainThreadELM ? do_GetAtom(NS_LITERAL_STRING("on") + aType) : nullptr;
   555   uint32_t type = nsContentUtils::GetEventId(atom);
   556   AddEventListenerInternal(aListenerHolder, type, atom, aType, aFlags);
   557 }
   559 void
   560 EventListenerManager::RemoveEventListenerByType(
   561                         const EventListenerHolder& aListenerHolder,
   562                         const nsAString& aType,
   563                         const EventListenerFlags& aFlags)
   564 {
   565   nsCOMPtr<nsIAtom> atom =
   566     mIsMainThreadELM ? do_GetAtom(NS_LITERAL_STRING("on") + aType) : nullptr;
   567   uint32_t type = nsContentUtils::GetEventId(atom);
   568   RemoveEventListenerInternal(aListenerHolder, type, atom, aType, aFlags);
   569 }
   571 EventListenerManager::Listener*
   572 EventListenerManager::FindEventHandler(uint32_t aEventType,
   573                                        nsIAtom* aTypeAtom,
   574                                        const nsAString& aTypeString)
   575 {
   576   // Run through the listeners for this type and see if a script
   577   // listener is registered
   578   Listener* listener;
   579   uint32_t count = mListeners.Length();
   580   for (uint32_t i = 0; i < count; ++i) {
   581     listener = &mListeners.ElementAt(i);
   582     if (listener->mListenerIsHandler &&
   583         EVENT_TYPE_EQUALS(listener, aEventType, aTypeAtom, aTypeString,
   584                           false)) {
   585       return listener;
   586     }
   587   }
   588   return nullptr;
   589 }
   591 EventListenerManager::Listener*
   592 EventListenerManager::SetEventHandlerInternal(
   593                         nsIAtom* aName,
   594                         const nsAString& aTypeString,
   595                         const TypedEventHandler& aTypedHandler,
   596                         bool aPermitUntrustedEvents)
   597 {
   598   MOZ_ASSERT(aName || !aTypeString.IsEmpty());
   600   uint32_t eventType = nsContentUtils::GetEventId(aName);
   601   Listener* listener = FindEventHandler(eventType, aName, aTypeString);
   603   if (!listener) {
   604     // If we didn't find a script listener or no listeners existed
   605     // create and add a new one.
   606     EventListenerFlags flags;
   607     flags.mListenerIsJSListener = true;
   609     nsCOMPtr<JSEventHandler> jsEventHandler;
   610     NS_NewJSEventHandler(mTarget, aName,
   611                          aTypedHandler, getter_AddRefs(jsEventHandler));
   612     EventListenerHolder listenerHolder(jsEventHandler);
   613     AddEventListenerInternal(listenerHolder, eventType, aName, aTypeString,
   614                              flags, true);
   616     listener = FindEventHandler(eventType, aName, aTypeString);
   617   } else {
   618     JSEventHandler* jsEventHandler = listener->GetJSEventHandler();
   619     MOZ_ASSERT(jsEventHandler,
   620                "How can we have an event handler with no JSEventHandler?");
   622     bool same = jsEventHandler->GetTypedEventHandler() == aTypedHandler;
   623     // Possibly the same listener, but update still the context and scope.
   624     jsEventHandler->SetHandler(aTypedHandler);
   625     if (mTarget && !same && aName) {
   626       mTarget->EventListenerRemoved(aName);
   627       mTarget->EventListenerAdded(aName);
   628     }
   629   }
   631   // Set flag to indicate possible need for compilation later
   632   listener->mHandlerIsString = !aTypedHandler.HasEventHandler();
   633   if (aPermitUntrustedEvents) {
   634     listener->mFlags.mAllowUntrustedEvents = true;
   635   }
   637   return listener;
   638 }
   640 nsresult
   641 EventListenerManager::SetEventHandler(nsIAtom* aName,
   642                                       const nsAString& aBody,
   643                                       uint32_t aLanguage,
   644                                       bool aDeferCompilation,
   645                                       bool aPermitUntrustedEvents,
   646                                       Element* aElement)
   647 {
   648   NS_PRECONDITION(aLanguage != nsIProgrammingLanguage::UNKNOWN,
   649                   "Must know the language for the script event listener");
   651   // |aPermitUntrustedEvents| is set to False for chrome - events
   652   // *generated* from an unknown source are not allowed.
   653   // However, for script languages with no 'sandbox', we want to reject
   654   // such scripts based on the source of their code, not just the source
   655   // of the event.
   656   if (aPermitUntrustedEvents && 
   657       aLanguage != nsIProgrammingLanguage::JAVASCRIPT) {
   658     NS_WARNING("Discarding non-JS event listener from untrusted source");
   659     return NS_ERROR_FAILURE;
   660   }
   662   nsCOMPtr<nsIDocument> doc;
   663   nsCOMPtr<nsIScriptGlobalObject> global =
   664     GetScriptGlobalAndDocument(getter_AddRefs(doc));
   666   if (!global) {
   667     // This can happen; for example this document might have been
   668     // loaded as data.
   669     return NS_OK;
   670   }
   672 #ifdef DEBUG
   673   nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(global);
   674   if (win) {
   675     MOZ_ASSERT(win->IsInnerWindow(), "We should not have an outer window here!");
   676   }
   677 #endif
   679   nsresult rv = NS_OK;
   680   // return early preventing the event listener from being added
   681   // 'doc' is fetched above
   682   if (doc) {
   683     // Don't allow adding an event listener if the document is sandboxed
   684     // without 'allow-scripts'.
   685     if (doc->GetSandboxFlags() & SANDBOXED_SCRIPTS) {
   686       return NS_ERROR_DOM_SECURITY_ERR;
   687     }
   689     nsCOMPtr<nsIContentSecurityPolicy> csp;
   690     rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
   691     NS_ENSURE_SUCCESS(rv, rv);
   693     if (csp) {
   694       bool inlineOK = true;
   695       bool reportViolations = false;
   696       rv = csp->GetAllowsInlineScript(&reportViolations, &inlineOK);
   697       NS_ENSURE_SUCCESS(rv, rv);
   699       if (reportViolations) {
   700         // gather information to log with violation report
   701         nsIURI* uri = doc->GetDocumentURI();
   702         nsAutoCString asciiSpec;
   703         if (uri)
   704           uri->GetAsciiSpec(asciiSpec);
   705         nsAutoString scriptSample, attr, tagName(NS_LITERAL_STRING("UNKNOWN"));
   706         aName->ToString(attr);
   707         nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mTarget));
   708         if (domNode)
   709           domNode->GetNodeName(tagName);
   710         // build a "script sample" based on what we know about this element
   711         scriptSample.Assign(attr);
   712         scriptSample.AppendLiteral(" attribute on ");
   713         scriptSample.Append(tagName);
   714         scriptSample.AppendLiteral(" element");
   715         csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT,
   716                                  NS_ConvertUTF8toUTF16(asciiSpec),
   717                                  scriptSample,
   718                                  0,
   719                                  EmptyString(),
   720                                  EmptyString());
   721       }
   723       // return early if CSP wants us to block inline scripts
   724       if (!inlineOK) {
   725         return NS_OK;
   726       }
   727     }
   728   }
   730   // This might be the first reference to this language in the global
   731   // We must init the language before we attempt to fetch its context.
   732   if (NS_FAILED(global->EnsureScriptEnvironment())) {
   733     NS_WARNING("Failed to setup script environment for this language");
   734     // but fall through and let the inevitable failure below handle it.
   735   }
   737   nsIScriptContext* context = global->GetScriptContext();
   738   NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
   739   NS_ENSURE_STATE(global->GetGlobalJSObject());
   741   Listener* listener = SetEventHandlerInternal(aName,
   742                                                EmptyString(),
   743                                                TypedEventHandler(),
   744                                                aPermitUntrustedEvents);
   746   if (!aDeferCompilation) {
   747     return CompileEventHandlerInternal(listener, &aBody, aElement);
   748   }
   750   return NS_OK;
   751 }
   753 void
   754 EventListenerManager::RemoveEventHandler(nsIAtom* aName,
   755                                          const nsAString& aTypeString)
   756 {
   757   if (mClearingListeners) {
   758     return;
   759   }
   761   uint32_t eventType = nsContentUtils::GetEventId(aName);
   762   Listener* listener = FindEventHandler(eventType, aName, aTypeString);
   764   if (listener) {
   765     mListeners.RemoveElementAt(uint32_t(listener - &mListeners.ElementAt(0)));
   766     mNoListenerForEvent = NS_EVENT_NULL;
   767     mNoListenerForEventAtom = nullptr;
   768     if (mTarget && aName) {
   769       mTarget->EventListenerRemoved(aName);
   770     }
   771   }
   772 }
   774 nsresult
   775 EventListenerManager::CompileEventHandlerInternal(Listener* aListener,
   776                                                   const nsAString* aBody,
   777                                                   Element* aElement)
   778 {
   779   MOZ_ASSERT(aListener->GetJSEventHandler());
   780   MOZ_ASSERT(aListener->mHandlerIsString, "Why are we compiling a non-string JS listener?");
   781   JSEventHandler* jsEventHandler = aListener->GetJSEventHandler();
   782   MOZ_ASSERT(!jsEventHandler->GetTypedEventHandler().HasEventHandler(),
   783              "What is there to compile?");
   785   nsresult result = NS_OK;
   786   nsCOMPtr<nsIDocument> doc;
   787   nsCOMPtr<nsIScriptGlobalObject> global =
   788     GetScriptGlobalAndDocument(getter_AddRefs(doc));
   789   NS_ENSURE_STATE(global);
   791   nsIScriptContext* context = global->GetScriptContext();
   792   NS_ENSURE_STATE(context);
   794   // Activate JSAPI, and make sure that exceptions are reported on the right
   795   // Window.
   796   AutoJSAPIWithErrorsReportedToWindow jsapi(context);
   797   JSContext* cx = jsapi.cx();
   799   nsCOMPtr<nsIAtom> typeAtom = aListener->mTypeAtom;
   800   nsIAtom* attrName = typeAtom;
   802   // Flag us as not a string so we don't keep trying to compile strings which
   803   // can't be compiled.
   804   aListener->mHandlerIsString = false;
   806   // mTarget may not be an Element if it's a window and we're
   807   // getting an inline event listener forwarded from <html:body> or
   808   // <html:frameset> or <xul:window> or the like.
   809   // XXX I don't like that we have to reference content from
   810   // here. The alternative is to store the event handler string on
   811   // the JSEventHandler itself, and that still doesn't address
   812   // the arg names issue.
   813   nsCOMPtr<Element> element = do_QueryInterface(mTarget);
   814   MOZ_ASSERT(element || aBody, "Where will we get our body?");
   815   nsAutoString handlerBody;
   816   const nsAString* body = aBody;
   817   if (!aBody) {
   818     if (aListener->mTypeAtom == nsGkAtoms::onSVGLoad) {
   819       attrName = nsGkAtoms::onload;
   820     } else if (aListener->mTypeAtom == nsGkAtoms::onSVGUnload) {
   821       attrName = nsGkAtoms::onunload;
   822     } else if (aListener->mTypeAtom == nsGkAtoms::onSVGResize) {
   823       attrName = nsGkAtoms::onresize;
   824     } else if (aListener->mTypeAtom == nsGkAtoms::onSVGScroll) {
   825       attrName = nsGkAtoms::onscroll;
   826     } else if (aListener->mTypeAtom == nsGkAtoms::onSVGZoom) {
   827       attrName = nsGkAtoms::onzoom;
   828     } else if (aListener->mTypeAtom == nsGkAtoms::onbeginEvent) {
   829       attrName = nsGkAtoms::onbegin;
   830     } else if (aListener->mTypeAtom == nsGkAtoms::onrepeatEvent) {
   831       attrName = nsGkAtoms::onrepeat;
   832     } else if (aListener->mTypeAtom == nsGkAtoms::onendEvent) {
   833       attrName = nsGkAtoms::onend;
   834     }
   836     element->GetAttr(kNameSpaceID_None, attrName, handlerBody);
   837     body = &handlerBody;
   838     aElement = element;
   839   }
   840   aListener = nullptr;
   842   uint32_t lineNo = 0;
   843   nsAutoCString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener"));
   844   MOZ_ASSERT(body);
   845   MOZ_ASSERT(aElement);
   846   nsIURI *uri = aElement->OwnerDoc()->GetDocumentURI();
   847   if (uri) {
   848     uri->GetSpec(url);
   849     lineNo = 1;
   850   }
   852   uint32_t argCount;
   853   const char **argNames;
   854   nsContentUtils::GetEventArgNames(aElement->GetNameSpaceID(),
   855                                    typeAtom,
   856                                    &argCount, &argNames);
   858   // Wrap the event target, so that we can use it as the scope for the event
   859   // handler. Note that mTarget is different from aElement in the <body> case,
   860   // where mTarget is a Window.
   861   //
   862   // The wrapScope doesn't really matter here, because the target will create
   863   // its reflector in the proper scope, and then we'll enter that compartment.
   864   JS::Rooted<JSObject*> wrapScope(cx, context->GetWindowProxy());
   865   JS::Rooted<JS::Value> v(cx);
   866   {
   867     JSAutoCompartment ac(cx, wrapScope);
   868     nsresult rv = nsContentUtils::WrapNative(cx, mTarget, &v,
   869                                              /* aAllowWrapping = */ false);
   870     if (NS_WARN_IF(NS_FAILED(rv))) {
   871       return rv;
   872     }
   873   }
   874   JS::Rooted<JSObject*> target(cx, &v.toObject());
   875   JSAutoCompartment ac(cx, target);
   877   nsDependentAtomString str(attrName);
   878   // Most of our names are short enough that we don't even have to malloc
   879   // the JS string stuff, so don't worry about playing games with
   880   // refcounting XPCOM stringbuffers.
   881   JS::Rooted<JSString*> jsStr(cx, JS_NewUCStringCopyN(cx,
   882                                                       str.BeginReading(),
   883                                                       str.Length()));
   884   NS_ENSURE_TRUE(jsStr, NS_ERROR_OUT_OF_MEMORY);
   886   // Get the reflector for |aElement|, so that we can pass to setElement.
   887   if (NS_WARN_IF(!WrapNewBindingObject(cx, target, aElement, &v))) {
   888     return NS_ERROR_FAILURE;
   889   }
   890   JS::CompileOptions options(cx);
   891   options.setIntroductionType("eventHandler")
   892          .setFileAndLine(url.get(), lineNo)
   893          .setVersion(SCRIPTVERSION_DEFAULT)
   894          .setElement(&v.toObject())
   895          .setElementAttributeName(jsStr)
   896          .setDefineOnScope(false);
   898   JS::Rooted<JSObject*> handler(cx);
   899   result = nsJSUtils::CompileFunction(cx, target, options,
   900                                       nsAtomCString(typeAtom),
   901                                       argCount, argNames, *body, handler.address());
   902   NS_ENSURE_SUCCESS(result, result);
   903   NS_ENSURE_TRUE(handler, NS_ERROR_FAILURE);
   905   nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mTarget);
   906   if (jsEventHandler->EventName() == nsGkAtoms::onerror && win) {
   907     nsRefPtr<OnErrorEventHandlerNonNull> handlerCallback =
   908       new OnErrorEventHandlerNonNull(handler, /* aIncumbentGlobal = */ nullptr);
   909     jsEventHandler->SetHandler(handlerCallback);
   910   } else if (jsEventHandler->EventName() == nsGkAtoms::onbeforeunload && win) {
   911     nsRefPtr<OnBeforeUnloadEventHandlerNonNull> handlerCallback =
   912       new OnBeforeUnloadEventHandlerNonNull(handler, /* aIncumbentGlobal = */ nullptr);
   913     jsEventHandler->SetHandler(handlerCallback);
   914   } else {
   915     nsRefPtr<EventHandlerNonNull> handlerCallback =
   916       new EventHandlerNonNull(handler, /* aIncumbentGlobal = */ nullptr);
   917     jsEventHandler->SetHandler(handlerCallback);
   918   }
   920   return result;
   921 }
   923 nsresult
   924 EventListenerManager::HandleEventSubType(Listener* aListener,
   925                                          nsIDOMEvent* aDOMEvent,
   926                                          EventTarget* aCurrentTarget)
   927 {
   928   nsresult result = NS_OK;
   929   EventListenerHolder listenerHolder(aListener->mListener);  // strong ref
   931   // If this is a script handler and we haven't yet
   932   // compiled the event handler itself
   933   if ((aListener->mListenerType == Listener::eJSEventListener) &&
   934       aListener->mHandlerIsString) {
   935     result = CompileEventHandlerInternal(aListener, nullptr, nullptr);
   936     aListener = nullptr;
   937   }
   939   if (NS_SUCCEEDED(result)) {
   940     if (mIsMainThreadELM) {
   941       nsContentUtils::EnterMicroTask();
   942     }
   943     // nsIDOMEvent::currentTarget is set in EventDispatcher.
   944     if (listenerHolder.HasWebIDLCallback()) {
   945       ErrorResult rv;
   946       listenerHolder.GetWebIDLCallback()->
   947         HandleEvent(aCurrentTarget, *(aDOMEvent->InternalDOMEvent()), rv);
   948       result = rv.ErrorCode();
   949     } else {
   950       result = listenerHolder.GetXPCOMCallback()->HandleEvent(aDOMEvent);
   951     }
   952     if (mIsMainThreadELM) {
   953       nsContentUtils::LeaveMicroTask();
   954     }
   955   }
   957   return result;
   958 }
   960 /**
   961 * Causes a check for event listeners and processing by them if they exist.
   962 * @param an event listener
   963 */
   965 void
   966 EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
   967                                           WidgetEvent* aEvent,
   968                                           nsIDOMEvent** aDOMEvent,
   969                                           EventTarget* aCurrentTarget,
   970                                           nsEventStatus* aEventStatus)
   971 {
   972   //Set the value of the internal PreventDefault flag properly based on aEventStatus
   973   if (*aEventStatus == nsEventStatus_eConsumeNoDefault) {
   974     aEvent->mFlags.mDefaultPrevented = true;
   975   }
   977   nsAutoTObserverArray<Listener, 2>::EndLimitedIterator iter(mListeners);
   978   Maybe<nsAutoPopupStatePusher> popupStatePusher;
   979   if (mIsMainThreadELM) {
   980     popupStatePusher.construct(Event::GetEventPopupControlState(aEvent));
   981   }
   983   bool hasListener = false;
   984   while (iter.HasMore()) {
   985     if (aEvent->mFlags.mImmediatePropagationStopped) {
   986       break;
   987     }
   988     Listener* listener = &iter.GetNext();
   989     // Check that the phase is same in event and event listener.
   990     // Handle only trusted events, except when listener permits untrusted events.
   991     if (ListenerCanHandle(listener, aEvent)) {
   992       hasListener = true;
   993       if (listener->IsListening(aEvent) &&
   994           (aEvent->mFlags.mIsTrusted ||
   995            listener->mFlags.mAllowUntrustedEvents)) {
   996         if (!*aDOMEvent) {
   997           // This is tiny bit slow, but happens only once per event.
   998           nsCOMPtr<EventTarget> et =
   999             do_QueryInterface(aEvent->originalTarget);
  1000           EventDispatcher::CreateEvent(et, aPresContext,
  1001                                        aEvent, EmptyString(), aDOMEvent);
  1003         if (*aDOMEvent) {
  1004           if (!aEvent->currentTarget) {
  1005             aEvent->currentTarget = aCurrentTarget->GetTargetForDOMEvent();
  1006             if (!aEvent->currentTarget) {
  1007               break;
  1011           if (NS_FAILED(HandleEventSubType(listener, *aDOMEvent,
  1012                                            aCurrentTarget))) {
  1013             aEvent->mFlags.mExceptionHasBeenRisen = true;
  1020   aEvent->currentTarget = nullptr;
  1022   if (mIsMainThreadELM && !hasListener) {
  1023     mNoListenerForEvent = aEvent->message;
  1024     mNoListenerForEventAtom = aEvent->userType;
  1027   if (aEvent->mFlags.mDefaultPrevented) {
  1028     *aEventStatus = nsEventStatus_eConsumeNoDefault;
  1032 void
  1033 EventListenerManager::Disconnect()
  1035   mTarget = nullptr;
  1036   RemoveAllListeners();
  1039 void
  1040 EventListenerManager::AddEventListener(
  1041                         const nsAString& aType,
  1042                         const EventListenerHolder& aListenerHolder,
  1043                         bool aUseCapture,
  1044                         bool aWantsUntrusted)
  1046   EventListenerFlags flags;
  1047   flags.mCapture = aUseCapture;
  1048   flags.mAllowUntrustedEvents = aWantsUntrusted;
  1049   return AddEventListenerByType(aListenerHolder, aType, flags);
  1052 void
  1053 EventListenerManager::RemoveEventListener(
  1054                         const nsAString& aType,
  1055                         const EventListenerHolder& aListenerHolder,
  1056                         bool aUseCapture)
  1058   EventListenerFlags flags;
  1059   flags.mCapture = aUseCapture;
  1060   RemoveEventListenerByType(aListenerHolder, aType, flags);
  1063 void
  1064 EventListenerManager::AddListenerForAllEvents(nsIDOMEventListener* aDOMListener,
  1065                                               bool aUseCapture,
  1066                                               bool aWantsUntrusted,
  1067                                               bool aSystemEventGroup)
  1069   EventListenerFlags flags;
  1070   flags.mCapture = aUseCapture;
  1071   flags.mAllowUntrustedEvents = aWantsUntrusted;
  1072   flags.mInSystemGroup = aSystemEventGroup;
  1073   EventListenerHolder listenerHolder(aDOMListener);
  1074   AddEventListenerInternal(listenerHolder, NS_EVENT_ALL, nullptr, EmptyString(),
  1075                            flags, false, true);
  1078 void
  1079 EventListenerManager::RemoveListenerForAllEvents(
  1080                         nsIDOMEventListener* aDOMListener,
  1081                         bool aUseCapture,
  1082                         bool aSystemEventGroup)
  1084   EventListenerFlags flags;
  1085   flags.mCapture = aUseCapture;
  1086   flags.mInSystemGroup = aSystemEventGroup;
  1087   EventListenerHolder listenerHolder(aDOMListener);
  1088   RemoveEventListenerInternal(listenerHolder, NS_EVENT_ALL, nullptr,
  1089                               EmptyString(), flags, true);
  1092 bool
  1093 EventListenerManager::HasMutationListeners()
  1095   if (mMayHaveMutationListeners) {
  1096     uint32_t count = mListeners.Length();
  1097     for (uint32_t i = 0; i < count; ++i) {
  1098       Listener* listener = &mListeners.ElementAt(i);
  1099       if (listener->mEventType >= NS_MUTATION_START &&
  1100           listener->mEventType <= NS_MUTATION_END) {
  1101         return true;
  1106   return false;
  1109 uint32_t
  1110 EventListenerManager::MutationListenerBits()
  1112   uint32_t bits = 0;
  1113   if (mMayHaveMutationListeners) {
  1114     uint32_t count = mListeners.Length();
  1115     for (uint32_t i = 0; i < count; ++i) {
  1116       Listener* listener = &mListeners.ElementAt(i);
  1117       if (listener->mEventType >= NS_MUTATION_START &&
  1118           listener->mEventType <= NS_MUTATION_END) {
  1119         if (listener->mEventType == NS_MUTATION_SUBTREEMODIFIED) {
  1120           return kAllMutationBits;
  1122         bits |= MutationBitForEventType(listener->mEventType);
  1126   return bits;
  1129 bool
  1130 EventListenerManager::HasListenersFor(const nsAString& aEventName)
  1132   nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + aEventName);
  1133   return HasListenersFor(atom);
  1136 bool
  1137 EventListenerManager::HasListenersFor(nsIAtom* aEventNameWithOn)
  1139 #ifdef DEBUG
  1140   nsAutoString name;
  1141   aEventNameWithOn->ToString(name);
  1142 #endif
  1143   NS_ASSERTION(StringBeginsWith(name, NS_LITERAL_STRING("on")),
  1144                "Event name does not start with 'on'");
  1145   uint32_t count = mListeners.Length();
  1146   for (uint32_t i = 0; i < count; ++i) {
  1147     Listener* listener = &mListeners.ElementAt(i);
  1148     if (listener->mTypeAtom == aEventNameWithOn) {
  1149       return true;
  1152   return false;
  1155 bool
  1156 EventListenerManager::HasListeners()
  1158   return !mListeners.IsEmpty();
  1161 nsresult
  1162 EventListenerManager::GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList)
  1164   nsCOMPtr<EventTarget> target = do_QueryInterface(mTarget);
  1165   NS_ENSURE_STATE(target);
  1166   aList->Clear();
  1167   uint32_t count = mListeners.Length();
  1168   for (uint32_t i = 0; i < count; ++i) {
  1169     const Listener& listener = mListeners.ElementAt(i);
  1170     // If this is a script handler and we haven't yet
  1171     // compiled the event handler itself go ahead and compile it
  1172     if (listener.mListenerType == Listener::eJSEventListener &&
  1173         listener.mHandlerIsString) {
  1174       CompileEventHandlerInternal(const_cast<Listener*>(&listener), nullptr,
  1175                                   nullptr);
  1177     nsAutoString eventType;
  1178     if (listener.mAllEvents) {
  1179       eventType.SetIsVoid(true);
  1180     } else {
  1181       eventType.Assign(Substring(nsDependentAtomString(listener.mTypeAtom), 2));
  1183     // EventListenerInfo is defined in XPCOM, so we have to go ahead
  1184     // and convert to an XPCOM callback here...
  1185     nsRefPtr<EventListenerInfo> info =
  1186       new EventListenerInfo(eventType, listener.mListener.ToXPCOMCallback(),
  1187                             listener.mFlags.mCapture,
  1188                             listener.mFlags.mAllowUntrustedEvents,
  1189                             listener.mFlags.mInSystemGroup);
  1190     aList->AppendObject(info);
  1192   return NS_OK;
  1195 bool
  1196 EventListenerManager::HasUnloadListeners()
  1198   uint32_t count = mListeners.Length();
  1199   for (uint32_t i = 0; i < count; ++i) {
  1200     Listener* listener = &mListeners.ElementAt(i);
  1201     if (listener->mEventType == NS_PAGE_UNLOAD ||
  1202         listener->mEventType == NS_BEFORE_PAGE_UNLOAD) {
  1203       return true;
  1206   return false;
  1209 void
  1210 EventListenerManager::SetEventHandler(nsIAtom* aEventName,
  1211                                       const nsAString& aTypeString,
  1212                                       EventHandlerNonNull* aHandler)
  1214   if (!aHandler) {
  1215     RemoveEventHandler(aEventName, aTypeString);
  1216     return;
  1219   // Untrusted events are always permitted for non-chrome script
  1220   // handlers.
  1221   SetEventHandlerInternal(aEventName, aTypeString, TypedEventHandler(aHandler),
  1222                           !mIsMainThreadELM ||
  1223                           !nsContentUtils::IsCallerChrome());
  1226 void
  1227 EventListenerManager::SetEventHandler(OnErrorEventHandlerNonNull* aHandler)
  1229   if (mIsMainThreadELM) {
  1230     if (!aHandler) {
  1231       RemoveEventHandler(nsGkAtoms::onerror, EmptyString());
  1232       return;
  1235     // Untrusted events are always permitted for non-chrome script
  1236     // handlers.
  1237     SetEventHandlerInternal(nsGkAtoms::onerror, EmptyString(),
  1238                             TypedEventHandler(aHandler),
  1239                             !nsContentUtils::IsCallerChrome());
  1240   } else {
  1241     if (!aHandler) {
  1242       RemoveEventHandler(nullptr, NS_LITERAL_STRING("error"));
  1243       return;
  1246     // Untrusted events are always permitted.
  1247     SetEventHandlerInternal(nullptr, NS_LITERAL_STRING("error"),
  1248                             TypedEventHandler(aHandler), true);
  1252 void
  1253 EventListenerManager::SetEventHandler(
  1254                         OnBeforeUnloadEventHandlerNonNull* aHandler)
  1256   if (!aHandler) {
  1257     RemoveEventHandler(nsGkAtoms::onbeforeunload, EmptyString());
  1258     return;
  1261   // Untrusted events are always permitted for non-chrome script
  1262   // handlers.
  1263   SetEventHandlerInternal(nsGkAtoms::onbeforeunload, EmptyString(),
  1264                           TypedEventHandler(aHandler),
  1265                           !mIsMainThreadELM ||
  1266                           !nsContentUtils::IsCallerChrome());
  1269 const TypedEventHandler*
  1270 EventListenerManager::GetTypedEventHandler(nsIAtom* aEventName,
  1271                                            const nsAString& aTypeString)
  1273   uint32_t eventType = nsContentUtils::GetEventId(aEventName);
  1274   Listener* listener = FindEventHandler(eventType, aEventName, aTypeString);
  1276   if (!listener) {
  1277     return nullptr;
  1280   JSEventHandler* jsEventHandler = listener->GetJSEventHandler();
  1282   if (listener->mHandlerIsString) {
  1283     CompileEventHandlerInternal(listener, nullptr, nullptr);
  1286   const TypedEventHandler& typedHandler =
  1287     jsEventHandler->GetTypedEventHandler();
  1288   return typedHandler.HasEventHandler() ? &typedHandler : nullptr;
  1291 size_t
  1292 EventListenerManager::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
  1294   size_t n = aMallocSizeOf(this);
  1295   n += mListeners.SizeOfExcludingThis(aMallocSizeOf);
  1296   uint32_t count = mListeners.Length();
  1297   for (uint32_t i = 0; i < count; ++i) {
  1298     JSEventHandler* jsEventHandler =
  1299       mListeners.ElementAt(i).GetJSEventHandler();
  1300     if (jsEventHandler) {
  1301       n += jsEventHandler->SizeOfIncludingThis(aMallocSizeOf);
  1304   return n;
  1307 void
  1308 EventListenerManager::MarkForCC()
  1310   uint32_t count = mListeners.Length();
  1311   for (uint32_t i = 0; i < count; ++i) {
  1312     const Listener& listener = mListeners.ElementAt(i);
  1313     JSEventHandler* jsEventHandler = listener.GetJSEventHandler();
  1314     if (jsEventHandler) {
  1315       const TypedEventHandler& typedHandler =
  1316         jsEventHandler->GetTypedEventHandler();
  1317       if (typedHandler.HasEventHandler()) {
  1318         JS::ExposeObjectToActiveJS(typedHandler.Ptr()->Callable());
  1320     } else if (listener.mListenerType == Listener::eWrappedJSListener) {
  1321       xpc_TryUnmarkWrappedGrayObject(listener.mListener.GetXPCOMCallback());
  1322     } else if (listener.mListenerType == Listener::eWebIDLListener) {
  1323       // Callback() unmarks gray
  1324       listener.mListener.GetWebIDLCallback()->Callback();
  1327   if (mRefCnt.IsPurple()) {
  1328     mRefCnt.RemovePurple();
  1332 already_AddRefed<nsIScriptGlobalObject>
  1333 EventListenerManager::GetScriptGlobalAndDocument(nsIDocument** aDoc)
  1335   nsCOMPtr<nsINode> node(do_QueryInterface(mTarget));
  1336   nsCOMPtr<nsIDocument> doc;
  1337   nsCOMPtr<nsIScriptGlobalObject> global;
  1338   if (node) {
  1339     // Try to get context from doc
  1340     // XXX sXBL/XBL2 issue -- do we really want the owner here?  What
  1341     // if that's the XBL document?
  1342     doc = node->OwnerDoc();
  1343     if (doc->IsLoadedAsData()) {
  1344       return nullptr;
  1347     // We want to allow compiling an event handler even in an unloaded
  1348     // document, so use GetScopeObject here, not GetScriptHandlingObject.
  1349     global = do_QueryInterface(doc->GetScopeObject());
  1350   } else {
  1351     nsCOMPtr<nsPIDOMWindow> win = GetTargetAsInnerWindow();
  1352     if (win) {
  1353       doc = win->GetExtantDoc();
  1354       global = do_QueryInterface(win);
  1355     } else {
  1356       global = do_QueryInterface(mTarget);
  1360   doc.forget(aDoc);
  1361   return global.forget();
  1364 } // namespace mozilla

mercurial