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/ScopedStyleTree.h"
     29 
     30 #include "core/css/RuleFeature.h"
     31 #include "core/dom/Document.h"
     32 #include "core/dom/shadow/ElementShadow.h"
     33 #include "core/dom/shadow/ShadowRoot.h"
     34 
     35 namespace WebCore {
     36 
     37 ScopedStyleResolver* ScopedStyleTree::ensureScopedStyleResolver(ContainerNode& scopingNode)
     38 {
     39     bool isNewEntry;
     40     ScopedStyleResolver* scopedStyleResolver = addScopedStyleResolver(scopingNode, isNewEntry);
     41     if (isNewEntry)
     42         setupScopedStylesTree(scopedStyleResolver);
     43     return scopedStyleResolver;
     44 }
     45 
     46 ScopedStyleResolver* ScopedStyleTree::scopedStyleResolverFor(const ContainerNode& scopingNode)
     47 {
     48     if (!scopingNode.hasScopedHTMLStyleChild()
     49         && !isShadowHost(&scopingNode)
     50         && !scopingNode.isDocumentNode()
     51         && !scopingNode.isShadowRoot())
     52         return 0;
     53     return lookupScopedStyleResolverFor(&scopingNode);
     54 }
     55 
     56 ScopedStyleResolver* ScopedStyleTree::addScopedStyleResolver(ContainerNode& scopingNode, bool& isNewEntry)
     57 {
     58     HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::AddResult addResult = m_authorStyles.add(&scopingNode, nullptr);
     59 
     60     if (addResult.isNewEntry) {
     61         addResult.iterator->value = ScopedStyleResolver::create(scopingNode);
     62         if (scopingNode.isDocumentNode())
     63             m_scopedResolverForDocument = addResult.iterator->value.get();
     64     }
     65     isNewEntry = addResult.isNewEntry;
     66     return addResult.iterator->value.get();
     67 }
     68 
     69 void ScopedStyleTree::setupScopedStylesTree(ScopedStyleResolver* target)
     70 {
     71     ASSERT(target);
     72 
     73     const ContainerNode& scopingNode = target->scopingNode();
     74 
     75     // Since StyleResolver creates RuleSets according to styles' document
     76     // order, a parent of the given ScopedRuleData has been already
     77     // prepared.
     78     for (ContainerNode* node = scopingNode.parentOrShadowHostNode(); node; node = node->parentOrShadowHostNode()) {
     79         if (ScopedStyleResolver* scopedResolver = scopedStyleResolverFor(*node)) {
     80             target->setParent(scopedResolver);
     81             break;
     82         }
     83         if (node->isDocumentNode()) {
     84             bool dummy;
     85             ScopedStyleResolver* scopedResolver = addScopedStyleResolver(*node, dummy);
     86             target->setParent(scopedResolver);
     87             setupScopedStylesTree(scopedResolver);
     88             break;
     89         }
     90     }
     91 
     92     if (m_buildInDocumentOrder)
     93         return;
     94 
     95     // Reparent all nodes whose scoping node is contained by target's one.
     96     for (HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::iterator it = m_authorStyles.begin(); it != m_authorStyles.end(); ++it) {
     97         if (it->value == target)
     98             continue;
     99         ASSERT(it->key->inDocument());
    100         if (it->value->parent() == target->parent() && scopingNode.containsIncludingShadowDOM(it->key))
    101             it->value->setParent(target);
    102     }
    103 }
    104 
    105 void ScopedStyleTree::clear()
    106 {
    107     m_authorStyles.clear();
    108     m_scopedResolverForDocument = 0;
    109     m_cache.clear();
    110 }
    111 
    112 void ScopedStyleTree::resolveScopedStyles(const Element* element, Vector<ScopedStyleResolver*, 8>& resolvers)
    113 {
    114     for (ScopedStyleResolver* scopedResolver = scopedResolverFor(element); scopedResolver; scopedResolver = scopedResolver->parent())
    115         resolvers.append(scopedResolver);
    116 }
    117 
    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; shadowRoot = shadowRoot->olderShadowRoot()) {
    126         if (shadowRoot->hasScopedHTMLStyleChild()) {
    127             if (ScopedStyleResolver* resolver = scopedStyleResolverFor(*shadowRoot))
    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)
    136 {
    137     Document& document = element->document();
    138     TreeScope& treeScope = element->treeScope();
    139     bool applyAuthorStyles = treeScope.applyAuthorStyles();
    140 
    141     for (ScopedStyleResolver* scopedResolver = scopedResolverFor(element); scopedResolver; scopedResolver = scopedResolver->parent()) {
    142         if (scopedResolver->treeScope() == treeScope || (applyAuthorStyles && scopedResolver->treeScope() == document))
    143             resolvers.append(scopedResolver);
    144     }
    145 }
    146 
    147 inline ScopedStyleResolver* ScopedStyleTree::enclosingScopedStyleResolverFor(const ContainerNode* scopingNode)
    148 {
    149     for (; scopingNode; scopingNode = scopingNode->parentOrShadowHostNode()) {
    150         if (ScopedStyleResolver* scopedStyleResolver = scopedStyleResolverFor(*scopingNode))
    151             return scopedStyleResolver;
    152     }
    153     return 0;
    154 }
    155 
    156 void ScopedStyleTree::resolveStyleCache(const ContainerNode* scopingNode)
    157 {
    158     m_cache.scopedResolver = enclosingScopedStyleResolverFor(scopingNode);
    159     m_cache.nodeForScopedStyles = scopingNode;
    160 }
    161 
    162 void ScopedStyleTree::pushStyleCache(const ContainerNode& scopingNode, const ContainerNode* parent)
    163 {
    164     if (m_authorStyles.isEmpty())
    165         return;
    166 
    167     if (!cacheIsValid(parent)) {
    168         resolveStyleCache(&scopingNode);
    169         return;
    170     }
    171 
    172     ScopedStyleResolver* scopedResolver = scopedStyleResolverFor(scopingNode);
    173     if (scopedResolver)
    174         m_cache.scopedResolver = scopedResolver;
    175     m_cache.nodeForScopedStyles = &scopingNode;
    176 }
    177 
    178 void ScopedStyleTree::popStyleCache(const ContainerNode& scopingNode)
    179 {
    180     if (!cacheIsValid(&scopingNode))
    181         return;
    182 
    183     if (m_cache.scopedResolver && m_cache.scopedResolver->scopingNode() == scopingNode)
    184         m_cache.scopedResolver = m_cache.scopedResolver->parent();
    185     m_cache.nodeForScopedStyles = scopingNode.parentOrShadowHostNode();
    186 }
    187 
    188 void ScopedStyleTree::collectFeaturesTo(RuleFeatureSet& features)
    189 {
    190     for (HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::iterator it = m_authorStyles.begin(); it != m_authorStyles.end(); ++it)
    191         it->value->collectFeaturesTo(features);
    192 }
    193 
    194 inline void ScopedStyleTree::reparentNodes(const ScopedStyleResolver* oldParent, ScopedStyleResolver* newParent)
    195 {
    196     // FIXME: this takes O(N) (N = number of all scoping nodes).
    197     for (HashMap<const ContainerNode*, OwnPtr<ScopedStyleResolver> >::iterator it = m_authorStyles.begin(); it != m_authorStyles.end(); ++it) {
    198         if (it->value->parent() == oldParent)
    199             it->value->setParent(newParent);
    200     }
    201 }
    202 
    203 void ScopedStyleTree::remove(const ContainerNode* scopingNode)
    204 {
    205     if (!scopingNode || scopingNode->isDocumentNode())
    206         return;
    207 
    208     ScopedStyleResolver* resolverRemoved = lookupScopedStyleResolverFor(scopingNode);
    209     if (!resolverRemoved)
    210         return;
    211 
    212     reparentNodes(resolverRemoved, resolverRemoved->parent());
    213     if (m_cache.scopedResolver == resolverRemoved)
    214         m_cache.clear();
    215 
    216     m_authorStyles.remove(scopingNode);
    217 }
    218 
    219 } // namespace WebCore
    220