Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Side by Side Diff: third_party/WebKit/Source/core/dom/SelectorQuery.cpp

Issue 1496533003: Implement a simple version of SelectorQuery. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Revert change to SelectorFilter.h Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2011, 2013 Apple Inc. All rights reserved. 2 * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
3 * Copyright (C) 2014 Samsung Electronics. All rights reserved. 3 * Copyright (C) 2014 Samsung Electronics. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 8 *
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 10 matching lines...) Expand all
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 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 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 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. 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */ 25 */
26 26
27 #include "config.h" 27 #include "config.h"
28 #include "core/dom/SelectorQuery.h" 28 #include "core/dom/SelectorQuery.h"
29 29
30 #include "bindings/core/v8/ExceptionState.h" 30 #include "bindings/core/v8/ExceptionState.h"
31 #include "core/css/SelectorChecker.h"
32 #include "core/css/parser/CSSParser.h" 31 #include "core/css/parser/CSSParser.h"
32 #include "core/dom/ContainerNode.h"
33 #include "core/dom/Document.h" 33 #include "core/dom/Document.h"
34 #include "core/dom/ElementTraversal.h" 34 #include "core/dom/Element.h"
35 #include "core/dom/ExceptionCode.h" 35 #include "core/dom/ExceptionCode.h"
36 #include "core/dom/Node.h"
37 #include "core/dom/StaticNodeList.h" 36 #include "core/dom/StaticNodeList.h"
38 #include "core/dom/shadow/ElementShadow.h" 37 #include "core/dom/query/SelectorAnyMatcher.h"
39 #include "core/dom/shadow/ShadowRoot.h" 38 #include "core/dom/query/SelectorCheckerMatcher.h"
39 #include "core/dom/query/SelectorClassMatcher.h"
40 #include "core/dom/query/SelectorIdMatcher.h"
41 #include "core/dom/query/SelectorMatcher.h"
42 #include "core/dom/query/SelectorTagMatcher.h"
40 43
41 namespace blink { 44 namespace blink {
42 45
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::nextSkippingChildr en(*m_currentElement, m_rootNode));
81 else
82 m_currentElement = nextInternal(ElementTraversal::next(*m_currentEle ment, 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_classNam e))
91 return element;
92 }
93 return nullptr;
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_usesDeepCombinatorOrShadowPseudo = false;
110 m_needsUpdatedDistribution = false;
111 m_selectors.reserveInitialCapacity(selectorCount);
112 unsigned index = 0;
113 for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector), ++index) {
114 m_selectors.uncheckedAppend(selector);
115 m_usesDeepCombinatorOrShadowPseudo |= selectorList.selectorUsesDeepCombi natorOrShadowPseudo(index);
116 m_needsUpdatedDistribution |= selectorList.selectorNeedsUpdatedDistribut ion(index);
117 }
118 }
119
120 inline bool SelectorDataList::selectorMatches(const CSSSelector& selector, Eleme nt& element, const ContainerNode& rootNode) const
121 {
122 SelectorChecker selectorChecker(SelectorChecker::QueryingRules);
123 SelectorChecker::SelectorCheckingContext selectorCheckingContext(&element, S electorChecker::VisitedMatchDisabled);
124 selectorCheckingContext.selector = &selector;
125 selectorCheckingContext.scope = &rootNode;
126 return selectorChecker.match(selectorCheckingContext);
127 }
128
129 bool SelectorDataList::matches(Element& targetElement) const
130 {
131 if (m_needsUpdatedDistribution)
132 targetElement.updateDistribution();
133
134 unsigned selectorCount = m_selectors.size();
135 for (unsigned i = 0; i < selectorCount; ++i) {
136 if (selectorMatches(*m_selectors[i], targetElement, targetElement))
137 return true;
138 }
139
140 return false;
141 }
142
143 Element* SelectorDataList::closest(Element& targetElement) const
144 {
145 if (m_needsUpdatedDistribution)
146 targetElement.updateDistribution();
147
148 unsigned selectorCount = m_selectors.size();
149 for (Element* currentElement = &targetElement; currentElement; currentElemen t = currentElement->parentElement()) {
150 for (unsigned i = 0; i < selectorCount; ++i) {
151 if (selectorMatches(*m_selectors[i], *currentElement, targetElement) )
152 return currentElement;
153 }
154 }
155 return nullptr;
156 }
157
158 PassRefPtrWillBeRawPtr<StaticElementList> SelectorDataList::queryAll(ContainerNo de& rootNode) const
159 {
160 WillBeHeapVector<RefPtrWillBeMember<Element>> result;
161 execute<AllElementsSelectorQueryTrait>(rootNode, result);
162 return StaticElementList::adopt(result);
163 }
164
165 PassRefPtrWillBeRawPtr<Element> SelectorDataList::queryFirst(ContainerNode& root Node) const
166 {
167 Element* matchedElement = nullptr;
168 execute<SingleElementSelectorQueryTrait>(rootNode, matchedElement);
169 return matchedElement;
170 }
171
172 template <typename SelectorQueryTrait>
173 void SelectorDataList::collectElementsByClassName(ContainerNode& rootNode, const AtomicString& className, typename SelectorQueryTrait::OutputType& output) cons t
174 {
175 for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
176 if (element.hasClass() && element.classNames().contains(className)) {
177 SelectorQueryTrait::appendElement(output, element);
178 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
179 return;
180 }
181 }
182 }
183
184 inline bool matchesTagName(const QualifiedName& tagName, const Element& element)
185 {
186 if (tagName == anyQName())
187 return true;
188 if (element.hasLocalName(tagName.localName()))
189 return true;
190 // Non-html elements in html documents are normalized to their camel-cased
191 // version during parsing if applicable. Yet, type selectors are lower-cased
192 // for selectors in html documents. Compare the upper case converted names
193 // instead to allow matching SVG elements like foreignObject.
194 if (!element.isHTMLElement() && element.document().isHTMLDocument())
195 return element.tagQName().localNameUpper() == tagName.localNameUpper();
196 return false;
197 }
198
199 template <typename SelectorQueryTrait>
200 void SelectorDataList::collectElementsByTagName(ContainerNode& rootNode, const Q ualifiedName& tagName, typename SelectorQueryTrait::OutputType& output) const
201 {
202 for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
203 // querySelector*() doesn't allow namespaces and throws before it gets
204 // here so we can ignore them.
205 ASSERT(tagName.namespaceURI() == starAtom);
206 if (matchesTagName(tagName, element)) {
207 SelectorQueryTrait::appendElement(output, element);
208 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
209 return;
210 }
211 }
212 }
213
214 inline bool SelectorDataList::canUseFastQuery(const ContainerNode& rootNode) con st
215 {
216 if (m_usesDeepCombinatorOrShadowPseudo)
217 return false;
218 if (m_needsUpdatedDistribution)
219 return false;
220 if (rootNode.document().inQuirksMode())
221 return false;
222 if (!rootNode.inDocument())
223 return false;
224 return m_selectors.size() == 1;
225 }
226
227 inline bool ancestorHasClassName(ContainerNode& rootNode, const AtomicString& cl assName)
228 {
229 if (!rootNode.isElementNode())
230 return false;
231
232 for (Element* element = &toElement(rootNode); element; element = element->pa rentElement()) {
233 if (element->hasClass() && element->classNames().contains(className))
234 return true;
235 }
236 return false;
237 }
238
239
240 // If returns true, traversalRoots has the elements that may match the selector query.
241 //
242 // If returns false, traversalRoots has the rootNode parameter or descendants of rootNode representing
243 // the subtree for which we can limit the querySelector traversal.
244 //
245 // The travseralRoots may be empty, regardless of the returned bool value, if th is method finds that the selectors won't
246 // match any element.
247 template <typename SelectorQueryTrait>
248 void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type name SelectorQueryTrait::OutputType& output) const
249 {
250 // We need to return the matches in document order. To use id lookup while t here is possiblity of multiple matches
251 // we would need to sort the results. For now, just traverse the document in that case.
252 ASSERT(m_selectors.size() == 1);
253
254 bool isRightmostSelector = true;
255 bool startFromParent = false;
256
257 for (const CSSSelector* selector = m_selectors[0]; selector; selector = sele ctor->tagHistory()) {
258 if (selector->match() == CSSSelector::Id && !rootNode.document().contain sMultipleElementsWithId(selector->value())) {
259 Element* element = rootNode.treeScope().getElementById(selector->val ue());
260 ContainerNode* adjustedNode = &rootNode;
261 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf (&rootNode)))
262 adjustedNode = element;
263 else if (!element || isRightmostSelector)
264 adjustedNode = nullptr;
265 if (isRightmostSelector) {
266 executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], adju stedNode, MatchesTraverseRoots, rootNode, output);
267 return;
268 }
269
270 if (startFromParent && adjustedNode)
271 adjustedNode = adjustedNode->parentNode();
272
273 executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], adjusted Node, DoesNotMatchTraverseRoots, rootNode, output);
274 return;
275 }
276
277 // If we have both CSSSelector::Id and CSSSelector::Class at the same ti me, we should use Id
278 // to find traverse root.
279 if (!SelectorQueryTrait::shouldOnlyMatchFirstElement && !startFromParent && selector->match() == CSSSelector::Class) {
280 if (isRightmostSelector) {
281 ClassElementList<AllElements> traverseRoots(rootNode, selector-> value());
282 executeForTraverseRoots<SelectorQueryTrait>(*m_selectors[0], tra verseRoots, MatchesTraverseRoots, rootNode, output);
283 return;
284 }
285 // Since there exists some ancestor element which has the class name , we need to see all children of rootNode.
286 if (ancestorHasClassName(rootNode, selector->value())) {
287 executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], &roo tNode, DoesNotMatchTraverseRoots, rootNode, output);
288 return;
289 }
290
291 ClassElementList<OnlyRoots> traverseRoots(rootNode, selector->value( ));
292 executeForTraverseRoots<SelectorQueryTrait>(*m_selectors[0], travers eRoots, DoesNotMatchTraverseRoots, rootNode, output);
293 return;
294 }
295
296 if (selector->relation() == CSSSelector::SubSelector)
297 continue;
298 isRightmostSelector = false;
299 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel ation() == CSSSelector::IndirectAdjacent)
300 startFromParent = true;
301 else
302 startFromParent = false;
303 }
304
305 executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], &rootNode, DoesN otMatchTraverseRoots, rootNode, output);
306 }
307
308 template <typename SelectorQueryTrait>
309 void SelectorDataList::executeForTraverseRoot(const CSSSelector& selector, Conta inerNode* traverseRoot, MatchTraverseRootState matchTraverseRoot, ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
310 {
311 if (!traverseRoot)
312 return;
313
314 if (matchTraverseRoot) {
315 if (selectorMatches(selector, toElement(*traverseRoot), rootNode))
316 SelectorQueryTrait::appendElement(output, toElement(*traverseRoot));
317 return;
318 }
319
320 for (Element& element : ElementTraversal::descendantsOf(*traverseRoot)) {
321 if (selectorMatches(selector, element, rootNode)) {
322 SelectorQueryTrait::appendElement(output, element);
323 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
324 return;
325 }
326 }
327 }
328
329 template <typename SelectorQueryTrait, typename SimpleElementListType>
330 void SelectorDataList::executeForTraverseRoots(const CSSSelector& selector, Simp leElementListType& traverseRoots, MatchTraverseRootState matchTraverseRoots, Con tainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
331 {
332 if (traverseRoots.isEmpty())
333 return;
334
335 if (matchTraverseRoots) {
336 while (!traverseRoots.isEmpty()) {
337 Element& element = *traverseRoots.next();
338 if (selectorMatches(selector, element, rootNode)) {
339 SelectorQueryTrait::appendElement(output, element);
340 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
341 return;
342 }
343 }
344 return;
345 }
346
347 while (!traverseRoots.isEmpty()) {
348 for (Element& element : ElementTraversal::descendantsOf(*traverseRoots.n ext())) {
349 if (selectorMatches(selector, element, rootNode)) {
350 SelectorQueryTrait::appendElement(output, element);
351 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
352 return;
353 }
354 }
355 }
356 }
357
358 template <typename SelectorQueryTrait>
359 bool SelectorDataList::selectorListMatches(ContainerNode& rootNode, Element& ele ment, typename SelectorQueryTrait::OutputType& output) const
360 {
361 for (unsigned i = 0; i < m_selectors.size(); ++i) {
362 if (selectorMatches(*m_selectors[i], element, rootNode)) {
363 SelectorQueryTrait::appendElement(output, element);
364 return true;
365 }
366 }
367 return false;
368 }
369
370 template <typename SelectorQueryTrait>
371 void SelectorDataList::executeSlow(ContainerNode& rootNode, typename SelectorQue ryTrait::OutputType& output) const
372 {
373 for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
374 if (selectorListMatches<SelectorQueryTrait>(rootNode, element, output) & & SelectorQueryTrait::shouldOnlyMatchFirstElement)
375 return;
376 }
377 }
378
379 // FIXME: Move the following helper functions, authorShadowRootOf, firstWithinTr aversingShadowTree,
380 // nextTraversingShadowTree to the best place, e.g. NodeTraversal.
381 static ShadowRoot* authorShadowRootOf(const ContainerNode& node)
382 {
383 if (!node.isElementNode() || !isShadowHost(&node))
384 return nullptr;
385
386 ElementShadow* shadow = toElement(node).shadow();
387 ASSERT(shadow);
388 for (ShadowRoot* shadowRoot = shadow->oldestShadowRoot(); shadowRoot; shadow Root = shadowRoot->youngerShadowRoot()) {
389 if (shadowRoot->type() == ShadowRootType::V0 || shadowRoot->type() == Sh adowRootType::Open)
390 return shadowRoot;
391 }
392 return nullptr;
393 }
394
395 static ContainerNode* firstWithinTraversingShadowTree(const ContainerNode& rootN ode)
396 {
397 if (ShadowRoot* shadowRoot = authorShadowRootOf(rootNode))
398 return shadowRoot;
399 return ElementTraversal::firstWithin(rootNode);
400 }
401
402 static ContainerNode* nextTraversingShadowTree(const ContainerNode& node, const ContainerNode* rootNode)
403 {
404 if (ShadowRoot* shadowRoot = authorShadowRootOf(node))
405 return shadowRoot;
406
407 const ContainerNode* current = &node;
408 while (current) {
409 if (Element* next = ElementTraversal::next(*current, rootNode))
410 return next;
411
412 if (!current->isInShadowTree())
413 return nullptr;
414
415 ShadowRoot* shadowRoot = current->containingShadowRoot();
416 if (shadowRoot == rootNode)
417 return nullptr;
418 if (ShadowRoot* youngerShadowRoot = shadowRoot->youngerShadowRoot()) {
419 // Should not obtain any elements in closed or user-agent shadow roo t.
420 ASSERT(youngerShadowRoot->type() == ShadowRootType::V0 || youngerSha dowRoot->type() == ShadowRootType::Open);
421 return youngerShadowRoot;
422 }
423
424 current = shadowRoot->host();
425 }
426 return nullptr;
427 }
428
429 template <typename SelectorQueryTrait>
430 void SelectorDataList::executeSlowTraversingShadowTree(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
431 {
432 for (ContainerNode* node = firstWithinTraversingShadowTree(rootNode); node; node = nextTraversingShadowTree(*node, &rootNode)) {
433 if (!node->isElementNode())
434 continue;
435 Element* element = toElement(node);
436 if (selectorListMatches<SelectorQueryTrait>(rootNode, *element, output) && SelectorQueryTrait::shouldOnlyMatchFirstElement)
437 return;
438 }
439 }
440
441 const CSSSelector* SelectorDataList::selectorForIdLookup(const CSSSelector& firs tSelector) const
442 {
443 for (const CSSSelector* selector = &firstSelector; selector; selector = sele ctor->tagHistory()) {
444 if (selector->match() == CSSSelector::Id)
445 return selector;
446 if (selector->relation() != CSSSelector::SubSelector)
447 break;
448 }
449 return nullptr;
450 }
451
452 template <typename SelectorQueryTrait>
453 void SelectorDataList::execute(ContainerNode& rootNode, typename SelectorQueryTr ait::OutputType& output) const
454 {
455 if (!canUseFastQuery(rootNode)) {
456 if (m_needsUpdatedDistribution)
457 rootNode.updateDistribution();
458 if (m_usesDeepCombinatorOrShadowPseudo) {
459 executeSlowTraversingShadowTree<SelectorQueryTrait>(rootNode, output );
460 } else {
461 executeSlow<SelectorQueryTrait>(rootNode, output);
462 }
463 return;
464 }
465
466 ASSERT(m_selectors.size() == 1);
467
468 const CSSSelector& selector = *m_selectors[0];
469 const CSSSelector& firstSelector = selector;
470
471 // Fast path for querySelector*('#id'), querySelector*('tag#id').
472 if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) {
473 const AtomicString& idToMatch = idSelector->value();
474 if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) {
475 const WillBeHeapVector<RawPtrWillBeMember<Element>>& elements = root Node.treeScope().getAllElementsById(idToMatch);
476 size_t count = elements.size();
477 for (size_t i = 0; i < count; ++i) {
478 Element& element = *elements[i];
479 if (!(isTreeScopeRoot(rootNode) || element.isDescendantOf(&rootN ode)))
480 continue;
481 if (selectorMatches(selector, element, rootNode)) {
482 SelectorQueryTrait::appendElement(output, element);
483 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
484 return;
485 }
486 }
487 return;
488 }
489 Element* element = rootNode.treeScope().getElementById(idToMatch);
490 if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(& rootNode)))
491 return;
492 if (selectorMatches(selector, *element, rootNode))
493 SelectorQueryTrait::appendElement(output, *element);
494 return;
495 }
496
497 if (!firstSelector.tagHistory()) {
498 // Fast path for querySelector*('.foo'), and querySelector*('div').
499 switch (firstSelector.match()) {
500 case CSSSelector::Class:
501 collectElementsByClassName<SelectorQueryTrait>(rootNode, firstSelect or.value(), output);
502 return;
503 case CSSSelector::Tag:
504 collectElementsByTagName<SelectorQueryTrait>(rootNode, firstSelector .tagQName(), output);
505 return;
506 default:
507 break; // If we need another fast path, add here.
508 }
509 }
510
511 findTraverseRootsAndExecute<SelectorQueryTrait>(rootNode, output);
512 }
513
514 PassOwnPtr<SelectorQuery> SelectorQuery::adopt(CSSSelectorList& selectorList) 46 PassOwnPtr<SelectorQuery> SelectorQuery::adopt(CSSSelectorList& selectorList)
515 { 47 {
516 return adoptPtr(new SelectorQuery(selectorList)); 48 return adoptPtr(new SelectorQuery(selectorList));
517 } 49 }
518 50
51 SelectorQuery::~SelectorQuery()
52 {
53 }
54
55 static PassOwnPtr<SelectorMatcher> createMatcher(CSSSelectorList& selectorList)
56 {
57 if (selectorList.hasOneSelector() && !selectorList.first()->tagHistory()) {
58 const CSSSelector* selector = selectorList.first();
59 switch (selector->match()) {
60 case CSSSelector::Id:
61 return adoptPtr(new SelectorIdMatcher(selector->value()));
62 case CSSSelector::Class:
63 return adoptPtr(new SelectorClassMatcher(selector->value()));
64 case CSSSelector::Tag:
65 if (selector->tagQName() == anyQName())
66 return adoptPtr(new SelectorAnyMatcher());
67 return adoptPtr(new SelectorTagMatcher(selector->tagQName()));
68 default:
69 break;
70 }
71 }
72 return adoptPtr(new SelectorCheckerMatcher(selectorList));
73 }
74
519 SelectorQuery::SelectorQuery(CSSSelectorList& selectorList) 75 SelectorQuery::SelectorQuery(CSSSelectorList& selectorList)
76 : m_matcher(createMatcher(selectorList))
520 { 77 {
521 m_selectorList.adopt(selectorList); 78 ASSERT(m_matcher);
522 m_selectors.initialize(m_selectorList);
523 } 79 }
524 80
525 bool SelectorQuery::matches(Element& element) const 81 bool SelectorQuery::matches(Element& element) const
526 { 82 {
527 return m_selectors.matches(element); 83 return m_matcher->match(element, element);
528 } 84 }
529 85
530 Element* SelectorQuery::closest(Element& element) const 86 Element* SelectorQuery::closest(Element& element) const
531 { 87 {
532 return m_selectors.closest(element); 88 for (Element* current = &element; current; current = current->parentElement( )) {
89 if (m_matcher->match(*current, element))
90 return current;
91 }
92 return nullptr;
533 } 93 }
534 94
535 PassRefPtrWillBeRawPtr<StaticElementList> SelectorQuery::queryAll(ContainerNode& rootNode) const 95 PassRefPtrWillBeRawPtr<StaticElementList> SelectorQuery::queryAll(ContainerNode& rootNode) const
536 { 96 {
537 return m_selectors.queryAll(rootNode); 97 WillBeHeapVector<RefPtrWillBeMember<Element>> result;
98 m_matcher->findAll(rootNode, result);
99 return StaticElementList::adopt(result);
538 } 100 }
539 101
540 PassRefPtrWillBeRawPtr<Element> SelectorQuery::queryFirst(ContainerNode& rootNod e) const 102 Element* SelectorQuery::queryFirst(ContainerNode& rootNode) const
541 { 103 {
542 return m_selectors.queryFirst(rootNode); 104 return m_matcher->findFirst(rootNode);
543 } 105 }
544 106
545 SelectorQuery* SelectorQueryCache::add(const AtomicString& selectors, const Docu ment& document, ExceptionState& exceptionState) 107 SelectorQuery* SelectorQueryCache::add(const AtomicString& selectors, const Docu ment& document, ExceptionState& exceptionState)
546 { 108 {
547 HashMap<AtomicString, OwnPtr<SelectorQuery>>::iterator it = m_entries.find(s electors); 109 HashMap<AtomicString, OwnPtr<SelectorQuery>>::iterator it = m_entries.find(s electors);
548 if (it != m_entries.end()) 110 if (it != m_entries.end())
549 return it->value.get(); 111 return it->value.get();
550 112
551 CSSSelectorList selectorList; 113 CSSSelectorList selectorList;
552 CSSParser::parseSelector(CSSParserContext(document, nullptr), selectors, sel ectorList); 114 CSSParser::parseSelector(CSSParserContext(document, nullptr), selectors, sel ectorList);
(...skipping 15 matching lines...) Expand all
568 130
569 return m_entries.add(selectors, SelectorQuery::adopt(selectorList)).storedVa lue->value.get(); 131 return m_entries.add(selectors, SelectorQuery::adopt(selectorList)).storedVa lue->value.get();
570 } 132 }
571 133
572 void SelectorQueryCache::invalidate() 134 void SelectorQueryCache::invalidate()
573 { 135 {
574 m_entries.clear(); 136 m_entries.clear();
575 } 137 }
576 138
577 } 139 }
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/dom/SelectorQuery.h ('k') | third_party/WebKit/Source/core/dom/query/SelectorAnyMatcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698