TreeScopeEventContext* EventPath::ensureTreeScopeEventContext(Node* currentTarget, TreeScope* treeScope, TreeScopeEventContextMap& treeScopeEventContextMap) { if (!treeScope) return 0; TreeScopeEventContext* treeScopeEventContext; bool isNewEntry; { TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(treeScope, nullptr); isNewEntry = addResult.isNewEntry; if (isNewEntry) addResult.storedValue->value = TreeScopeEventContext::create(*treeScope); treeScopeEventContext = addResult.storedValue->value.get(); } if (isNewEntry) { TreeScopeEventContext* parentTreeScopeEventContext = ensureTreeScopeEventContext(0, treeScope->olderShadowRootOrParentTreeScope(), treeScopeEventContextMap); if (parentTreeScopeEventContext && parentTreeScopeEventContext->target()) { treeScopeEventContext->setTarget(parentTreeScopeEventContext->target()); } else if (currentTarget) { treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(*currentTarget)); } } else if (!treeScopeEventContext->target() && currentTarget) { treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(*currentTarget)); } return treeScopeEventContext; }
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 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*, 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(); } } }
EventPath::EventPath(Node& targetNode, Event& event) { bool inDocument = targetNode.inDocument(); bool isSVGElement = targetNode.isSVGElement(); bool isMouseOrFocusEvent = event.isMouseEvent() || event.isFocusEvent(); #if ENABLE(TOUCH_EVENTS) bool isTouchEvent = event.isTouchEvent(); #endif EventTarget* target = 0; Node* node = nodeOrHostIfPseudoElement(&targetNode); while (node) { if (!target || !isSVGElement) // FIXME: This code doesn't make sense once we've climbed out of the SVG subtree in a HTML document. target = &eventTargetRespectingTargetRules(*node); for (; node; node = node->parentNode()) { EventTarget& currentTarget = eventTargetRespectingTargetRules(*node); if (isMouseOrFocusEvent) m_path.append(std::make_unique<MouseOrFocusEventContext>(node, ¤tTarget, target)); #if ENABLE(TOUCH_EVENTS) else if (isTouchEvent) m_path.append(std::make_unique<TouchEventContext>(node, ¤tTarget, target)); #endif else m_path.append(std::make_unique<EventContext>(node, ¤tTarget, target)); if (!inDocument) return; if (node->isShadowRoot()) break; } if (!node || !shouldEventCrossShadowBoundary(event, *toShadowRoot(node), *target)) return; node = toShadowRoot(node)->hostElement(); } }
bool EventDispatcher::dispatchEvent(Node* origin, PassRefPtr<Event> prpEvent) { ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden()); if (!prpEvent) return true; ASSERT(origin); RefPtr<Node> node(origin); RefPtr<Event> event(prpEvent); RefPtr<FrameView> view = node->document().view(); EventPath eventPath(*node, *event); if (EventTarget* relatedTarget = event->relatedTarget()) eventPath.setRelatedTarget(*node, *relatedTarget); #if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) if (is<TouchEvent>(*event)) { if (!eventPath.updateTouchLists(downcast<TouchEvent>(*event))) return true; } #endif ChildNodesLazySnapshot::takeChildNodesLazySnapshot(); EventTarget* target = eventTargetRespectingTargetRules(*node); event->setTarget(target); if (!event->target()) return true; ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden()); WindowEventContext windowEventContext(node.get(), eventPath.lastContextIfExists()); InputElementClickState clickHandlingState; if (is<HTMLInputElement>(*node)) downcast<HTMLInputElement>(*node).willDispatchEvent(*event, clickHandlingState); if (!event->propagationStopped() && !eventPath.isEmpty()) dispatchEventInDOM(*event, eventPath, windowEventContext); event->setTarget(eventTargetRespectingTargetRules(*node)); event->setCurrentTarget(nullptr); event->setEventPhase(0); if (clickHandlingState.stateful) downcast<HTMLInputElement>(*node).didDispatchClickEvent(*event, clickHandlingState); // 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()) callDefaultEventHandlersInTheBubblingOrder(*event, eventPath); // Ensure that after event dispatch, the event's target object is the // outermost shadow DOM boundary. event->setTarget(windowEventContext.target()); event->setCurrentTarget(0); return !event->defaultPrevented(); }
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); } }
EventPath::EventPath(Node& originalTarget, Event& event) : m_event(event) { bool isMouseOrFocusEvent = event.isMouseEvent() || event.isFocusEvent(); #if ENABLE(TOUCH_EVENTS) bool isTouchEvent = event.isTouchEvent(); #endif Node* node = nodeOrHostIfPseudoElement(&originalTarget); Node* target = node ? eventTargetRespectingTargetRules(*node) : nullptr; while (node) { while (node) { EventTarget* currentTarget = eventTargetRespectingTargetRules(*node); if (isMouseOrFocusEvent) m_path.append(std::make_unique<MouseOrFocusEventContext>(node, currentTarget, target)); #if ENABLE(TOUCH_EVENTS) else if (isTouchEvent) m_path.append(std::make_unique<TouchEventContext>(node, currentTarget, target)); #endif else m_path.append(std::make_unique<EventContext>(node, currentTarget, target)); if (is<ShadowRoot>(*node)) break; ContainerNode* parent = node->parentNode(); if (!parent) return; #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT) if (ShadowRoot* shadowRootOfParent = parent->shadowRoot()) { if (auto* assignedSlot = shadowRootOfParent->findAssignedSlot(*node)) { // node is assigned to a slot. Continue dispatching the event at this slot. parent = assignedSlot; } } #endif node = parent; } bool exitingShadowTreeOfTarget = &target->treeScope() == &node->treeScope(); ShadowRoot& shadowRoot = downcast<ShadowRoot>(*node); if (!shouldEventCrossShadowBoundary(event, shadowRoot, originalTarget)) return; node = shadowRoot.host(); if (exitingShadowTreeOfTarget) target = eventTargetRespectingTargetRules(*node); } }
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(); }
inline void EventDispatcher::dispatchEventPostProcess(PassRefPtr<Event> event, void* preDispatchEventHandlerResult) { event->setTarget(eventTargetRespectingTargetRules(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; } } } }
void EventPath::calculateAdjustedTargets() { const TreeScope* lastTreeScope = 0; bool useDeprecatedSVGUseTreeEventRules = usesDeprecatedSVGUseTreeEventRules(at(0).node()); TreeScopeEventContextMap treeScopeEventContextMap; TreeScopeEventContext* lastTreeScopeEventContext = 0; for (size_t i = 0; i < size(); ++i) { Node* currentNode = at(i).node(); TreeScope& currentTreeScope = currentNode->treeScope(); if (lastTreeScope != ¤tTreeScope) { if (!useDeprecatedSVGUseTreeEventRules) { lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, ¤tTreeScope, treeScopeEventContextMap); } else { TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(¤tTreeScope, TreeScopeEventContext::create(currentTreeScope)); lastTreeScopeEventContext = addResult.storedValue->value.get(); if (addResult.isNewEntry) { // Don't adjust an event target for SVG. lastTreeScopeEventContext->setTarget(eventTargetRespectingTargetRules(at(0).node())); } } } ASSERT(lastTreeScopeEventContext); at(i).setTreeScopeEventContext(lastTreeScopeEventContext); lastTreeScope = ¤tTreeScope; } m_treeScopeEventContexts.appendRange(treeScopeEventContextMap.values().begin(), treeScopeEventContextMap.values().end()); }
void EventPath::calculatePath() { ASSERT(m_node); ASSERT(m_nodeEventContexts.isEmpty()); m_node->updateDistribution(); // For performance and memory usage reasons we want to store the // path using as few bytes as possible and with as few allocations // as possible which is why we gather the data on the stack before // storing it in a perfectly sized m_nodeEventContexts Vector. WillBeHeapVector<RawPtrWillBeMember<Node>, 64> nodesInPath; Node* current = m_node; nodesInPath.append(current); while (current) { if (m_event && current->keepEventInNode(m_event)) break; WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints; collectDestinationInsertionPoints(*current, insertionPoints); if (!insertionPoints.isEmpty()) { for (const auto& insertionPoint : insertionPoints) { if (insertionPoint->isShadowInsertionPoint()) { ShadowRoot* containingShadowRoot = insertionPoint->containingShadowRoot(); ASSERT(containingShadowRoot); if (!containingShadowRoot->isOldest()) nodesInPath.append(containingShadowRoot->olderShadowRoot()); } nodesInPath.append(insertionPoint); } current = insertionPoints.last(); continue; } if (current->isShadowRoot()) { if (m_event && shouldStopAtShadowRoot(*m_event, *toShadowRoot(current), *m_node)) break; current = current->shadowHost(); #if !ENABLE(OILPAN) // TODO(kochi): crbug.com/507413 This check is necessary when some asynchronous event // is queued while its shadow host is removed and the shadow root gets the event // immediately after it. When Oilpan is enabled, this situation does not happen. // Except this case, shadow root's host is assumed to be non-null. if (current) nodesInPath.append(current); #else nodesInPath.append(current); #endif } else { current = current->parentNode(); if (current) nodesInPath.append(current); } } m_nodeEventContexts.reserveCapacity(nodesInPath.size()); for (Node* nodeInPath : nodesInPath) { m_nodeEventContexts.append(NodeEventContext(nodeInPath, eventTargetRespectingTargetRules(*nodeInPath))); } }
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(&eventTargetRespectingTargetRules(node)); ScopedEventQueue::instance().enqueueEvent(event); }
void EventPath::addNodeEventContext(Node& node) { m_nodeEventContexts.append(NodeEventContext(&node, eventTargetRespectingTargetRules(node))); }
EventPath::EventPath(Node& originalTarget, Event& event) : m_event(event) { #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT) Vector<EventTarget*, 16> targetStack; #endif bool isMouseOrFocusEvent = event.isMouseEvent() || event.isFocusEvent(); #if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) bool isTouchEvent = event.isTouchEvent(); #endif EventTarget* target = nullptr; Node* node = nodeOrHostIfPseudoElement(&originalTarget); while (node) { if (!target) target = eventTargetRespectingTargetRules(*node); ContainerNode* parent; for (; node; node = parent) { EventTarget* currentTarget = eventTargetRespectingTargetRules(*node); if (isMouseOrFocusEvent) m_path.append(std::make_unique<MouseOrFocusEventContext>(node, currentTarget, target)); #if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) else if (isTouchEvent) m_path.append(std::make_unique<TouchEventContext>(node, currentTarget, target)); #endif else m_path.append(std::make_unique<EventContext>(node, currentTarget, target)); if (is<ShadowRoot>(*node)) break; parent = node->parentNode(); if (!parent) return; #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT) if (ShadowRoot* shadowRootOfParent = parent->shadowRoot()) { if (auto* assignedSlot = shadowRootOfParent->findAssignedSlot(*node)) { // node is assigned to a slot. Continue dispatching the event at this slot. targetStack.append(target); parent = assignedSlot; target = assignedSlot; } } #endif node = parent; } ShadowRoot& shadowRoot = downcast<ShadowRoot>(*node); // At a shadow root. Continue dispatching the event at the shadow host. #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT) if (!targetStack.isEmpty()) { // Move target back to a descendant of the shadow host if the event did not originate in this shadow tree or its inner shadow trees. target = targetStack.last(); targetStack.removeLast(); ASSERT(shadowRoot.host()->contains(target->toNode())); } else #endif target = nullptr; if (!shouldEventCrossShadowBoundary(event, shadowRoot, originalTarget)) return; node = shadowRoot.host(); } }
void EventDispatcher::dispatchScopedEvent(Node& node, Event& event) { // We need to set the target here because it can go away by the time we actually fire the event. event.setTarget(eventTargetRespectingTargetRules(node)); ScopedEventQueue::singleton().enqueueEvent(event); }
void EventDispatcher::dispatchScopedEvent(Node* node, PassRefPtr<EventDispatchMediator> mediator) { // We need to set the target here because it can go away by the time we actually fire the event. mediator->event()->setTarget(eventTargetRespectingTargetRules(node)); ScopedEventQueue::instance()->enqueueEventDispatchMediator(mediator); }