OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2011 Apple Inc. All rights reserved. | 2 * Copyright (C) 2011 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 19 matching lines...) Expand all Loading... |
30 #include "core/css/CSSSelectorList.h" | 30 #include "core/css/CSSSelectorList.h" |
31 #include "core/css/SelectorChecker.h" | 31 #include "core/css/SelectorChecker.h" |
32 #include "core/css/SelectorCheckerFastPath.h" | 32 #include "core/css/SelectorCheckerFastPath.h" |
33 #include "core/css/SiblingTraversalStrategies.h" | 33 #include "core/css/SiblingTraversalStrategies.h" |
34 #include "core/dom/Document.h" | 34 #include "core/dom/Document.h" |
35 #include "core/dom/NodeTraversal.h" | 35 #include "core/dom/NodeTraversal.h" |
36 #include "core/dom/StaticNodeList.h" | 36 #include "core/dom/StaticNodeList.h" |
37 | 37 |
38 namespace WebCore { | 38 namespace WebCore { |
39 | 39 |
| 40 class SimpleNodeList { |
| 41 public: |
| 42 virtual ~SimpleNodeList() { } |
| 43 virtual bool isEmpty() const = 0; |
| 44 virtual Node* next() = 0; |
| 45 }; |
| 46 |
| 47 class SingleNodeList : public SimpleNodeList { |
| 48 public: |
| 49 explicit SingleNodeList(Node* rootNode) : m_currentNode(rootNode) { } |
| 50 |
| 51 bool isEmpty() const { return !m_currentNode; } |
| 52 |
| 53 Node* next() |
| 54 { |
| 55 Node* current = m_currentNode; |
| 56 m_currentNode = 0; |
| 57 return current; |
| 58 } |
| 59 |
| 60 private: |
| 61 Node* m_currentNode; |
| 62 }; |
| 63 |
| 64 class ClassRootNodeList : public SimpleNodeList { |
| 65 public: |
| 66 explicit ClassRootNodeList(Node* rootNode, const AtomicString& className) |
| 67 : m_className(className) |
| 68 , m_rootNode(rootNode) |
| 69 , m_currentElement(nextInternal(ElementTraversal::firstWithin(rootNode))
) { } |
| 70 |
| 71 bool isEmpty() const { return !m_currentElement; } |
| 72 |
| 73 Node* next() |
| 74 { |
| 75 Node* current = m_currentElement; |
| 76 ASSERT(current); |
| 77 m_currentElement = nextInternal(ElementTraversal::nextSkippingChildren(m
_currentElement, m_rootNode)); |
| 78 return current; |
| 79 } |
| 80 |
| 81 private: |
| 82 Element* nextInternal(Element* element) |
| 83 { |
| 84 for (; element; element = ElementTraversal::next(element, m_rootNode)) { |
| 85 if (element->hasClass() && element->classNames().contains(m_classNam
e)) |
| 86 return element; |
| 87 } |
| 88 return 0; |
| 89 } |
| 90 |
| 91 const AtomicString& m_className; |
| 92 Node* m_rootNode; |
| 93 Element* m_currentElement; |
| 94 }; |
| 95 |
| 96 class ClassElementList : public SimpleNodeList { |
| 97 public: |
| 98 explicit ClassElementList(Node* rootNode, const AtomicString& className) |
| 99 : m_className(className) |
| 100 , m_rootNode(rootNode) |
| 101 , m_currentElement(nextInternal(ElementTraversal::firstWithin(rootNode))
) { } |
| 102 |
| 103 bool isEmpty() const { return !m_currentElement; } |
| 104 |
| 105 Node* next() |
| 106 { |
| 107 Node* current = m_currentElement; |
| 108 ASSERT(current); |
| 109 m_currentElement = nextInternal(ElementTraversal::next(m_currentElement,
m_rootNode)); |
| 110 return current; |
| 111 } |
| 112 |
| 113 private: |
| 114 Element* nextInternal(Element* element) |
| 115 { |
| 116 for (; element; element = ElementTraversal::next(element, m_rootNode)) { |
| 117 if (element->hasClass() && element->classNames().contains(m_classNam
e)) |
| 118 return element; |
| 119 } |
| 120 return 0; |
| 121 } |
| 122 |
| 123 const AtomicString& m_className; |
| 124 Node* m_rootNode; |
| 125 Element* m_currentElement; |
| 126 }; |
| 127 |
40 void SelectorDataList::initialize(const CSSSelectorList& selectorList) | 128 void SelectorDataList::initialize(const CSSSelectorList& selectorList) |
41 { | 129 { |
42 ASSERT(m_selectors.isEmpty()); | 130 ASSERT(m_selectors.isEmpty()); |
43 | 131 |
44 unsigned selectorCount = 0; | 132 unsigned selectorCount = 0; |
45 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(selector)) | 133 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(selector)) |
46 selectorCount++; | 134 selectorCount++; |
47 | 135 |
48 m_selectors.reserveInitialCapacity(selectorCount); | 136 m_selectors.reserveInitialCapacity(selectorCount); |
49 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(selector)) | 137 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(selector)) |
(...skipping 26 matching lines...) Expand all Loading... |
76 if (selectorMatches(m_selectors[i], targetElement, targetElement)) | 164 if (selectorMatches(m_selectors[i], targetElement, targetElement)) |
77 return true; | 165 return true; |
78 } | 166 } |
79 | 167 |
80 return false; | 168 return false; |
81 } | 169 } |
82 | 170 |
83 PassRefPtr<NodeList> SelectorDataList::queryAll(Node* rootNode) const | 171 PassRefPtr<NodeList> SelectorDataList::queryAll(Node* rootNode) const |
84 { | 172 { |
85 Vector<RefPtr<Node> > result; | 173 Vector<RefPtr<Node> > result; |
86 execute<false>(rootNode, result); | 174 executeQueryAll(rootNode, result); |
87 return StaticNodeList::adopt(result); | 175 return StaticNodeList::adopt(result); |
88 } | 176 } |
89 | 177 |
90 PassRefPtr<Element> SelectorDataList::queryFirst(Node* rootNode) const | 178 PassRefPtr<Element> SelectorDataList::queryFirst(Node* rootNode) const |
91 { | 179 { |
92 Vector<RefPtr<Node> > result; | 180 return executeQueryFirst(rootNode); |
93 execute<true>(rootNode, result); | |
94 if (result.isEmpty()) | |
95 return 0; | |
96 ASSERT(result.size() == 1); | |
97 ASSERT(result.first()->isElementNode()); | |
98 return toElement(result.first().get()); | |
99 } | 181 } |
100 | 182 |
101 static inline bool isTreeScopeRoot(Node* node) | 183 static inline bool isTreeScopeRoot(Node* node) |
102 { | 184 { |
103 ASSERT(node); | 185 ASSERT(node); |
104 return node->isDocumentNode() || node->isShadowRoot(); | 186 return node->isDocumentNode() || node->isShadowRoot(); |
105 } | 187 } |
106 | 188 |
107 // If the first pair value is true, the returned Node is the single Element that
may match the selector query. | 189 void SelectorDataList::collectElementsByClassName(Node* rootNode, const AtomicSt
ring& className, Vector<RefPtr<Node> >& traversalRoots) const |
108 // | 190 { |
109 // If the first value is false, the returned Node is the rootNode parameter or a
descendant of rootNode representing | 191 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el
ement = ElementTraversal::next(element, rootNode)) { |
| 192 if (element->hasClass() && element->classNames().contains(className)) |
| 193 traversalRoots.append(element); |
| 194 } |
| 195 } |
| 196 |
| 197 void SelectorDataList::collectElementsByTagName(Node* rootNode, const QualifiedN
ame& tagName, Vector<RefPtr<Node> >& traversalRoots) const |
| 198 { |
| 199 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el
ement = ElementTraversal::next(element, rootNode)) { |
| 200 if (SelectorChecker::tagMatches(element, tagName)) |
| 201 traversalRoots.append(element); |
| 202 } |
| 203 } |
| 204 |
| 205 Element* SelectorDataList::findElementByClassName(Node* rootNode, const AtomicSt
ring& className) const |
| 206 { |
| 207 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el
ement = ElementTraversal::next(element, rootNode)) { |
| 208 if (element->hasClass() && element->classNames().contains(className)) |
| 209 return element; |
| 210 } |
| 211 return 0; |
| 212 } |
| 213 |
| 214 Element* SelectorDataList::findElementByTagName(Node* rootNode, const QualifiedN
ame& tagName) const |
| 215 { |
| 216 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el
ement = ElementTraversal::next(element, rootNode)) { |
| 217 if (SelectorChecker::tagMatches(element, tagName)) |
| 218 return element; |
| 219 } |
| 220 return 0; |
| 221 } |
| 222 |
| 223 inline bool SelectorDataList::canUseFastQuery(Node* rootNode) const |
| 224 { |
| 225 return m_selectors.size() == 1 && rootNode->inDocument() && !rootNode->docum
ent()->inQuirksMode(); |
| 226 } |
| 227 |
| 228 // If returns true, traversalRoots has the elements that may match the selector
query. |
| 229 // |
| 230 // If returns false, traversalRoots has the rootNode parameter or descendants of
rootNode representing |
110 // the subtree for which we can limit the querySelector traversal. | 231 // the subtree for which we can limit the querySelector traversal. |
111 // | 232 // |
112 // The returned Node may be 0, regardless of the returned bool value, if this me
thod finds that the selectors won't | 233 // The travseralRoots may be empty, regardless of the returned bool value, if th
is method finds that the selectors won't |
113 // match any element. | 234 // match any element. |
114 std::pair<bool, Node*> SelectorDataList::findTraverseRoot(Node* rootNode) const | 235 PassOwnPtr<SimpleNodeList> SelectorDataList::findTraverseRoots(Node* rootNode, b
ool& matchTraverseRoots) const |
115 { | 236 { |
116 // We need to return the matches in document order. To use id lookup while t
here is possiblity of multiple matches | 237 // We need to return the matches in document order. To use id lookup while t
here is possiblity of multiple matches |
117 // we would need to sort the results. For now, just traverse the document in
that case. | 238 // we would need to sort the results. For now, just traverse the document in
that case. |
118 if (m_selectors.size() != 1) | 239 ASSERT(rootNode); |
119 return std::make_pair(false, rootNode); | 240 ASSERT(m_selectors.size() == 1); |
120 if (!rootNode->inDocument()) | 241 ASSERT(m_selectors[0].selector); |
121 return std::make_pair(false, rootNode); | 242 |
122 if (rootNode->document()->inQuirksMode()) | 243 bool isRightmostSelector = true; |
123 return std::make_pair(false, rootNode); | 244 bool startFromParent = false; |
| 245 |
| 246 for (const CSSSelector* selector = m_selectors[0].selector; selector; select
or = selector->tagHistory()) { |
| 247 if (selector->m_match == CSSSelector::Id && !rootNode->document()->conta
insMultipleElementsWithId(selector->value())) { |
| 248 Element* element = rootNode->treeScope()->getElementById(selector->v
alue()); |
| 249 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf
(rootNode))) |
| 250 rootNode = element; |
| 251 else if (!element || isRightmostSelector) |
| 252 rootNode = 0; |
| 253 if (isRightmostSelector) { |
| 254 matchTraverseRoots = true; |
| 255 return adoptPtr(new SingleNodeList(rootNode)); |
| 256 } |
| 257 if (startFromParent && rootNode) |
| 258 rootNode = rootNode->parentNode(); |
| 259 |
| 260 matchTraverseRoots = false; |
| 261 return adoptPtr(new SingleNodeList(rootNode)); |
| 262 } |
| 263 |
| 264 // If we have both CSSSelector::Id and CSSSelector::Class at the same ti
me, we should use Id |
| 265 // to find traverse root. |
| 266 if (!startFromParent && selector->m_match == CSSSelector::Class) { |
| 267 if (isRightmostSelector) { |
| 268 matchTraverseRoots = true; |
| 269 return adoptPtr(new ClassElementList(rootNode, selector->value()
)); |
| 270 } |
| 271 matchTraverseRoots = false; |
| 272 return adoptPtr(new ClassRootNodeList(rootNode, selector->value())); |
| 273 } |
| 274 |
| 275 if (selector->relation() == CSSSelector::SubSelector) |
| 276 continue; |
| 277 isRightmostSelector = false; |
| 278 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel
ation() == CSSSelector::IndirectAdjacent) |
| 279 startFromParent = true; |
| 280 else |
| 281 startFromParent = false; |
| 282 } |
| 283 |
| 284 matchTraverseRoots = false; |
| 285 return adoptPtr(new SingleNodeList(rootNode)); |
| 286 } |
| 287 |
| 288 void SelectorDataList::executeSlowQueryAll(Node* rootNode, Vector<RefPtr<Node> >
& matchedElements) const |
| 289 { |
| 290 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el
ement = ElementTraversal::next(element, rootNode)) { |
| 291 for (unsigned i = 0; i < m_selectors.size(); ++i) { |
| 292 if (selectorMatches(m_selectors[i], element, rootNode)) { |
| 293 matchedElements.append(element); |
| 294 break; |
| 295 } |
| 296 } |
| 297 } |
| 298 } |
| 299 |
| 300 void SelectorDataList::executeQueryAll(Node* rootNode, Vector<RefPtr<Node> >& ma
tchedElements) const |
| 301 { |
| 302 if (!canUseFastQuery(rootNode)) |
| 303 return executeSlowQueryAll(rootNode, matchedElements); |
| 304 |
| 305 ASSERT(m_selectors.size() == 1); |
| 306 ASSERT(m_selectors[0].selector); |
| 307 |
| 308 const CSSSelector* firstSelector = m_selectors[0].selector; |
| 309 |
| 310 if (!firstSelector->tagHistory()) { |
| 311 // Fast path for querySelectorAll('#id'), querySelectorAl('.foo'), and q
uerySelectorAll('div'). |
| 312 switch (firstSelector->m_match) { |
| 313 case CSSSelector::Id: |
| 314 { |
| 315 if (rootNode->document()->containsMultipleElementsWithId(firstSe
lector->value())) |
| 316 break; |
| 317 |
| 318 // Just the same as getElementById. |
| 319 Element* element = rootNode->treeScope()->getElementById(firstSe
lector->value()); |
| 320 if (element && (isTreeScopeRoot(rootNode) || element->isDescenda
ntOf(rootNode))) |
| 321 matchedElements.append(element); |
| 322 return; |
| 323 } |
| 324 case CSSSelector::Class: |
| 325 return collectElementsByClassName(rootNode, firstSelector->value(),
matchedElements); |
| 326 case CSSSelector::Tag: |
| 327 return collectElementsByTagName(rootNode, firstSelector->tagQName(),
matchedElements); |
| 328 default: |
| 329 break; // If we need another fast path, add here. |
| 330 } |
| 331 } |
| 332 |
| 333 bool matchTraverseRoots; |
| 334 OwnPtr<SimpleNodeList> traverseRoots = findTraverseRoots(rootNode, matchTrav
erseRoots); |
| 335 if (traverseRoots->isEmpty()) |
| 336 return; |
| 337 |
| 338 const SelectorData& selector = m_selectors[0]; |
| 339 if (matchTraverseRoots) { |
| 340 while (!traverseRoots->isEmpty()) { |
| 341 Node* node = traverseRoots->next(); |
| 342 Element* element = toElement(node); |
| 343 if (selectorMatches(selector, element, rootNode)) |
| 344 matchedElements.append(element); |
| 345 } |
| 346 return; |
| 347 } |
| 348 |
| 349 while (!traverseRoots->isEmpty()) { |
| 350 Node* traverseRoot = traverseRoots->next(); |
| 351 for (Element* element = ElementTraversal::firstWithin(traverseRoot); ele
ment; element = ElementTraversal::next(element, traverseRoot)) { |
| 352 if (selectorMatches(selector, element, rootNode)) |
| 353 matchedElements.append(element); |
| 354 } |
| 355 } |
| 356 } |
| 357 |
| 358 // If matchTraverseRoot is true, the returned Node is the single Element that ma
y match the selector query. |
| 359 // |
| 360 // If matchTraverseRoot is false, the returned Node is the rootNode parameter or
a descendant of rootNode representing |
| 361 // the subtree for which we can limit the querySelector traversal. |
| 362 // |
| 363 // The returned Node may be 0, regardless of matchTraverseRoot, if this method f
inds that the selectors won't |
| 364 // match any element. |
| 365 Node* SelectorDataList::findTraverseRoot(Node* rootNode, bool& matchTraverseRoot
) const |
| 366 { |
| 367 // We need to return the matches in document order. To use id lookup while t
here is possiblity of multiple matches |
| 368 // we would need to sort the results. For now, just traverse the document in
that case. |
| 369 ASSERT(rootNode); |
| 370 ASSERT(m_selectors.size() == 1); |
| 371 ASSERT(m_selectors[0].selector); |
124 | 372 |
125 bool matchSingleNode = true; | 373 bool matchSingleNode = true; |
126 bool startFromParent = false; | 374 bool startFromParent = false; |
127 for (const CSSSelector* selector = m_selectors[0].selector; selector; select
or = selector->tagHistory()) { | 375 for (const CSSSelector* selector = m_selectors[0].selector; selector; select
or = selector->tagHistory()) { |
128 if (selector->m_match == CSSSelector::Id && !rootNode->document()->conta
insMultipleElementsWithId(selector->value())) { | 376 if (selector->m_match == CSSSelector::Id && !rootNode->document()->conta
insMultipleElementsWithId(selector->value())) { |
129 Element* element = rootNode->treeScope()->getElementById(selector->v
alue()); | 377 Element* element = rootNode->treeScope()->getElementById(selector->v
alue()); |
130 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf
(rootNode))) | 378 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf
(rootNode))) |
131 rootNode = element; | 379 rootNode = element; |
132 else if (!element || matchSingleNode) | 380 else if (!element || matchSingleNode) |
133 rootNode = 0; | 381 rootNode = 0; |
134 if (matchSingleNode) | 382 if (matchSingleNode) { |
135 return std::make_pair(true, rootNode); | 383 matchTraverseRoot = true; |
| 384 return rootNode; |
| 385 } |
136 if (startFromParent && rootNode) | 386 if (startFromParent && rootNode) |
137 rootNode = rootNode->parentNode(); | 387 rootNode = rootNode->parentNode(); |
138 return std::make_pair(false, rootNode); | 388 matchTraverseRoot = false; |
| 389 return rootNode; |
139 } | 390 } |
140 if (selector->relation() == CSSSelector::SubSelector) | 391 if (selector->relation() == CSSSelector::SubSelector) |
141 continue; | 392 continue; |
142 matchSingleNode = false; | 393 matchSingleNode = false; |
143 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel
ation() == CSSSelector::IndirectAdjacent) | 394 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel
ation() == CSSSelector::IndirectAdjacent) |
144 startFromParent = true; | 395 startFromParent = true; |
145 else | 396 else |
146 startFromParent = false; | 397 startFromParent = false; |
147 } | 398 } |
148 return std::make_pair(false, rootNode); | 399 matchTraverseRoot = false; |
149 } | 400 return rootNode; |
150 | 401 } |
151 template <bool firstMatchOnly> | 402 |
152 void SelectorDataList::execute(Node* rootNode, Vector<RefPtr<Node> >& matchedEle
ments) const | 403 Element* SelectorDataList::executeSlowQueryFirst(Node* rootNode) const |
153 { | 404 { |
154 std::pair<bool, Node*> traverseRoot = findTraverseRoot(rootNode); | 405 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el
ement = ElementTraversal::next(element, rootNode)) { |
155 if (!traverseRoot.second) | 406 for (unsigned i = 0; i < m_selectors.size(); ++i) { |
156 return; | 407 if (selectorMatches(m_selectors[i], element, rootNode)) |
157 Node* traverseRootNode = traverseRoot.second; | 408 return element; |
158 if (traverseRoot.first) { | 409 } |
| 410 } |
| 411 return 0; |
| 412 } |
| 413 |
| 414 Element* SelectorDataList::executeQueryFirst(Node* rootNode) const |
| 415 { |
| 416 if (!canUseFastQuery(rootNode)) |
| 417 return executeSlowQueryFirst(rootNode); |
| 418 |
| 419 |
| 420 const CSSSelector* selector = m_selectors[0].selector; |
| 421 ASSERT(selector); |
| 422 |
| 423 if (!selector->tagHistory()) { |
| 424 // Fast path for querySelector('#id'), querySelector('.foo'), and queryS
elector('div'). |
| 425 // Many web developers uses querySelector with these simple selectors. |
| 426 switch (selector->m_match) { |
| 427 case CSSSelector::Id: |
| 428 { |
| 429 if (rootNode->document()->containsMultipleElementsWithId(selecto
r->value())) |
| 430 break; |
| 431 Element* element = rootNode->treeScope()->getElementById(selecto
r->value()); |
| 432 return element && (isTreeScopeRoot(rootNode) || element->isDesce
ndantOf(rootNode)) ? element : 0; |
| 433 } |
| 434 case CSSSelector::Class: |
| 435 return findElementByClassName(rootNode, selector->value()); |
| 436 case CSSSelector::Tag: |
| 437 return findElementByTagName(rootNode, selector->tagQName()); |
| 438 default: |
| 439 break; // If we need another fast path, add here. |
| 440 } |
| 441 } |
| 442 |
| 443 bool matchTraverseRoot; |
| 444 Node* traverseRootNode = findTraverseRoot(rootNode, matchTraverseRoot); |
| 445 if (!traverseRootNode) |
| 446 return 0; |
| 447 if (matchTraverseRoot) { |
159 ASSERT(m_selectors.size() == 1); | 448 ASSERT(m_selectors.size() == 1); |
160 ASSERT(traverseRootNode->isElementNode()); | 449 ASSERT(traverseRootNode->isElementNode()); |
161 Element* element = toElement(traverseRootNode); | 450 Element* element = toElement(traverseRootNode); |
| 451 return selectorMatches(m_selectors[0], element, rootNode) ? element : 0; |
| 452 } |
| 453 |
| 454 for (Element* element = ElementTraversal::firstWithin(traverseRootNode); ele
ment; element = ElementTraversal::next(element, traverseRootNode)) { |
162 if (selectorMatches(m_selectors[0], element, rootNode)) | 455 if (selectorMatches(m_selectors[0], element, rootNode)) |
163 matchedElements.append(element); | 456 return element; |
164 return; | 457 } |
165 } | 458 return 0; |
166 | |
167 unsigned selectorCount = m_selectors.size(); | |
168 if (selectorCount == 1) { | |
169 const SelectorData& selector = m_selectors[0]; | |
170 for (Element* element = ElementTraversal::firstWithin(rootNode); element
; element = ElementTraversal::next(element, rootNode)) { | |
171 if (selectorMatches(selector, element, rootNode)) { | |
172 matchedElements.append(element); | |
173 if (firstMatchOnly) | |
174 return; | |
175 } | |
176 } | |
177 return; | |
178 } | |
179 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el
ement = ElementTraversal::next(element, rootNode)) { | |
180 for (unsigned i = 0; i < selectorCount; ++i) { | |
181 if (selectorMatches(m_selectors[i], element, rootNode)) { | |
182 matchedElements.append(element); | |
183 if (firstMatchOnly) | |
184 return; | |
185 break; | |
186 } | |
187 } | |
188 } | |
189 } | 459 } |
190 | 460 |
191 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList) | 461 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList) |
192 : m_selectorList(selectorList) | 462 : m_selectorList(selectorList) |
193 { | 463 { |
194 m_selectors.initialize(m_selectorList); | 464 m_selectors.initialize(m_selectorList); |
195 } | 465 } |
196 | 466 |
197 bool SelectorQuery::matches(Element* element) const | 467 bool SelectorQuery::matches(Element* element) const |
198 { | 468 { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 m_entries.add(selectors, selectorQuery.release()); | 509 m_entries.add(selectors, selectorQuery.release()); |
240 return rawSelectorQuery; | 510 return rawSelectorQuery; |
241 } | 511 } |
242 | 512 |
243 void SelectorQueryCache::invalidate() | 513 void SelectorQueryCache::invalidate() |
244 { | 514 { |
245 m_entries.clear(); | 515 m_entries.clear(); |
246 } | 516 } |
247 | 517 |
248 } | 518 } |
OLD | NEW |