static inline bool isKeyboardFocusableShadowHost(Node* node) { ASSERT(node); if (!node->isElementNode()) return false; Element* element = toElement(node); return element->isKeyboardFocusable() && isShadowHost(element); }
ScopedStyleResolver* ScopedStyleTree::scopedStyleResolverFor(const ContainerNode& scopingNode) { if (!scopingNode.hasScopedHTMLStyleChild() && !isShadowHost(&scopingNode) && !scopingNode.isDocumentNode() && !scopingNode.isShadowRoot()) return 0; return lookupScopedStyleResolverFor(&scopingNode); }
PassRefPtr<EventTarget> EventDispatcher::adjustToShadowBoundaries(PassRefPtr<Node> relatedTarget, const Vector<Node*> relatedTargetAncestors) { Vector<EventContext>::const_iterator lowestCommonBoundary = m_ancestors.end(); // Assume divergent boundary is the relatedTarget itself (in other words, related target ancestor chain does not cross any shadow DOM boundaries). Vector<Node*>::const_iterator firstDivergentBoundary = relatedTargetAncestors.begin(); Vector<EventContext>::const_iterator targetAncestor = m_ancestors.end(); // Walk down from the top, looking for lowest common ancestor, also monitoring shadow DOM boundaries. bool diverged = false; for (Vector<Node*>::const_iterator i = relatedTargetAncestors.end() - 1; i >= relatedTargetAncestors.begin(); --i) { if (diverged) { if (isShadowRootOrSVGShadowRoot(*i)) { firstDivergentBoundary = i + 1; break; } continue; } if (targetAncestor == m_ancestors.begin()) { diverged = true; continue; } targetAncestor--; if (isShadowRootOrSVGShadowRoot(*i)) lowestCommonBoundary = targetAncestor; if ((*i) != (*targetAncestor).node()) diverged = true; } if (!diverged) { // The relatedTarget is an ancestor or shadowHost of the target. // FIXME: Remove the first check once conversion to new shadow DOM is complete <http://webkit.org/b/48698> if (m_node->shadowHost() == relatedTarget.get() || isShadowHost(relatedTarget.get())) { Vector<EventContext>::const_iterator relatedTargetChild = targetAncestor - 1; if (relatedTargetChild >= m_ancestors.begin() && isShadowRootOrSVGShadowRoot(relatedTargetChild->node())) lowestCommonBoundary = relatedTargetChild; } } else if ((*firstDivergentBoundary) == m_node.get()) { // Since ancestors does not contain target itself, we must account // for the possibility that target is a shadowHost of relatedTarget // and thus serves as the lowestCommonBoundary. // Luckily, in this case the firstDivergentBoundary is target. lowestCommonBoundary = m_ancestors.begin(); m_shouldPreventDispatch = true; } if (lowestCommonBoundary != m_ancestors.end()) { // Trim ancestors to lowestCommonBoundary to keep events inside of the common shadow DOM subtree. m_ancestors.shrink(lowestCommonBoundary - m_ancestors.begin()); } // Set event's related target to the first encountered shadow DOM boundary in the divergent subtree. return firstDivergentBoundary != relatedTargetAncestors.begin() ? *firstDivergentBoundary : relatedTarget; }
Node* ComposedShadowTreeWalker::traverseChild(const Node* node, TraversalDirection direction) const { ASSERT(node); if (canCrossUpperBoundary()) { return node->shadowRoot() ? traverseLightChildren(node->shadowRoot(), direction) : traverseLightChildren(node, direction); } if (isShadowHost(node)) return 0; return traverseLightChildren(node, direction); }
Node* ComposedShadowTreeWalker::traverseChild(const Node* node, TraversalDirection direction) const { ASSERT(node); if (canCrossUpperBoundary()) { ElementShadow* shadow = shadowFor(node); return shadow ? traverseLightChildren(shadow->youngestShadowRoot(), direction) : traverseLightChildren(node, direction); } if (isShadowHost(node)) return 0; return traverseLightChildren(node, direction); }
static void invalidateStyleForLinkRecursively(Node& rootNode, LinkHash linkHash) { for (Node& node : NodeTraversal::startsAt(rootNode)) { if (node.isLink() && linkHashForElement(toElement(node)) == linkHash) { toElement(node).pseudoStateChanged(CSSSelector::PseudoLink); toElement(node).pseudoStateChanged(CSSSelector::PseudoVisited); toElement(node).pseudoStateChanged(CSSSelector::PseudoAnyLink); } if (isShadowHost(&node)) for (ShadowRoot* root = node.youngestShadowRoot(); root; root = root->olderShadowRoot()) invalidateStyleForLinkRecursively(*root, linkHash); } }
// FIXME: Move the following helper functions, authorShadowRootOf, firstWithinTraversingShadowTree, // nextTraversingShadowTree to the best place, e.g. NodeTraversal. static ShadowRoot* authorShadowRootOf(const ContainerNode& node) { if (!node.isElementNode() || !isShadowHost(&node)) return 0; ElementShadow* shadow = toElement(node).shadow(); ASSERT(shadow); for (ShadowRoot* shadowRoot = shadow->oldestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->youngerShadowRoot()) { if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot) return shadowRoot; } return 0; }
// FIXME: Move the following helper functions, authorShadowRootOf, firstWithinTraversingShadowTree, // nextTraversingShadowTree to the best place, e.g. NodeTraversal. static ShadowRoot* authorShadowRootOf(const ContainerNode& node) { if (!node.isElementNode() || !isShadowHost(&node)) return nullptr; ElementShadow* shadow = toElement(node).shadow(); ASSERT(shadow); for (ShadowRoot* shadowRoot = shadow->oldestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->youngerShadowRoot()) { if (shadowRoot->type() == ShadowRootType::OpenByDefault || shadowRoot->type() == ShadowRootType::Open) return shadowRoot; } return nullptr; }
static void invalidateStyleForAllLinksRecursively(Node& rootNode, bool invalidateVisitedLinkHashes) { for (Node& node : NodeTraversal::startsAt(rootNode)) { if (node.isLink()) { if (invalidateVisitedLinkHashes && isHTMLAnchorElement(node)) toHTMLAnchorElement(node).invalidateCachedVisitedLinkHash(); toElement(node).pseudoStateChanged(CSSSelector::PseudoLink); toElement(node).pseudoStateChanged(CSSSelector::PseudoVisited); toElement(node).pseudoStateChanged(CSSSelector::PseudoAnyLink); } if (isShadowHost(&node)) { for (ShadowRoot* root = node.youngestShadowRoot(); root; root = root->olderShadowRoot()) invalidateStyleForAllLinksRecursively(*root, invalidateVisitedLinkHashes); } } }
FocusNavigationScope FocusNavigationScope::ownedByShadowHost(Node* node) { ASSERT(isShadowHost(node)); return FocusNavigationScope(toElement(node)->shadow()->shadowRoot()); }