| Index: Source/core/css/resolver/ScopedStyleTree.cpp
|
| diff --git a/Source/core/css/resolver/ScopedStyleTree.cpp b/Source/core/css/resolver/ScopedStyleTree.cpp
|
| index fe3f8a3d2cb031f689dde5679ab7c84a80743faf..0621d3372059310cb7299ca0e2506f8e66c41167 100644
|
| --- a/Source/core/css/resolver/ScopedStyleTree.cpp
|
| +++ b/Source/core/css/resolver/ScopedStyleTree.cpp
|
| @@ -66,6 +66,34 @@ ScopedStyleResolver* ScopedStyleTree::addScopedStyleResolver(ContainerNode& scop
|
| return addResult.iterator->value.get();
|
| }
|
|
|
| +// To make younger shadow root act as a child of its older shadow root.
|
| +ContainerNode* ScopedStyleTree::traverseParent(const ContainerNode* node) const
|
| +{
|
| + if (node->isShadowRoot()) {
|
| + const ShadowRoot* shadowRoot = toShadowRoot(node);
|
| + if (shadowRoot->isOldest())
|
| + return shadowRoot->host();
|
| + return shadowRoot->olderShadowRoot();
|
| + }
|
| +
|
| + ContainerNode* parent = node->parentOrShadowHostNode();
|
| + return parent && parent->isShadowRoot() ? toShadowRoot(parent)->owner()->youngestShadowRoot() : parent;
|
| +}
|
| +
|
| +static inline bool containsIncludingShadowRoots(const ContainerNode* node1, const ContainerNode* node2)
|
| +{
|
| + ASSERT(node1);
|
| + ASSERT(node2);
|
| +
|
| + // If node1 is a older shadow root and node2 is an younger shadow root hosted by the
|
| + // same shadow host, treat as if node1 contains node2.
|
| + if (node1->isShadowRoot()) {
|
| + Node* host = toShadowRoot(node1)->host();
|
| + return host != node2 && host->containsIncludingShadowDOM(node2);
|
| + }
|
| + return node1->containsIncludingShadowDOM(node2);
|
| +}
|
| +
|
| void ScopedStyleTree::setupScopedStylesTree(ScopedStyleResolver* target)
|
| {
|
| ASSERT(target);
|
| @@ -75,7 +103,7 @@ void ScopedStyleTree::setupScopedStylesTree(ScopedStyleResolver* target)
|
| // Since StyleResolver creates RuleSets according to styles' document
|
| // order, a parent of the given ScopedRuleData has been already
|
| // prepared.
|
| - for (ContainerNode* node = scopingNode.parentOrShadowHostNode(); node; node = node->parentOrShadowHostNode()) {
|
| + for (ContainerNode* node = traverseParent(&scopingNode); node; node = traverseParent(node)) {
|
| if (ScopedStyleResolver* scopedResolver = scopedStyleResolverFor(*node)) {
|
| target->setParent(scopedResolver);
|
| break;
|
| @@ -97,7 +125,7 @@ void ScopedStyleTree::setupScopedStylesTree(ScopedStyleResolver* target)
|
| if (it->value == target)
|
| continue;
|
| ASSERT(it->key->inDocument());
|
| - if (it->value->parent() == target->parent() && scopingNode.containsIncludingShadowDOM(it->key))
|
| + if (it->value->parent() == target->parent() && containsIncludingShadowRoots(&scopingNode, it->key))
|
| it->value->setParent(target);
|
| }
|
| }
|
| @@ -115,43 +143,33 @@ void ScopedStyleTree::resolveScopedStyles(const Element* element, Vector<ScopedS
|
| resolvers.append(scopedResolver);
|
| }
|
|
|
| -void ScopedStyleTree::collectScopedResolversForHostedShadowTrees(const Element* element, Vector<ScopedStyleResolver*, 8>& resolvers)
|
| -{
|
| - ElementShadow* shadow = element->shadow();
|
| - if (!shadow)
|
| - return;
|
| -
|
| - // Adding scoped resolver for active shadow roots for shadow host styling.
|
| - for (ShadowRoot* shadowRoot = shadow->youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot()) {
|
| - if (shadowRoot->hasScopedHTMLStyleChild()) {
|
| - if (ScopedStyleResolver* resolver = scopedStyleResolverFor(*shadowRoot))
|
| - resolvers.append(resolver);
|
| - }
|
| - if (!shadowRoot->containsShadowElements())
|
| - break;
|
| - }
|
| -}
|
| -
|
| void ScopedStyleTree::resolveScopedKeyframesRules(const Element* element, Vector<ScopedStyleResolver*, 8>& resolvers)
|
| {
|
| Document& document = element->document();
|
| TreeScope& treeScope = element->treeScope();
|
| bool applyAuthorStyles = treeScope.applyAuthorStyles();
|
|
|
| - // Add resolvers for shadow roots hosted by the given element.
|
| - collectScopedResolversForHostedShadowTrees(element, resolvers);
|
| -
|
| // Add resolvers while walking up DOM tree from the given element.
|
| - for (ScopedStyleResolver* scopedResolver = scopedResolverFor(element); scopedResolver; scopedResolver = scopedResolver->parent()) {
|
| - if (scopedResolver->treeScope() == treeScope || (applyAuthorStyles && scopedResolver->treeScope() == document))
|
| + ScopedStyleResolver* scopedResolver = scopedResolverFor(element);
|
| + for (; scopedResolver; scopedResolver = scopedResolver->parent()) {
|
| + if (scopedResolver->treeScope() == treeScope
|
| + || (scopedResolver->scopingNode().isShadowRoot() && toShadowRoot(&scopedResolver->scopingNode())->host() == element)
|
| + || (applyAuthorStyles && scopedResolver->treeScope() == document))
|
| resolvers.append(scopedResolver);
|
| }
|
| }
|
|
|
| inline ScopedStyleResolver* ScopedStyleTree::enclosingScopedStyleResolverFor(const ContainerNode* scopingNode)
|
| {
|
| - for (; scopingNode; scopingNode = scopingNode->parentOrShadowHostNode()) {
|
| - if (ScopedStyleResolver* scopedStyleResolver = scopedStyleResolverFor(*scopingNode))
|
| + const ContainerNode* node;
|
| + // FIXME: we should split "style tree" traversal logic out from this method.
|
| + if (isShadowHost(scopingNode)) {
|
| + node = toElement(scopingNode)->shadow()->youngestShadowRoot();
|
| + } else {
|
| + node = scopingNode->isShadowRoot() ? toShadowRoot(scopingNode)->owner()->youngestShadowRoot() : scopingNode;
|
| + }
|
| + for (; node; node = traverseParent(node)) {
|
| + if (ScopedStyleResolver* scopedStyleResolver = scopedStyleResolverFor(*node))
|
| return scopedStyleResolver;
|
| }
|
| return 0;
|
| @@ -179,13 +197,43 @@ void ScopedStyleTree::pushStyleCache(const ContainerNode& scopingNode, const Con
|
| m_cache.nodeForScopedStyles = &scopingNode;
|
| }
|
|
|
| +static inline bool shadowRootHasTheSameShadowHost(const ContainerNode& node, const Node* host)
|
| +{
|
| + if (!node.isShadowRoot())
|
| + return false;
|
| + return toShadowRoot(&node)->host() == host;
|
| +}
|
| +
|
| void ScopedStyleTree::popStyleCache(const ContainerNode& scopingNode)
|
| {
|
| if (!cacheIsValid(&scopingNode))
|
| return;
|
|
|
| - if (m_cache.scopedResolver && m_cache.scopedResolver->scopingNode() == scopingNode)
|
| - m_cache.scopedResolver = m_cache.scopedResolver->parent();
|
| + if (!scopingNode.isShadowRoot()) {
|
| + if (m_cache.scopedResolver && m_cache.scopedResolver->scopingNode() == scopingNode)
|
| + m_cache.scopedResolver = m_cache.scopedResolver->parent();
|
| +
|
| + m_cache.nodeForScopedStyles = scopingNode.parentOrShadowHostNode();
|
| + return;
|
| + }
|
| +
|
| + const ShadowRoot* shadowRoot = toShadowRoot(&scopingNode);
|
| + const Node* host = shadowRoot->host();
|
| +
|
| + // If a given scoping node is the oldest shadow root and cached resolver's scoping node
|
| + // is a shadow root (mostly, the youngest shadow root) hosted by the same host of
|
| + // the given shadow root, update cacheed resolver.
|
| + if (m_cache.scopedResolver
|
| + && shadowRoot->isOldest()
|
| + && shadowRootHasTheSameShadowHost(m_cache.scopedResolver->scopingNode(), host)) {
|
| + ScopedStyleResolver* resolver = m_cache.scopedResolver;
|
| +
|
| + while (shadowRootHasTheSameShadowHost(resolver->scopingNode(), host))
|
| + resolver = resolver->parent();
|
| +
|
| + m_cache.scopedResolver = resolver;
|
| + }
|
| +
|
| m_cache.nodeForScopedStyles = scopingNode.parentOrShadowHostNode();
|
| }
|
|
|
|
|