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

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

Issue 2788953003: Remove ClassElementList and reuse collectElementsByClassName in SelectorQuery. (Closed)
Patch Set: Woops missed a return. Created 3 years, 8 months 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 57
58 struct AllElementsSelectorQueryTrait { 58 struct AllElementsSelectorQueryTrait {
59 typedef HeapVector<Member<Element>> OutputType; 59 typedef HeapVector<Member<Element>> OutputType;
60 static const bool shouldOnlyMatchFirstElement = false; 60 static const bool shouldOnlyMatchFirstElement = false;
61 ALWAYS_INLINE static void appendElement(OutputType& output, 61 ALWAYS_INLINE static void appendElement(OutputType& output,
62 Element& element) { 62 Element& element) {
63 output.push_back(&element); 63 output.push_back(&element);
64 } 64 }
65 }; 65 };
66 66
67 enum ClassElementListBehavior { AllElements, OnlyRoots }; 67 // TODO(esprehn): Move this to Element and update callers elsewhere.
68 68 inline bool hasClassName(const Element& element,
69 template <ClassElementListBehavior onlyRoots> 69 const AtomicString& className) {
70 class ClassElementList { 70 return element.hasClass() && element.classNames().contains(className);
71 STACK_ALLOCATED(); 71 }
72
73 public:
74 ClassElementList(ContainerNode& rootNode, const AtomicString& className)
75 : m_className(className),
76 m_rootNode(&rootNode),
77 m_currentElement(
78 nextInternal(ElementTraversal::firstWithin(rootNode))) {}
79
80 bool isEmpty() const { return !m_currentElement; }
81
82 Element* next() {
83 Element* current = m_currentElement;
84 DCHECK(current);
85 if (onlyRoots)
86 m_currentElement = nextInternal(ElementTraversal::nextSkippingChildren(
87 *m_currentElement, m_rootNode));
88 else
89 m_currentElement =
90 nextInternal(ElementTraversal::next(*m_currentElement, m_rootNode));
91 return current;
92 }
93
94 private:
95 Element* nextInternal(Element* element) {
96 for (; element; element = ElementTraversal::next(*element, m_rootNode)) {
97 if (element->hasClass() && element->classNames().contains(m_className))
98 return element;
99 }
100 return nullptr;
101 }
102
103 const AtomicString& m_className;
104 Member<ContainerNode> m_rootNode;
105 Member<Element> m_currentElement;
106 };
107 72
108 inline bool selectorMatches(const CSSSelector& selector, 73 inline bool selectorMatches(const CSSSelector& selector,
109 Element& element, 74 Element& element,
110 const ContainerNode& rootNode) { 75 const ContainerNode& rootNode) {
111 SelectorChecker::Init init; 76 SelectorChecker::Init init;
112 init.mode = SelectorChecker::QueryingRules; 77 init.mode = SelectorChecker::QueryingRules;
113 SelectorChecker checker(init); 78 SelectorChecker checker(init);
114 SelectorChecker::SelectorCheckingContext context( 79 SelectorChecker::SelectorCheckingContext context(
115 &element, SelectorChecker::VisitedMatchDisabled); 80 &element, SelectorChecker::VisitedMatchDisabled);
116 context.selector = &selector; 81 context.selector = &selector;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 NthIndexCache nthIndexCache(rootNode.document()); 114 NthIndexCache nthIndexCache(rootNode.document());
150 Element* matchedElement = nullptr; 115 Element* matchedElement = nullptr;
151 execute<SingleElementSelectorQueryTrait>(rootNode, matchedElement); 116 execute<SingleElementSelectorQueryTrait>(rootNode, matchedElement);
152 return matchedElement; 117 return matchedElement;
153 } 118 }
154 119
155 template <typename SelectorQueryTrait> 120 template <typename SelectorQueryTrait>
156 static void collectElementsByClassName( 121 static void collectElementsByClassName(
157 ContainerNode& rootNode, 122 ContainerNode& rootNode,
158 const AtomicString& className, 123 const AtomicString& className,
124 const CSSSelector* selector,
159 typename SelectorQueryTrait::OutputType& output) { 125 typename SelectorQueryTrait::OutputType& output) {
160 for (Element& element : ElementTraversal::descendantsOf(rootNode)) { 126 for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
161 if (element.hasClass() && element.classNames().contains(className)) { 127 if (!hasClassName(element, className))
162 SelectorQueryTrait::appendElement(output, element); 128 continue;
163 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) 129 if (selector && !selectorMatches(*selector, element, rootNode))
164 return; 130 continue;
165 } 131 SelectorQueryTrait::appendElement(output, element);
132 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
133 return;
166 } 134 }
167 } 135 }
168 136
169 inline bool matchesTagName(const QualifiedName& tagName, 137 inline bool matchesTagName(const QualifiedName& tagName,
170 const Element& element) { 138 const Element& element) {
171 if (tagName == anyQName()) 139 if (tagName == anyQName())
172 return true; 140 return true;
173 if (element.hasLocalName(tagName.localName())) 141 if (element.hasLocalName(tagName.localName()))
174 return true; 142 return true;
175 // Non-html elements in html documents are normalized to their camel-cased 143 // Non-html elements in html documents are normalized to their camel-cased
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 return m_selectors.size() == 1; 177 return m_selectors.size() == 1;
210 } 178 }
211 179
212 inline bool ancestorHasClassName(ContainerNode& rootNode, 180 inline bool ancestorHasClassName(ContainerNode& rootNode,
213 const AtomicString& className) { 181 const AtomicString& className) {
214 if (!rootNode.isElementNode()) 182 if (!rootNode.isElementNode())
215 return false; 183 return false;
216 184
217 for (Element* element = &toElement(rootNode); element; 185 for (Element* element = &toElement(rootNode); element;
218 element = element->parentElement()) { 186 element = element->parentElement()) {
219 if (element->hasClass() && element->classNames().contains(className)) 187 if (hasClassName(*element, className))
220 return true; 188 return true;
221 } 189 }
222 return false; 190 return false;
223 } 191 }
224 192
225 template <typename SelectorQueryTrait> 193 template <typename SelectorQueryTrait>
226 void SelectorQuery::findTraverseRootsAndExecute( 194 void SelectorQuery::findTraverseRootsAndExecute(
227 ContainerNode& rootNode, 195 ContainerNode& rootNode,
228 typename SelectorQueryTrait::OutputType& output) const { 196 typename SelectorQueryTrait::OutputType& output) const {
229 // We need to return the matches in document order. To use id lookup while 197 // We need to return the matches in document order. To use id lookup while
(...skipping 25 matching lines...) Expand all
255 return; 223 return;
256 executeForTraverseRoot<SelectorQueryTrait>(*start, rootNode, output); 224 executeForTraverseRoot<SelectorQueryTrait>(*start, rootNode, output);
257 return; 225 return;
258 } 226 }
259 227
260 // If we have both CSSSelector::Id and CSSSelector::Class at the same time, 228 // If we have both CSSSelector::Id and CSSSelector::Class at the same time,
261 // we should use Id to find traverse root. 229 // we should use Id to find traverse root.
262 if (!SelectorQueryTrait::shouldOnlyMatchFirstElement && !startFromParent && 230 if (!SelectorQueryTrait::shouldOnlyMatchFirstElement && !startFromParent &&
263 selector->match() == CSSSelector::Class) { 231 selector->match() == CSSSelector::Class) {
264 if (isRightmostSelector) { 232 if (isRightmostSelector) {
265 ClassElementList<AllElements> traverseRoots(rootNode, 233 collectElementsByClassName<SelectorQueryTrait>(
266 selector->value()); 234 rootNode, selector->value(), m_selectors[0], output);
267 while (!traverseRoots.isEmpty()) {
268 Element& element = *traverseRoots.next();
269 if (selectorMatches(*m_selectors[0], element, rootNode))
270 SelectorQueryTrait::appendElement(output, element);
271 }
272 return; 235 return;
273 } 236 }
274 // Since there exists some ancestor element which has the class name, we 237 // Since there exists some ancestor element which has the class name, we
275 // need to see all children of rootNode. 238 // need to see all children of rootNode.
276 if (ancestorHasClassName(rootNode, selector->value())) 239 if (ancestorHasClassName(rootNode, selector->value()))
277 break; 240 break;
278 241
279 ClassElementList<OnlyRoots> traverseRoots(rootNode, selector->value()); 242 const AtomicString& className = selector->value();
280 while (!traverseRoots.isEmpty()) { 243 Element* element = ElementTraversal::firstWithin(rootNode);
281 executeForTraverseRoot<SelectorQueryTrait>(*traverseRoots.next(), 244 while (element) {
282 rootNode, output); 245 if (hasClassName(*element, className)) {
246 executeForTraverseRoot<SelectorQueryTrait>(*element, rootNode,
247 output);
248 element = ElementTraversal::nextSkippingChildren(*element, &rootNode);
249 } else {
250 element = ElementTraversal::next(*element, &rootNode);
251 }
283 } 252 }
284 return; 253 return;
285 } 254 }
286 255
287 if (selector->relation() == CSSSelector::SubSelector) 256 if (selector->relation() == CSSSelector::SubSelector)
288 continue; 257 continue;
289 isRightmostSelector = false; 258 isRightmostSelector = false;
290 if (selector->relation() == CSSSelector::DirectAdjacent || 259 if (selector->relation() == CSSSelector::DirectAdjacent ||
291 selector->relation() == CSSSelector::IndirectAdjacent) 260 selector->relation() == CSSSelector::IndirectAdjacent)
292 startFromParent = true; 261 startFromParent = true;
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
466 if (selectorMatches(selector, *element, rootNode)) 435 if (selectorMatches(selector, *element, rootNode))
467 SelectorQueryTrait::appendElement(output, *element); 436 SelectorQueryTrait::appendElement(output, *element);
468 return; 437 return;
469 } 438 }
470 439
471 if (!firstSelector.tagHistory()) { 440 if (!firstSelector.tagHistory()) {
472 // Fast path for querySelector*('.foo'), and querySelector*('div'). 441 // Fast path for querySelector*('.foo'), and querySelector*('div').
473 switch (firstSelector.match()) { 442 switch (firstSelector.match()) {
474 case CSSSelector::Class: 443 case CSSSelector::Class:
475 collectElementsByClassName<SelectorQueryTrait>( 444 collectElementsByClassName<SelectorQueryTrait>(
476 rootNode, firstSelector.value(), output); 445 rootNode, firstSelector.value(), nullptr, output);
477 return; 446 return;
478 case CSSSelector::Tag: 447 case CSSSelector::Tag:
479 if (firstSelector.tagQName().namespaceURI() == starAtom) { 448 if (firstSelector.tagQName().namespaceURI() == starAtom) {
480 collectElementsByTagName<SelectorQueryTrait>( 449 collectElementsByTagName<SelectorQueryTrait>(
481 rootNode, firstSelector.tagQName(), output); 450 rootNode, firstSelector.tagQName(), output);
482 return; 451 return;
483 } 452 }
484 // querySelector*() doesn't allow namespace prefix resolution and 453 // querySelector*() doesn't allow namespace prefix resolution and
485 // throws before we get here, but we still may have selectors for 454 // throws before we get here, but we still may have selectors for
486 // elements without a namespace. 455 // elements without a namespace.
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
548 return m_entries 517 return m_entries
549 .insert(selectors, SelectorQuery::adopt(std::move(selectorList))) 518 .insert(selectors, SelectorQuery::adopt(std::move(selectorList)))
550 .storedValue->value.get(); 519 .storedValue->value.get();
551 } 520 }
552 521
553 void SelectorQueryCache::invalidate() { 522 void SelectorQueryCache::invalidate() {
554 m_entries.clear(); 523 m_entries.clear();
555 } 524 }
556 525
557 } // namespace blink 526 } // namespace blink
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698