PositionInComposedTree toPositionInComposedTree(const Position& pos) { if (pos.isNull()) return PositionInComposedTree(); if (pos.isOffsetInAnchor()) { Node* anchor = pos.anchorNode(); if (anchor->offsetInCharacters()) return PositionInComposedTree(anchor, pos.computeOffsetInContainerNode()); ASSERT(!anchor->isSlotOrActiveInsertionPoint()); int offset = pos.computeOffsetInContainerNode(); Node* child = NodeTraversal::childAt(*anchor, offset); if (!child) { if (anchor->isShadowRoot()) return PositionInComposedTree(anchor->shadowHost(), PositionAnchorType::AfterChildren); return PositionInComposedTree(anchor, PositionAnchorType::AfterChildren); } child->updateDistribution(); if (child->isSlotOrActiveInsertionPoint()) { if (anchor->isShadowRoot()) return PositionInComposedTree(anchor->shadowHost(), offset); return PositionInComposedTree(anchor, offset); } if (Node* parent = ComposedTreeTraversal::parent(*child)) return PositionInComposedTree(parent, ComposedTreeTraversal::index(*child)); // When |pos| isn't appeared in composed tree, we map |pos| to after // children of shadow host. // e.g. "foo",0 in <progress>foo</progress> if (anchor->isShadowRoot()) return PositionInComposedTree(anchor->shadowHost(), PositionAnchorType::AfterChildren); return PositionInComposedTree(anchor, PositionAnchorType::AfterChildren); } return PositionInComposedTree(pos.anchorNode(), pos.anchorType()); }
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)); } }
bool InspectorOverlay::handleMouseMove(const PlatformMouseEvent& event) { if (!shouldSearchForNode()) return false; LocalFrame* frame = m_webViewImpl->mainFrameImpl()->frame(); if (!frame->view() || !frame->contentLayoutObject()) return false; Node* node = hoveredNodeForEvent(frame, event, event.shiftKey()); // Do not highlight within user agent shadow root unless requested. if (m_inspectMode != InspectorDOMAgent::SearchingForUAShadow) { ShadowRoot* shadowRoot = InspectorDOMAgent::userAgentShadowRoot(node); if (shadowRoot) node = shadowRoot->host(); } // Shadow roots don't have boxes - use host element instead. if (node && node->isShadowRoot()) node = node->parentOrShadowHostNode(); if (!node) return true; Node* eventTarget = event.shiftKey() ? hoveredNodeForEvent(m_webViewImpl->mainFrameImpl()->frame(), event, false) : nullptr; if (eventTarget == node) eventTarget = nullptr; if (node && m_inspectModeHighlightConfig) { m_hoveredNodeForInspectMode = node; m_domAgent->nodeHighlightedInOverlay(node); highlightNode(node, eventTarget, *m_inspectModeHighlightConfig, event.ctrlKey() || event.metaKey()); } return true; }
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(); } }
static String nodePosition(Node* node) { String result; Element* body = node->document()->body(); Node* parent; for (Node* n = node; n; n = parent) { parent = n->parentOrHostNode(); if (n != node) result += " of "; if (parent) { if (body && n == body) { // We don't care what offset body may be in the document. result += "body"; break; } if (n->isShadowRoot()) result += "{" + getTagName(n) + "}"; else result += "child " + String::number(n->nodeIndex()) + " {" + getTagName(n) + "}"; } else result += "document"; } return result; }
static String nodePosition(Node* node) { StringBuilder result; Element* body = node->document()->body(); Node* parent; for (Node* n = node; n; n = parent) { parent = n->parentOrHostNode(); if (n != node) result.appendLiteral(" of "); if (parent) { if (body && n == body) { // We don't care what offset body may be in the document. result.appendLiteral("body"); break; } if (n->isShadowRoot()) { result.append('{'); result.append(getTagName(n)); result.append('}'); } else { result.appendLiteral("child "); result.appendNumber(n->nodeIndex()); result.appendLiteral(" {"); result.append(getTagName(n)); result.append('}'); } } else result.appendLiteral("document"); } return result.toString(); }
inline void TreeScopeAdopter::moveNodeToNewDocument( Node& node, Document& oldDocument, Document& newDocument) const { DCHECK_NE(oldDocument, newDocument); if (node.hasRareData()) { NodeRareData* rareData = node.rareData(); if (rareData->nodeLists()) rareData->nodeLists()->adoptDocument(oldDocument, newDocument); } oldDocument.moveNodeIteratorsToNewDocument(node, newDocument); if (node.getCustomElementState() == CustomElementState::Custom) { Element& element = toElement(node); CustomElement::enqueueAdoptedCallback(&element, &oldDocument, &newDocument); } if (node.isShadowRoot()) toShadowRoot(node).setDocument(newDocument); #if DCHECK_IS_ON() didMoveToNewDocumentWasCalled = false; oldDocumentDidMoveToNewDocumentWasCalledWith = &oldDocument; #endif node.didMoveToNewDocument(oldDocument); #if DCHECK_IS_ON() DCHECK(didMoveToNewDocumentWasCalled); #endif }
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*> 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(); } } }
Element* TreeScope::adjustedFocusedElement() { Document& document = rootNode()->document(); Element* element = document.focusedElement(); if (!element && document.page()) element = focusedFrameOwnerElement(document.page()->focusController().focusedFrame(), document.frame()); if (!element) return 0; Vector<Node*> targetStack; for (EventPathWalker walker(element); walker.node(); walker.moveToParent()) { Node* node = walker.node(); if (targetStack.isEmpty()) targetStack.append(node); else if (walker.isVisitingInsertionPointInReprojection()) targetStack.append(targetStack.last()); if (node == rootNode()) { // targetStack.last() is one of the followings: // - InsertionPoint // - shadow host // - Document::focusedElement() // So, it's safe to do toElement(). return toElement(targetStack.last()); } if (node->isShadowRoot()) { ASSERT(!targetStack.isEmpty()); targetStack.removeLast(); } } return 0; }
inline EventTarget& eventTargetRespectingTargetRules(Node& referenceNode) { if (referenceNode.isPseudoElement()) { EventTarget* hostElement = toPseudoElement(referenceNode).hostElement(); ASSERT(hostElement); return *hostElement; } #if ENABLE(SVG) if (!referenceNode.isSVGElement() || !referenceNode.isInShadowTree()) return referenceNode; // Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included // as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects Node* rootNode = referenceNode.treeScope().rootNode(); Element* shadowHostElement = rootNode->isShadowRoot() ? toShadowRoot(rootNode)->hostElement() : 0; // At this time, SVG nodes are not supported in non-<use> shadow trees. if (!shadowHostElement || !shadowHostElement->hasTagName(SVGNames::useTag)) return referenceNode; SVGUseElement* useElement = toSVGUseElement(shadowHostElement); if (SVGElementInstance* instance = useElement->instanceForShadowTreeElement(&referenceNode)) return *instance; #endif return referenceNode; }
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 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))); } }
// FIXME: Once https://bugs.webkit.org/show_bug.cgi?id=52963 lands, this should // be greatly improved. See https://bugs.webkit.org/show_bug.cgi?id=54025. static Node* pullOutOfShadow(Node* node) { Node* outermostShadowBoundary = node; for (Node* n = node; n; n = n->parentOrHostNode()) { if (n->isShadowRoot()) outermostShadowBoundary = n->parentOrHostNode(); } return outermostShadowBoundary; }
Element* FocusNavigationScope::owner() const { Node* root = rootNode(); if (root->isShadowRoot()) { ShadowRoot* shadowRoot = toShadowRoot(root); return shadowRoot->host(); } return 0; }
Element* FocusNavigationScope::owner() const { Node* root = rootNode(); if (root->isShadowRoot()) return toShadowRoot(root)->host(); if (Frame* frame = root->document()->frame()) return frame->ownerElement(); return 0; }
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); } }
ShadowRoot* InsertionPoint::assignedFrom() const { Node* treeScopeRoot = treeScope()->rootNode(); if (!treeScopeRoot->isShadowRoot()) return 0; ShadowRoot* olderShadowRoot = toShadowRoot(treeScopeRoot)->olderShadowRoot(); if (olderShadowRoot && olderShadowRoot->assignedTo() == this) return olderShadowRoot; return 0; }
Element* TreeScope::elementFromPoint(int x, int y) const { Node* node = nodeFromPoint(&rootNode()->document(), x, y); if (node && node->isTextNode()) node = node->parentNode(); ASSERT(!node || node->isElementNode() || node->isShadowRoot()); node = ancestorInThisScope(node); if (!node || !node->isElementNode()) return 0; return toElement(node); }
Node* DOMPatchSupport::patchNode(Node* node, const String& markup, ExceptionState& exceptionState) { // Don't parse <html> as a fragment. if (node->isDocumentNode() || (node->parentNode() && node->parentNode()->isDocumentNode())) { patchDocument(markup); return 0; } Node* previousSibling = node->previousSibling(); RefPtrWillBeRawPtr<DocumentFragment> fragment = DocumentFragment::create(m_document); Node* targetNode = node->parentElementOrShadowRoot() ? node->parentElementOrShadowRoot() : m_document.documentElement(); // Use the document BODY as the context element when editing immediate shadow root children, // as it provides an equivalent parsing context. if (targetNode->isShadowRoot()) targetNode = m_document.body(); Element* targetElement = toElement(targetNode); // FIXME: This code should use one of createFragment* in markup.h if (m_document.isHTMLDocument()) fragment->parseHTML(markup, targetElement); else fragment->parseXML(markup, targetElement); // Compose the old list. ContainerNode* parentNode = node->parentNode(); Vector<OwnPtr<Digest> > oldList; for (Node* child = parentNode->firstChild(); child; child = child->nextSibling()) oldList.append(createDigest(child, 0)); // Compose the new list. String markupCopy = markup.lower(); Vector<OwnPtr<Digest> > newList; for (Node* child = parentNode->firstChild(); child != node; child = child->nextSibling()) newList.append(createDigest(child, 0)); for (Node* child = fragment->firstChild(); child; child = child->nextSibling()) { if (isHTMLHeadElement(*child) && !child->firstChild() && markupCopy.find("</head>") == kNotFound) continue; // HTML5 parser inserts empty <head> tag whenever it parses <body> if (isHTMLBodyElement(*child) && !child->firstChild() && markupCopy.find("</body>") == kNotFound) continue; // HTML5 parser inserts empty <body> tag whenever it parses </head> newList.append(createDigest(child, &m_unusedNodesMap)); } for (Node* child = node->nextSibling(); child; child = child->nextSibling()) newList.append(createDigest(child, 0)); if (!innerPatchChildren(parentNode, oldList, newList, exceptionState)) { // Fall back to total replace. if (!m_domEditor->replaceChild(parentNode, fragment.release(), node, exceptionState)) return 0; } return previousSibling ? previousSibling->nextSibling() : parentNode->firstChild(); }
inline Node* ComposedTreeWalker::traverseParentOrHost(const Node* node) const { Node* parent = node->parentNode(); if (!parent) return 0; if (!parent->isShadowRoot()) return parent; ShadowRoot* shadowRoot = toShadowRoot(parent); ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot()); if (!shadowRoot->isYoungest()) return 0; return shadowRoot->host(); }
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); } } }
Element* TreeScope::hitTestPoint(int x, int y, const HitTestRequest& request) const { HitTestResult result = hitTestInDocument(&rootNode().document(), x, y, request); Node* node = result.innerNode(); if (!node || node->isDocumentNode()) return 0; if (node->isPseudoElement() || node->isTextNode()) node = node->parentOrShadowHostNode(); ASSERT(!node || node->isElementNode() || node->isShadowRoot()); node = ancestorInThisScope(node); if (!node || !node->isElementNode()) return 0; return toElement(node); }
static inline bool nodeCanBeDistributed(const Node* node) { ASSERT(node); Node* parent = parentNodeForDistribution(node); if (!parent) return false; if (ShadowRoot* shadowRoot = parent->isShadowRoot() ? toShadowRoot(parent) : 0) return ScopeContentDistribution::assignedTo(shadowRoot); if (parent->isElementNode() && toElement(parent)->shadow()) return true; return false; }
inline void TreeScopeAdopter::moveNodeToNewDocument(Node& node, Document& oldDocument, Document& newDocument) const { ASSERT(oldDocument != newDocument); if (node.isShadowRoot()) toShadowRoot(node).setDocument(newDocument); #if ENABLE(ASSERT) didMoveToNewDocumentWasCalled = false; oldDocumentDidMoveToNewDocumentWasCalledWith = &oldDocument; #endif node.didMoveToNewDocument(oldDocument); ASSERT(didMoveToNewDocumentWasCalled); }
static inline bool nodeCanBeDistributed(const Node* node) { ASSERT(node); Node* parent = parentNodeForDistribution(node); if (!parent) return false; if (ShadowRoot* shadowRoot = parent->isShadowRoot() ? toShadowRoot(parent) : 0) return shadowRoot->insertionPoint(); if (parent->isElementNode() && toElement(parent)->shadow()) return true; return false; }
void EventRelatedTargetAdjuster::adjust(Vector<EventContext, 32>& ancestors) { // Synthetic mouse events can have a relatedTarget which is identical to the target. bool targetIsIdenticalToToRelatedTarget = (m_node.get() == m_relatedTarget.get()); Vector<EventTarget*, 32> relatedTargetStack; TreeScope* lastTreeScope = 0; for (AncestorChainWalker walker(m_relatedTarget.get()); walker.get(); walker.parent()) { Node* node = walker.get(); if (relatedTargetStack.isEmpty()) relatedTargetStack.append(node); else if (walker.crossingInsertionPoint()) relatedTargetStack.append(relatedTargetStack.last()); TreeScope* scope = node->treeScope(); // Skips adding a node to the map if treeScope does not change. Just for the performance optimization. if (scope != lastTreeScope) m_relatedTargetMap.add(scope, relatedTargetStack.last()); lastTreeScope = scope; if (node->isShadowRoot()) { ASSERT(!relatedTargetStack.isEmpty()); relatedTargetStack.removeLast(); } } lastTreeScope = 0; EventTarget* adjustedRelatedTarget = 0; for (Vector<EventContext, 32>::iterator iter = ancestors.begin(); iter < ancestors.end(); ++iter) { TreeScope* scope = iter->node()->treeScope(); if (scope == lastTreeScope) { // Re-use the previous adjustedRelatedTarget if treeScope does not change. Just for the performance optimization. iter->setRelatedTarget(adjustedRelatedTarget); } else { adjustedRelatedTarget = findRelatedTarget(scope); iter->setRelatedTarget(adjustedRelatedTarget); } lastTreeScope = scope; if (targetIsIdenticalToToRelatedTarget) { if (m_node->treeScope()->rootNode() == iter->node()) { ancestors.shrink(iter + 1 - ancestors.begin()); break; } } else if (iter->target() == adjustedRelatedTarget) { // Event dispatching should be stopped here. ancestors.shrink(iter - ancestors.begin()); break; } } }
Node* DOMSelection::shadowAdjustedNode(const Position& position) const { if (position.isNull()) return 0; Node* containerNode = position.computeContainerNode(); Node* adjustedNode = m_treeScope->ancestorInThisScope(containerNode); if (!adjustedNode) return 0; if (containerNode == adjustedNode) return containerNode; DCHECK(!adjustedNode->isShadowRoot()) << adjustedNode; return adjustedNode->parentOrShadowHostNode(); }
String SVGStyledElement::title() const { // According to spec, we should not return titles when hovering over root <svg> elements (those // <title> elements are the title of the document, not a tooltip) so we instantly return. if (hasTagName(SVGNames::svgTag)) { const SVGSVGElement* svg = static_cast<const SVGSVGElement*>(this); if (svg->isOutermostSVG()) return String(); } // Walk up the tree, to find out whether we're inside a <use> shadow tree, to find the right title. Node* parent = const_cast<SVGStyledElement*>(this); while (parent) { if (!parent->isShadowRoot()) { parent = parent->parentNodeGuaranteedHostFree(); continue; } // Get the <use> element. Element* shadowParent = parent->shadowHost(); if (shadowParent && shadowParent->isSVGElement() && shadowParent->hasTagName(SVGNames::useTag)) { SVGUseElement* useElement = static_cast<SVGUseElement*>(shadowParent); // If the <use> title is not empty we found the title to use. String useTitle(useElement->title()); if (useTitle.isEmpty()) break; return useTitle; } parent = parent->parentNode(); } // If we aren't an instance in a <use> or the <use> title was not found, then find the first // <title> child of this element. Element* titleElement = firstElementChild(); for (; titleElement; titleElement = titleElement->nextElementSibling()) { if (titleElement->hasTagName(SVGNames::titleTag) && titleElement->isSVGElement()) break; } // If a title child was found, return the text contents. if (titleElement) return titleElement->innerText(); // Otherwise return a null/empty string. return String(); }