Home | History | Annotate | Download | only in resolver
      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