void EventRetargeter::calculateEventPath(Node* targetNode, Event* event, EventPath& eventPath) { bool inDocument = targetNode->inDocument(); bool isSVGElement = targetNode->isSVGElement(); bool isMouseOrFocusEvent = event->isMouseEvent() || event->isFocusEvent(); #if ENABLE(TOUCH_EVENTS) bool isTouchEvent = event->isTouchEvent(); #endif Vector<EventTarget*, 32> targetStack; for (Node* node = nodeOrHostIfPseudoElement(targetNode); node; node = node->parentOrShadowHostNode()) { if (targetStack.isEmpty()) targetStack.append(eventTargetRespectingTargetRules(node)); if (isMouseOrFocusEvent) eventPath.append(adoptPtr(new MouseOrFocusEventContext(node, eventTargetRespectingTargetRules(node), targetStack.last()))); #if ENABLE(TOUCH_EVENTS) else if (isTouchEvent) eventPath.append(adoptPtr(new TouchEventContext(node, eventTargetRespectingTargetRules(node), targetStack.last()))); #endif else eventPath.append(adoptPtr(new EventContext(node, eventTargetRespectingTargetRules(node), targetStack.last()))); if (!inDocument) return; if (!node->isShadowRoot()) continue; if (determineDispatchBehavior(event, toShadowRoot(node), targetStack.last()) == StayInsideShadowDOM) return; if (!isSVGElement) { ASSERT(!targetStack.isEmpty()); targetStack.removeLast(); } } }
void EventDispatcher::ensureEventAncestors(Event* event) { if (m_ancestorsInitialized) return; m_ancestorsInitialized = true; bool inDocument = m_node->inDocument(); bool isSVGElement = m_node->isSVGElement(); Vector<EventTarget*, 32> targetStack; for (AncestorChainWalker walker(m_node.get()); walker.get(); walker.parent()) { Node* node = walker.get(); if (targetStack.isEmpty()) targetStack.append(eventTargetRespectingTargetRules(node)); else if (walker.crossingInsertionPoint()) targetStack.append(targetStack.last()); m_ancestors.append(EventContext(node, eventTargetRespectingTargetRules(node), targetStack.last())); if (!inDocument) return; if (!node->isShadowRoot()) continue; if (determineDispatchBehavior(event, toShadowRoot(node), targetStack.last()) == StayInsideShadowDOM) return; if (!isSVGElement) { ASSERT(!targetStack.isEmpty()); targetStack.removeLast(); } } }
void EventRetargeter::calculateEventPath(Node* node, Event* event) { EventPath& eventPath = event->eventPath(); eventPath.clear(); bool inDocument = node->inDocument(); bool isSVGElement = node->isSVGElement(); bool isMouseOrFocusEvent = event->isMouseEvent() || event->isFocusEvent(); bool isTouchEvent = event->isTouchEvent(); Vector<EventTarget*, 32> targetStack; for (EventPathWalker walker(node); walker.node(); walker.moveToParent()) { Node* node = walker.node(); if (targetStack.isEmpty()) targetStack.append(eventTargetRespectingTargetRules(node)); else if (walker.isVisitingInsertionPointInReprojection()) targetStack.append(targetStack.last()); if (isMouseOrFocusEvent) eventPath.append(adoptPtr(new MouseOrFocusEventContext(node, eventTargetRespectingTargetRules(node), targetStack.last()))); else if (isTouchEvent) eventPath.append(adoptPtr(new TouchEventContext(node, eventTargetRespectingTargetRules(node), targetStack.last()))); else eventPath.append(adoptPtr(new EventContext(node, eventTargetRespectingTargetRules(node), targetStack.last()))); if (!inDocument) return; if (!node->isShadowRoot()) continue; if (determineDispatchBehavior(event, toShadowRoot(node), targetStack.last()) == StayInsideShadowDOM) return; if (!isSVGElement) { ASSERT(!targetStack.isEmpty()); targetStack.removeLast(); } } }
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(); } } }
void EventRetargeter::calculateEventPath(Node* node, Event* event) { EventPath& eventPath = event->eventPath(); eventPath.clear(); bool inDocument = node->inDocument(); bool isSVGElement = node->isSVGElement(); bool isMouseOrFocusEvent = event->isMouseEvent() || event->isFocusEvent(); bool isTouchEvent = event->isTouchEvent(); Vector<EventTarget*, 32> targetStack; for (EventPathWalker walker(node); walker.node(); walker.moveToParent()) { Node* node = walker.node(); if (targetStack.isEmpty()) targetStack.append(eventTargetRespectingTargetRules(node)); else if (walker.isVisitingInsertionPointInReprojection()) targetStack.append(targetStack.last()); if (isMouseOrFocusEvent) eventPath.append(adoptPtr(new MouseOrFocusEventContext(node, eventTargetRespectingTargetRules(node), targetStack.last()))); else if (isTouchEvent) eventPath.append(adoptPtr(new TouchEventContext(node, eventTargetRespectingTargetRules(node), targetStack.last()))); else eventPath.append(adoptPtr(new EventContext(node, eventTargetRespectingTargetRules(node), targetStack.last()))); if (!inDocument) return; if (!node->isShadowRoot()) continue; if (determineDispatchBehavior(event, toShadowRoot(node), targetStack.last()) == StayInsideShadowDOM) return; if (!isSVGElement) { ASSERT(!targetStack.isEmpty()); targetStack.removeLast(); } } // Calculates eventPath for each node for Event.path() API. if (!RuntimeEnabledFeatures::experimentalShadowDOMEnabled()) return; TreeScope* lastScope = 0; size_t eventPathSize = eventPath.size(); for (size_t i = 0; i < eventPathSize; ++i) { TreeScope* currentScope = eventPath[i]->node()->treeScope(); if (currentScope == lastScope) { // Fast path. eventPath[i]->setEventPath(eventPath[i - 1]->eventPath()); continue; } lastScope = currentScope; Vector<RefPtr<Node> > nodes; for (size_t j = 0; j < eventPathSize; ++j) { Node* node = eventPath[j]->node(); if (node->treeScope()->isInclusiveAncestorOf(currentScope)) nodes.append(node); } eventPath[i]->adoptEventPath(nodes); } }
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)); } }
void EventPath::calculatePath() { ASSERT(m_node); ASSERT(m_nodeEventContexts.isEmpty()); m_node->document().updateDistributionForNodeIfNeeded(const_cast<Node*>(m_node)); Node* current = m_node; addNodeEventContext(current); if (!m_node->inDocument()) return; while (current) { if (current->isShadowRoot() && m_event && determineDispatchBehavior(m_event, toShadowRoot(current), m_node) == StayInsideShadowDOM) break; Vector<InsertionPoint*, 8> insertionPoints; collectDestinationInsertionPoints(*current, insertionPoints); if (!insertionPoints.isEmpty()) { for (size_t i = 0; i < insertionPoints.size(); ++i) { InsertionPoint* insertionPoint = insertionPoints[i]; if (insertionPoint->isShadowInsertionPoint()) { ShadowRoot* containingShadowRoot = insertionPoint->containingShadowRoot(); ASSERT(containingShadowRoot); if (!containingShadowRoot->isOldest()) addNodeEventContext(containingShadowRoot->olderShadowRoot()); } addNodeEventContext(insertionPoint); } current = insertionPoints.last(); continue; } if (current->isShadowRoot()) { current = current->shadowHost(); addNodeEventContext(current); } else { current = current->parentNode(); if (current) addNodeEventContext(current); } } }
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(); getEventAncestors(originalTarget.get(), determineDispatchBehavior(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 (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(); i; --i) { m_ancestors[i - 1].handleLocalEvents(event.get()); if (event->propagationStopped()) goto doneDispatching; } event->setEventPhase(Event::AT_TARGET); event->setTarget(originalTarget.get()); event->setCurrentTarget(eventTargetRespectingSVGTargetRules(m_node.get())); m_node->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 = 0; i < size; ++i) { m_ancestors[i].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 = 0; 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(); }