void EventListenerMap::removeFirstEventListenerCreatedFromMarkup(const AtomicString& eventType) { ASSERT(!m_activeIteratorCount); if (m_hashMap) { EventListenerHashMap::iterator result = m_hashMap->find(eventType); ASSERT(result != m_hashMap->end()); EventListenerVector* listenerVector = result->second; ASSERT(listenerVector); removeFirstListenerCreatedFromMarkup(listenerVector); if (listenerVector->isEmpty()) { delete listenerVector; m_hashMap->remove(result); } return; } ASSERT(m_singleEventListenerVector); ASSERT(m_singleEventListenerType == eventType); removeFirstListenerCreatedFromMarkup(m_singleEventListenerVector.get()); if (m_singleEventListenerVector->isEmpty()) { m_singleEventListenerVector.clear(); m_singleEventListenerType = nullAtom; } }
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)); } } }
static void removeFirstListenerCreatedFromMarkup(EventListenerVector& listenerVector) { bool foundListener = listenerVector.removeFirstMatching([] (const RegisteredEventListener& listener) { return listener.listener->wasCreatedFromMarkup(); }); ASSERT_UNUSED(foundListener, foundListener); }
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(); } }
static bool removeListenerFromVector(EventListenerVector& listeners, EventListener& listener, bool useCapture) { size_t indexOfRemovedListener = findListener(listeners, listener, useCapture); if (UNLIKELY(indexOfRemovedListener == notFound)) return false; listeners[indexOfRemovedListener]->markAsRemoved(); listeners.remove(indexOfRemovedListener); return true; }
static void removeFirstListenerCreatedFromMarkup(EventListenerVector& listenerVector) { bool foundListener = listenerVector.removeFirstMatching([] (const auto& registeredListener) { if (registeredListener->callback().wasCreatedFromMarkup()) { registeredListener->markAsRemoved(); return true; } return false; }); ASSERT_UNUSED(foundListener, foundListener); }
bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture) { EventTargetData* d = eventTargetData(); if (!d) return false; EventListenerMap::iterator result = d->eventListenerMap.find(eventType); if (result == d->eventListenerMap.end()) return false; EventListenerVector* entry = result->second; RegisteredEventListener registeredListener(listener, useCapture); size_t index = entry->find(registeredListener); if (index == notFound) return false; entry->remove(index); if (entry->isEmpty()) { delete entry; d->eventListenerMap.remove(result); } // Notify firing events planning to invoke the listener at 'index' that // they have one less listener to invoke. for (size_t i = 0; i < d->firingEventIterators.size(); ++i) { if (eventType != d->firingEventIterators[i].eventType) continue; if (index >= d->firingEventIterators[i].end) continue; --d->firingEventIterators[i].end; if (index <= d->firingEventIterators[i].iterator) --d->firingEventIterators[i].iterator; } return true; }
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 EventDispatcher::forceAddEventListener(EventListener* listener) { EventListenerVector* listeners = nullptr; EventListener::ListenerID listenerID = listener->getListenerID(); auto itr = _listenerMap.find(listenerID); if (itr == _listenerMap.end()) { listeners = new (std::nothrow) EventListenerVector(); _listenerMap.insert(std::make_pair(listenerID, listeners)); } else { listeners = itr->second; } listeners->push_back(listener); if (listener->getFixedPriority() == 0) { setDirty(listenerID, DirtyFlag::SCENE_GRAPH_PRIORITY); auto node = listener->getAssociatedNode(); CCASSERT(node != nullptr, "Invalid scene graph priority!"); associateNodeAndEventListener(node, listener); if (node->isRunning()) { resumeEventListenersForTarget(node); } } else { setDirty(listenerID, DirtyFlag::FIXED_PRIORITY); } }
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(); }