17ee8ba1a2642dd3fcd6c558751a6490fd3d2323
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / dom / shadow / ElementShadow.cpp
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
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"
38
39 namespace WebCore {
40
41 class DistributionPool {
42 public:
43     explicit DistributionPool(const ContainerNode&);
44     void clear();
45     ~DistributionPool();
46     void distributeTo(InsertionPoint*, ElementShadow*);
47     void populateChildren(const ContainerNode&);
48
49 private:
50     void detachNonDistributedNodes();
51     Vector<Node*, 32> m_nodes;
52     Vector<bool, 32> m_distributed;
53 };
54
55 inline DistributionPool::DistributionPool(const ContainerNode& parent)
56 {
57     populateChildren(parent);
58 }
59
60 inline void DistributionPool::clear()
61 {
62     detachNonDistributedNodes();
63     m_nodes.clear();
64     m_distributed.clear();
65 }
66
67 inline void DistributionPool::populateChildren(const ContainerNode& parent)
68 {
69     clear();
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));
75         } else {
76             m_nodes.append(child);
77         }
78     }
79     m_distributed.resize(m_nodes.size());
80     m_distributed.fill(false);
81 }
82
83 void DistributionPool::distributeTo(InsertionPoint* insertionPoint, ElementShadow* elementShadow)
84 {
85     ContentDistribution distribution;
86
87     for (size_t i = 0; i < m_nodes.size(); ++i) {
88         if (m_distributed[i])
89             continue;
90
91         if (insertionPoint->hasTagName(HTMLNames::contentTag) && !toHTMLContentElement(insertionPoint)->canSelectNode(m_nodes, i))
92             continue;
93
94         Node* node = m_nodes[i];
95         distribution.append(node);
96         elementShadow->didDistributeNode(node, insertionPoint);
97         m_distributed[i] = true;
98     }
99
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);
105         }
106     }
107     insertionPoint->setDistribution(distribution);
108 }
109
110 inline DistributionPool::~DistributionPool()
111 {
112     detachNonDistributedNodes();
113 }
114
115 inline void DistributionPool::detachNonDistributedNodes()
116 {
117     for (size_t i = 0; i < m_nodes.size(); ++i) {
118         if (m_distributed[i])
119             continue;
120         if (m_nodes[i]->renderer())
121             m_nodes[i]->lazyReattachIfAttached();
122     }
123 }
124
125 PassOwnPtr<ElementShadow> ElementShadow::create()
126 {
127     return adoptPtr(new ElementShadow());
128 }
129
130 ElementShadow::ElementShadow()
131     : m_needsDistributionRecalc(false)
132     , m_applyAuthorStyles(false)
133     , m_needsSelectFeatureSet(false)
134 {
135 }
136
137 ElementShadow::~ElementShadow()
138 {
139     removeDetachedShadowRoots();
140 }
141
142 ShadowRoot& ElementShadow::addShadowRoot(Element& shadowHost, ShadowRoot::ShadowRootType type)
143 {
144     RefPtr<ShadowRoot> shadowRoot = ShadowRoot::create(shadowHost.document(), type);
145
146     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot())
147         root->lazyReattachIfAttached();
148
149     shadowRoot->setParentOrShadowHostNode(&shadowHost);
150     shadowRoot->setParentTreeScope(shadowHost.treeScope());
151     m_shadowRoots.push(shadowRoot.get());
152     ChildNodeInsertionNotifier(shadowHost).notify(*shadowRoot);
153     setNeedsDistributionRecalc();
154
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;
158
159     shadowHost.didAddShadowRoot(*shadowRoot);
160     InspectorInstrumentation::didPushShadowRoot(&shadowHost, shadowRoot.get());
161
162     ASSERT(m_shadowRoots.head());
163     ASSERT(shadowRoot.get() == m_shadowRoots.head());
164     return *m_shadowRoots.head();
165 }
166
167 void ElementShadow::removeDetachedShadowRoots()
168 {
169     // Dont protect this ref count.
170     Element* shadowHost = host();
171     ASSERT(shadowHost);
172
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());
179         oldRoot->setPrev(0);
180         oldRoot->setNext(0);
181     }
182
183 }
184
185 void ElementShadow::attach(const Node::AttachContext& context)
186 {
187     Node::AttachContext childrenContext(context);
188     childrenContext.resolvedStyle = 0;
189
190     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
191         if (root->needsAttach())
192             root->attach(childrenContext);
193     }
194 }
195
196 void ElementShadow::detach(const Node::AttachContext& context)
197 {
198     Node::AttachContext childrenContext(context);
199     childrenContext.resolvedStyle = 0;
200
201     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot())
202         root->detach(childrenContext);
203 }
204
205 void ElementShadow::removeAllEventListeners()
206 {
207     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
208         for (Node* node = root; node; node = NodeTraversal::next(*node))
209             node->removeAllEventListeners();
210     }
211 }
212
213 void ElementShadow::setNeedsDistributionRecalc()
214 {
215     if (m_needsDistributionRecalc)
216         return;
217     m_needsDistributionRecalc = true;
218     host()->markAncestorsWithChildNeedsDistributionRecalc();
219     clearDistribution();
220 }
221
222 bool ElementShadow::didAffectApplyAuthorStyles()
223 {
224     bool applyAuthorStyles = resolveApplyAuthorStyles();
225
226     if (m_applyAuthorStyles == applyAuthorStyles)
227         return false;
228
229     m_applyAuthorStyles = applyAuthorStyles;
230     return true;
231 }
232
233 bool ElementShadow::containsActiveStyles() const
234 {
235     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
236         if (root->hasScopedHTMLStyleChild())
237             return true;
238         if (!root->containsShadowElements())
239             return false;
240     }
241     return false;
242 }
243
244 bool ElementShadow::hasSameStyles(ElementShadow *other) const
245 {
246     ShadowRoot* root = youngestShadowRoot();
247     ShadowRoot* otherRoot = other->youngestShadowRoot();
248     while (root || otherRoot) {
249         if (!root || !otherRoot)
250             return false;
251
252         StyleSheetList* list = root->styleSheets();
253         StyleSheetList* otherList = otherRoot->styleSheets();
254
255         if (list->length() != otherList->length())
256             return false;
257
258         for (size_t i = 0; i < list->length(); i++) {
259             if (toCSSStyleSheet(list->item(i))->contents() != toCSSStyleSheet(otherList->item(i))->contents())
260                 return false;
261         }
262         root = root->olderShadowRoot();
263         otherRoot = otherRoot->olderShadowRoot();
264     }
265
266     return true;
267 }
268
269 bool ElementShadow::resolveApplyAuthorStyles() const
270 {
271     for (const ShadowRoot* shadowRoot = youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot()) {
272         if (shadowRoot->applyAuthorStyles())
273             return true;
274         if (!shadowRoot->containsShadowElements())
275             break;
276     }
277     return false;
278 }
279
280 const InsertionPoint* ElementShadow::finalDestinationInsertionPointFor(const Node* key) const
281 {
282     NodeToDestinationInsertionPoints::const_iterator it = m_nodeToInsertionPoints.find(key);
283     return it == m_nodeToInsertionPoints.end() ? 0: it->value.last().get();
284 }
285
286 const DestinationInsertionPoints* ElementShadow::destinationInsertionPointsFor(const Node* key) const
287 {
288     NodeToDestinationInsertionPoints::const_iterator it = m_nodeToInsertionPoints.find(key);
289     return it == m_nodeToInsertionPoints.end() ? 0: &it->value;
290 }
291
292 void ElementShadow::distribute()
293 {
294     host()->setNeedsStyleRecalc(SubtreeStyleChange);
295     Vector<HTMLShadowElement*, 32> shadowInsertionPoints;
296     DistributionPool pool(*host());
297
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())
304                 continue;
305             if (point->hasTagName(HTMLNames::shadowTag)) {
306                 ASSERT(!shadowInsertionPoint);
307                 shadowInsertionPoint = toHTMLShadowElement(point);
308                 shadowInsertionPoints.append(shadowInsertionPoint);
309             } else {
310                 pool.distributeTo(point, this);
311                 if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*point))
312                     shadow->setNeedsDistributionRecalc();
313             }
314         }
315     }
316
317     for (size_t i = shadowInsertionPoints.size(); i > 0; --i) {
318         HTMLShadowElement* shadowInsertionPoint = shadowInsertionPoints[i - 1];
319         ShadowRoot* root = shadowInsertionPoint->containingShadowRoot();
320         ASSERT(root);
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);
329         }
330         if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*shadowInsertionPoint))
331             shadow->setNeedsDistributionRecalc();
332     }
333 }
334
335 void ElementShadow::didDistributeNode(const Node* node, InsertionPoint* insertionPoint)
336 {
337     NodeToDestinationInsertionPoints::AddResult result = m_nodeToInsertionPoints.add(node, DestinationInsertionPoints());
338     result.storedValue->value.append(insertionPoint);
339 }
340
341 const SelectRuleFeatureSet& ElementShadow::ensureSelectFeatureSet()
342 {
343     if (!m_needsSelectFeatureSet)
344         return m_selectFeatures;
345
346     m_selectFeatures.clear();
347     for (ShadowRoot* root = oldestShadowRoot(); root; root = root->youngerShadowRoot())
348         collectSelectFeatureSetFrom(*root);
349     m_needsSelectFeatureSet = false;
350     return m_selectFeatures;
351 }
352
353 void ElementShadow::collectSelectFeatureSetFrom(ShadowRoot& root)
354 {
355     if (!root.containsShadowRoots() && !root.containsContentElements())
356         return;
357
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))
362             continue;
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);
367         }
368     }
369 }
370
371 void ElementShadow::didAffectSelector(AffectedSelectorMask mask)
372 {
373     if (ensureSelectFeatureSet().hasSelectorFor(mask))
374         setNeedsDistributionRecalc();
375 }
376
377 void ElementShadow::willAffectSelector()
378 {
379     for (ElementShadow* shadow = this; shadow; shadow = shadow->containingShadow()) {
380         if (shadow->needsSelectFeatureSet())
381             break;
382         shadow->setNeedsSelectFeatureSet();
383     }
384     setNeedsDistributionRecalc();
385 }
386
387 void ElementShadow::clearDistribution()
388 {
389     m_nodeToInsertionPoints.clear();
390
391     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot())
392         root->setShadowInsertionPointOfYoungerShadowRoot(0);
393 }
394
395 } // namespace