nsresult nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct, const EventListenerHolder& aListener, nsIDOMEvent* aDOMEvent, EventTarget* aCurrentTarget, nsCxPusher* aPusher) { nsresult result = NS_OK; // If this is a script handler and we haven't yet // compiled the event handler itself if ((aListenerStruct->mListenerType == eJSEventListener) && aListenerStruct->mHandlerIsString) { nsIJSEventListener *jslistener = aListenerStruct->GetJSListener(); result = CompileEventHandlerInternal(aListenerStruct, jslistener->GetEventContext() != aPusher->GetCurrentScriptContext(), nullptr); } if (NS_SUCCEEDED(result)) { nsAutoMicroTask mt; // nsIDOMEvent::currentTarget is set in nsEventDispatcher. if (aListener.HasWebIDLCallback()) { ErrorResult rv; aListener.GetWebIDLCallback()-> HandleEvent(aCurrentTarget, *(aDOMEvent->InternalDOMEvent()), rv); result = rv.ErrorCode(); } else { result = aListener.GetXPCOMCallback()->HandleEvent(aDOMEvent); } } return result; }
void nsEventListenerManager::AddEventListenerInternal( const EventListenerHolder& aListener, uint32_t aType, nsIAtom* aTypeAtom, const nsAString& aTypeString, const EventListenerFlags& aFlags, bool aHandler, bool aAllEvents) { MOZ_ASSERT((NS_IsMainThread() && aType && aTypeAtom) || // Main thread (!NS_IsMainThread() && aType && !aTypeString.IsEmpty()) || // non-main-thread aAllEvents, "Missing type"); // all-events listener if (!aListener || mClearingListeners) { return; } // Since there is no public API to call us with an EventListenerHolder, we // know that there's an EventListenerHolder on the stack holding a strong ref // to the listener. nsListenerStruct* ls; uint32_t count = mListeners.Length(); for (uint32_t i = 0; i < count; i++) { ls = &mListeners.ElementAt(i); // mListener == aListener is the last one, since it can be a bit slow. if (ls->mListenerIsHandler == aHandler && ls->mFlags == aFlags && EVENT_TYPE_EQUALS(ls, aType, aTypeAtom, aTypeString, aAllEvents) && ls->mListener == aListener) { return; } } mNoListenerForEvent = NS_EVENT_NULL; mNoListenerForEventAtom = nullptr; ls = aAllEvents ? mListeners.InsertElementAt(0) : mListeners.AppendElement(); ls->mListener = aListener; MOZ_ASSERT(aType < PR_UINT16_MAX); ls->mEventType = aType; ls->mTypeString = aTypeString; ls->mTypeAtom = aTypeAtom; ls->mFlags = aFlags; ls->mListenerIsHandler = aHandler; ls->mHandlerIsString = false; ls->mAllEvents = aAllEvents; // Detect the type of event listener. nsCOMPtr<nsIXPConnectWrappedJS> wjs; if (aFlags.mListenerIsJSListener) { MOZ_ASSERT(!aListener.HasWebIDLCallback()); ls->mListenerType = eJSEventListener; } else if (aListener.HasWebIDLCallback()) { ls->mListenerType = eWebIDLListener; } else if ((wjs = do_QueryInterface(aListener.GetXPCOMCallback()))) { ls->mListenerType = eWrappedJSListener; } else { ls->mListenerType = eNativeListener; } if (aFlags.mInSystemGroup) { mMayHaveSystemGroupListeners = true; } if (aFlags.mCapture) { mMayHaveCapturingListeners = true; } if (aType == NS_AFTERPAINT) { mMayHavePaintEventListener = true; nsPIDOMWindow* window = GetInnerWindowForTarget(); if (window) { window->SetHasPaintEventListeners(); } } else if (aType == NS_MOZAUDIOAVAILABLE) { mMayHaveAudioAvailableEventListener = true; nsPIDOMWindow* window = GetInnerWindowForTarget(); if (window) { window->SetHasAudioAvailableEventListeners(); } } else if (aType >= NS_MUTATION_START && aType <= NS_MUTATION_END) { // For mutation listeners, we need to update the global bit on the DOM window. // Otherwise we won't actually fire the mutation event. mMayHaveMutationListeners = true; // Go from our target to the nearest enclosing DOM window. nsPIDOMWindow* window = GetInnerWindowForTarget(); if (window) { nsCOMPtr<nsIDocument> doc = window->GetExtantDoc(); if (doc) { doc->WarnOnceAbout(nsIDocument::eMutationEvent); } // If aType is NS_MUTATION_SUBTREEMODIFIED, we need to listen all // mutations. nsContentUtils::HasMutationListeners relies on this. window->SetMutationListeners((aType == NS_MUTATION_SUBTREEMODIFIED) ? kAllMutationBits : MutationBitForEventType(aType)); } } else if (aTypeAtom == nsGkAtoms::ondeviceorientation) { EnableDevice(NS_DEVICE_ORIENTATION); } else if (aTypeAtom == nsGkAtoms::ondeviceproximity || aTypeAtom == nsGkAtoms::onuserproximity) { EnableDevice(NS_DEVICE_PROXIMITY); } else if (aTypeAtom == nsGkAtoms::ondevicelight) { EnableDevice(NS_DEVICE_LIGHT); } else if (aTypeAtom == nsGkAtoms::ondevicemotion) { EnableDevice(NS_DEVICE_MOTION); #ifdef MOZ_B2G } else if (aTypeAtom == nsGkAtoms::onmoztimechange) { nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow(); if (window) { window->EnableTimeChangeNotifications(); } } else if (aTypeAtom == nsGkAtoms::onmoznetworkupload) { nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow(); if (window) { window->EnableNetworkEvent(NS_NETWORK_UPLOAD_EVENT); } } else if (aTypeAtom == nsGkAtoms::onmoznetworkdownload) { nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow(); if (window) { window->EnableNetworkEvent(NS_NETWORK_DOWNLOAD_EVENT); } #endif // MOZ_B2G } else if (aTypeAtom == nsGkAtoms::ontouchstart || aTypeAtom == nsGkAtoms::ontouchend || aTypeAtom == nsGkAtoms::ontouchmove || aTypeAtom == nsGkAtoms::ontouchenter || aTypeAtom == nsGkAtoms::ontouchleave || aTypeAtom == nsGkAtoms::ontouchcancel) { mMayHaveTouchEventListener = true; nsPIDOMWindow* window = GetInnerWindowForTarget(); // we don't want touchevent listeners added by scrollbars to flip this flag // so we ignore listeners created with system event flag if (window && !aFlags.mInSystemGroup) { window->SetHasTouchEventListeners(); } } else if (aTypeAtom == nsGkAtoms::onmouseenter || aTypeAtom == nsGkAtoms::onmouseleave) { mMayHaveMouseEnterLeaveEventListener = true; nsPIDOMWindow* window = GetInnerWindowForTarget(); if (window) { #ifdef DEBUG nsCOMPtr<nsIDocument> d = window->GetExtantDoc(); NS_WARN_IF_FALSE(!nsContentUtils::IsChromeDoc(d), "Please do not use mouseenter/leave events in chrome. " "They are slower than mouseover/out!"); #endif window->SetHasMouseEnterLeaveEventListeners(); } #ifdef MOZ_GAMEPAD } else if (aType >= NS_GAMEPAD_START && aType <= NS_GAMEPAD_END) { nsPIDOMWindow* window = GetInnerWindowForTarget(); if (window) { window->SetHasGamepadEventListener(); } #endif } if (aTypeAtom && mTarget) { mTarget->EventListenerAdded(aTypeAtom); } }