1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 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. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "core/css/resolver/ScopedStyleResolver.h" 29 30 #include "HTMLNames.h" 31 #include "core/css/CSSStyleSheet.h" 32 #include "core/css/PageRuleCollector.h" 33 #include "core/css/RuleFeature.h" 34 #include "core/css/RuleSet.h" 35 #include "core/css/StyleRule.h" 36 #include "core/css/resolver/StyleResolver.h" // For MatchRequest. 37 #include "core/dom/Document.h" 38 #include "core/dom/shadow/ContentDistributor.h" 39 #include "core/dom/shadow/ElementShadow.h" 40 #include "core/dom/shadow/ShadowRoot.h" 41 #include "core/html/HTMLStyleElement.h" 42 43 namespace WebCore { 44 45 ScopedStyleResolver* ScopedStyleTree::ensureScopedStyleResolver(const ContainerNode* scopingNode) 46 { 47 ASSERT(scopingNode); 48 bool isNewEntry; 49 ScopedStyleResolver* scopedStyleResolver = addScopedStyleResolver(scopingNode, isNewEntry); 50 if (isNewEntry) 51 setupScopedStylesTree(scopedStyleResolver); 52 return scopedStyleResolver; 53 } 54 55 ScopedStyleResolver* ScopedStyleTree::scopedStyleResolverFor(const ContainerNode* scopingNode) 56 { 57 if (!scopingNode->hasScopedHTMLStyleChild() 58 && !(scopingNode->isElementNode() && toElement(scopingNode)->shadow()) 59 && !scopingNode->isDocumentNode() 60 && !scopingNode->isShadowRoot()) 61 return 0; 62 HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::iterator it = m_authorStyles.find(scopingNode); 63 return it != m_authorStyles.end() ? it->value.get() : 0; 64 } 65 66 ScopedStyleResolver* ScopedStyleTree::addScopedStyleResolver(const ContainerNode* scopingNode, bool& isNewEntry) 67 { 68 HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::AddResult addResult = m_authorStyles.add(scopingNode, nullptr); 69 70 if (addResult.isNewEntry) { 71 addResult.iterator->value = ScopedStyleResolver::create(scopingNode); 72 if (!scopingNode || scopingNode->isDocumentNode()) 73 m_scopedResolverForDocument = addResult.iterator->value.get(); 74 } 75 isNewEntry = addResult.isNewEntry; 76 return addResult.iterator->value.get(); 77 } 78 79 void ScopedStyleTree::setupScopedStylesTree(ScopedStyleResolver* target) 80 { 81 ASSERT(target); 82 ASSERT(target->scopingNode()); 83 84 const ContainerNode* scopingNode = target->scopingNode(); 85 86 // Since StyleResolver creates RuleSets according to styles' document 87 // order, a parent of the given ScopedRuleData has been already 88 // prepared. 89 for (const ContainerNode* node = scopingNode->parentOrShadowHostNode(); node; node = node->parentOrShadowHostNode()) { 90 if (ScopedStyleResolver* scopedResolver = scopedStyleResolverFor(node)) { 91 target->setParent(scopedResolver); 92 break; 93 } 94 if (node->isDocumentNode()) { 95 bool dummy; 96 ScopedStyleResolver* scopedResolver = addScopedStyleResolver(node, dummy); 97 target->setParent(scopedResolver); 98 setupScopedStylesTree(scopedResolver); 99 break; 100 } 101 } 102 103 if (m_buildInDocumentOrder) 104 return; 105 106 // Reparent all nodes whose scoping node is contained by target's one. 107 for (HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::iterator it = m_authorStyles.begin(); it != m_authorStyles.end(); ++it) { 108 if (it->value == target) 109 continue; 110 if (it->value->parent() == target->parent() && scopingNode->containsIncludingShadowDOM(it->key)) 111 it->value->setParent(target); 112 } 113 } 114 115 void ScopedStyleTree::clear() 116 { 117 m_authorStyles.clear(); 118 m_scopedResolverForDocument = 0; 119 m_cache.clear(); 120 } 121 122 void ScopedStyleTree::resolveScopedStyles(const Element* element, Vector<ScopedStyleResolver*, 8>& resolvers) 123 { 124 for (ScopedStyleResolver* scopedResolver = scopedResolverFor(element); scopedResolver; scopedResolver = scopedResolver->parent()) 125 resolvers.append(scopedResolver); 126 } 127 128 void ScopedStyleTree::collectScopedResolversForHostedShadowTrees(const Element* element, Vector<ScopedStyleResolver*, 8>& resolvers) 129 { 130 ElementShadow* shadow = element->shadow(); 131 if (!shadow) 132 return; 133 134 // Adding scoped resolver for active shadow roots for shadow host styling. 135 for (ShadowRoot* shadowRoot = shadow->youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot()) { 136 if (shadowRoot->hasScopedHTMLStyleChild()) { 137 if (ScopedStyleResolver* resolver = scopedStyleResolverFor(shadowRoot)) 138 resolvers.append(resolver); 139 } 140 if (!shadowRoot->containsShadowElements()) 141 break; 142 } 143 } 144 145 void ScopedStyleTree::resolveScopedKeyframesRules(const Element* element, Vector<ScopedStyleResolver*, 8>& resolvers) 146 { 147 Document* document = element->document(); 148 TreeScope* treeScope = element->treeScope(); 149 bool applyAuthorStyles = treeScope->applyAuthorStyles(); 150 151 for (ScopedStyleResolver* scopedResolver = scopedResolverFor(element); scopedResolver; scopedResolver = scopedResolver->parent()) { 152 if (scopedResolver->treeScope() == treeScope || (applyAuthorStyles && scopedResolver->treeScope() == document)) 153 resolvers.append(scopedResolver); 154 } 155 } 156 157 inline ScopedStyleResolver* ScopedStyleTree::enclosingScopedStyleResolverFor(const ContainerNode* scopingNode) 158 { 159 for (; scopingNode; scopingNode = scopingNode->parentOrShadowHostNode()) { 160 if (ScopedStyleResolver* scopedStyleResolver = scopedStyleResolverFor(scopingNode)) 161 return scopedStyleResolver; 162 } 163 return 0; 164 } 165 166 void ScopedStyleTree::resolveStyleCache(const ContainerNode* scopingNode) 167 { 168 m_cache.scopedResolver = enclosingScopedStyleResolverFor(scopingNode); 169 m_cache.nodeForScopedStyles = scopingNode; 170 } 171 172 void ScopedStyleTree::pushStyleCache(const ContainerNode* scopingNode, const ContainerNode* parent) 173 { 174 if (m_authorStyles.isEmpty()) 175 return; 176 177 if (!cacheIsValid(parent)) { 178 resolveStyleCache(scopingNode); 179 return; 180 } 181 182 ScopedStyleResolver* scopedResolver = scopedStyleResolverFor(scopingNode); 183 if (scopedResolver) 184 m_cache.scopedResolver = scopedResolver; 185 m_cache.nodeForScopedStyles = scopingNode; 186 } 187 188 void ScopedStyleTree::popStyleCache(const ContainerNode* scopingNode) 189 { 190 if (!cacheIsValid(scopingNode)) 191 return; 192 193 if (m_cache.scopedResolver && m_cache.scopedResolver->scopingNode() == scopingNode) 194 m_cache.scopedResolver = m_cache.scopedResolver->parent(); 195 m_cache.nodeForScopedStyles = scopingNode->parentOrShadowHostNode(); 196 } 197 198 void ScopedStyleTree::collectFeaturesTo(RuleFeatureSet& features) 199 { 200 for (HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::iterator it = m_authorStyles.begin(); it != m_authorStyles.end(); ++it) 201 it->value->collectFeaturesTo(features); 202 } 203 204 inline void ScopedStyleTree::reparentNodes(const ScopedStyleResolver* oldParent, ScopedStyleResolver* newParent) 205 { 206 // FIXME: this takes O(N) (N = number of all scoping nodes). 207 for (HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::iterator it = m_authorStyles.begin(); it != m_authorStyles.end(); ++it) { 208 if (it->value->parent() == oldParent) 209 it->value->setParent(newParent); 210 } 211 } 212 213 void ScopedStyleTree::remove(const ContainerNode* scopingNode) 214 { 215 if (!scopingNode || scopingNode->isDocumentNode()) 216 return; 217 218 ScopedStyleResolver* resolverRemoved = scopedStyleResolverFor(scopingNode); 219 if (!resolverRemoved) 220 return; 221 222 reparentNodes(resolverRemoved, resolverRemoved->parent()); 223 if (m_cache.scopedResolver == resolverRemoved) 224 m_cache.clear(); 225 226 m_authorStyles.remove(scopingNode); 227 } 228 229 const ContainerNode* ScopedStyleResolver::scopingNodeFor(const CSSStyleSheet* sheet) 230 { 231 ASSERT(sheet); 232 233 Document* document = sheet->ownerDocument(); 234 if (!document) 235 return 0; 236 Node* ownerNode = sheet->ownerNode(); 237 if (!ownerNode || !ownerNode->hasTagName(HTMLNames::styleTag)) 238 return 0; 239 240 HTMLStyleElement* styleElement = toHTMLStyleElement(ownerNode); 241 if (!styleElement->scoped()) 242 return styleElement->isInShadowTree() ? styleElement->containingShadowRoot() : 0; 243 244 ContainerNode* parent = styleElement->parentNode(); 245 if (!parent) 246 return 0; 247 248 return (parent->isElementNode() || parent->isShadowRoot()) ? parent : 0; 249 } 250 251 void ScopedStyleResolver::addRulesFromSheet(StyleSheetContents* sheet, const MediaQueryEvaluator& medium, StyleResolver* resolver) 252 { 253 if (!m_authorStyle) 254 m_authorStyle = RuleSet::create(); 255 m_authorStyle->addRulesFromSheet(sheet, medium, resolver, m_scopingNode); 256 } 257 258 inline RuleSet* ScopedStyleResolver::ensureAtHostRuleSetFor(const ShadowRoot* shadowRoot) 259 { 260 HashMap<const ShadowRoot*, OwnPtr<RuleSet> >::AddResult addResult = m_atHostRules.add(shadowRoot, nullptr); 261 if (addResult.isNewEntry) 262 addResult.iterator->value = RuleSet::create(); 263 return addResult.iterator->value.get(); 264 } 265 266 void ScopedStyleResolver::addHostRule(StyleRuleHost* hostRule, bool hasDocumentSecurityOrigin, const ContainerNode* scopingNode) 267 { 268 if (!scopingNode) 269 return; 270 271 ShadowRoot* shadowRoot = scopingNode->containingShadowRoot(); 272 if (!shadowRoot || !shadowRoot->host()) 273 return; 274 275 RuleSet* rule = ensureAtHostRuleSetFor(shadowRoot); 276 277 const Vector<RefPtr<StyleRuleBase> >& childRules = hostRule->childRules(); 278 AddRuleFlags addRuleFlags = hasDocumentSecurityOrigin ? RuleHasDocumentSecurityOrigin : RuleHasNoSpecialState; 279 addRuleFlags = static_cast<AddRuleFlags>(addRuleFlags | RuleCanUseFastCheckSelector); 280 for (unsigned i = 0; i < childRules.size(); ++i) { 281 StyleRuleBase* hostStylingRule = childRules[i].get(); 282 if (hostStylingRule->isStyleRule()) 283 rule->addStyleRule(static_cast<StyleRule*>(hostStylingRule), addRuleFlags); 284 } 285 } 286 287 void ScopedStyleResolver::collectFeaturesTo(RuleFeatureSet& features) 288 { 289 if (m_authorStyle) 290 features.add(m_authorStyle->features()); 291 292 if (m_atHostRules.isEmpty()) 293 return; 294 295 for (HashMap<const ShadowRoot*, OwnPtr<RuleSet> >::iterator it = m_atHostRules.begin(); it != m_atHostRules.end(); ++it) 296 features.add(it->value->features()); 297 } 298 299 void ScopedStyleResolver::resetAuthorStyle() 300 { 301 m_authorStyle = RuleSet::create(); 302 m_keyframesRuleMap.clear(); 303 } 304 305 void ScopedStyleResolver::resetAtHostRules(const ShadowRoot* shadowRoot) 306 { 307 m_atHostRules.remove(shadowRoot); 308 } 309 310 bool ScopedStyleResolver::checkRegionStyle(Element* regionElement) 311 { 312 if (!m_authorStyle) 313 return false; 314 315 unsigned rulesSize = m_authorStyle->m_regionSelectorsAndRuleSets.size(); 316 for (unsigned i = 0; i < rulesSize; ++i) { 317 ASSERT(m_authorStyle->m_regionSelectorsAndRuleSets.at(i).ruleSet.get()); 318 if (checkRegionSelector(m_authorStyle->m_regionSelectorsAndRuleSets.at(i).selector, regionElement)) 319 return true; 320 } 321 return false; 322 } 323 324 const StyleRuleKeyframes* ScopedStyleResolver::keyframeStylesForAnimation(const StringImpl* animationName) 325 { 326 if (m_keyframesRuleMap.isEmpty()) 327 return 0; 328 329 KeyframesRuleMap::iterator it = m_keyframesRuleMap.find(animationName); 330 if (it == m_keyframesRuleMap.end()) 331 return 0; 332 333 return it->value.get(); 334 } 335 336 void ScopedStyleResolver::addKeyframeStyle(PassRefPtr<StyleRuleKeyframes> rule) 337 { 338 AtomicString s(rule->name()); 339 m_keyframesRuleMap.set(s.impl(), rule); 340 } 341 342 inline RuleSet* ScopedStyleResolver::atHostRuleSetFor(const ShadowRoot* shadowRoot) const 343 { 344 HashMap<const ShadowRoot*, OwnPtr<RuleSet> >::const_iterator it = m_atHostRules.find(shadowRoot); 345 return it != m_atHostRules.end() ? it->value.get() : 0; 346 } 347 348 void ScopedStyleResolver::matchHostRules(ElementRuleCollector& collector, bool includeEmptyRules) 349 { 350 // FIXME: Determine tree position. 351 CascadeScope cascadeScope = ignoreCascadeScope; 352 353 if (m_atHostRules.isEmpty() || !m_scopingNode->isElementNode()) 354 return; 355 356 ElementShadow* shadow = toElement(m_scopingNode)->shadow(); 357 if (!shadow) 358 return; 359 360 collector.clearMatchedRules(); 361 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1; 362 363 // FIXME(99827): https://bugs.webkit.org/show_bug.cgi?id=99827 364 // add a new flag to ElementShadow and cache whether any @host @-rules are 365 // applied to the element or not. So we can quickly exit this method 366 // by using the flag. 367 ShadowRoot* shadowRoot = shadow->youngestShadowRoot(); 368 for (; shadowRoot; shadowRoot = shadowRoot->olderShadowRoot()) 369 if (!shadowRoot->containsShadowElements()) 370 break; 371 // All shadow roots have <shadow>. 372 if (!shadowRoot) 373 shadowRoot = shadow->oldestShadowRoot(); 374 375 RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange(); 376 collector.setBehaviorAtBoundary(static_cast<SelectorChecker::BehaviorAtBoundary>(SelectorChecker::DoesNotCrossBoundary | SelectorChecker::ScopeContainsLastMatchedElement)); 377 for (; shadowRoot; shadowRoot = shadowRoot->youngerShadowRoot()) { 378 if (RuleSet* ruleSet = atHostRuleSetFor(shadowRoot)) 379 collector.collectMatchingRules(MatchRequest(ruleSet, includeEmptyRules, m_scopingNode), ruleRange, cascadeScope); 380 } 381 382 collector.sortAndTransferMatchedRules(); 383 } 384 385 void ScopedStyleResolver::matchAuthorRules(ElementRuleCollector& collector, bool includeEmptyRules, bool applyAuthorStyles) 386 { 387 collector.clearMatchedRules(); 388 collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1; 389 collectMatchingAuthorRules(collector, includeEmptyRules, applyAuthorStyles, ignoreCascadeScope); 390 collector.sortAndTransferMatchedRules(); 391 } 392 393 void ScopedStyleResolver::collectMatchingAuthorRules(ElementRuleCollector& collector, bool includeEmptyRules, bool applyAuthorStyles, CascadeScope cascadeScope, CascadeOrder cascadeOrder) 394 { 395 if (!m_authorStyle) 396 return; 397 398 const ContainerNode* scopingNode = m_scopingNode; 399 unsigned behaviorAtBoundary = SelectorChecker::DoesNotCrossBoundary; 400 401 if (!applyAuthorStyles) 402 behaviorAtBoundary |= SelectorChecker::ScopeContainsLastMatchedElement; 403 404 if (m_scopingNode->isShadowRoot()) { 405 scopingNode = toShadowRoot(m_scopingNode)->host(); 406 behaviorAtBoundary |= SelectorChecker::ScopeIsShadowHost; 407 } 408 409 MatchRequest matchRequest(m_authorStyle.get(), includeEmptyRules, scopingNode, applyAuthorStyles); 410 RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange(); 411 collector.setBehaviorAtBoundary(static_cast<SelectorChecker::BehaviorAtBoundary>(behaviorAtBoundary)); 412 collector.collectMatchingRules(matchRequest, ruleRange, cascadeScope, cascadeOrder); 413 collector.collectMatchingRulesForRegion(matchRequest, ruleRange, cascadeScope, cascadeOrder); 414 } 415 416 void ScopedStyleResolver::matchPageRules(PageRuleCollector& collector) 417 { 418 // Only consider the global author RuleSet for @page rules, as per the HTML5 spec. 419 ASSERT(m_scopingNode->isDocumentNode()); 420 collector.matchPageRules(m_authorStyle.get()); 421 } 422 423 void ScopedStyleResolver::collectViewportRulesTo(StyleResolver* resolver) const 424 { 425 if (m_authorStyle) 426 resolver->collectViewportRules(m_authorStyle.get()); 427 } 428 429 } // namespace WebCore 430