void RelatedNodeRetargeter::moveToNewTreeScope(TreeScope* previousTreeScope, TreeScope& newTreeScope) { if (m_hasDifferentTreeRoot) return; auto& currentRelatedNodeScope = m_retargetedRelatedNode->treeScope(); if (previousTreeScope != ¤tRelatedNodeScope) { // currentRelatedNode is still outside our shadow tree. New tree scope may contain currentRelatedNode // but there is no need to re-target it. Moving into a slot (thereby a deeper shadow tree) doesn't matter. return; } bool enteredSlot = newTreeScope.parentTreeScope() == previousTreeScope; if (enteredSlot) { if (m_lowestCommonAncestorIndex) { if (m_ancestorTreeScopes.isEmpty()) collectTreeScopes(); bool relatedNodeIsInSlot = m_ancestorTreeScopes[m_lowestCommonAncestorIndex - 1] == &newTreeScope; if (relatedNodeIsInSlot) { m_lowestCommonAncestorIndex--; m_retargetedRelatedNode = nodeInLowestCommonAncestor(); ASSERT(&newTreeScope == &m_retargetedRelatedNode->treeScope()); } } else ASSERT(m_retargetedRelatedNode == &m_relatedNode); } else { ASSERT(previousTreeScope->parentTreeScope() == &newTreeScope); m_lowestCommonAncestorIndex++; ASSERT_WITH_SECURITY_IMPLICATION(m_ancestorTreeScopes.isEmpty() || m_lowestCommonAncestorIndex < m_ancestorTreeScopes.size()); m_retargetedRelatedNode = downcast<ShadowRoot>(currentRelatedNodeScope.rootNode()).host(); ASSERT(&newTreeScope == &m_retargetedRelatedNode->treeScope()); } }
ScopedStyleResolver* ScopedStyleResolver::parent() const { for (TreeScope* scope = treeScope().parentTreeScope(); scope; scope = scope->parentTreeScope()) { if (ScopedStyleResolver* resolver = scope->scopedStyleResolver()) return resolver; } return nullptr; }
void ScopedStyleResolver::keyframesRulesAdded(const TreeScope& treeScope) { // Called when @keyframes rules are about to be added/removed from a // TreeScope. @keyframes rules may apply to animations on elements in the // same TreeScope as the stylesheet, or the host element in the parent // TreeScope if the TreeScope is a shadow tree. ScopedStyleResolver* resolver = treeScope.scopedStyleResolver(); ScopedStyleResolver* parentResolver = treeScope.parentTreeScope() ? treeScope.parentTreeScope()->scopedStyleResolver() : nullptr; bool hadUnresolvedKeyframes = false; if (resolver && resolver->m_hasUnresolvedKeyframesRule) { resolver->m_hasUnresolvedKeyframesRule = false; hadUnresolvedKeyframes = true; } if (parentResolver && parentResolver->m_hasUnresolvedKeyframesRule) { parentResolver->m_hasUnresolvedKeyframesRule = false; hadUnresolvedKeyframes = true; } if (hadUnresolvedKeyframes) { // If an animation ended up not being started because no @keyframes // rules were found for the animation-name, we need to recalculate style // for the elements in the scope, including its shadow host if // applicable. invalidationRootForTreeScope(treeScope).setNeedsStyleRecalc( SubtreeStyleChange, StyleChangeReasonForTracing::create( StyleChangeReason::StyleSheetChange)); return; } // If we have animations running, added/removed @keyframes may affect these. treeScope.document().timeline().invalidateKeyframeEffects(treeScope); }
Node* moveToParentOrShadowHost(Node& newTarget) { TreeScope& newTreeScope = newTarget.treeScope(); if (&newTreeScope == m_currentTreeScope) return m_relatedNodeInCurrentTreeScope; if (m_currentTreeScope) { ASSERT(is<ShadowRoot>(m_currentTreeScope->rootNode())); ASSERT(&newTarget == downcast<ShadowRoot>(m_currentTreeScope->rootNode()).host()); ASSERT(m_currentTreeScope->parentTreeScope() == &newTreeScope); } if (&newTreeScope == &m_relatedNodeTreeScope) m_relatedNodeInCurrentTreeScope = &m_relatedNode; else if (m_relatedNodeInCurrentTreeScope) { ASSERT(m_currentTreeScope); m_relatedNodeInCurrentTreeScope = &newTarget; } else { if (!m_currentTreeScope) { TreeScope* newTreeScopeAncestor = &newTreeScope; do { m_relatedNodeInCurrentTreeScope = findHostOfTreeScopeInTargetTreeScope(m_relatedNodeTreeScope, *newTreeScopeAncestor); newTreeScopeAncestor = newTreeScopeAncestor->parentTreeScope(); if (newTreeScopeAncestor == &m_relatedNodeTreeScope) { m_relatedNodeInCurrentTreeScope = &m_relatedNode; break; } } while (newTreeScopeAncestor && !m_relatedNodeInCurrentTreeScope); } ASSERT(m_relatedNodeInCurrentTreeScope || findHostOfTreeScopeInTargetTreeScope(newTreeScope, m_relatedNodeTreeScope) || &newTreeScope.documentScope() != &m_relatedNodeTreeScope.documentScope()); } m_currentTreeScope = &newTreeScope; return m_relatedNodeInCurrentTreeScope; }
void RelatedNodeRetargeter::collectTreeScopes() { ASSERT(m_ancestorTreeScopes.isEmpty()); for (TreeScope* currentTreeScope = &m_relatedNode.treeScope(); currentTreeScope; currentTreeScope = currentTreeScope->parentTreeScope()) m_ancestorTreeScopes.append(currentTreeScope); ASSERT_WITH_SECURITY_IMPLICATION(!m_ancestorTreeScopes.isEmpty()); }
RelatedNodeRetargeter::RelatedNodeRetargeter(Node& relatedNode, Node& target) : m_relatedNode(relatedNode) , m_retargetedRelatedNode(&relatedNode) { auto& targetTreeScope = target.treeScope(); TreeScope* currentTreeScope = &m_relatedNode.treeScope(); if (LIKELY(currentTreeScope == &targetTreeScope && target.inDocument() && m_relatedNode.inDocument())) return; if (¤tTreeScope->documentScope() != &targetTreeScope.documentScope()) { m_hasDifferentTreeRoot = true; m_retargetedRelatedNode = nullptr; return; } if (relatedNode.inDocument() != target.inDocument()) { m_hasDifferentTreeRoot = true; m_retargetedRelatedNode = moveOutOfAllShadowRoots(relatedNode); return; } collectTreeScopes(); // FIXME: We should collect this while constructing the event path. Vector<TreeScope*, 8> targetTreeScopeAncestors; for (TreeScope* currentTreeScope = &targetTreeScope; currentTreeScope; currentTreeScope = currentTreeScope->parentTreeScope()) targetTreeScopeAncestors.append(currentTreeScope); ASSERT_WITH_SECURITY_IMPLICATION(!targetTreeScopeAncestors.isEmpty()); unsigned i = m_ancestorTreeScopes.size(); unsigned j = targetTreeScopeAncestors.size(); ASSERT_WITH_SECURITY_IMPLICATION(m_ancestorTreeScopes.last() == targetTreeScopeAncestors.last()); while (m_ancestorTreeScopes[i - 1] == targetTreeScopeAncestors[j - 1]) { i--; j--; if (!i || !j) break; } bool lowestCommonAncestorIsDocumentScope = i + 1 == m_ancestorTreeScopes.size(); if (lowestCommonAncestorIsDocumentScope && !relatedNode.inDocument() && !target.inDocument()) { Node& targetAncestorInDocumentScope = i ? *downcast<ShadowRoot>(m_ancestorTreeScopes[i - 1]->rootNode()).shadowHost() : target; Node& relatedNodeAncestorInDocumentScope = j ? *downcast<ShadowRoot>(targetTreeScopeAncestors[j - 1]->rootNode()).shadowHost() : relatedNode; if (targetAncestorInDocumentScope.rootNode() != relatedNodeAncestorInDocumentScope.rootNode()) { m_hasDifferentTreeRoot = true; m_retargetedRelatedNode = moveOutOfAllShadowRoots(relatedNode); return; } } m_lowestCommonAncestorIndex = i; m_retargetedRelatedNode = nodeInLowestCommonAncestor(); }
RelatedNodeRetargeter(Node& relatedNode, TreeScope& targetTreeScope) : m_relatedNode(relatedNode) , m_retargetedRelatedNode(&relatedNode) { TreeScope* currentTreeScope = &m_relatedNode.treeScope(); if (LIKELY(currentTreeScope == &targetTreeScope)) return; if (¤tTreeScope->documentScope() != &targetTreeScope.documentScope()) { m_hasDifferentTreeRoot = true; m_retargetedRelatedNode = nullptr; return; } if (relatedNode.inDocument() != targetTreeScope.rootNode().inDocument()) { m_hasDifferentTreeRoot = true; while (m_retargetedRelatedNode->isInShadowTree()) m_retargetedRelatedNode = downcast<ShadowRoot>(m_retargetedRelatedNode->treeScope().rootNode()).host(); return; } collectTreeScopes(); // FIXME: We should collect this while constructing the event path. Vector<TreeScope*, 8> targetTreeScopeAncestors; for (TreeScope* currentTreeScope = &targetTreeScope; currentTreeScope; currentTreeScope = currentTreeScope->parentTreeScope()) targetTreeScopeAncestors.append(currentTreeScope); ASSERT_WITH_SECURITY_IMPLICATION(!targetTreeScopeAncestors.isEmpty()); unsigned i = m_ancestorTreeScopes.size(); unsigned j = targetTreeScopeAncestors.size(); ASSERT_WITH_SECURITY_IMPLICATION(m_ancestorTreeScopes.last() == targetTreeScopeAncestors.last()); while (m_ancestorTreeScopes[i - 1] == targetTreeScopeAncestors[j - 1]) { i--; j--; if (!i || !j) break; } m_lowestCommonAncestorIndex = i; m_retargetedRelatedNode = nodeInLowestCommonAncestor(); }