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))); } }
const TreeScope* TreeScope::commonAncestorTreeScope(const TreeScope& other) const { WillBeHeapVector<RawPtrWillBeMember<const TreeScope>, 16> thisChain; for (const TreeScope* tree = this; tree; tree = tree->parentTreeScope()) thisChain.append(tree); WillBeHeapVector<RawPtrWillBeMember<const TreeScope>, 16> otherChain; for (const TreeScope* tree = &other; tree; tree = tree->parentTreeScope()) otherChain.append(tree); // Keep popping out the last elements of these chains until a mismatched pair is found. If |this| and |other| // belong to different documents, null will be returned. const TreeScope* lastAncestor = nullptr; while (!thisChain.isEmpty() && !otherChain.isEmpty() && thisChain.last() == otherChain.last()) { lastAncestor = thisChain.last(); thisChain.removeLast(); otherChain.removeLast(); } return lastAncestor; }
WillBeHeapVector<RawPtrWillBeMember<Element>> TreeScope::elementsFromPoint(int x, int y) const { WillBeHeapVector<RawPtrWillBeMember<Element>> elements; Document& document = rootNode().document(); IntPoint hitPoint(x, y); if (!pointWithScrollAndZoomIfPossible(document, hitPoint)) return elements; HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ListBased | HitTestRequest::PenetratingList); HitTestResult result(request, hitPoint); document.layoutView()->hitTest(result); Node* lastNode = nullptr; for (const auto rectBasedNode : result.listBasedTestResult()) { Node* node = rectBasedNode.get(); if (!node || !node->isElementNode() || node->isDocumentNode()) continue; if (node->isPseudoElement() || node->isTextNode()) node = node->parentOrShadowHostNode(); node = ancestorInThisScope(node); // Prune duplicate entries. A pseduo ::before content above its parent // node should only result in a single entry. if (node == lastNode) continue; if (node && node->isElementNode()) { elements.append(toElement(node)); lastNode = node; } } if (rootNode().isDocumentNode()) { if (Element* rootElement = toDocument(rootNode()).documentElement()) { if (elements.isEmpty() || elements.last() != rootElement) elements.append(rootElement); } } return elements; }
void EventPath::calculatePath() { ASSERT(m_node); ASSERT(m_nodeEventContexts.isEmpty()); m_node->document().updateDistributionForNodeIfNeeded(const_cast<Node*>(m_node.get())); Node* current = m_node; addNodeEventContext(*current); if (!m_node->inDocument()) return; 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()) addNodeEventContext(*containingShadowRoot->olderShadowRoot()); } addNodeEventContext(*insertionPoint); } current = insertionPoints.last(); continue; } if (current->isShadowRoot()) { if (m_event && shouldStopAtShadowRoot(*m_event, *toShadowRoot(current), *m_node)) break; current = current->shadowHost(); addNodeEventContext(*current); } else { current = current->parentNode(); if (current) addNodeEventContext(*current); } } }