HeapVector<Member<Element>> TreeScope::elementsFromHitTestResult( HitTestResult& result) const { HeapVector<Member<Element>> elements; 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; }
const TreeScope* TreeScope::commonAncestorTreeScope(const TreeScope& other) const { HeapVector<Member<const TreeScope>, 16> thisChain; for (const TreeScope* tree = this; tree; tree = tree->parentTreeScope()) thisChain.append(tree); HeapVector<Member<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; }
Node* StyledMarkupTraverser<Strategy>::traverse(Node* startNode, Node* pastEnd) { HeapVector<Member<ContainerNode>> ancestorsToClose; Node* next; Node* lastClosed = nullptr; for (Node* n = startNode; n && n != pastEnd; n = next) { // If |n| is a selection boundary such as <input>, traverse the child // nodes in the DOM tree instead of the flat tree. if (handleSelectionBoundary<Strategy>(*n)) { lastClosed = StyledMarkupTraverser<EditingStrategy>(m_accumulator, m_lastClosed.get()).traverse(n, EditingStrategy::nextSkippingChildren(*n)); next = EditingInFlatTreeStrategy::nextSkippingChildren(*n); } else { next = Strategy::next(*n); if (isEnclosingBlock(n) && canHaveChildrenForEditing(n) && next == pastEnd) { // Don't write out empty block containers that aren't fully selected. continue; } if (!n->layoutObject() && !enclosingElementWithTag(firstPositionInOrBeforeNode(n), selectTag)) { next = Strategy::nextSkippingChildren(*n); // Don't skip over pastEnd. if (pastEnd && Strategy::isDescendantOf(*pastEnd, *n)) next = pastEnd; } else { // Add the node to the markup if we're not skipping the descendants appendStartMarkup(*n); // If node has no children, close the tag now. if (Strategy::hasChildren(*n)) { ancestorsToClose.append(toContainerNode(n)); continue; } appendEndMarkup(*n); lastClosed = n; } } // If we didn't insert open tag and there's no more siblings or we're at the end of the traversal, take care of ancestors. // FIXME: What happens if we just inserted open tag and reached the end? if (Strategy::nextSibling(*n) && next != pastEnd) continue; // Close up the ancestors. while (!ancestorsToClose.isEmpty()) { ContainerNode* ancestor = ancestorsToClose.last(); ASSERT(ancestor); if (next && next != pastEnd && Strategy::isDescendantOf(*next, *ancestor)) break; // Not at the end of the range, close ancestors up to sibling of next node. appendEndMarkup(*ancestor); lastClosed = ancestor; ancestorsToClose.removeLast(); } // Surround the currently accumulated markup with markup for ancestors we never opened as we leave the subtree(s) rooted at those ancestors. ContainerNode* nextParent = next ? Strategy::parent(*next) : nullptr; if (next == pastEnd || n == nextParent) continue; ASSERT(n); Node* lastAncestorClosedOrSelf = (lastClosed && Strategy::isDescendantOf(*n, *lastClosed)) ? lastClosed : n; for (ContainerNode* parent = Strategy::parent(*lastAncestorClosedOrSelf); parent && parent != nextParent; parent = Strategy::parent(*parent)) { // All ancestors that aren't in the ancestorsToClose list should either be a) unrendered: if (!parent->layoutObject()) continue; // or b) ancestors that we never encountered during a pre-order traversal starting at startNode: ASSERT(startNode); ASSERT(Strategy::isDescendantOf(*startNode, *parent)); RawPtr<EditingStyle> style = createInlineStyleIfNeeded(*parent); wrapWithNode(*parent, style); lastClosed = parent; } } return lastClosed; }
void ElementVisibilityObserver::onVisibilityChanged( const HeapVector<Member<IntersectionObserverEntry>>& entries) { bool isVisible = entries.last()->intersectionRatio() > 0.f; (*m_callback.get())(isVisible); }