Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / dom / SelectorQuery.cpp
1 /*
2  * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
3  * Copyright (C) 2014 Samsung Electronics. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "core/dom/SelectorQuery.h"
29
30 #include "bindings/core/v8/ExceptionState.h"
31 #include "core/css/SelectorChecker.h"
32 #include "core/css/SiblingTraversalStrategies.h"
33 #include "core/css/parser/CSSParser.h"
34 #include "core/dom/Document.h"
35 #include "core/dom/ElementTraversal.h"
36 #include "core/dom/Node.h"
37 #include "core/dom/StaticNodeList.h"
38 #include "core/dom/shadow/ElementShadow.h"
39 #include "core/dom/shadow/ShadowRoot.h"
40
41 namespace blink {
42
43 struct SingleElementSelectorQueryTrait {
44     typedef Element* OutputType;
45     static const bool shouldOnlyMatchFirstElement = true;
46     ALWAYS_INLINE static void appendElement(OutputType& output, Element& element)
47     {
48         ASSERT(!output);
49         output = &element;
50     }
51 };
52
53 struct AllElementsSelectorQueryTrait {
54     typedef WillBeHeapVector<RefPtrWillBeMember<Element> > OutputType;
55     static const bool shouldOnlyMatchFirstElement = false;
56     ALWAYS_INLINE static void appendElement(OutputType& output, Element& element)
57     {
58         output.append(&element);
59     }
60 };
61
62 enum ClassElementListBehavior { AllElements, OnlyRoots };
63
64 template <ClassElementListBehavior onlyRoots>
65 class ClassElementList {
66     STACK_ALLOCATED();
67 public:
68     ClassElementList(ContainerNode& rootNode, const AtomicString& className)
69         : m_className(className)
70         , m_rootNode(&rootNode)
71         , m_currentElement(nextInternal(ElementTraversal::firstWithin(rootNode))) { }
72
73     bool isEmpty() const { return !m_currentElement; }
74
75     Element* next()
76     {
77         Element* current = m_currentElement;
78         ASSERT(current);
79         if (onlyRoots)
80             m_currentElement = nextInternal(ElementTraversal::nextSkippingChildren(*m_currentElement, m_rootNode));
81         else
82             m_currentElement = nextInternal(ElementTraversal::next(*m_currentElement, m_rootNode));
83         return current;
84     }
85
86 private:
87     Element* nextInternal(Element* element)
88     {
89         for (; element; element = ElementTraversal::next(*element, m_rootNode)) {
90             if (element->hasClass() && element->classNames().contains(m_className))
91                 return element;
92         }
93         return 0;
94     }
95
96     const AtomicString& m_className;
97     RawPtrWillBeMember<ContainerNode> m_rootNode;
98     RawPtrWillBeMember<Element> m_currentElement;
99 };
100
101 void SelectorDataList::initialize(const CSSSelectorList& selectorList)
102 {
103     ASSERT(m_selectors.isEmpty());
104
105     unsigned selectorCount = 0;
106     for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector))
107         selectorCount++;
108
109     m_crossesTreeBoundary = false;
110     m_selectors.reserveInitialCapacity(selectorCount);
111     unsigned index = 0;
112     for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector), ++index) {
113         m_selectors.uncheckedAppend(selector);
114         m_crossesTreeBoundary |= selectorList.selectorCrossesTreeScopes(index);
115     }
116 }
117
118 inline bool SelectorDataList::selectorMatches(const CSSSelector& selector, Element& element, const ContainerNode& rootNode) const
119 {
120     SelectorChecker selectorChecker(element.document(), SelectorChecker::QueryingRules);
121     SelectorChecker::SelectorCheckingContext selectorCheckingContext(selector, &element, SelectorChecker::VisitedMatchDisabled);
122     selectorCheckingContext.scope = !rootNode.isDocumentNode() ? &rootNode : 0;
123     if (selectorCheckingContext.scope)
124         selectorCheckingContext.scopeContainsLastMatchedElement = true;
125     return selectorChecker.match(selectorCheckingContext, DOMSiblingTraversalStrategy()) == SelectorChecker::SelectorMatches;
126 }
127
128 bool SelectorDataList::matches(Element& targetElement) const
129 {
130     unsigned selectorCount = m_selectors.size();
131     for (unsigned i = 0; i < selectorCount; ++i) {
132         if (selectorMatches(*m_selectors[i], targetElement, targetElement))
133             return true;
134     }
135
136     return false;
137 }
138
139 PassRefPtrWillBeRawPtr<StaticElementList> SelectorDataList::queryAll(ContainerNode& rootNode) const
140 {
141     WillBeHeapVector<RefPtrWillBeMember<Element> > result;
142     execute<AllElementsSelectorQueryTrait>(rootNode, result);
143     return StaticElementList::adopt(result);
144 }
145
146 PassRefPtrWillBeRawPtr<Element> SelectorDataList::queryFirst(ContainerNode& rootNode) const
147 {
148     Element* matchedElement = 0;
149     execute<SingleElementSelectorQueryTrait>(rootNode, matchedElement);
150     return matchedElement;
151 }
152
153 template <typename SelectorQueryTrait>
154 void SelectorDataList::collectElementsByClassName(ContainerNode& rootNode, const AtomicString& className,  typename SelectorQueryTrait::OutputType& output) const
155 {
156     for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
157         if (element.hasClass() && element.classNames().contains(className)) {
158             SelectorQueryTrait::appendElement(output, element);
159             if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
160                 return;
161         }
162     }
163 }
164
165 template <typename SelectorQueryTrait>
166 void SelectorDataList::collectElementsByTagName(ContainerNode& rootNode, const QualifiedName& tagName,  typename SelectorQueryTrait::OutputType& output) const
167 {
168     for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
169         if (SelectorChecker::tagMatches(element, tagName)) {
170             SelectorQueryTrait::appendElement(output, element);
171             if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
172                 return;
173         }
174     }
175 }
176
177 inline bool SelectorDataList::canUseFastQuery(const ContainerNode& rootNode) const
178 {
179     return m_selectors.size() == 1 && !m_crossesTreeBoundary && rootNode.inDocument() && !rootNode.document().inQuirksMode();
180 }
181
182 inline bool ancestorHasClassName(ContainerNode& rootNode, const AtomicString& className)
183 {
184     if (!rootNode.isElementNode())
185         return false;
186
187     for (Element* element = &toElement(rootNode); element; element = element->parentElement()) {
188         if (element->hasClass() && element->classNames().contains(className))
189             return true;
190     }
191     return false;
192 }
193
194
195 // If returns true, traversalRoots has the elements that may match the selector query.
196 //
197 // If returns false, traversalRoots has the rootNode parameter or descendants of rootNode representing
198 // the subtree for which we can limit the querySelector traversal.
199 //
200 // The travseralRoots may be empty, regardless of the returned bool value, if this method finds that the selectors won't
201 // match any element.
202 template <typename SelectorQueryTrait>
203 void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
204 {
205     // We need to return the matches in document order. To use id lookup while there is possiblity of multiple matches
206     // we would need to sort the results. For now, just traverse the document in that case.
207     ASSERT(m_selectors.size() == 1);
208
209     bool isRightmostSelector = true;
210     bool startFromParent = false;
211
212     for (const CSSSelector* selector = m_selectors[0]; selector; selector = selector->tagHistory()) {
213         if (selector->match() == CSSSelector::Id && !rootNode.document().containsMultipleElementsWithId(selector->value())) {
214             Element* element = rootNode.treeScope().getElementById(selector->value());
215             ContainerNode* adjustedNode = &rootNode;
216             if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode)))
217                 adjustedNode = element;
218             else if (!element || isRightmostSelector)
219                 adjustedNode = 0;
220             if (isRightmostSelector) {
221                 executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], adjustedNode, MatchesTraverseRoots, rootNode, output);
222                 return;
223             }
224
225             if (startFromParent && adjustedNode)
226                 adjustedNode = adjustedNode->parentNode();
227
228             executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], adjustedNode, DoesNotMatchTraverseRoots, rootNode, output);
229             return;
230         }
231
232         // If we have both CSSSelector::Id and CSSSelector::Class at the same time, we should use Id
233         // to find traverse root.
234         if (!SelectorQueryTrait::shouldOnlyMatchFirstElement && !startFromParent && selector->match() == CSSSelector::Class) {
235             if (isRightmostSelector) {
236                 ClassElementList<AllElements> traverseRoots(rootNode, selector->value());
237                 executeForTraverseRoots<SelectorQueryTrait>(*m_selectors[0], traverseRoots, MatchesTraverseRoots, rootNode, output);
238                 return;
239             }
240             // Since there exists some ancestor element which has the class name, we need to see all children of rootNode.
241             if (ancestorHasClassName(rootNode, selector->value())) {
242                 executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], &rootNode, DoesNotMatchTraverseRoots, rootNode, output);
243                 return;
244             }
245
246             ClassElementList<OnlyRoots> traverseRoots(rootNode, selector->value());
247             executeForTraverseRoots<SelectorQueryTrait>(*m_selectors[0], traverseRoots, DoesNotMatchTraverseRoots, rootNode, output);
248             return;
249         }
250
251         if (selector->relation() == CSSSelector::SubSelector)
252             continue;
253         isRightmostSelector = false;
254         if (selector->relation() == CSSSelector::DirectAdjacent || selector->relation() == CSSSelector::IndirectAdjacent)
255             startFromParent = true;
256         else
257             startFromParent = false;
258     }
259
260     executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], &rootNode, DoesNotMatchTraverseRoots, rootNode, output);
261 }
262
263 template <typename SelectorQueryTrait>
264 void SelectorDataList::executeForTraverseRoot(const CSSSelector& selector, ContainerNode* traverseRoot, MatchTraverseRootState matchTraverseRoot, ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
265 {
266     if (!traverseRoot)
267         return;
268
269     if (matchTraverseRoot) {
270         if (selectorMatches(selector, toElement(*traverseRoot), rootNode))
271             SelectorQueryTrait::appendElement(output, toElement(*traverseRoot));
272         return;
273     }
274
275     for (Element& element : ElementTraversal::descendantsOf(*traverseRoot)) {
276         if (selectorMatches(selector, element, rootNode)) {
277             SelectorQueryTrait::appendElement(output, element);
278             if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
279                 return;
280         }
281     }
282 }
283
284 template <typename SelectorQueryTrait, typename SimpleElementListType>
285 void SelectorDataList::executeForTraverseRoots(const CSSSelector& selector, SimpleElementListType& traverseRoots, MatchTraverseRootState matchTraverseRoots, ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
286 {
287     if (traverseRoots.isEmpty())
288         return;
289
290     if (matchTraverseRoots) {
291         while (!traverseRoots.isEmpty()) {
292             Element& element = *traverseRoots.next();
293             if (selectorMatches(selector, element, rootNode)) {
294                 SelectorQueryTrait::appendElement(output, element);
295                 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
296                     return;
297             }
298         }
299         return;
300     }
301
302     while (!traverseRoots.isEmpty()) {
303         for (Element& element : ElementTraversal::descendantsOf(*traverseRoots.next())) {
304             if (selectorMatches(selector, element, rootNode)) {
305                 SelectorQueryTrait::appendElement(output, element);
306                 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
307                     return;
308             }
309         }
310     }
311 }
312
313 template <typename SelectorQueryTrait>
314 bool SelectorDataList::selectorListMatches(ContainerNode& rootNode, Element& element, typename SelectorQueryTrait::OutputType& output) const
315 {
316     for (unsigned i = 0; i < m_selectors.size(); ++i) {
317         if (selectorMatches(*m_selectors[i], element, rootNode)) {
318             SelectorQueryTrait::appendElement(output, element);
319             return true;
320         }
321     }
322     return false;
323 }
324
325 template <typename SelectorQueryTrait>
326 void SelectorDataList::executeSlow(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
327 {
328     for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
329         if (selectorListMatches<SelectorQueryTrait>(rootNode, element, output) && SelectorQueryTrait::shouldOnlyMatchFirstElement)
330             return;
331     }
332 }
333
334 // FIXME: Move the following helper functions, authorShadowRootOf, firstWithinTraversingShadowTree,
335 // nextTraversingShadowTree to the best place, e.g. NodeTraversal.
336 static ShadowRoot* authorShadowRootOf(const ContainerNode& node)
337 {
338     if (!node.isElementNode() || !isShadowHost(&node))
339         return 0;
340
341     ElementShadow* shadow = toElement(node).shadow();
342     ASSERT(shadow);
343     for (ShadowRoot* shadowRoot = shadow->oldestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->youngerShadowRoot()) {
344         if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot)
345             return shadowRoot;
346     }
347     return 0;
348 }
349
350 static ContainerNode* firstWithinTraversingShadowTree(const ContainerNode& rootNode)
351 {
352     if (ShadowRoot* shadowRoot = authorShadowRootOf(rootNode))
353         return shadowRoot;
354     return ElementTraversal::firstWithin(rootNode);
355 }
356
357 static ContainerNode* nextTraversingShadowTree(const ContainerNode& node, const ContainerNode* rootNode)
358 {
359     if (ShadowRoot* shadowRoot = authorShadowRootOf(node))
360         return shadowRoot;
361
362     const ContainerNode* current = &node;
363     while (current) {
364         if (Element* next = ElementTraversal::next(*current, rootNode))
365             return next;
366
367         if (!current->isInShadowTree())
368             return 0;
369
370         ShadowRoot* shadowRoot = current->containingShadowRoot();
371         if (shadowRoot == rootNode)
372             return 0;
373         if (ShadowRoot* youngerShadowRoot = shadowRoot->youngerShadowRoot()) {
374             // Should not obtain any elements in user-agent shadow root.
375             ASSERT(youngerShadowRoot->type() == ShadowRoot::AuthorShadowRoot);
376             return youngerShadowRoot;
377         }
378
379         current = shadowRoot->host();
380     }
381     return 0;
382 }
383
384 template <typename SelectorQueryTrait>
385 void SelectorDataList::executeSlowTraversingShadowTree(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
386 {
387     for (ContainerNode* node = firstWithinTraversingShadowTree(rootNode); node; node = nextTraversingShadowTree(*node, &rootNode)) {
388         if (!node->isElementNode())
389             continue;
390         Element* element = toElement(node);
391         if (selectorListMatches<SelectorQueryTrait>(rootNode, *element, output) && SelectorQueryTrait::shouldOnlyMatchFirstElement)
392             return;
393     }
394 }
395
396 const CSSSelector* SelectorDataList::selectorForIdLookup(const CSSSelector& firstSelector) const
397 {
398     for (const CSSSelector* selector = &firstSelector; selector; selector = selector->tagHistory()) {
399         if (selector->match() == CSSSelector::Id)
400             return selector;
401         if (selector->relation() != CSSSelector::SubSelector)
402             break;
403     }
404     return 0;
405 }
406
407 template <typename SelectorQueryTrait>
408 void SelectorDataList::execute(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
409 {
410     if (!canUseFastQuery(rootNode)) {
411         if (m_crossesTreeBoundary) {
412             rootNode.document().updateDistributionForNodeIfNeeded(&rootNode);
413             executeSlowTraversingShadowTree<SelectorQueryTrait>(rootNode, output);
414         } else {
415             executeSlow<SelectorQueryTrait>(rootNode, output);
416         }
417         return;
418     }
419
420     ASSERT(m_selectors.size() == 1);
421
422     const CSSSelector& selector = *m_selectors[0];
423     const CSSSelector& firstSelector = selector;
424
425     // Fast path for querySelector*('#id'), querySelector*('tag#id').
426     if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) {
427         const AtomicString& idToMatch = idSelector->value();
428         if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) {
429             const WillBeHeapVector<RawPtrWillBeMember<Element> >& elements = rootNode.treeScope().getAllElementsById(idToMatch);
430             size_t count = elements.size();
431             for (size_t i = 0; i < count; ++i) {
432                 Element& element = *elements[i];
433                 if (!(isTreeScopeRoot(rootNode) || element.isDescendantOf(&rootNode)))
434                     continue;
435                 if (selectorMatches(selector, element, rootNode)) {
436                     SelectorQueryTrait::appendElement(output, element);
437                     if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
438                         return;
439                 }
440             }
441             return;
442         }
443         Element* element = rootNode.treeScope().getElementById(idToMatch);
444         if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode)))
445             return;
446         if (selectorMatches(selector, *element, rootNode))
447             SelectorQueryTrait::appendElement(output, *element);
448         return;
449     }
450
451     if (!firstSelector.tagHistory()) {
452         // Fast path for querySelector*('.foo'), and querySelector*('div').
453         switch (firstSelector.match()) {
454         case CSSSelector::Class:
455             collectElementsByClassName<SelectorQueryTrait>(rootNode, firstSelector.value(), output);
456             return;
457         case CSSSelector::Tag:
458             collectElementsByTagName<SelectorQueryTrait>(rootNode, firstSelector.tagQName(), output);
459             return;
460         default:
461             break; // If we need another fast path, add here.
462         }
463     }
464
465     findTraverseRootsAndExecute<SelectorQueryTrait>(rootNode, output);
466 }
467
468 PassOwnPtr<SelectorQuery> SelectorQuery::adopt(CSSSelectorList& selectorList)
469 {
470     return adoptPtr(new SelectorQuery(selectorList));
471 }
472
473 SelectorQuery::SelectorQuery(CSSSelectorList& selectorList)
474 {
475     m_selectorList.adopt(selectorList);
476     m_selectors.initialize(m_selectorList);
477 }
478
479 bool SelectorQuery::matches(Element& element) const
480 {
481     return m_selectors.matches(element);
482 }
483
484 PassRefPtrWillBeRawPtr<StaticElementList> SelectorQuery::queryAll(ContainerNode& rootNode) const
485 {
486     return m_selectors.queryAll(rootNode);
487 }
488
489 PassRefPtrWillBeRawPtr<Element> SelectorQuery::queryFirst(ContainerNode& rootNode) const
490 {
491     return m_selectors.queryFirst(rootNode);
492 }
493
494 SelectorQuery* SelectorQueryCache::add(const AtomicString& selectors, const Document& document, ExceptionState& exceptionState)
495 {
496     HashMap<AtomicString, OwnPtr<SelectorQuery> >::iterator it = m_entries.find(selectors);
497     if (it != m_entries.end())
498         return it->value.get();
499
500     CSSParser parser(CSSParserContext(document, 0));
501     CSSSelectorList selectorList;
502     parser.parseSelector(selectors, selectorList);
503
504     if (!selectorList.first()) {
505         exceptionState.throwDOMException(SyntaxError, "'" + selectors + "' is not a valid selector.");
506         return 0;
507     }
508
509     // throw a NamespaceError if the selector includes any namespace prefixes.
510     if (selectorList.selectorsNeedNamespaceResolution()) {
511         exceptionState.throwDOMException(NamespaceError, "'" + selectors + "' contains namespaces, which are not supported.");
512         return 0;
513     }
514
515     const unsigned maximumSelectorQueryCacheSize = 256;
516     if (m_entries.size() == maximumSelectorQueryCacheSize)
517         m_entries.remove(m_entries.begin());
518
519     return m_entries.add(selectors, SelectorQuery::adopt(selectorList)).storedValue->value.get();
520 }
521
522 void SelectorQueryCache::invalidate()
523 {
524     m_entries.clear();
525 }
526
527 }