- add third_party src.
[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 #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"
38
39 namespace WebCore {
40
41 class DistributionPool {
42 public:
43     explicit DistributionPool(const ContainerNode*);
44     ~DistributionPool();
45     void distributeTo(InsertionPoint*, ElementShadow*);
46
47 private:
48     void populateChildren(const ContainerNode*);
49     void detachNonDistributedNodes();
50     Vector<Node*, 32> m_nodes;
51     Vector<bool, 32> m_distributed;
52 };
53
54 inline DistributionPool::DistributionPool(const ContainerNode* parent)
55 {
56     if (parent)
57         populateChildren(parent);
58 }
59
60 inline void DistributionPool::populateChildren(const ContainerNode* parent)
61 {
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));
67         } else {
68             m_nodes.append(child);
69         }
70     }
71     m_distributed.resize(m_nodes.size());
72     m_distributed.fill(false);
73 }
74
75 void DistributionPool::distributeTo(InsertionPoint* insertionPoint, ElementShadow* elementShadow)
76 {
77     ContentDistribution distribution;
78
79     for (size_t i = 0; i < m_nodes.size(); ++i) {
80         if (m_distributed[i])
81             continue;
82
83         if (isHTMLContentElement(insertionPoint) && !toHTMLContentElement(insertionPoint)->canSelectNode(m_nodes, i))
84             continue;
85
86         Node* node = m_nodes[i];
87         distribution.append(node);
88         elementShadow->didDistributeNode(node, insertionPoint);
89         m_distributed[i] = true;
90     }
91
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);
97         }
98     }
99     insertionPoint->setDistribution(distribution);
100 }
101
102 inline DistributionPool::~DistributionPool()
103 {
104     detachNonDistributedNodes();
105 }
106
107 inline void DistributionPool::detachNonDistributedNodes()
108 {
109     for (size_t i = 0; i < m_nodes.size(); ++i) {
110         if (m_distributed[i])
111             continue;
112         if (m_nodes[i]->renderer())
113             m_nodes[i]->lazyReattachIfAttached();
114     }
115 }
116
117 PassOwnPtr<ElementShadow> ElementShadow::create()
118 {
119     return adoptPtr(new ElementShadow());
120 }
121
122 ElementShadow::ElementShadow()
123     : m_needsDistributionRecalc(false)
124     , m_applyAuthorStyles(false)
125     , m_needsSelectFeatureSet(false)
126 {
127 }
128
129 ElementShadow::~ElementShadow()
130 {
131     removeAllShadowRoots();
132 }
133
134 ShadowRoot* ElementShadow::addShadowRoot(Element& shadowHost, ShadowRoot::ShadowRootType type)
135 {
136     RefPtr<ShadowRoot> shadowRoot = ShadowRoot::create(&shadowHost.document(), type);
137
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();
144
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;
148
149     shadowHost.didAddShadowRoot(*shadowRoot);
150     InspectorInstrumentation::didPushShadowRoot(&shadowHost, shadowRoot.get());
151
152     return shadowRoot.get();
153 }
154
155 void ElementShadow::removeAllShadowRoots()
156 {
157     // Dont protect this ref count.
158     Element* shadowHost = host();
159     ASSERT(shadowHost);
160
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());
167         oldRoot->setPrev(0);
168         oldRoot->setNext(0);
169         ChildNodeRemovalNotifier(*shadowHost).notify(*oldRoot);
170     }
171 }
172
173 void ElementShadow::attach(const Node::AttachContext& context)
174 {
175     Node::AttachContext childrenContext(context);
176     childrenContext.resolvedStyle = 0;
177
178     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
179         if (root->needsAttach())
180             root->attach(childrenContext);
181     }
182 }
183
184 void ElementShadow::detach(const Node::AttachContext& context)
185 {
186     Node::AttachContext childrenContext(context);
187     childrenContext.resolvedStyle = 0;
188
189     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot())
190         root->detach(childrenContext);
191 }
192
193 void ElementShadow::removeAllEventListeners()
194 {
195     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
196         for (Node* node = root; node; node = NodeTraversal::next(node))
197             node->removeAllEventListeners();
198     }
199 }
200
201 void ElementShadow::setNeedsDistributionRecalc()
202 {
203     if (m_needsDistributionRecalc)
204         return;
205     m_needsDistributionRecalc = true;
206     host()->markAncestorsWithChildNeedsDistributionRecalc();
207     clearDistribution();
208 }
209
210 bool ElementShadow::didAffectApplyAuthorStyles()
211 {
212     bool applyAuthorStyles = resolveApplyAuthorStyles();
213
214     if (m_applyAuthorStyles == applyAuthorStyles)
215         return false;
216
217     m_applyAuthorStyles = applyAuthorStyles;
218     return true;
219 }
220
221 bool ElementShadow::containsActiveStyles() const
222 {
223     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
224         if (root->hasScopedHTMLStyleChild())
225             return true;
226         if (!root->containsShadowElements())
227             return false;
228     }
229     return false;
230 }
231
232 bool ElementShadow::resolveApplyAuthorStyles() const
233 {
234     for (const ShadowRoot* shadowRoot = youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot()) {
235         if (shadowRoot->applyAuthorStyles())
236             return true;
237         if (!shadowRoot->containsShadowElements())
238             break;
239     }
240     return false;
241 }
242
243 const InsertionPoint* ElementShadow::finalDestinationInsertionPointFor(const Node* key) const
244 {
245     NodeToDestinationInsertionPoints::const_iterator it = m_nodeToInsertionPoints.find(key);
246     return it == m_nodeToInsertionPoints.end() ? 0: it->value.last().get();
247 }
248
249 const DestinationInsertionPoints* ElementShadow::destinationInsertionPointsFor(const Node* key) const
250 {
251     NodeToDestinationInsertionPoints::const_iterator it = m_nodeToInsertionPoints.find(key);
252     return it == m_nodeToInsertionPoints.end() ? 0: &it->value;
253 }
254
255 void ElementShadow::distribute()
256 {
257     host()->setNeedsStyleRecalc();
258
259     const ContainerNode* poolContainer = host();
260
261     Vector<HTMLShadowElement*, 32> shadowInsertionPoints;
262     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
263         DistributionPool pool(poolContainer);
264
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())
270                 continue;
271             if (isHTMLShadowElement(point)) {
272                 if (!shadowInsertionPoint)
273                     shadowInsertionPoint = toHTMLShadowElement(point);
274             } else {
275                 pool.distributeTo(point, this);
276                 if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*point))
277                     shadow->setNeedsDistributionRecalc();
278             }
279         }
280         if (shadowInsertionPoint)
281             shadowInsertionPoints.append(shadowInsertionPoint);
282         poolContainer = shadowInsertionPoint;
283     }
284
285     for (size_t i = shadowInsertionPoints.size(); i > 0; --i) {
286         HTMLShadowElement* shadowInsertionPoint = shadowInsertionPoints[i - 1];
287         ShadowRoot* root = shadowInsertionPoint->containingShadowRoot();
288         ASSERT(root);
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);
297         }
298         if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*shadowInsertionPoint))
299             shadow->setNeedsDistributionRecalc();
300     }
301 }
302
303 void ElementShadow::didDistributeNode(const Node* node, InsertionPoint* insertionPoint)
304 {
305     NodeToDestinationInsertionPoints::AddResult result = m_nodeToInsertionPoints.add(node, DestinationInsertionPoints());
306     result.iterator->value.append(insertionPoint);
307 }
308
309 void ElementShadow::distributeNodeChildrenTo(InsertionPoint* insertionPoint, ContainerNode* containerNode)
310 {
311     DistributionPool pool(containerNode);
312     pool.distributeTo(insertionPoint, this);
313 }
314
315 const SelectRuleFeatureSet& ElementShadow::ensureSelectFeatureSet()
316 {
317     if (!m_needsSelectFeatureSet)
318         return m_selectFeatures;
319
320     m_selectFeatures.clear();
321     for (ShadowRoot* root = oldestShadowRoot(); root; root = root->youngerShadowRoot())
322         collectSelectFeatureSetFrom(root);
323     m_needsSelectFeatureSet = false;
324     return m_selectFeatures;
325 }
326
327 void ElementShadow::collectSelectFeatureSetFrom(ShadowRoot* root)
328 {
329     if (!root->containsShadowRoots() && !root->containsContentElements())
330         return;
331
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))
336             continue;
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);
341         }
342     }
343 }
344
345 void ElementShadow::didAffectSelector(AffectedSelectorMask mask)
346 {
347     if (ensureSelectFeatureSet().hasSelectorFor(mask))
348         setNeedsDistributionRecalc();
349 }
350
351 void ElementShadow::willAffectSelector()
352 {
353     for (ElementShadow* shadow = this; shadow; shadow = shadow->containingShadow()) {
354         if (shadow->needsSelectFeatureSet())
355             break;
356         shadow->setNeedsSelectFeatureSet();
357     }
358     setNeedsDistributionRecalc();
359 }
360
361 void ElementShadow::clearDistribution()
362 {
363     m_nodeToInsertionPoints.clear();
364
365     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot())
366         root->setShadowInsertionPointOfYoungerShadowRoot(0);
367 }
368
369 } // namespace