// FIXME: Once https://bugs.webkit.org/show_bug.cgi?id=52963 lands, this should // be greatly improved. See https://bugs.webkit.org/show_bug.cgi?id=54025. PassRefPtr<EventTarget> EventDispatcher::adjustRelatedTarget(Event* event, PassRefPtr<EventTarget> prpRelatedTarget) { if (!prpRelatedTarget) return 0; RefPtr<Node> relatedTarget = prpRelatedTarget->toNode(); if (!relatedTarget) return 0; Node* target = m_node.get(); if (!target) return prpRelatedTarget; ensureEventAncestors(event); // Calculate early if the common boundary is even possible by looking at // ancestors size and if the retargeting has occured (indicating the presence of shadow DOM boundaries). // If there are no boundaries detected, the target and related target can't have a common boundary. bool noCommonBoundary = ancestorsCrossShadowBoundaries(m_ancestors); Vector<Node*> relatedTargetAncestors; Node* outermostShadowBoundary = relatedTarget.get(); for (Node* n = outermostShadowBoundary; n; n = n->parentOrHostNode()) { if (isShadowRootOrSVGShadowRoot(n)) outermostShadowBoundary = n->parentOrHostNode(); if (!noCommonBoundary) relatedTargetAncestors.append(n); } // Short-circuit the fast case when we know there is no need to calculate a common boundary. if (noCommonBoundary) return outermostShadowBoundary; return adjustToShadowBoundaries(relatedTarget.release(), relatedTargetAncestors); }
bool EventDispatcher::dispatchEvent(PassRefPtr<Event> prpEvent) { #ifndef NDEBUG ASSERT(!m_eventDispatched); m_eventDispatched = true; #endif RefPtr<Event> event = prpEvent; ChildNodesLazySnapshot::takeChildNodesLazySnapshot(); event->setTarget(eventTargetRespectingTargetRules(m_node.get())); ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); ASSERT(event->target()); ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null. ensureEventAncestors(event.get()); WindowEventContext windowEventContext(event.get(), m_node.get(), topEventContext()); InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEvent(m_node->document(), *event, windowEventContext.window(), m_node.get(), m_ancestors); void* preDispatchEventHandlerResult; if (dispatchEventPreProcess(event, preDispatchEventHandlerResult) == ContinueDispatching) if (dispatchEventAtCapturing(event, windowEventContext) == ContinueDispatching) if (dispatchEventAtTarget(event) == ContinueDispatching) dispatchEventAtBubbling(event, windowEventContext); dispatchEventPostProcess(event, preDispatchEventHandlerResult); // Ensure that after event dispatch, the event's target object is the // outermost shadow DOM boundary. event->setTarget(windowEventContext.target()); event->setCurrentTarget(0); InspectorInstrumentation::didDispatchEvent(cookie); return !event->defaultPrevented(); }
void EventDispatcher::adjustRelatedTarget(Event* event, PassRefPtr<EventTarget> prpRelatedTarget) { if (!prpRelatedTarget) return; RefPtr<Node> relatedTarget = prpRelatedTarget->toNode(); if (!relatedTarget) return; if (!m_node.get()) return; ensureEventAncestors(event); EventRelatedTargetAdjuster(m_node, relatedTarget.release()).adjust(m_ancestors); }
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(); }