inline EventDispatchContinuation EventDispatcher::dispatchEventAtBubbling(PassRefPtr<Event> event, WindowEventContext& windowContext) { if (event->bubbles() && !event->cancelBubble()) { // Trigger bubbling event handlers, starting at the bottom and working our way up. event->setEventPhase(Event::BUBBLING_PHASE); size_t size = m_ancestors.size(); for (size_t i = 1; i < size; ++i) { const EventContext& eventContext = m_ancestors[i]; if (eventContext.currentTargetSameAsTarget()) event->setEventPhase(Event::AT_TARGET); else event->setEventPhase(Event::BUBBLING_PHASE); eventContext.handleLocalEvents(event.get()); if (event->propagationStopped() || event->cancelBubble()) return DoneDispatching; } windowContext.handleLocalEvents(event.get()); } return ContinueDispatching; }
bool EventDispatcher::dispatchEvent(PassRefPtr<Event> event) { event->setTarget(eventTargetRespectingSVGTargetRules(m_node.get())); ASSERT(!eventDispatchForbidden()); ASSERT(event->target()); ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null. RefPtr<EventTarget> originalTarget = event->target(); ensureEventAncestors(event.get()); WindowEventContext windowContext(event.get(), m_node.get(), topEventContext()); InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEvent(m_node->document(), *event, windowContext.window(), m_node.get(), m_ancestors); // Give the target node a chance to do some work before DOM event handlers get a crack. void* data = m_node->preDispatchEventHandler(event.get()); if (m_ancestors.isEmpty() || m_shouldPreventDispatch || event->propagationStopped()) goto doneDispatching; // Trigger capturing event handlers, starting at the top and working our way down. event->setEventPhase(Event::CAPTURING_PHASE); if (windowContext.handleLocalEvents(event.get()) && event->propagationStopped()) goto doneDispatching; for (size_t i = m_ancestors.size() - 1; i > 0; --i) { const EventContext& eventContext = m_ancestors[i]; if (eventContext.currentTargetSameAsTarget()) { if (event->bubbles()) continue; event->setEventPhase(Event::AT_TARGET); } else event->setEventPhase(Event::CAPTURING_PHASE); eventContext.handleLocalEvents(event.get()); if (event->propagationStopped()) goto doneDispatching; } event->setEventPhase(Event::AT_TARGET); event->setTarget(originalTarget.get()); event->setCurrentTarget(eventTargetRespectingSVGTargetRules(m_node.get())); m_ancestors[0].handleLocalEvents(event.get()); if (event->propagationStopped()) goto doneDispatching; if (event->bubbles() && !event->cancelBubble()) { // Trigger bubbling event handlers, starting at the bottom and working our way up. event->setEventPhase(Event::BUBBLING_PHASE); size_t size = m_ancestors.size(); for (size_t i = 1; i < size; ++i) { const EventContext& eventContext = m_ancestors[i]; if (eventContext.currentTargetSameAsTarget()) event->setEventPhase(Event::AT_TARGET); else event->setEventPhase(Event::BUBBLING_PHASE); eventContext.handleLocalEvents(event.get()); if (event->propagationStopped() || event->cancelBubble()) goto doneDispatching; } windowContext.handleLocalEvents(event.get()); } doneDispatching: event->setTarget(originalTarget.get()); event->setCurrentTarget(0); event->setEventPhase(0); // Pass the data from the preDispatchEventHandler to the postDispatchEventHandler. m_node->postDispatchEventHandler(event.get(), data); // Call default event handlers. While the DOM does have a concept of preventing // default handling, the detail of which handlers are called is an internal // implementation detail and not part of the DOM. if (!event->defaultPrevented() && !event->defaultHandled()) { // Non-bubbling events call only one default event handler, the one for the target. m_node->defaultEventHandler(event.get()); ASSERT(!event->defaultPrevented()); if (event->defaultHandled()) goto doneWithDefault; // For bubbling events, call default event handlers on the same targets in the // same order as the bubbling phase. if (event->bubbles()) { size_t size = m_ancestors.size(); for (size_t i = 1; i < size; ++i) { m_ancestors[i].node()->defaultEventHandler(event.get()); ASSERT(!event->defaultPrevented()); if (event->defaultHandled()) goto doneWithDefault; } } } doneWithDefault: // Ensure that after event dispatch, the event's target object is the // outermost shadow DOM boundary. event->setTarget(windowContext.target()); event->setCurrentTarget(0); InspectorInstrumentation::didDispatchEvent(cookie); return !event->defaultPrevented(); }