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