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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/css/resolver/ScopedStyleTree.h ('k') | Source/core/css/resolver/StyleResolver.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. 3 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
4 * Copyright (C) 2012 Google Inc. All rights reserved. 4 * Copyright (C) 2012 Google Inc. All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
59 59
60 if (addResult.isNewEntry) { 60 if (addResult.isNewEntry) {
61 addResult.iterator->value = ScopedStyleResolver::create(scopingNode); 61 addResult.iterator->value = ScopedStyleResolver::create(scopingNode);
62 if (scopingNode.isDocumentNode()) 62 if (scopingNode.isDocumentNode())
63 m_scopedResolverForDocument = addResult.iterator->value.get(); 63 m_scopedResolverForDocument = addResult.iterator->value.get();
64 } 64 }
65 isNewEntry = addResult.isNewEntry; 65 isNewEntry = addResult.isNewEntry;
66 return addResult.iterator->value.get(); 66 return addResult.iterator->value.get();
67 } 67 }
68 68
69 // To make younger shadow root act as a child of its older shadow root.
70 ContainerNode* ScopedStyleTree::traverseParent(const ContainerNode* node) const
71 {
72 if (node->isShadowRoot()) {
73 const ShadowRoot* shadowRoot = toShadowRoot(node);
74 if (shadowRoot->isOldest())
75 return shadowRoot->host();
76 return shadowRoot->olderShadowRoot();
77 }
78
79 ContainerNode* parent = node->parentOrShadowHostNode();
80 return parent && parent->isShadowRoot() ? toShadowRoot(parent)->owner()->you ngestShadowRoot() : parent;
81 }
82
83 static inline bool containsIncludingShadowRoots(const ContainerNode* node1, cons t ContainerNode* node2)
84 {
85 ASSERT(node1);
86 ASSERT(node2);
87
88 // If node1 is a older shadow root and node2 is an younger shadow root hoste d by the
89 // same shadow host, treat as if node1 contains node2.
90 if (node1->isShadowRoot()) {
91 Node* host = toShadowRoot(node1)->host();
92 return host != node2 && host->containsIncludingShadowDOM(node2);
93 }
94 return node1->containsIncludingShadowDOM(node2);
95 }
96
69 void ScopedStyleTree::setupScopedStylesTree(ScopedStyleResolver* target) 97 void ScopedStyleTree::setupScopedStylesTree(ScopedStyleResolver* target)
70 { 98 {
71 ASSERT(target); 99 ASSERT(target);
72 100
73 const ContainerNode& scopingNode = target->scopingNode(); 101 const ContainerNode& scopingNode = target->scopingNode();
74 102
75 // Since StyleResolver creates RuleSets according to styles' document 103 // Since StyleResolver creates RuleSets according to styles' document
76 // order, a parent of the given ScopedRuleData has been already 104 // order, a parent of the given ScopedRuleData has been already
77 // prepared. 105 // prepared.
78 for (ContainerNode* node = scopingNode.parentOrShadowHostNode(); node; node = node->parentOrShadowHostNode()) { 106 for (ContainerNode* node = traverseParent(&scopingNode); node; node = traver seParent(node)) {
79 if (ScopedStyleResolver* scopedResolver = scopedStyleResolverFor(*node)) { 107 if (ScopedStyleResolver* scopedResolver = scopedStyleResolverFor(*node)) {
80 target->setParent(scopedResolver); 108 target->setParent(scopedResolver);
81 break; 109 break;
82 } 110 }
83 if (node->isDocumentNode()) { 111 if (node->isDocumentNode()) {
84 bool dummy; 112 bool dummy;
85 ScopedStyleResolver* scopedResolver = addScopedStyleResolver(*node, dummy); 113 ScopedStyleResolver* scopedResolver = addScopedStyleResolver(*node, dummy);
86 target->setParent(scopedResolver); 114 target->setParent(scopedResolver);
87 setupScopedStylesTree(scopedResolver); 115 setupScopedStylesTree(scopedResolver);
88 break; 116 break;
89 } 117 }
90 } 118 }
91 119
92 if (m_buildInDocumentOrder) 120 if (m_buildInDocumentOrder)
93 return; 121 return;
94 122
95 // Reparent all nodes whose scoping node is contained by target's one. 123 // Reparent all nodes whose scoping node is contained by target's one.
96 for (HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::iterator i t = m_authorStyles.begin(); it != m_authorStyles.end(); ++it) { 124 for (HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::iterator i t = m_authorStyles.begin(); it != m_authorStyles.end(); ++it) {
97 if (it->value == target) 125 if (it->value == target)
98 continue; 126 continue;
99 ASSERT(it->key->inDocument()); 127 ASSERT(it->key->inDocument());
100 if (it->value->parent() == target->parent() && scopingNode.containsInclu dingShadowDOM(it->key)) 128 if (it->value->parent() == target->parent() && containsIncludingShadowRo ots(&scopingNode, it->key))
101 it->value->setParent(target); 129 it->value->setParent(target);
102 } 130 }
103 } 131 }
104 132
105 void ScopedStyleTree::clear() 133 void ScopedStyleTree::clear()
106 { 134 {
107 m_authorStyles.clear(); 135 m_authorStyles.clear();
108 m_scopedResolverForDocument = 0; 136 m_scopedResolverForDocument = 0;
109 m_cache.clear(); 137 m_cache.clear();
110 } 138 }
111 139
112 void ScopedStyleTree::resolveScopedStyles(const Element* element, Vector<ScopedS tyleResolver*, 8>& resolvers) 140 void ScopedStyleTree::resolveScopedStyles(const Element* element, Vector<ScopedS tyleResolver*, 8>& resolvers)
113 { 141 {
114 for (ScopedStyleResolver* scopedResolver = scopedResolverFor(element); scope dResolver; scopedResolver = scopedResolver->parent()) 142 for (ScopedStyleResolver* scopedResolver = scopedResolverFor(element); scope dResolver; scopedResolver = scopedResolver->parent())
115 resolvers.append(scopedResolver); 143 resolvers.append(scopedResolver);
116 } 144 }
117 145
118 void ScopedStyleTree::collectScopedResolversForHostedShadowTrees(const Element* element, Vector<ScopedStyleResolver*, 8>& resolvers)
119 {
120 ElementShadow* shadow = element->shadow();
121 if (!shadow)
122 return;
123
124 // Adding scoped resolver for active shadow roots for shadow host styling.
125 for (ShadowRoot* shadowRoot = shadow->youngestShadowRoot(); shadowRoot; shad owRoot = shadowRoot->olderShadowRoot()) {
126 if (shadowRoot->hasScopedHTMLStyleChild()) {
127 if (ScopedStyleResolver* resolver = scopedStyleResolverFor(*shadowRo ot))
128 resolvers.append(resolver);
129 }
130 if (!shadowRoot->containsShadowElements())
131 break;
132 }
133 }
134
135 void ScopedStyleTree::resolveScopedKeyframesRules(const Element* element, Vector <ScopedStyleResolver*, 8>& resolvers) 146 void ScopedStyleTree::resolveScopedKeyframesRules(const Element* element, Vector <ScopedStyleResolver*, 8>& resolvers)
136 { 147 {
137 Document& document = element->document(); 148 Document& document = element->document();
138 TreeScope& treeScope = element->treeScope(); 149 TreeScope& treeScope = element->treeScope();
139 bool applyAuthorStyles = treeScope.applyAuthorStyles(); 150 bool applyAuthorStyles = treeScope.applyAuthorStyles();
140 151
141 // Add resolvers for shadow roots hosted by the given element.
142 collectScopedResolversForHostedShadowTrees(element, resolvers);
143
144 // Add resolvers while walking up DOM tree from the given element. 152 // Add resolvers while walking up DOM tree from the given element.
145 for (ScopedStyleResolver* scopedResolver = scopedResolverFor(element); scope dResolver; scopedResolver = scopedResolver->parent()) { 153 ScopedStyleResolver* scopedResolver = scopedResolverFor(element);
146 if (scopedResolver->treeScope() == treeScope || (applyAuthorStyles && sc opedResolver->treeScope() == document)) 154 for (; scopedResolver; scopedResolver = scopedResolver->parent()) {
155 if (scopedResolver->treeScope() == treeScope
156 || (scopedResolver->scopingNode().isShadowRoot() && toShadowRoot(&sc opedResolver->scopingNode())->host() == element)
157 || (applyAuthorStyles && scopedResolver->treeScope() == document))
147 resolvers.append(scopedResolver); 158 resolvers.append(scopedResolver);
148 } 159 }
149 } 160 }
150 161
151 inline ScopedStyleResolver* ScopedStyleTree::enclosingScopedStyleResolverFor(con st ContainerNode* scopingNode) 162 inline ScopedStyleResolver* ScopedStyleTree::enclosingScopedStyleResolverFor(con st ContainerNode* scopingNode)
152 { 163 {
153 for (; scopingNode; scopingNode = scopingNode->parentOrShadowHostNode()) { 164 const ContainerNode* node;
154 if (ScopedStyleResolver* scopedStyleResolver = scopedStyleResolverFor(*s copingNode)) 165 // FIXME: we should split "style tree" traversal logic out from this method.
166 if (isShadowHost(scopingNode)) {
167 node = toElement(scopingNode)->shadow()->youngestShadowRoot();
168 } else {
169 node = scopingNode->isShadowRoot() ? toShadowRoot(scopingNode)->owner()- >youngestShadowRoot() : scopingNode;
170 }
171 for (; node; node = traverseParent(node)) {
172 if (ScopedStyleResolver* scopedStyleResolver = scopedStyleResolverFor(*n ode))
155 return scopedStyleResolver; 173 return scopedStyleResolver;
156 } 174 }
157 return 0; 175 return 0;
158 } 176 }
159 177
160 void ScopedStyleTree::resolveStyleCache(const ContainerNode* scopingNode) 178 void ScopedStyleTree::resolveStyleCache(const ContainerNode* scopingNode)
161 { 179 {
162 m_cache.scopedResolver = enclosingScopedStyleResolverFor(scopingNode); 180 m_cache.scopedResolver = enclosingScopedStyleResolverFor(scopingNode);
163 m_cache.nodeForScopedStyles = scopingNode; 181 m_cache.nodeForScopedStyles = scopingNode;
164 } 182 }
165 183
166 void ScopedStyleTree::pushStyleCache(const ContainerNode& scopingNode, const Con tainerNode* parent) 184 void ScopedStyleTree::pushStyleCache(const ContainerNode& scopingNode, const Con tainerNode* parent)
167 { 185 {
168 if (m_authorStyles.isEmpty()) 186 if (m_authorStyles.isEmpty())
169 return; 187 return;
170 188
171 if (!cacheIsValid(parent)) { 189 if (!cacheIsValid(parent)) {
172 resolveStyleCache(&scopingNode); 190 resolveStyleCache(&scopingNode);
173 return; 191 return;
174 } 192 }
175 193
176 ScopedStyleResolver* scopedResolver = scopedStyleResolverFor(scopingNode); 194 ScopedStyleResolver* scopedResolver = scopedStyleResolverFor(scopingNode);
177 if (scopedResolver) 195 if (scopedResolver)
178 m_cache.scopedResolver = scopedResolver; 196 m_cache.scopedResolver = scopedResolver;
179 m_cache.nodeForScopedStyles = &scopingNode; 197 m_cache.nodeForScopedStyles = &scopingNode;
180 } 198 }
181 199
200 static inline bool shadowRootHasTheSameShadowHost(const ContainerNode& node, con st Node* host)
201 {
202 if (!node.isShadowRoot())
203 return false;
204 return toShadowRoot(&node)->host() == host;
205 }
206
182 void ScopedStyleTree::popStyleCache(const ContainerNode& scopingNode) 207 void ScopedStyleTree::popStyleCache(const ContainerNode& scopingNode)
183 { 208 {
184 if (!cacheIsValid(&scopingNode)) 209 if (!cacheIsValid(&scopingNode))
185 return; 210 return;
186 211
187 if (m_cache.scopedResolver && m_cache.scopedResolver->scopingNode() == scopi ngNode) 212 if (!scopingNode.isShadowRoot()) {
188 m_cache.scopedResolver = m_cache.scopedResolver->parent(); 213 if (m_cache.scopedResolver && m_cache.scopedResolver->scopingNode() == s copingNode)
214 m_cache.scopedResolver = m_cache.scopedResolver->parent();
215
216 m_cache.nodeForScopedStyles = scopingNode.parentOrShadowHostNode();
217 return;
218 }
219
220 const ShadowRoot* shadowRoot = toShadowRoot(&scopingNode);
221 const Node* host = shadowRoot->host();
222
223 // If a given scoping node is the oldest shadow root and cached resolver's s coping node
224 // is a shadow root (mostly, the youngest shadow root) hosted by the same ho st of
225 // the given shadow root, update cacheed resolver.
226 if (m_cache.scopedResolver
227 && shadowRoot->isOldest()
228 && shadowRootHasTheSameShadowHost(m_cache.scopedResolver->scopingNode(), host)) {
229 ScopedStyleResolver* resolver = m_cache.scopedResolver;
230
231 while (shadowRootHasTheSameShadowHost(resolver->scopingNode(), host))
232 resolver = resolver->parent();
233
234 m_cache.scopedResolver = resolver;
235 }
236
189 m_cache.nodeForScopedStyles = scopingNode.parentOrShadowHostNode(); 237 m_cache.nodeForScopedStyles = scopingNode.parentOrShadowHostNode();
190 } 238 }
191 239
192 void ScopedStyleTree::collectFeaturesTo(RuleFeatureSet& features) 240 void ScopedStyleTree::collectFeaturesTo(RuleFeatureSet& features)
193 { 241 {
194 for (HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::iterator i t = m_authorStyles.begin(); it != m_authorStyles.end(); ++it) 242 for (HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::iterator i t = m_authorStyles.begin(); it != m_authorStyles.end(); ++it)
195 it->value->collectFeaturesTo(features); 243 it->value->collectFeaturesTo(features);
196 } 244 }
197 245
198 inline void ScopedStyleTree::reparentNodes(const ScopedStyleResolver* oldParent, ScopedStyleResolver* newParent) 246 inline void ScopedStyleTree::reparentNodes(const ScopedStyleResolver* oldParent, ScopedStyleResolver* newParent)
(...skipping 15 matching lines...) Expand all
214 return; 262 return;
215 263
216 reparentNodes(resolverRemoved, resolverRemoved->parent()); 264 reparentNodes(resolverRemoved, resolverRemoved->parent());
217 if (m_cache.scopedResolver == resolverRemoved) 265 if (m_cache.scopedResolver == resolverRemoved)
218 m_cache.clear(); 266 m_cache.clear();
219 267
220 m_authorStyles.remove(scopingNode); 268 m_authorStyles.remove(scopingNode);
221 } 269 }
222 270
223 } // namespace WebCore 271 } // namespace WebCore
OLDNEW
« 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