1 /* 2 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Neither the name of Google Inc. nor the names of its 11 * contributors may be used to endorse or promote products derived from 12 * this software without specific prior written permission. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "core/dom/shadow/ElementShadow.h" 29 30 #include "core/dom/ContainerNodeAlgorithms.h" 31 #include "core/dom/ElementTraversal.h" 32 #include "core/dom/NodeTraversal.h" 33 #include "core/dom/shadow/ContentDistribution.h" 34 #include "core/html/shadow/HTMLContentElement.h" 35 #include "core/html/shadow/HTMLShadowElement.h" 36 37 namespace WebCore { 38 39 class DistributionPool { 40 public: 41 explicit DistributionPool(const ContainerNode&); 42 void clear(); 43 ~DistributionPool(); 44 void distributeTo(InsertionPoint*, ElementShadow*); 45 void populateChildren(const ContainerNode&); 46 47 private: 48 void detachNonDistributedNodes(); 49 Vector<Node*, 32> m_nodes; 50 Vector<bool, 32> m_distributed; 51 }; 52 53 inline DistributionPool::DistributionPool(const ContainerNode& parent) 54 { 55 populateChildren(parent); 56 } 57 58 inline void DistributionPool::clear() 59 { 60 detachNonDistributedNodes(); 61 m_nodes.clear(); 62 m_distributed.clear(); 63 } 64 65 inline void DistributionPool::populateChildren(const ContainerNode& parent) 66 { 67 clear(); 68 for (Node* child = parent.firstChild(); child; child = child->nextSibling()) { 69 if (isActiveInsertionPoint(*child)) { 70 InsertionPoint* insertionPoint = toInsertionPoint(child); 71 for (size_t i = 0; i < insertionPoint->size(); ++i) 72 m_nodes.append(insertionPoint->at(i)); 73 } else { 74 m_nodes.append(child); 75 } 76 } 77 m_distributed.resize(m_nodes.size()); 78 m_distributed.fill(false); 79 } 80 81 void DistributionPool::distributeTo(InsertionPoint* insertionPoint, ElementShadow* elementShadow) 82 { 83 ContentDistribution distribution; 84 85 for (size_t i = 0; i < m_nodes.size(); ++i) { 86 if (m_distributed[i]) 87 continue; 88 89 if (isHTMLContentElement(insertionPoint) && !toHTMLContentElement(insertionPoint)->canSelectNode(m_nodes, i)) 90 continue; 91 92 Node* node = m_nodes[i]; 93 distribution.append(node); 94 elementShadow->didDistributeNode(node, insertionPoint); 95 m_distributed[i] = true; 96 } 97 98 // Distributes fallback elements 99 if (insertionPoint->isContentInsertionPoint() && distribution.isEmpty()) { 100 for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fallbackNode = fallbackNode->nextSibling()) { 101 distribution.append(fallbackNode); 102 elementShadow->didDistributeNode(fallbackNode, insertionPoint); 103 } 104 } 105 insertionPoint->setDistribution(distribution); 106 } 107 108 inline DistributionPool::~DistributionPool() 109 { 110 detachNonDistributedNodes(); 111 } 112 113 inline void DistributionPool::detachNonDistributedNodes() 114 { 115 for (size_t i = 0; i < m_nodes.size(); ++i) { 116 if (m_distributed[i]) 117 continue; 118 if (m_nodes[i]->renderer()) 119 m_nodes[i]->lazyReattachIfAttached(); 120 } 121 } 122 123 PassOwnPtr<ElementShadow> ElementShadow::create() 124 { 125 return adoptPtr(new ElementShadow()); 126 } 127 128 ElementShadow::ElementShadow() 129 : m_needsDistributionRecalc(false) 130 , m_applyAuthorStyles(false) 131 , m_needsSelectFeatureSet(false) 132 { 133 } 134 135 ElementShadow::~ElementShadow() 136 { 137 removeAllShadowRoots(); 138 } 139 140 ShadowRoot& ElementShadow::addShadowRoot(Element& shadowHost, ShadowRoot::ShadowRootType type) 141 { 142 RefPtr<ShadowRoot> shadowRoot = ShadowRoot::create(&shadowHost.document(), type); 143 144 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) 145 root->lazyReattachIfAttached(); 146 147 shadowRoot->setParentOrShadowHostNode(&shadowHost); 148 shadowRoot->setParentTreeScope(&shadowHost.treeScope()); 149 m_shadowRoots.push(shadowRoot.get()); 150 ChildNodeInsertionNotifier(shadowHost).notify(*shadowRoot); 151 setNeedsDistributionRecalc(); 152 153 // addShadowRoot() affects apply-author-styles. However, we know that the youngest shadow root has not had any children yet. 154 // The youngest shadow root's apply-author-styles is default (false). So we can just set m_applyAuthorStyles false. 155 m_applyAuthorStyles = false; 156 157 shadowHost.didAddShadowRoot(*shadowRoot); 158 InspectorInstrumentation::didPushShadowRoot(&shadowHost, shadowRoot.get()); 159 160 ASSERT(m_shadowRoots.head()); 161 ASSERT(shadowRoot.get() == m_shadowRoots.head()); 162 return *m_shadowRoots.head(); 163 } 164 165 void ElementShadow::removeAllShadowRoots() 166 { 167 // Dont protect this ref count. 168 Element* shadowHost = host(); 169 ASSERT(shadowHost); 170 171 while (RefPtr<ShadowRoot> oldRoot = m_shadowRoots.head()) { 172 InspectorInstrumentation::willPopShadowRoot(shadowHost, oldRoot.get()); 173 shadowHost->document().removeFocusedElementOfSubtree(oldRoot.get()); 174 m_shadowRoots.removeHead(); 175 oldRoot->setParentOrShadowHostNode(0); 176 oldRoot->setParentTreeScope(&shadowHost->document()); 177 oldRoot->setPrev(0); 178 oldRoot->setNext(0); 179 ChildNodeRemovalNotifier(*shadowHost).notify(*oldRoot); 180 } 181 } 182 183 void ElementShadow::attach(const Node::AttachContext& context) 184 { 185 Node::AttachContext childrenContext(context); 186 childrenContext.resolvedStyle = 0; 187 188 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) { 189 if (root->needsAttach()) 190 root->attach(childrenContext); 191 } 192 } 193 194 void ElementShadow::detach(const Node::AttachContext& context) 195 { 196 Node::AttachContext childrenContext(context); 197 childrenContext.resolvedStyle = 0; 198 199 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) 200 root->detach(childrenContext); 201 } 202 203 void ElementShadow::removeAllEventListeners() 204 { 205 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) { 206 for (Node* node = root; node; node = NodeTraversal::next(*node)) 207 node->removeAllEventListeners(); 208 } 209 } 210 211 void ElementShadow::setNeedsDistributionRecalc() 212 { 213 if (m_needsDistributionRecalc) 214 return; 215 m_needsDistributionRecalc = true; 216 host()->markAncestorsWithChildNeedsDistributionRecalc(); 217 clearDistribution(); 218 } 219 220 bool ElementShadow::didAffectApplyAuthorStyles() 221 { 222 bool applyAuthorStyles = resolveApplyAuthorStyles(); 223 224 if (m_applyAuthorStyles == applyAuthorStyles) 225 return false; 226 227 m_applyAuthorStyles = applyAuthorStyles; 228 return true; 229 } 230 231 bool ElementShadow::containsActiveStyles() const 232 { 233 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) { 234 if (root->hasScopedHTMLStyleChild()) 235 return true; 236 if (!root->containsShadowElements()) 237 return false; 238 } 239 return false; 240 } 241 242 bool ElementShadow::resolveApplyAuthorStyles() const 243 { 244 for (const ShadowRoot* shadowRoot = youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot()) { 245 if (shadowRoot->applyAuthorStyles()) 246 return true; 247 if (!shadowRoot->containsShadowElements()) 248 break; 249 } 250 return false; 251 } 252 253 const InsertionPoint* ElementShadow::finalDestinationInsertionPointFor(const Node* key) const 254 { 255 NodeToDestinationInsertionPoints::const_iterator it = m_nodeToInsertionPoints.find(key); 256 return it == m_nodeToInsertionPoints.end() ? 0: it->value.last().get(); 257 } 258 259 const DestinationInsertionPoints* ElementShadow::destinationInsertionPointsFor(const Node* key) const 260 { 261 NodeToDestinationInsertionPoints::const_iterator it = m_nodeToInsertionPoints.find(key); 262 return it == m_nodeToInsertionPoints.end() ? 0: &it->value; 263 } 264 265 void ElementShadow::distribute() 266 { 267 host()->setNeedsStyleRecalc(); 268 Vector<HTMLShadowElement*, 32> shadowInsertionPoints; 269 DistributionPool pool(*host()); 270 271 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) { 272 HTMLShadowElement* shadowInsertionPoint = 0; 273 const Vector<RefPtr<InsertionPoint> >& insertionPoints = root->descendantInsertionPoints(); 274 for (size_t i = 0; i < insertionPoints.size(); ++i) { 275 InsertionPoint* point = insertionPoints[i].get(); 276 if (!point->isActive()) 277 continue; 278 if (isHTMLShadowElement(point)) { 279 if (!shadowInsertionPoint) 280 shadowInsertionPoint = toHTMLShadowElement(point); 281 } else { 282 pool.distributeTo(point, this); 283 if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*point)) 284 shadow->setNeedsDistributionRecalc(); 285 } 286 } 287 if (shadowInsertionPoint) { 288 shadowInsertionPoints.append(shadowInsertionPoint); 289 if (shadowInsertionPoint->hasChildNodes()) 290 pool.populateChildren(*shadowInsertionPoint); 291 } else { 292 pool.clear(); 293 } 294 } 295 296 for (size_t i = shadowInsertionPoints.size(); i > 0; --i) { 297 HTMLShadowElement* shadowInsertionPoint = shadowInsertionPoints[i - 1]; 298 ShadowRoot* root = shadowInsertionPoint->containingShadowRoot(); 299 ASSERT(root); 300 if (root->isOldest()) { 301 pool.distributeTo(shadowInsertionPoint, this); 302 } else if (root->olderShadowRoot()->type() == root->type()) { 303 // Only allow reprojecting older shadow roots between the same type to 304 // disallow reprojecting UA elements into author shadows. 305 DistributionPool olderShadowRootPool(*root->olderShadowRoot()); 306 olderShadowRootPool.distributeTo(shadowInsertionPoint, this); 307 root->olderShadowRoot()->setShadowInsertionPointOfYoungerShadowRoot(shadowInsertionPoint); 308 } 309 if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*shadowInsertionPoint)) 310 shadow->setNeedsDistributionRecalc(); 311 } 312 } 313 314 void ElementShadow::didDistributeNode(const Node* node, InsertionPoint* insertionPoint) 315 { 316 NodeToDestinationInsertionPoints::AddResult result = m_nodeToInsertionPoints.add(node, DestinationInsertionPoints()); 317 result.iterator->value.append(insertionPoint); 318 } 319 320 const SelectRuleFeatureSet& ElementShadow::ensureSelectFeatureSet() 321 { 322 if (!m_needsSelectFeatureSet) 323 return m_selectFeatures; 324 325 m_selectFeatures.clear(); 326 for (ShadowRoot* root = oldestShadowRoot(); root; root = root->youngerShadowRoot()) 327 collectSelectFeatureSetFrom(*root); 328 m_needsSelectFeatureSet = false; 329 return m_selectFeatures; 330 } 331 332 void ElementShadow::collectSelectFeatureSetFrom(ShadowRoot& root) 333 { 334 if (!root.containsShadowRoots() && !root.containsContentElements()) 335 return; 336 337 for (Element* element = ElementTraversal::firstWithin(root); element; element = ElementTraversal::next(*element, &root)) { 338 if (ElementShadow* shadow = element->shadow()) 339 m_selectFeatures.add(shadow->ensureSelectFeatureSet()); 340 if (!isHTMLContentElement(element)) 341 continue; 342 const CSSSelectorList& list = toHTMLContentElement(element)->selectorList(); 343 for (const CSSSelector* selector = list.first(); selector; selector = CSSSelectorList::next(selector)) { 344 for (const CSSSelector* component = selector; component; component = component->tagHistory()) 345 m_selectFeatures.collectFeaturesFromSelector(component); 346 } 347 } 348 } 349 350 void ElementShadow::didAffectSelector(AffectedSelectorMask mask) 351 { 352 if (ensureSelectFeatureSet().hasSelectorFor(mask)) 353 setNeedsDistributionRecalc(); 354 } 355 356 void ElementShadow::willAffectSelector() 357 { 358 for (ElementShadow* shadow = this; shadow; shadow = shadow->containingShadow()) { 359 if (shadow->needsSelectFeatureSet()) 360 break; 361 shadow->setNeedsSelectFeatureSet(); 362 } 363 setNeedsDistributionRecalc(); 364 } 365 366 void ElementShadow::clearDistribution() 367 { 368 m_nodeToInsertionPoints.clear(); 369 370 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) 371 root->setShadowInsertionPointOfYoungerShadowRoot(0); 372 } 373 374 } // namespace 375