Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 a child of its older shadow root. | |
|
dglazkov
2014/01/16 17:31:31
To make younger shadow root _act_ as a child of th
tasak
2014/01/20 03:50:06
Yes. Done.
| |
| 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 if (isShadowHost(scopingNode)) { |
|
dglazkov
2014/01/16 17:31:31
There's a definite "style tree" (needs better name
tasak
2014/01/20 03:50:06
I see.
I will done in another patch.
| |
| 166 node = toElement(scopingNode)->shadow()->youngestShadowRoot(); | |
| 167 } else { | |
| 168 node = scopingNode->isShadowRoot() ? toShadowRoot(scopingNode)->owner()- >youngestShadowRoot() : scopingNode; | |
| 169 } | |
| 170 for (; node; node = traverseParent(node)) { | |
| 171 if (ScopedStyleResolver* scopedStyleResolver = scopedStyleResolverFor(*n ode)) | |
| 155 return scopedStyleResolver; | 172 return scopedStyleResolver; |
| 156 } | 173 } |
| 157 return 0; | 174 return 0; |
| 158 } | 175 } |
| 159 | 176 |
| 160 void ScopedStyleTree::resolveStyleCache(const ContainerNode* scopingNode) | 177 void ScopedStyleTree::resolveStyleCache(const ContainerNode* scopingNode) |
| 161 { | 178 { |
| 162 m_cache.scopedResolver = enclosingScopedStyleResolverFor(scopingNode); | 179 m_cache.scopedResolver = enclosingScopedStyleResolverFor(scopingNode); |
| 163 m_cache.nodeForScopedStyles = scopingNode; | 180 m_cache.nodeForScopedStyles = scopingNode; |
| 164 } | 181 } |
| 165 | 182 |
| 166 void ScopedStyleTree::pushStyleCache(const ContainerNode& scopingNode, const Con tainerNode* parent) | 183 void ScopedStyleTree::pushStyleCache(const ContainerNode& scopingNode, const Con tainerNode* parent) |
| 167 { | 184 { |
| 168 if (m_authorStyles.isEmpty()) | 185 if (m_authorStyles.isEmpty()) |
| 169 return; | 186 return; |
| 170 | 187 |
| 171 if (!cacheIsValid(parent)) { | 188 if (!cacheIsValid(parent)) { |
| 172 resolveStyleCache(&scopingNode); | 189 resolveStyleCache(&scopingNode); |
| 173 return; | 190 return; |
| 174 } | 191 } |
| 175 | 192 |
| 176 ScopedStyleResolver* scopedResolver = scopedStyleResolverFor(scopingNode); | 193 ScopedStyleResolver* scopedResolver = scopedStyleResolverFor(scopingNode); |
| 177 if (scopedResolver) | 194 if (scopedResolver) |
| 178 m_cache.scopedResolver = scopedResolver; | 195 m_cache.scopedResolver = scopedResolver; |
| 179 m_cache.nodeForScopedStyles = &scopingNode; | 196 m_cache.nodeForScopedStyles = &scopingNode; |
| 180 } | 197 } |
| 181 | 198 |
| 199 static inline bool shadowRootHasTheSameShadowHost(const ContainerNode& node, con st Node* host) | |
| 200 { | |
| 201 if (!node.isShadowRoot()) | |
| 202 return false; | |
| 203 return toShadowRoot(&node)->host() == host; | |
| 204 } | |
| 205 | |
| 182 void ScopedStyleTree::popStyleCache(const ContainerNode& scopingNode) | 206 void ScopedStyleTree::popStyleCache(const ContainerNode& scopingNode) |
| 183 { | 207 { |
| 184 if (!cacheIsValid(&scopingNode)) | 208 if (!cacheIsValid(&scopingNode)) |
| 185 return; | 209 return; |
| 186 | 210 |
| 187 if (m_cache.scopedResolver && m_cache.scopedResolver->scopingNode() == scopi ngNode) | 211 if (!scopingNode.isShadowRoot()) { |
| 188 m_cache.scopedResolver = m_cache.scopedResolver->parent(); | 212 if (m_cache.scopedResolver && m_cache.scopedResolver->scopingNode() == s copingNode) |
| 213 m_cache.scopedResolver = m_cache.scopedResolver->parent(); | |
| 214 | |
| 215 m_cache.nodeForScopedStyles = scopingNode.parentOrShadowHostNode(); | |
| 216 return; | |
| 217 } | |
| 218 | |
| 219 const ShadowRoot* shadowRoot = toShadowRoot(&scopingNode); | |
| 220 const Node* host = shadowRoot->host(); | |
| 221 | |
| 222 // If a given scoping node is the oldest shadow root and cached resolver's s coping node | |
| 223 // is a shadow root (mostly, the youngest shadow root) hosted by the same ho st of | |
| 224 // the given shadow root, update cacheed resolver. | |
| 225 if (m_cache.scopedResolver | |
| 226 && shadowRoot->isOldest() | |
| 227 && shadowRootHasTheSameShadowHost(m_cache.scopedResolver->scopingNode(), host)) { | |
| 228 ScopedStyleResolver* resolver = m_cache.scopedResolver; | |
| 229 | |
| 230 while (shadowRootHasTheSameShadowHost(resolver->scopingNode(), host)) | |
| 231 resolver = resolver->parent(); | |
| 232 | |
| 233 m_cache.scopedResolver = resolver; | |
| 234 } | |
| 235 | |
| 189 m_cache.nodeForScopedStyles = scopingNode.parentOrShadowHostNode(); | 236 m_cache.nodeForScopedStyles = scopingNode.parentOrShadowHostNode(); |
| 190 } | 237 } |
| 191 | 238 |
| 192 void ScopedStyleTree::collectFeaturesTo(RuleFeatureSet& features) | 239 void ScopedStyleTree::collectFeaturesTo(RuleFeatureSet& features) |
| 193 { | 240 { |
| 194 for (HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::iterator i t = m_authorStyles.begin(); it != m_authorStyles.end(); ++it) | 241 for (HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::iterator i t = m_authorStyles.begin(); it != m_authorStyles.end(); ++it) |
| 195 it->value->collectFeaturesTo(features); | 242 it->value->collectFeaturesTo(features); |
| 196 } | 243 } |
| 197 | 244 |
| 198 inline void ScopedStyleTree::reparentNodes(const ScopedStyleResolver* oldParent, ScopedStyleResolver* newParent) | 245 inline void ScopedStyleTree::reparentNodes(const ScopedStyleResolver* oldParent, ScopedStyleResolver* newParent) |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 214 return; | 261 return; |
| 215 | 262 |
| 216 reparentNodes(resolverRemoved, resolverRemoved->parent()); | 263 reparentNodes(resolverRemoved, resolverRemoved->parent()); |
| 217 if (m_cache.scopedResolver == resolverRemoved) | 264 if (m_cache.scopedResolver == resolverRemoved) |
| 218 m_cache.clear(); | 265 m_cache.clear(); |
| 219 | 266 |
| 220 m_authorStyles.remove(scopingNode); | 267 m_authorStyles.remove(scopingNode); |
| 221 } | 268 } |
| 222 | 269 |
| 223 } // namespace WebCore | 270 } // namespace WebCore |
| OLD | NEW |