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"
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/dom/shadow/InsertionPoint.h"
35 #include "core/dom/shadow/ShadowRoot.h"
36 #include "core/html/shadow/HTMLContentElement.h"
37 #include "core/html/shadow/HTMLShadowElement.h"
41 class DistributionPool {
43 explicit DistributionPool(const ContainerNode*);
45 void distributeTo(InsertionPoint*, ElementShadow*);
48 void populateChildren(const ContainerNode*);
49 void detachNonDistributedNodes();
50 Vector<Node*, 32> m_nodes;
51 Vector<bool, 32> m_distributed;
54 inline DistributionPool::DistributionPool(const ContainerNode* parent)
57 populateChildren(parent);
60 inline void DistributionPool::populateChildren(const ContainerNode* parent)
62 for (Node* child = parent->firstChild(); child; child = child->nextSibling()) {
63 if (isActiveInsertionPoint(*child)) {
64 InsertionPoint* insertionPoint = toInsertionPoint(child);
65 for (size_t i = 0; i < insertionPoint->size(); ++i)
66 m_nodes.append(insertionPoint->at(i));
68 m_nodes.append(child);
71 m_distributed.resize(m_nodes.size());
72 m_distributed.fill(false);
75 void DistributionPool::distributeTo(InsertionPoint* insertionPoint, ElementShadow* elementShadow)
77 ContentDistribution distribution;
79 for (size_t i = 0; i < m_nodes.size(); ++i) {
83 if (isHTMLContentElement(insertionPoint) && !toHTMLContentElement(insertionPoint)->canSelectNode(m_nodes, i))
86 Node* node = m_nodes[i];
87 distribution.append(node);
88 elementShadow->didDistributeNode(node, insertionPoint);
89 m_distributed[i] = true;
92 // Distributes fallback elements
93 if (insertionPoint->isContentInsertionPoint() && distribution.isEmpty()) {
94 for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fallbackNode = fallbackNode->nextSibling()) {
95 distribution.append(fallbackNode);
96 elementShadow->didDistributeNode(fallbackNode, insertionPoint);
99 insertionPoint->setDistribution(distribution);
102 inline DistributionPool::~DistributionPool()
104 detachNonDistributedNodes();
107 inline void DistributionPool::detachNonDistributedNodes()
109 for (size_t i = 0; i < m_nodes.size(); ++i) {
110 if (m_distributed[i])
112 if (m_nodes[i]->renderer())
113 m_nodes[i]->lazyReattachIfAttached();
117 PassOwnPtr<ElementShadow> ElementShadow::create()
119 return adoptPtr(new ElementShadow());
122 ElementShadow::ElementShadow()
123 : m_needsDistributionRecalc(false)
124 , m_applyAuthorStyles(false)
125 , m_needsSelectFeatureSet(false)
129 ElementShadow::~ElementShadow()
131 removeAllShadowRoots();
134 ShadowRoot* ElementShadow::addShadowRoot(Element& shadowHost, ShadowRoot::ShadowRootType type)
136 RefPtr<ShadowRoot> shadowRoot = ShadowRoot::create(&shadowHost.document(), type);
138 shadowRoot->setParentOrShadowHostNode(&shadowHost);
139 shadowRoot->setParentTreeScope(&shadowHost.treeScope());
140 m_shadowRoots.push(shadowRoot.get());
141 ChildNodeInsertionNotifier(shadowHost).notify(*shadowRoot);
142 setNeedsDistributionRecalc();
143 shadowHost.lazyReattachIfAttached();
145 // addShadowRoot() affects apply-author-styles. However, we know that the youngest shadow root has not had any children yet.
146 // The youngest shadow root's apply-author-styles is default (false). So we can just set m_applyAuthorStyles false.
147 m_applyAuthorStyles = false;
149 shadowHost.didAddShadowRoot(*shadowRoot);
150 InspectorInstrumentation::didPushShadowRoot(&shadowHost, shadowRoot.get());
152 return shadowRoot.get();
155 void ElementShadow::removeAllShadowRoots()
157 // Dont protect this ref count.
158 Element* shadowHost = host();
161 while (RefPtr<ShadowRoot> oldRoot = m_shadowRoots.head()) {
162 InspectorInstrumentation::willPopShadowRoot(shadowHost, oldRoot.get());
163 shadowHost->document().removeFocusedElementOfSubtree(oldRoot.get());
164 m_shadowRoots.removeHead();
165 oldRoot->setParentOrShadowHostNode(0);
166 oldRoot->setParentTreeScope(&shadowHost->document());
169 ChildNodeRemovalNotifier(*shadowHost).notify(*oldRoot);
173 void ElementShadow::attach(const Node::AttachContext& context)
175 Node::AttachContext childrenContext(context);
176 childrenContext.resolvedStyle = 0;
178 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
179 if (root->needsAttach())
180 root->attach(childrenContext);
184 void ElementShadow::detach(const Node::AttachContext& context)
186 Node::AttachContext childrenContext(context);
187 childrenContext.resolvedStyle = 0;
189 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot())
190 root->detach(childrenContext);
193 void ElementShadow::removeAllEventListeners()
195 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
196 for (Node* node = root; node; node = NodeTraversal::next(node))
197 node->removeAllEventListeners();
201 void ElementShadow::setNeedsDistributionRecalc()
203 if (m_needsDistributionRecalc)
205 m_needsDistributionRecalc = true;
206 host()->markAncestorsWithChildNeedsDistributionRecalc();
210 bool ElementShadow::didAffectApplyAuthorStyles()
212 bool applyAuthorStyles = resolveApplyAuthorStyles();
214 if (m_applyAuthorStyles == applyAuthorStyles)
217 m_applyAuthorStyles = applyAuthorStyles;
221 bool ElementShadow::containsActiveStyles() const
223 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
224 if (root->hasScopedHTMLStyleChild())
226 if (!root->containsShadowElements())
232 bool ElementShadow::resolveApplyAuthorStyles() const
234 for (const ShadowRoot* shadowRoot = youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot()) {
235 if (shadowRoot->applyAuthorStyles())
237 if (!shadowRoot->containsShadowElements())
243 const InsertionPoint* ElementShadow::finalDestinationInsertionPointFor(const Node* key) const
245 NodeToDestinationInsertionPoints::const_iterator it = m_nodeToInsertionPoints.find(key);
246 return it == m_nodeToInsertionPoints.end() ? 0: it->value.last().get();
249 const DestinationInsertionPoints* ElementShadow::destinationInsertionPointsFor(const Node* key) const
251 NodeToDestinationInsertionPoints::const_iterator it = m_nodeToInsertionPoints.find(key);
252 return it == m_nodeToInsertionPoints.end() ? 0: &it->value;
255 void ElementShadow::distribute()
257 host()->setNeedsStyleRecalc();
259 const ContainerNode* poolContainer = host();
261 Vector<HTMLShadowElement*, 32> shadowInsertionPoints;
262 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
263 DistributionPool pool(poolContainer);
265 HTMLShadowElement* shadowInsertionPoint = 0;
266 const Vector<RefPtr<InsertionPoint> >& insertionPoints = root->descendantInsertionPoints();
267 for (size_t i = 0; i < insertionPoints.size(); ++i) {
268 InsertionPoint* point = insertionPoints[i].get();
269 if (!point->isActive())
271 if (isHTMLShadowElement(point)) {
272 if (!shadowInsertionPoint)
273 shadowInsertionPoint = toHTMLShadowElement(point);
275 pool.distributeTo(point, this);
276 if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*point))
277 shadow->setNeedsDistributionRecalc();
280 if (shadowInsertionPoint)
281 shadowInsertionPoints.append(shadowInsertionPoint);
282 poolContainer = shadowInsertionPoint;
285 for (size_t i = shadowInsertionPoints.size(); i > 0; --i) {
286 HTMLShadowElement* shadowInsertionPoint = shadowInsertionPoints[i - 1];
287 ShadowRoot* root = shadowInsertionPoint->containingShadowRoot();
289 if (root->olderShadowRoot() && root->olderShadowRoot()->type() == root->type()) {
290 // Only allow reprojecting older shadow roots between the same type to
291 // disallow reprojecting UA elements into author shadows.
292 distributeNodeChildrenTo(shadowInsertionPoint, root->olderShadowRoot());
293 root->olderShadowRoot()->setShadowInsertionPointOfYoungerShadowRoot(shadowInsertionPoint);
294 } else if (root->isOldest()) {
295 DistributionPool pool(shadowInsertionPoint);
296 pool.distributeTo(shadowInsertionPoint, this);
298 if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*shadowInsertionPoint))
299 shadow->setNeedsDistributionRecalc();
303 void ElementShadow::didDistributeNode(const Node* node, InsertionPoint* insertionPoint)
305 NodeToDestinationInsertionPoints::AddResult result = m_nodeToInsertionPoints.add(node, DestinationInsertionPoints());
306 result.iterator->value.append(insertionPoint);
309 void ElementShadow::distributeNodeChildrenTo(InsertionPoint* insertionPoint, ContainerNode* containerNode)
311 DistributionPool pool(containerNode);
312 pool.distributeTo(insertionPoint, this);
315 const SelectRuleFeatureSet& ElementShadow::ensureSelectFeatureSet()
317 if (!m_needsSelectFeatureSet)
318 return m_selectFeatures;
320 m_selectFeatures.clear();
321 for (ShadowRoot* root = oldestShadowRoot(); root; root = root->youngerShadowRoot())
322 collectSelectFeatureSetFrom(root);
323 m_needsSelectFeatureSet = false;
324 return m_selectFeatures;
327 void ElementShadow::collectSelectFeatureSetFrom(ShadowRoot* root)
329 if (!root->containsShadowRoots() && !root->containsContentElements())
332 for (Element* element = ElementTraversal::firstWithin(root); element; element = ElementTraversal::next(element, root)) {
333 if (ElementShadow* shadow = element->shadow())
334 m_selectFeatures.add(shadow->ensureSelectFeatureSet());
335 if (!isHTMLContentElement(element))
337 const CSSSelectorList& list = toHTMLContentElement(element)->selectorList();
338 for (const CSSSelector* selector = list.first(); selector; selector = CSSSelectorList::next(selector)) {
339 for (const CSSSelector* component = selector; component; component = component->tagHistory())
340 m_selectFeatures.collectFeaturesFromSelector(component);
345 void ElementShadow::didAffectSelector(AffectedSelectorMask mask)
347 if (ensureSelectFeatureSet().hasSelectorFor(mask))
348 setNeedsDistributionRecalc();
351 void ElementShadow::willAffectSelector()
353 for (ElementShadow* shadow = this; shadow; shadow = shadow->containingShadow()) {
354 if (shadow->needsSelectFeatureSet())
356 shadow->setNeedsSelectFeatureSet();
358 setNeedsDistributionRecalc();
361 void ElementShadow::clearDistribution()
363 m_nodeToInsertionPoints.clear();
365 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot())
366 root->setShadowInsertionPointOfYoungerShadowRoot(0);