2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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.
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.
28 #include "core/dom/shadow/ElementShadow.h"
31 #include "core/css/StyleSheetList.h"
32 #include "core/dom/ContainerNodeAlgorithms.h"
33 #include "core/dom/ElementTraversal.h"
34 #include "core/dom/NodeTraversal.h"
35 #include "core/dom/shadow/ContentDistribution.h"
36 #include "core/html/shadow/HTMLContentElement.h"
37 #include "core/html/shadow/HTMLShadowElement.h"
41 class DistributionPool {
43 explicit DistributionPool(const ContainerNode&);
46 void distributeTo(InsertionPoint*, ElementShadow*);
47 void populateChildren(const ContainerNode&);
50 void detachNonDistributedNodes();
51 Vector<Node*, 32> m_nodes;
52 Vector<bool, 32> m_distributed;
55 inline DistributionPool::DistributionPool(const ContainerNode& parent)
57 populateChildren(parent);
60 inline void DistributionPool::clear()
62 detachNonDistributedNodes();
64 m_distributed.clear();
67 inline void DistributionPool::populateChildren(const ContainerNode& parent)
70 for (Node* child = parent.firstChild(); child; child = child->nextSibling()) {
71 if (isActiveInsertionPoint(*child)) {
72 InsertionPoint* insertionPoint = toInsertionPoint(child);
73 for (size_t i = 0; i < insertionPoint->size(); ++i)
74 m_nodes.append(insertionPoint->at(i));
76 m_nodes.append(child);
79 m_distributed.resize(m_nodes.size());
80 m_distributed.fill(false);
83 void DistributionPool::distributeTo(InsertionPoint* insertionPoint, ElementShadow* elementShadow)
85 ContentDistribution distribution;
87 for (size_t i = 0; i < m_nodes.size(); ++i) {
91 if (insertionPoint->hasTagName(HTMLNames::contentTag) && !toHTMLContentElement(insertionPoint)->canSelectNode(m_nodes, i))
94 Node* node = m_nodes[i];
95 distribution.append(node);
96 elementShadow->didDistributeNode(node, insertionPoint);
97 m_distributed[i] = true;
100 // Distributes fallback elements
101 if (insertionPoint->isContentInsertionPoint() && distribution.isEmpty()) {
102 for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fallbackNode = fallbackNode->nextSibling()) {
103 distribution.append(fallbackNode);
104 elementShadow->didDistributeNode(fallbackNode, insertionPoint);
107 insertionPoint->setDistribution(distribution);
110 inline DistributionPool::~DistributionPool()
112 detachNonDistributedNodes();
115 inline void DistributionPool::detachNonDistributedNodes()
117 for (size_t i = 0; i < m_nodes.size(); ++i) {
118 if (m_distributed[i])
120 if (m_nodes[i]->renderer())
121 m_nodes[i]->lazyReattachIfAttached();
125 PassOwnPtr<ElementShadow> ElementShadow::create()
127 return adoptPtr(new ElementShadow());
130 ElementShadow::ElementShadow()
131 : m_needsDistributionRecalc(false)
132 , m_applyAuthorStyles(false)
133 , m_needsSelectFeatureSet(false)
137 ElementShadow::~ElementShadow()
139 removeDetachedShadowRoots();
142 ShadowRoot& ElementShadow::addShadowRoot(Element& shadowHost, ShadowRoot::ShadowRootType type)
144 RefPtr<ShadowRoot> shadowRoot = ShadowRoot::create(shadowHost.document(), type);
146 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot())
147 root->lazyReattachIfAttached();
149 shadowRoot->setParentOrShadowHostNode(&shadowHost);
150 shadowRoot->setParentTreeScope(shadowHost.treeScope());
151 m_shadowRoots.push(shadowRoot.get());
152 ChildNodeInsertionNotifier(shadowHost).notify(*shadowRoot);
153 setNeedsDistributionRecalc();
155 // addShadowRoot() affects apply-author-styles. However, we know that the youngest shadow root has not had any children yet.
156 // The youngest shadow root's apply-author-styles is default (false). So we can just set m_applyAuthorStyles false.
157 m_applyAuthorStyles = false;
159 shadowHost.didAddShadowRoot(*shadowRoot);
160 InspectorInstrumentation::didPushShadowRoot(&shadowHost, shadowRoot.get());
162 ASSERT(m_shadowRoots.head());
163 ASSERT(shadowRoot.get() == m_shadowRoots.head());
164 return *m_shadowRoots.head();
167 void ElementShadow::removeDetachedShadowRoots()
169 // Dont protect this ref count.
170 Element* shadowHost = host();
173 while (RefPtr<ShadowRoot> oldRoot = m_shadowRoots.head()) {
174 InspectorInstrumentation::willPopShadowRoot(shadowHost, oldRoot.get());
175 shadowHost->document().removeFocusedElementOfSubtree(oldRoot.get());
176 m_shadowRoots.removeHead();
177 oldRoot->setParentOrShadowHostNode(0);
178 oldRoot->setParentTreeScope(shadowHost->document());
185 void ElementShadow::attach(const Node::AttachContext& context)
187 Node::AttachContext childrenContext(context);
188 childrenContext.resolvedStyle = 0;
190 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
191 if (root->needsAttach())
192 root->attach(childrenContext);
196 void ElementShadow::detach(const Node::AttachContext& context)
198 Node::AttachContext childrenContext(context);
199 childrenContext.resolvedStyle = 0;
201 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot())
202 root->detach(childrenContext);
205 void ElementShadow::removeAllEventListeners()
207 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
208 for (Node* node = root; node; node = NodeTraversal::next(*node))
209 node->removeAllEventListeners();
213 void ElementShadow::setNeedsDistributionRecalc()
215 if (m_needsDistributionRecalc)
217 m_needsDistributionRecalc = true;
218 host()->markAncestorsWithChildNeedsDistributionRecalc();
222 bool ElementShadow::didAffectApplyAuthorStyles()
224 bool applyAuthorStyles = resolveApplyAuthorStyles();
226 if (m_applyAuthorStyles == applyAuthorStyles)
229 m_applyAuthorStyles = applyAuthorStyles;
233 bool ElementShadow::containsActiveStyles() const
235 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
236 if (root->hasScopedHTMLStyleChild())
238 if (!root->containsShadowElements())
244 bool ElementShadow::hasSameStyles(ElementShadow *other) const
246 ShadowRoot* root = youngestShadowRoot();
247 ShadowRoot* otherRoot = other->youngestShadowRoot();
248 while (root || otherRoot) {
249 if (!root || !otherRoot)
252 StyleSheetList* list = root->styleSheets();
253 StyleSheetList* otherList = otherRoot->styleSheets();
255 if (list->length() != otherList->length())
258 for (size_t i = 0; i < list->length(); i++) {
259 if (toCSSStyleSheet(list->item(i))->contents() != toCSSStyleSheet(otherList->item(i))->contents())
262 root = root->olderShadowRoot();
263 otherRoot = otherRoot->olderShadowRoot();
269 bool ElementShadow::resolveApplyAuthorStyles() const
271 for (const ShadowRoot* shadowRoot = youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot()) {
272 if (shadowRoot->applyAuthorStyles())
274 if (!shadowRoot->containsShadowElements())
280 const InsertionPoint* ElementShadow::finalDestinationInsertionPointFor(const Node* key) const
282 NodeToDestinationInsertionPoints::const_iterator it = m_nodeToInsertionPoints.find(key);
283 return it == m_nodeToInsertionPoints.end() ? 0: it->value.last().get();
286 const DestinationInsertionPoints* ElementShadow::destinationInsertionPointsFor(const Node* key) const
288 NodeToDestinationInsertionPoints::const_iterator it = m_nodeToInsertionPoints.find(key);
289 return it == m_nodeToInsertionPoints.end() ? 0: &it->value;
292 void ElementShadow::distribute()
294 host()->setNeedsStyleRecalc();
295 Vector<HTMLShadowElement*, 32> shadowInsertionPoints;
296 DistributionPool pool(*host());
298 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
299 HTMLShadowElement* shadowInsertionPoint = 0;
300 const Vector<RefPtr<InsertionPoint> >& insertionPoints = root->descendantInsertionPoints();
301 for (size_t i = 0; i < insertionPoints.size(); ++i) {
302 InsertionPoint* point = insertionPoints[i].get();
303 if (!point->isActive())
305 if (point->hasTagName(HTMLNames::shadowTag)) {
306 ASSERT(!shadowInsertionPoint);
307 shadowInsertionPoint = toHTMLShadowElement(point);
308 shadowInsertionPoints.append(shadowInsertionPoint);
310 pool.distributeTo(point, this);
311 if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*point))
312 shadow->setNeedsDistributionRecalc();
317 for (size_t i = shadowInsertionPoints.size(); i > 0; --i) {
318 HTMLShadowElement* shadowInsertionPoint = shadowInsertionPoints[i - 1];
319 ShadowRoot* root = shadowInsertionPoint->containingShadowRoot();
321 if (root->isOldest()) {
322 pool.distributeTo(shadowInsertionPoint, this);
323 } else if (root->olderShadowRoot()->type() == root->type()) {
324 // Only allow reprojecting older shadow roots between the same type to
325 // disallow reprojecting UA elements into author shadows.
326 DistributionPool olderShadowRootPool(*root->olderShadowRoot());
327 olderShadowRootPool.distributeTo(shadowInsertionPoint, this);
328 root->olderShadowRoot()->setShadowInsertionPointOfYoungerShadowRoot(shadowInsertionPoint);
330 if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*shadowInsertionPoint))
331 shadow->setNeedsDistributionRecalc();
335 void ElementShadow::didDistributeNode(const Node* node, InsertionPoint* insertionPoint)
337 NodeToDestinationInsertionPoints::AddResult result = m_nodeToInsertionPoints.add(node, DestinationInsertionPoints());
338 result.iterator->value.append(insertionPoint);
341 const SelectRuleFeatureSet& ElementShadow::ensureSelectFeatureSet()
343 if (!m_needsSelectFeatureSet)
344 return m_selectFeatures;
346 m_selectFeatures.clear();
347 for (ShadowRoot* root = oldestShadowRoot(); root; root = root->youngerShadowRoot())
348 collectSelectFeatureSetFrom(*root);
349 m_needsSelectFeatureSet = false;
350 return m_selectFeatures;
353 void ElementShadow::collectSelectFeatureSetFrom(ShadowRoot& root)
355 if (!root.containsShadowRoots() && !root.containsContentElements())
358 for (Element* element = ElementTraversal::firstWithin(root); element; element = ElementTraversal::next(*element, &root)) {
359 if (ElementShadow* shadow = element->shadow())
360 m_selectFeatures.add(shadow->ensureSelectFeatureSet());
361 if (!element->hasTagName(HTMLNames::contentTag))
363 const CSSSelectorList& list = toHTMLContentElement(element)->selectorList();
364 for (const CSSSelector* selector = list.first(); selector; selector = CSSSelectorList::next(selector)) {
365 for (const CSSSelector* component = selector; component; component = component->tagHistory())
366 m_selectFeatures.collectFeaturesFromSelector(component);
371 void ElementShadow::didAffectSelector(AffectedSelectorMask mask)
373 if (ensureSelectFeatureSet().hasSelectorFor(mask))
374 setNeedsDistributionRecalc();
377 void ElementShadow::willAffectSelector()
379 for (ElementShadow* shadow = this; shadow; shadow = shadow->containingShadow()) {
380 if (shadow->needsSelectFeatureSet())
382 shadow->setNeedsSelectFeatureSet();
384 setNeedsDistributionRecalc();
387 void ElementShadow::clearDistribution()
389 m_nodeToInsertionPoints.clear();
391 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot())
392 root->setShadowInsertionPointOfYoungerShadowRoot(0);