Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(491)

Unified Diff: Source/core/css/resolver/ScopedStyleTree.cpp

Issue 102953007: Selectors in styles in shadowRoots should match in all of the host's shadowRoots. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/css/resolver/ScopedStyleTree.h ('k') | Source/core/css/resolver/StyleResolver.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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();
}
« no previous file with comments | « Source/core/css/resolver/ScopedStyleTree.h ('k') | Source/core/css/resolver/StyleResolver.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698