• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DistributionPool(const ContainerNode & parent)53 inline DistributionPool::DistributionPool(const ContainerNode& parent)
54 {
55     populateChildren(parent);
56 }
57 
clear()58 inline void DistributionPool::clear()
59 {
60     detachNonDistributedNodes();
61     m_nodes.clear();
62     m_distributed.clear();
63 }
64 
populateChildren(const ContainerNode & parent)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 
distributeTo(InsertionPoint * insertionPoint,ElementShadow * elementShadow)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 
~DistributionPool()108 inline DistributionPool::~DistributionPool()
109 {
110     detachNonDistributedNodes();
111 }
112 
detachNonDistributedNodes()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 
create()123 PassOwnPtr<ElementShadow> ElementShadow::create()
124 {
125     return adoptPtr(new ElementShadow());
126 }
127 
ElementShadow()128 ElementShadow::ElementShadow()
129     : m_needsDistributionRecalc(false)
130     , m_applyAuthorStyles(false)
131     , m_needsSelectFeatureSet(false)
132 {
133 }
134 
~ElementShadow()135 ElementShadow::~ElementShadow()
136 {
137     removeAllShadowRoots();
138 }
139 
addShadowRoot(Element & shadowHost,ShadowRoot::ShadowRootType type)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 
removeAllShadowRoots()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 
attach(const Node::AttachContext & context)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 
detach(const Node::AttachContext & context)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 
removeAllEventListeners()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 
setNeedsDistributionRecalc()211 void ElementShadow::setNeedsDistributionRecalc()
212 {
213     if (m_needsDistributionRecalc)
214         return;
215     m_needsDistributionRecalc = true;
216     host()->markAncestorsWithChildNeedsDistributionRecalc();
217     clearDistribution();
218 }
219 
didAffectApplyAuthorStyles()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 
containsActiveStyles() const231 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 
resolveApplyAuthorStyles() const242 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 
finalDestinationInsertionPointFor(const Node * key) const253 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 
destinationInsertionPointsFor(const Node * key) const259 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 
distribute()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 
didDistributeNode(const Node * node,InsertionPoint * insertionPoint)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 
ensureSelectFeatureSet()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 
collectSelectFeatureSetFrom(ShadowRoot & root)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 
didAffectSelector(AffectedSelectorMask mask)350 void ElementShadow::didAffectSelector(AffectedSelectorMask mask)
351 {
352     if (ensureSelectFeatureSet().hasSelectorFor(mask))
353         setNeedsDistributionRecalc();
354 }
355 
willAffectSelector()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 
clearDistribution()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