void EventDispatcher::ensureEventAncestors(Event* event) { if (m_ancestorsInitialized) return; m_ancestorsInitialized = true; bool inDocument = m_node->inDocument(); bool isSVGElement = m_node->isSVGElement(); Vector<EventTarget*> targetStack; Node* last = 0; for (ComposedShadowTreeParentWalker walker(m_node.get()); walker.get(); walker.parentIncludingInsertionPointAndShadowRoot()) { Node* node = walker.get(); if (targetStack.isEmpty()) targetStack.append(eventTargetRespectingSVGTargetRules(node)); else if (isInsertionPoint(node) && toInsertionPoint(node)->contains(last)) targetStack.append(targetStack.last()); m_ancestors.append(EventContext(node, eventTargetRespectingSVGTargetRules(node), targetStack.last())); if (!inDocument) return; last = node; if (!node->isShadowRoot()) continue; if (determineDispatchBehavior(event, toShadowRoot(node), targetStack.last()) == StayInsideShadowDOM) return; if (!isSVGElement) { ASSERT(!targetStack.isEmpty()); targetStack.removeLast(); } } }
inline void EventDispatcher::dispatchEventPostProcess(PassRefPtr<Event> event, void* preDispatchEventHandlerResult) { event->setTarget(eventTargetRespectingSVGTargetRules(m_node.get())); event->setCurrentTarget(0); event->setEventPhase(0); // Pass the data from the preDispatchEventHandler to the postDispatchEventHandler. m_node->postDispatchEventHandler(event.get(), preDispatchEventHandlerResult); // 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()) return; // 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()) return; } } } }
bool EventDispatcher::dispatchEvent(PassRefPtr<Event> prpEvent) { #ifndef NDEBUG ASSERT(!m_eventDispatched); m_eventDispatched = true; #endif RefPtr<Event> event = prpEvent; ChildNodesLazySnapshot::takeChildNodesLazySnapshot(); 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. 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::dispatchScopedEvent(Node* node, PassRefPtr<Event> event) { // We need to set the target here because it can go away by the time we actually fire the event. event->setTarget(eventTargetRespectingSVGTargetRules(node)); ScopedEventQueue::instance()->enqueueEvent(event); }
void EventDispatcher::getEventAncestors(EventTarget* originalTarget, EventDispatchBehavior behavior) { if (!m_node->inDocument()) return; if (ancestorsInitialized()) return; EventTarget* target = originalTarget; Node* ancestor = m_node.get(); bool shouldSkipNextAncestor = false; while (true) { if (ancestor->isShadowRoot()) { if (behavior == StayInsideShadowDOM) return; ancestor = ancestor->shadowHost(); if (!shouldSkipNextAncestor) target = ancestor; } else ancestor = ancestor->parentNodeGuaranteedHostFree(); if (!ancestor) return; #if ENABLE(SVG) // Skip SVGShadowTreeRootElement. shouldSkipNextAncestor = ancestor->isSVGElement() && ancestor->isShadowRoot(); if (shouldSkipNextAncestor) continue; #endif // FIXME: Unroll the extra loop inside eventTargetRespectingSVGTargetRules into this loop. m_ancestors.append(EventContext(ancestor, eventTargetRespectingSVGTargetRules(ancestor), target)); } }
void EventDispatcher::ensureEventAncestors(Event* event) { if (!m_node->inDocument()) return; if (m_ancestorsInitialized) return; m_ancestorsInitialized = true; Node* ancestor = m_node.get(); EventTarget* target = eventTargetRespectingSVGTargetRules(ancestor); bool shouldSkipNextAncestor = false; while (true) { bool isSVGShadowRoot = ancestor->isSVGShadowRoot(); if (isSVGShadowRoot || ancestor->isShadowRoot()) { if (determineDispatchBehavior(event, ancestor) == StayInsideShadowDOM) return; #if ENABLE(SVG) ancestor = isSVGShadowRoot ? ancestor->svgShadowHost() : ancestor->shadowHost(); #else ancestor = ancestor->shadowHost(); #endif if (!shouldSkipNextAncestor) target = ancestor; } else ancestor = ancestor->parentNodeGuaranteedHostFree(); if (!ancestor) return; #if ENABLE(SVG) // Skip SVGShadowTreeRootElement. shouldSkipNextAncestor = ancestor->isSVGShadowRoot(); if (shouldSkipNextAncestor) continue; #endif // FIXME: Unroll the extra loop inside eventTargetRespectingSVGTargetRules into this loop. m_ancestors.append(EventContext(ancestor, eventTargetRespectingSVGTargetRules(ancestor), target)); } }
bool EventTargetNode::dispatchEvent(PassRefPtr<Event> e, ExceptionCode& ec) { RefPtr<Event> evt(e); ASSERT(!eventDispatchForbidden()); if (!evt || evt->type().isEmpty()) { ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR; return false; } evt->setTarget(eventTargetRespectingSVGTargetRules(this)); RefPtr<FrameView> view = document()->view(); return dispatchGenericEvent(evt.release()); }
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(); }
bool EventTargetNode::dispatchGenericEvent(PassRefPtr<Event> prpEvent) { RefPtr<Event> event(prpEvent); ASSERT(!eventDispatchForbidden()); ASSERT(event->target()); ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null. // Make a vector of ancestors to send the event to. // If the node is not in a document just send the event to it. // Be sure to ref all of nodes since event handlers could result in the last reference going away. RefPtr<EventTargetNode> thisNode(this); Vector<RefPtr<ContainerNode> > ancestors; if (inDocument()) { for (ContainerNode* ancestor = eventParentNode(); ancestor; ancestor = ancestor->eventParentNode()) { #if ENABLE(SVG) // Skip <use> shadow tree elements. if (ancestor->isSVGElement() && ancestor->isShadowNode()) continue; #endif ancestors.append(ancestor); } } // Set up a pointer to indicate whether to dispatch window events. // We don't dispatch load events to the window. That quirk was originally // added because Mozilla doesn't propagate load events to the window object. Document* documentForWindowEvents = 0; if (event->type() != eventNames().loadEvent) { EventTargetNode* topLevelContainer = ancestors.isEmpty() ? this : ancestors.last().get(); if (topLevelContainer->isDocumentNode()) documentForWindowEvents = static_cast<Document*>(topLevelContainer); } // Give the target node a chance to do some work before DOM event handlers get a crack. void* data = preDispatchEventHandler(event.get()); if (event->propagationStopped()) goto doneDispatching; // Trigger capturing event handlers, starting at the top and working our way down. event->setEventPhase(Event::CAPTURING_PHASE); if (documentForWindowEvents) { event->setCurrentTarget(documentForWindowEvents); documentForWindowEvents->handleWindowEvent(event.get(), true); if (event->propagationStopped()) goto doneDispatching; } for (size_t i = ancestors.size(); i; --i) { ContainerNode* ancestor = ancestors[i - 1].get(); event->setCurrentTarget(eventTargetRespectingSVGTargetRules(ancestor)); ancestor->handleLocalEvents(event.get(), true); if (event->propagationStopped()) goto doneDispatching; } event->setEventPhase(Event::AT_TARGET); // We do want capturing event listeners to be invoked here, even though // that violates some versions of the DOM specification; Mozilla does it. event->setCurrentTarget(eventTargetRespectingSVGTargetRules(this)); handleLocalEvents(event.get(), true); if (event->propagationStopped()) goto doneDispatching; handleLocalEvents(event.get(), false); 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 = ancestors.size(); for (size_t i = 0; i < size; ++i) { ContainerNode* ancestor = ancestors[i].get(); event->setCurrentTarget(eventTargetRespectingSVGTargetRules(ancestor)); ancestor->handleLocalEvents(event.get(), false); if (event->propagationStopped() || event->cancelBubble()) goto doneDispatching; } if (documentForWindowEvents) { event->setCurrentTarget(documentForWindowEvents); documentForWindowEvents->handleWindowEvent(event.get(), false); if (event->propagationStopped() || event->cancelBubble()) goto doneDispatching; } } doneDispatching: event->setCurrentTarget(0); event->setEventPhase(0); // Pass the data from the preDispatchEventHandler to the postDispatchEventHandler. 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. 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 = ancestors.size(); for (size_t i = 0; i < size; ++i) { ContainerNode* ancestor = ancestors[i].get(); ancestor->defaultEventHandler(event.get()); ASSERT(!event->defaultPrevented()); if (event->defaultHandled()) goto doneWithDefault; } } } doneWithDefault: Document::updateDocumentsRendering(); return !event->defaultPrevented(); }
bool EventTarget::dispatchGenericEvent(EventTargetNode* referenceNode, PassRefPtr<Event> e, ExceptionCode&, bool tempEvent) { RefPtr<Event> evt(e); ASSERT(!eventDispatchForbidden()); ASSERT(evt->target()); ASSERT(!evt->type().isNull()); // JavaScript code could create an event with an empty name // work out what nodes to send event to DeprecatedPtrList<Node> nodeChain; if (referenceNode->inDocument()) { for (Node* n = referenceNode; n; n = n->eventParentNode()) { n->ref(); nodeChain.prepend(n); } } else { // if node is not in the document just send event to itself referenceNode->ref(); nodeChain.prepend(referenceNode); } DeprecatedPtrListIterator<Node> it(nodeChain); // Before we begin dispatching events, give the target node a chance to do some work prior // to the DOM event handlers getting a crack. void* data = preDispatchEventHandler(evt.get()); // trigger any capturing event handlers on our way down evt->setEventPhase(Event::CAPTURING_PHASE); it.toFirst(); // Handle window events for capture phase, except load events, this quirk is needed // because Mozilla used to never propagate load events to the window object if (evt->type() != eventNames().loadEvent && it.current()->isDocumentNode() && !evt->propagationStopped()) static_cast<Document*>(it.current())->handleWindowEvent(evt.get(), true); EventTargetNode* eventTargetNode = 0; for (; it.current() && it.current() != referenceNode && !evt->propagationStopped(); ++it) { eventTargetNode = EventTargetNodeCast(it.current()); evt->setCurrentTarget(eventTargetRespectingSVGTargetRules(eventTargetNode)); eventTargetNode->handleLocalEvents(evt.get(), true); } // dispatch to the actual target node it.toLast(); if (!evt->propagationStopped()) { evt->setEventPhase(Event::AT_TARGET); eventTargetNode = EventTargetNodeCast(it.current()); evt->setCurrentTarget(eventTargetRespectingSVGTargetRules(eventTargetNode)); // We do want capturing event listeners to be invoked here, even though // that violates the specification since Mozilla does it. eventTargetNode->handleLocalEvents(evt.get(), true); eventTargetNode->handleLocalEvents(evt.get(), false); } --it; // ok, now bubble up again (only non-capturing event handlers will be called) // ### recalculate the node chain here? (e.g. if target node moved in document by previous event handlers) // no. the DOM specs says: // The chain of EventTargets from the event target to the top of the tree // is determined before the initial dispatch of the event. // If modifications occur to the tree during event processing, // event flow will proceed based on the initial state of the tree. // // since the initial dispatch is before the capturing phase, // there's no need to recalculate the node chain. // (tobias) if (evt->bubbles()) { evt->setEventPhase(Event::BUBBLING_PHASE); for (; it.current() && !evt->propagationStopped() && !evt->cancelBubble(); --it) { eventTargetNode = EventTargetNodeCast(it.current()); evt->setCurrentTarget(eventTargetRespectingSVGTargetRules(eventTargetNode)); eventTargetNode->handleLocalEvents(evt.get(), false); } it.toFirst(); // Handle window events for bubbling phase, except load events, this quirk is needed // because Mozilla used to never propagate load events at all if (evt->type() != eventNames().loadEvent && it.current()->isDocumentNode() && !evt->propagationStopped() && !evt->cancelBubble()) { evt->setCurrentTarget(EventTargetNodeCast(it.current())); static_cast<Document*>(it.current())->handleWindowEvent(evt.get(), false); } } evt->setCurrentTarget(0); evt->setEventPhase(0); // I guess this is correct, the spec does not seem to say // anything about the default event handler phase. // Now call the post dispatch. postDispatchEventHandler(evt.get(), data); // now we call all default event handlers (this is not part of DOM - it is internal to WebCore) it.toLast(); if (evt->bubbles()) for (; it.current() && !evt->defaultPrevented() && !evt->defaultHandled(); --it) EventTargetNodeCast(it.current())->defaultEventHandler(evt.get()); else if (!evt->defaultPrevented() && !evt->defaultHandled()) EventTargetNodeCast(it.current())->defaultEventHandler(evt.get()); // deref all nodes in chain it.toFirst(); for (; it.current(); ++it) it.current()->deref(); // this may delete us Document::updateDocumentsRendering(); // If tempEvent is true, this means that the DOM implementation // will not be storing a reference to the event, i.e. there is no // way to retrieve it from javascript if a script does not already // have a reference to it in a variable. So there is no need for // the interpreter to keep the event in it's cache Frame* frame = referenceNode->document()->frame(); if (tempEvent && frame && frame->script()->isEnabled()) frame->script()->finishedWithEvent(evt.get()); return !evt->defaultPrevented(); // ### what if defaultPrevented was called before dispatchEvent? }