void EventListenerInfo::getEventListeners(EventTarget* target, WillBeHeapVector<EventListenerInfo>& eventInformation, bool includeAncestors) { // The Node's Ancestors including self. WillBeHeapVector<RawPtrWillBeMember<EventTarget>> ancestors; ancestors.append(target); if (includeAncestors) { Node* node = target->toNode(); for (ContainerNode* ancestor = node ? node->parentOrShadowHostNode() : nullptr; ancestor; ancestor = ancestor->parentOrShadowHostNode()) ancestors.append(ancestor); } // Nodes and their Listeners for the concerned event types (order is top to bottom) for (size_t i = ancestors.size(); i; --i) { EventTarget* ancestor = ancestors[i - 1]; Vector<AtomicString> eventTypes = ancestor->eventTypes(); for (size_t j = 0; j < eventTypes.size(); ++j) { AtomicString& type = eventTypes[j]; EventListenerVector* listeners = ancestor->getEventListeners(type); if (!listeners) continue; EventListenerVector filteredListeners; filteredListeners.reserveCapacity(listeners->size()); for (size_t k = 0; k < listeners->size(); ++k) { if (listeners->at(k).listener->type() == EventListener::JSEventListenerType) filteredListeners.append(listeners->at(k)); } if (!filteredListeners.isEmpty()) eventInformation.append(EventListenerInfo(ancestor, type, filteredListeners)); } } }
void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry) { RefPtr<EventTarget> protect = this; // Fire all listeners registered for this event. Don't fire listeners removed // during event dispatch. Also, don't fire event listeners added during event // dispatch. Conveniently, all new event listeners will be added after 'end', // so iterating to 'end' naturally excludes new event listeners. size_t i = 0; size_t end = entry.size(); d->firingEventIterators.append(FiringEventIterator(event->type(), i, end)); for ( ; i < end; ++i) { RegisteredEventListener& registeredListener = entry[i]; if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture) continue; if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture) continue; // If stopImmediatePropagation has been called, we just break out immediately, without // handling any more events on this target. if (event->immediatePropagationStopped()) break; // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling // event listeners, even though that violates some versions of the DOM spec. registeredListener.listener->handleEvent(scriptExecutionContext(), event); } d->firingEventIterators.removeLast(); }
static inline size_t findListener(const EventListenerVector& listeners, EventListener& listener, bool useCapture) { for (size_t i = 0; i < listeners.size(); ++i) { auto& registeredListener = listeners[i]; if (registeredListener->callback() == listener && registeredListener->useCapture() == useCapture) return i; } return notFound; }
void EventTarget::fireEventListeners(Event& event, EventTargetData* d, EventListenerVector& entry) { Ref<EventTarget> protectedThis(*this); // Fire all listeners registered for this event. Don't fire listeners removed during event dispatch. // Also, don't fire event listeners added during event dispatch. Conveniently, all new event listeners will be added // after or at index |size|, so iterating up to (but not including) |size| naturally excludes new event listeners. size_t i = 0; size_t size = entry.size(); if (!d->firingEventIterators) d->firingEventIterators = std::make_unique<FiringEventIteratorVector>(); d->firingEventIterators->append(FiringEventIterator(event.type(), i, size)); ScriptExecutionContext* context = scriptExecutionContext(); Document* document = nullptr; InspectorInstrumentationCookie willDispatchEventCookie; if (is<Document>(context)) { document = downcast<Document>(context); willDispatchEventCookie = InspectorInstrumentation::willDispatchEvent(*document, event, size > 0); } for (; i < size; ++i) { RegisteredEventListener registeredListener = entry[i]; if (event.eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture) continue; if (event.eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture) continue; // If stopImmediatePropagation has been called, we just break out immediately, without // handling any more events on this target. if (event.immediatePropagationStopped()) break; // Do this before invocation to avoid reentrancy issues. if (registeredListener.isOnce) removeEventListener(event.type(), *registeredListener.listener, ListenerOptions(registeredListener.useCapture)); if (registeredListener.isPassive) event.setInPassiveListener(true); InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(context, event); // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling // event listeners, even though that violates some versions of the DOM spec. registeredListener.listener->handleEvent(context, &event); InspectorInstrumentation::didHandleEvent(cookie); if (registeredListener.isPassive) event.setInPassiveListener(false); } d->firingEventIterators->removeLast(); if (document) InspectorInstrumentation::didDispatchEvent(willDispatchEventCookie); }
void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry) { RefPtr<EventTarget> protect = this; // Fire all listeners registered for this event. Don't fire listeners removed // during event dispatch. Also, don't fire event listeners added during event // dispatch. Conveniently, all new event listeners will be added after or at // index |size|, so iterating up to (but not including) |size| naturally excludes // new event listeners. if (event->type() == EventTypeNames::beforeunload) { if (DOMWindow* executingWindow = this->executingWindow()) { if (executingWindow->top()) UseCounter::count(executingWindow->document(), UseCounter::SubFrameBeforeUnloadFired); UseCounter::count(executingWindow->document(), UseCounter::DocumentBeforeUnloadFired); } } else if (event->type() == EventTypeNames::unload) { if (DOMWindow* executingWindow = this->executingWindow()) UseCounter::count(executingWindow->document(), UseCounter::DocumentUnloadFired); } bool userEventWasHandled = false; size_t i = 0; size_t size = entry.size(); if (!d->firingEventIterators) d->firingEventIterators = adoptPtr(new FiringEventIteratorVector); d->firingEventIterators->append(FiringEventIterator(event->type(), i, size)); for ( ; i < size; ++i) { RegisteredEventListener& registeredListener = entry[i]; if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture) continue; if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture) continue; // If stopImmediatePropagation has been called, we just break out immediately, without // handling any more events on this target. if (event->immediatePropagationStopped()) break; ExecutionContext* context = executionContext(); if (!context) break; InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(this, event->type(), registeredListener.listener.get(), registeredListener.useCapture); // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling // event listeners, even though that violates some versions of the DOM spec. registeredListener.listener->handleEvent(context, event); if (!userEventWasHandled && UserGestureIndicator::processingUserGesture()) userEventWasHandled = true; InspectorInstrumentation::didHandleEvent(cookie); } d->firingEventIterators->removeLast(); if (userEventWasHandled) { if (ExecutionContext* context = executionContext()) context->userEventWasHandled(); } }
void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry) { Ref<EventTarget> protect(*this); // Fire all listeners registered for this event. Don't fire listeners removed during event dispatch. // Also, don't fire event listeners added during event dispatch. Conveniently, all new event listeners will be added // after or at index |size|, so iterating up to (but not including) |size| naturally excludes new event listeners. bool userEventWasHandled = false; size_t i = 0; size_t size = entry.size(); if (!d->firingEventIterators) d->firingEventIterators = std::make_unique<FiringEventIteratorVector>(); d->firingEventIterators->append(FiringEventIterator(event->type(), i, size)); ScriptExecutionContext* context = scriptExecutionContext(); Document* document = nullptr; InspectorInstrumentationCookie willDispatchEventCookie; if (context && context->isDocument()) { document = toDocument(context); willDispatchEventCookie = InspectorInstrumentation::willDispatchEvent(document, *event, size > 0); } for (; i < size; ++i) { RegisteredEventListener& registeredListener = entry[i]; if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture) continue; if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture) continue; // If stopImmediatePropagation has been called, we just break out immediately, without // handling any more events on this target. if (event->immediatePropagationStopped()) break; InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(context, event); // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling // event listeners, even though that violates some versions of the DOM spec. registeredListener.listener->handleEvent(context, event); if (!userEventWasHandled && ScriptController::processingUserGesture()) userEventWasHandled = true; InspectorInstrumentation::didHandleEvent(cookie); } d->firingEventIterators->removeLast(); if (userEventWasHandled && document) document->resetLastHandledUserGestureTimestamp(); if (document) InspectorInstrumentation::didDispatchEvent(willDispatchEventCookie); }
void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry) { RefPtr<EventTarget> protect = this; // Fire all listeners registered for this event. Don't fire listeners removed // during event dispatch. Also, don't fire event listeners added during event // dispatch. Conveniently, all new event listeners will be added after 'end', // so iterating to 'end' naturally excludes new event listeners. bool userEventWasHandled = false; size_t i = 0; size_t end = entry.size(); if (!d->firingEventIterators) d->firingEventIterators = adoptPtr(new FiringEventIteratorVector); d->firingEventIterators->append(FiringEventIterator(event->type(), i, end)); for ( ; i < end; ++i) { RegisteredEventListener& registeredListener = entry[i]; if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture) continue; if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture) continue; // If stopImmediatePropagation has been called, we just break out immediately, without // handling any more events on this target. if (event->immediatePropagationStopped()) break; ScriptExecutionContext* context = scriptExecutionContext(); InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(context, event); // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling // event listeners, even though that violates some versions of the DOM spec. registeredListener.listener->handleEvent(context, event); if (!userEventWasHandled && ScriptController::processingUserGesture()) userEventWasHandled = true; InspectorInstrumentation::didHandleEvent(cookie); } d->firingEventIterators->removeLast(); if (userEventWasHandled) { ScriptExecutionContext* context = scriptExecutionContext(); if (context && context->isDocument()) { Document* document = toDocument(context); document->resetLastHandledUserGestureTimestamp(); } } }
void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry) { RefPtr<EventTarget> protect(this); // Fire all listeners registered for this event. Don't fire listeners removed // during event dispatch. Also, don't fire event listeners added during event // dispatch. Conveniently, all new event listeners will be added after or at // index |size|, so iterating up to (but not including) |size| naturally excludes // new event listeners. size_t i = 0; size_t size = entry.size(); if (!d->firingEventIterators) d->firingEventIterators = adoptPtr(new FiringEventIteratorVector); d->firingEventIterators->append(FiringEventIterator(event->type(), i, size)); for ( ; i < size; ++i) { RegisteredEventListener& registeredListener = entry[i]; if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture) continue; if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture) continue; // If stopImmediatePropagation has been called, we just break out immediately, without // handling any more events on this target. if (event->immediatePropagationStopped()) break; ExecutionContext* context = executionContext(); if (!context) break; // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling // event listeners, even though that violates some versions of the DOM spec. registeredListener.listener->handleEvent(context, event); } d->firingEventIterators->removeLast(); }
void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry) { RefPtrWillBeRawPtr<EventTarget> protect(this); // Fire all listeners registered for this event. Don't fire listeners removed // during event dispatch. Also, don't fire event listeners added during event // dispatch. Conveniently, all new event listeners will be added after or at // index |size|, so iterating up to (but not including) |size| naturally excludes // new event listeners. if (event->type() == EventTypeNames::beforeunload) { if (LocalDOMWindow* executingWindow = this->executingWindow()) { if (executingWindow->top()) UseCounter::count(executingWindow->document(), UseCounter::SubFrameBeforeUnloadFired); UseCounter::count(executingWindow->document(), UseCounter::DocumentBeforeUnloadFired); } } else if (event->type() == EventTypeNames::unload) { if (LocalDOMWindow* executingWindow = this->executingWindow()) UseCounter::count(executingWindow->document(), UseCounter::DocumentUnloadFired); } else if (event->type() == EventTypeNames::DOMFocusIn || event->type() == EventTypeNames::DOMFocusOut) { if (LocalDOMWindow* executingWindow = this->executingWindow()) UseCounter::count(executingWindow->document(), UseCounter::DOMFocusInOutEvent); } else if (event->type() == EventTypeNames::focusin || event->type() == EventTypeNames::focusout) { if (LocalDOMWindow* executingWindow = this->executingWindow()) UseCounter::count(executingWindow->document(), UseCounter::FocusInOutEvent); } else if (event->type() == EventTypeNames::textInput) { if (LocalDOMWindow* executingWindow = this->executingWindow()) UseCounter::count(executingWindow->document(), UseCounter::TextInputFired); } size_t i = 0; size_t size = entry.size(); if (!d->firingEventIterators) d->firingEventIterators = adoptPtr(new FiringEventIteratorVector); d->firingEventIterators->append(FiringEventIterator(event->type(), i, size)); while (i < size) { RegisteredEventListener& registeredListener = entry[i]; // Move the iterator past this event listener. This must match // the handling of the FiringEventIterator::iterator in // EventTarget::removeEventListener. ++i; if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture) continue; if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture) continue; // If stopImmediatePropagation has been called, we just break out immediately, without // handling any more events on this target. if (event->immediatePropagationStopped()) break; ExecutionContext* context = executionContext(); if (!context) break; InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(this, event, registeredListener.listener.get(), registeredListener.useCapture); // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling // event listeners, even though that violates some versions of the DOM spec. registeredListener.listener->handleEvent(context, event); RELEASE_ASSERT(i <= size); InspectorInstrumentation::didHandleEvent(cookie); } d->firingEventIterators->removeLast(); }