| 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 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 | 132 |
| 133 unsigned selectorCount = 0; | 133 unsigned selectorCount = 0; |
| 134 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(selector)) | 134 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(selector)) |
| 135 selectorCount++; | 135 selectorCount++; |
| 136 | 136 |
| 137 m_selectors.reserveInitialCapacity(selectorCount); | 137 m_selectors.reserveInitialCapacity(selectorCount); |
| 138 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(selector)) | 138 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(selector)) |
| 139 m_selectors.uncheckedAppend(SelectorData(selector, SelectorCheckerFastPa
th::canUse(selector))); | 139 m_selectors.uncheckedAppend(SelectorData(selector, SelectorCheckerFastPa
th::canUse(selector))); |
| 140 } | 140 } |
| 141 | 141 |
| 142 inline bool SelectorDataList::selectorMatches(const SelectorData& selectorData,
Element* element, const Node* rootNode) const | 142 inline bool SelectorDataList::selectorMatches(const SelectorData& selectorData,
Element& element, const Node& rootNode) const |
| 143 { | 143 { |
| 144 if (selectorData.isFastCheckable && !element->isSVGElement()) { | 144 if (selectorData.isFastCheckable && !element.isSVGElement()) { |
| 145 SelectorCheckerFastPath selectorCheckerFastPath(selectorData.selector, e
lement); | 145 SelectorCheckerFastPath selectorCheckerFastPath(selectorData.selector, e
lement); |
| 146 if (!selectorCheckerFastPath.matchesRightmostSelector(SelectorChecker::V
isitedMatchDisabled)) | 146 if (!selectorCheckerFastPath.matchesRightmostSelector(SelectorChecker::V
isitedMatchDisabled)) |
| 147 return false; | 147 return false; |
| 148 return selectorCheckerFastPath.matches(); | 148 return selectorCheckerFastPath.matches(); |
| 149 } | 149 } |
| 150 | 150 |
| 151 SelectorChecker selectorChecker(element->document(), SelectorChecker::Queryi
ngRules); | 151 SelectorChecker selectorChecker(element.document(), SelectorChecker::Queryin
gRules); |
| 152 SelectorChecker::SelectorCheckingContext selectorCheckingContext(selectorDat
a.selector, element, SelectorChecker::VisitedMatchDisabled); | 152 SelectorChecker::SelectorCheckingContext selectorCheckingContext(selectorDat
a.selector, &element, SelectorChecker::VisitedMatchDisabled); |
| 153 selectorCheckingContext.behaviorAtBoundary = SelectorChecker::StaysWithinTre
eScope; | 153 selectorCheckingContext.behaviorAtBoundary = SelectorChecker::StaysWithinTre
eScope; |
| 154 selectorCheckingContext.scope = !rootNode->isDocumentNode() && rootNode->isC
ontainerNode() ? toContainerNode(rootNode) : 0; | 154 selectorCheckingContext.scope = !rootNode.isDocumentNode() && rootNode.isCon
tainerNode() ? &toContainerNode(rootNode) : 0; |
| 155 PseudoId ignoreDynamicPseudo = NOPSEUDO; | 155 PseudoId ignoreDynamicPseudo = NOPSEUDO; |
| 156 return selectorChecker.match(selectorCheckingContext, ignoreDynamicPseudo, D
OMSiblingTraversalStrategy()) == SelectorChecker::SelectorMatches; | 156 return selectorChecker.match(selectorCheckingContext, ignoreDynamicPseudo, D
OMSiblingTraversalStrategy()) == SelectorChecker::SelectorMatches; |
| 157 } | 157 } |
| 158 | 158 |
| 159 bool SelectorDataList::matches(Element* targetElement) const | 159 bool SelectorDataList::matches(Element& targetElement) const |
| 160 { | 160 { |
| 161 ASSERT(targetElement); | |
| 162 | |
| 163 unsigned selectorCount = m_selectors.size(); | 161 unsigned selectorCount = m_selectors.size(); |
| 164 for (unsigned i = 0; i < selectorCount; ++i) { | 162 for (unsigned i = 0; i < selectorCount; ++i) { |
| 165 if (selectorMatches(m_selectors[i], targetElement, targetElement)) | 163 if (selectorMatches(m_selectors[i], targetElement, targetElement)) |
| 166 return true; | 164 return true; |
| 167 } | 165 } |
| 168 | 166 |
| 169 return false; | 167 return false; |
| 170 } | 168 } |
| 171 | 169 |
| 172 PassRefPtr<NodeList> SelectorDataList::queryAll(Node* rootNode) const | 170 PassRefPtr<NodeList> SelectorDataList::queryAll(Node& rootNode) const |
| 173 { | 171 { |
| 174 Vector<RefPtr<Node> > result; | 172 Vector<RefPtr<Node> > result; |
| 175 executeQueryAll(rootNode, result); | 173 executeQueryAll(rootNode, result); |
| 176 return StaticNodeList::adopt(result); | 174 return StaticNodeList::adopt(result); |
| 177 } | 175 } |
| 178 | 176 |
| 179 PassRefPtr<Element> SelectorDataList::queryFirst(Node* rootNode) const | 177 PassRefPtr<Element> SelectorDataList::queryFirst(Node& rootNode) const |
| 180 { | 178 { |
| 181 return executeQueryFirst(rootNode); | 179 return executeQueryFirst(rootNode); |
| 182 } | 180 } |
| 183 | 181 |
| 184 static inline bool isTreeScopeRoot(Node* node) | 182 static inline bool isTreeScopeRoot(Node* node) |
| 185 { | 183 { |
| 186 ASSERT(node); | 184 ASSERT(node); |
| 187 return node->isDocumentNode() || node->isShadowRoot(); | 185 return node->isDocumentNode() || node->isShadowRoot(); |
| 188 } | 186 } |
| 189 | 187 |
| 190 void SelectorDataList::collectElementsByClassName(Node* rootNode, const AtomicSt
ring& className, Vector<RefPtr<Node> >& traversalRoots) const | 188 void SelectorDataList::collectElementsByClassName(Node& rootNode, const AtomicSt
ring& className, Vector<RefPtr<Node> >& traversalRoots) const |
| 191 { | 189 { |
| 192 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el
ement = ElementTraversal::next(element, rootNode)) { | 190 for (Element* element = ElementTraversal::firstWithin(&rootNode); element; e
lement = ElementTraversal::next(element, &rootNode)) { |
| 193 if (element->hasClass() && element->classNames().contains(className)) | 191 if (element->hasClass() && element->classNames().contains(className)) |
| 194 traversalRoots.append(element); | 192 traversalRoots.append(element); |
| 195 } | 193 } |
| 196 } | 194 } |
| 197 | 195 |
| 198 void SelectorDataList::collectElementsByTagName(Node* rootNode, const QualifiedN
ame& tagName, Vector<RefPtr<Node> >& traversalRoots) const | 196 void SelectorDataList::collectElementsByTagName(Node& rootNode, const QualifiedN
ame& tagName, Vector<RefPtr<Node> >& traversalRoots) const |
| 199 { | 197 { |
| 200 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el
ement = ElementTraversal::next(element, rootNode)) { | 198 for (Element* element = ElementTraversal::firstWithin(&rootNode); element; e
lement = ElementTraversal::next(element, &rootNode)) { |
| 201 if (SelectorChecker::tagMatches(element, tagName)) | 199 if (SelectorChecker::tagMatches(*element, tagName)) |
| 202 traversalRoots.append(element); | 200 traversalRoots.append(element); |
| 203 } | 201 } |
| 204 } | 202 } |
| 205 | 203 |
| 206 Element* SelectorDataList::findElementByClassName(Node* rootNode, const AtomicSt
ring& className) const | 204 Element* SelectorDataList::findElementByClassName(Node& rootNode, const AtomicSt
ring& className) const |
| 207 { | 205 { |
| 208 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el
ement = ElementTraversal::next(element, rootNode)) { | 206 for (Element* element = ElementTraversal::firstWithin(&rootNode); element; e
lement = ElementTraversal::next(element, &rootNode)) { |
| 209 if (element->hasClass() && element->classNames().contains(className)) | 207 if (element->hasClass() && element->classNames().contains(className)) |
| 210 return element; | 208 return element; |
| 211 } | 209 } |
| 212 return 0; | 210 return 0; |
| 213 } | 211 } |
| 214 | 212 |
| 215 Element* SelectorDataList::findElementByTagName(Node* rootNode, const QualifiedN
ame& tagName) const | 213 Element* SelectorDataList::findElementByTagName(Node& rootNode, const QualifiedN
ame& tagName) const |
| 216 { | 214 { |
| 217 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el
ement = ElementTraversal::next(element, rootNode)) { | 215 for (Element* element = ElementTraversal::firstWithin(&rootNode); element; e
lement = ElementTraversal::next(element, &rootNode)) { |
| 218 if (SelectorChecker::tagMatches(element, tagName)) | 216 if (SelectorChecker::tagMatches(*element, tagName)) |
| 219 return element; | 217 return element; |
| 220 } | 218 } |
| 221 return 0; | 219 return 0; |
| 222 } | 220 } |
| 223 | 221 |
| 224 inline bool SelectorDataList::canUseFastQuery(Node* rootNode) const | 222 inline bool SelectorDataList::canUseFastQuery(const Node& rootNode) const |
| 225 { | 223 { |
| 226 return m_selectors.size() == 1 && rootNode->inDocument() && !rootNode->docum
ent().inQuirksMode(); | 224 return m_selectors.size() == 1 && rootNode.inDocument() && !rootNode.documen
t().inQuirksMode(); |
| 227 } | 225 } |
| 228 | 226 |
| 229 inline bool ancestorHasClassName(Node* rootNode, const AtomicString& className) | 227 inline bool ancestorHasClassName(Node* rootNode, const AtomicString& className) |
| 230 { | 228 { |
| 231 if (!rootNode->isElementNode()) | 229 if (!rootNode->isElementNode()) |
| 232 return false; | 230 return false; |
| 233 | 231 |
| 234 for (Element* element = toElement(rootNode); element; element = element->par
entElement()) { | 232 for (Element* element = toElement(rootNode); element; element = element->par
entElement()) { |
| 235 if (element->hasClass() && element->classNames().contains(className)) | 233 if (element->hasClass() && element->classNames().contains(className)) |
| 236 return true; | 234 return true; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 296 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel
ation() == CSSSelector::IndirectAdjacent) | 294 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel
ation() == CSSSelector::IndirectAdjacent) |
| 297 startFromParent = true; | 295 startFromParent = true; |
| 298 else | 296 else |
| 299 startFromParent = false; | 297 startFromParent = false; |
| 300 } | 298 } |
| 301 | 299 |
| 302 matchTraverseRoots = false; | 300 matchTraverseRoots = false; |
| 303 return adoptPtr(new SingleNodeList(rootNode)); | 301 return adoptPtr(new SingleNodeList(rootNode)); |
| 304 } | 302 } |
| 305 | 303 |
| 306 void SelectorDataList::executeSlowQueryAll(Node* rootNode, Vector<RefPtr<Node> >
& matchedElements) const | 304 void SelectorDataList::executeSlowQueryAll(Node& rootNode, Vector<RefPtr<Node> >
& matchedElements) const |
| 307 { | 305 { |
| 308 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el
ement = ElementTraversal::next(element, rootNode)) { | 306 for (Element* element = ElementTraversal::firstWithin(&rootNode); element; e
lement = ElementTraversal::next(element, &rootNode)) { |
| 309 for (unsigned i = 0; i < m_selectors.size(); ++i) { | 307 for (unsigned i = 0; i < m_selectors.size(); ++i) { |
| 310 if (selectorMatches(m_selectors[i], element, rootNode)) { | 308 if (selectorMatches(m_selectors[i], *element, rootNode)) { |
| 311 matchedElements.append(element); | 309 matchedElements.append(element); |
| 312 break; | 310 break; |
| 313 } | 311 } |
| 314 } | 312 } |
| 315 } | 313 } |
| 316 } | 314 } |
| 317 | 315 |
| 318 void SelectorDataList::executeQueryAll(Node* rootNode, Vector<RefPtr<Node> >& ma
tchedElements) const | 316 void SelectorDataList::executeQueryAll(Node& rootNode, Vector<RefPtr<Node> >& ma
tchedElements) const |
| 319 { | 317 { |
| 320 if (!canUseFastQuery(rootNode)) | 318 if (!canUseFastQuery(rootNode)) |
| 321 return executeSlowQueryAll(rootNode, matchedElements); | 319 return executeSlowQueryAll(rootNode, matchedElements); |
| 322 | 320 |
| 323 ASSERT(m_selectors.size() == 1); | 321 ASSERT(m_selectors.size() == 1); |
| 324 ASSERT(m_selectors[0].selector); | 322 ASSERT(m_selectors[0].selector); |
| 325 | 323 |
| 326 const CSSSelector* firstSelector = m_selectors[0].selector; | 324 const CSSSelector* firstSelector = m_selectors[0].selector; |
| 327 | 325 |
| 328 if (!firstSelector->tagHistory()) { | 326 if (!firstSelector->tagHistory()) { |
| 329 // Fast path for querySelectorAll('#id'), querySelectorAl('.foo'), and q
uerySelectorAll('div'). | 327 // Fast path for querySelectorAll('#id'), querySelectorAl('.foo'), and q
uerySelectorAll('div'). |
| 330 switch (firstSelector->m_match) { | 328 switch (firstSelector->m_match) { |
| 331 case CSSSelector::Id: | 329 case CSSSelector::Id: |
| 332 { | 330 { |
| 333 if (rootNode->document().containsMultipleElementsWithId(firstSel
ector->value())) | 331 if (rootNode.document().containsMultipleElementsWithId(firstSele
ctor->value())) |
| 334 break; | 332 break; |
| 335 | 333 |
| 336 // Just the same as getElementById. | 334 // Just the same as getElementById. |
| 337 Element* element = rootNode->treeScope().getElementById(firstSel
ector->value()); | 335 Element* element = rootNode.treeScope().getElementById(firstSele
ctor->value()); |
| 338 if (element && (isTreeScopeRoot(rootNode) || element->isDescenda
ntOf(rootNode))) | 336 if (element && (isTreeScopeRoot(rootNode) || element->isDescenda
ntOf(&rootNode))) |
| 339 matchedElements.append(element); | 337 matchedElements.append(element); |
| 340 return; | 338 return; |
| 341 } | 339 } |
| 342 case CSSSelector::Class: | 340 case CSSSelector::Class: |
| 343 return collectElementsByClassName(rootNode, firstSelector->value(),
matchedElements); | 341 return collectElementsByClassName(rootNode, firstSelector->value(),
matchedElements); |
| 344 case CSSSelector::Tag: | 342 case CSSSelector::Tag: |
| 345 return collectElementsByTagName(rootNode, firstSelector->tagQName(),
matchedElements); | 343 return collectElementsByTagName(rootNode, firstSelector->tagQName(),
matchedElements); |
| 346 default: | 344 default: |
| 347 break; // If we need another fast path, add here. | 345 break; // If we need another fast path, add here. |
| 348 } | 346 } |
| 349 } | 347 } |
| 350 | 348 |
| 351 bool matchTraverseRoots; | 349 bool matchTraverseRoots; |
| 352 OwnPtr<SimpleNodeList> traverseRoots = findTraverseRoots(rootNode, matchTrav
erseRoots); | 350 OwnPtr<SimpleNodeList> traverseRoots = findTraverseRoots(&rootNode, matchTra
verseRoots); |
| 353 if (traverseRoots->isEmpty()) | 351 if (traverseRoots->isEmpty()) |
| 354 return; | 352 return; |
| 355 | 353 |
| 356 const SelectorData& selector = m_selectors[0]; | 354 const SelectorData& selector = m_selectors[0]; |
| 357 if (matchTraverseRoots) { | 355 if (matchTraverseRoots) { |
| 358 while (!traverseRoots->isEmpty()) { | 356 while (!traverseRoots->isEmpty()) { |
| 359 Node* node = traverseRoots->next(); | 357 Node& node = *traverseRoots->next(); |
| 360 Element* element = toElement(node); | 358 Element& element = toElement(node); |
| 361 if (selectorMatches(selector, element, rootNode)) | 359 if (selectorMatches(selector, element, rootNode)) |
| 362 matchedElements.append(element); | 360 matchedElements.append(&element); |
| 363 } | 361 } |
| 364 return; | 362 return; |
| 365 } | 363 } |
| 366 | 364 |
| 367 while (!traverseRoots->isEmpty()) { | 365 while (!traverseRoots->isEmpty()) { |
| 368 Node* traverseRoot = traverseRoots->next(); | 366 Node* traverseRoot = traverseRoots->next(); |
| 369 for (Element* element = ElementTraversal::firstWithin(traverseRoot); ele
ment; element = ElementTraversal::next(element, traverseRoot)) { | 367 for (Element* element = ElementTraversal::firstWithin(traverseRoot); ele
ment; element = ElementTraversal::next(element, traverseRoot)) { |
| 370 if (selectorMatches(selector, element, rootNode)) | 368 if (selectorMatches(selector, *element, rootNode)) |
| 371 matchedElements.append(element); | 369 matchedElements.append(element); |
| 372 } | 370 } |
| 373 } | 371 } |
| 374 } | 372 } |
| 375 | 373 |
| 376 // If matchTraverseRoot is true, the returned Node is the single Element that ma
y match the selector query. | 374 // If matchTraverseRoot is true, the returned Node is the single Element that ma
y match the selector query. |
| 377 // | 375 // |
| 378 // If matchTraverseRoot is false, the returned Node is the rootNode parameter or
a descendant of rootNode representing | 376 // If matchTraverseRoot is false, the returned Node is the rootNode parameter or
a descendant of rootNode representing |
| 379 // the subtree for which we can limit the querySelector traversal. | 377 // the subtree for which we can limit the querySelector traversal. |
| 380 // | 378 // |
| 381 // The returned Node may be 0, regardless of matchTraverseRoot, if this method f
inds that the selectors won't | 379 // The returned Node may be 0, regardless of matchTraverseRoot, if this method f
inds that the selectors won't |
| 382 // match any element. | 380 // match any element. |
| 383 Node* SelectorDataList::findTraverseRoot(Node* rootNode, bool& matchTraverseRoot
) const | 381 Node* SelectorDataList::findTraverseRoot(Node& rootNode, bool& matchTraverseRoot
) const |
| 384 { | 382 { |
| 385 // We need to return the matches in document order. To use id lookup while t
here is possiblity of multiple matches | 383 // We need to return the matches in document order. To use id lookup while t
here is possiblity of multiple matches |
| 386 // we would need to sort the results. For now, just traverse the document in
that case. | 384 // we would need to sort the results. For now, just traverse the document in
that case. |
| 387 ASSERT(rootNode); | |
| 388 ASSERT(m_selectors.size() == 1); | 385 ASSERT(m_selectors.size() == 1); |
| 389 ASSERT(m_selectors[0].selector); | 386 ASSERT(m_selectors[0].selector); |
| 390 | 387 |
| 391 bool matchSingleNode = true; | 388 bool matchSingleNode = true; |
| 392 bool startFromParent = false; | 389 bool startFromParent = false; |
| 393 for (const CSSSelector* selector = m_selectors[0].selector; selector; select
or = selector->tagHistory()) { | 390 for (const CSSSelector* selector = m_selectors[0].selector; selector; select
or = selector->tagHistory()) { |
| 394 if (selector->m_match == CSSSelector::Id && !rootNode->document().contai
nsMultipleElementsWithId(selector->value())) { | 391 if (selector->m_match == CSSSelector::Id && !rootNode.document().contain
sMultipleElementsWithId(selector->value())) { |
| 395 Element* element = rootNode->treeScope().getElementById(selector->va
lue()); | 392 Element* element = rootNode.treeScope().getElementById(selector->val
ue()); |
| 396 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf
(rootNode))) | 393 Node* adjustedRootNode = &rootNode; |
| 397 rootNode = element; | 394 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf
(&rootNode))) |
| 395 adjustedRootNode = element; |
| 398 else if (!element || matchSingleNode) | 396 else if (!element || matchSingleNode) |
| 399 rootNode = 0; | 397 adjustedRootNode = 0; |
| 400 if (matchSingleNode) { | 398 if (matchSingleNode) { |
| 401 matchTraverseRoot = true; | 399 matchTraverseRoot = true; |
| 402 return rootNode; | 400 return adjustedRootNode; |
| 403 } | 401 } |
| 404 if (startFromParent && rootNode) | 402 if (startFromParent && adjustedRootNode) |
| 405 rootNode = rootNode->parentNode(); | 403 adjustedRootNode = adjustedRootNode->parentNode(); |
| 406 matchTraverseRoot = false; | 404 matchTraverseRoot = false; |
| 407 return rootNode; | 405 return adjustedRootNode; |
| 408 } | 406 } |
| 409 if (selector->relation() == CSSSelector::SubSelector) | 407 if (selector->relation() == CSSSelector::SubSelector) |
| 410 continue; | 408 continue; |
| 411 matchSingleNode = false; | 409 matchSingleNode = false; |
| 412 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel
ation() == CSSSelector::IndirectAdjacent) | 410 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel
ation() == CSSSelector::IndirectAdjacent) |
| 413 startFromParent = true; | 411 startFromParent = true; |
| 414 else | 412 else |
| 415 startFromParent = false; | 413 startFromParent = false; |
| 416 } | 414 } |
| 417 matchTraverseRoot = false; | 415 matchTraverseRoot = false; |
| 418 return rootNode; | 416 return &rootNode; |
| 419 } | 417 } |
| 420 | 418 |
| 421 Element* SelectorDataList::executeSlowQueryFirst(Node* rootNode) const | 419 Element* SelectorDataList::executeSlowQueryFirst(Node& rootNode) const |
| 422 { | 420 { |
| 423 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el
ement = ElementTraversal::next(element, rootNode)) { | 421 for (Element* element = ElementTraversal::firstWithin(&rootNode); element; e
lement = ElementTraversal::next(element, &rootNode)) { |
| 424 for (unsigned i = 0; i < m_selectors.size(); ++i) { | 422 for (unsigned i = 0; i < m_selectors.size(); ++i) { |
| 425 if (selectorMatches(m_selectors[i], element, rootNode)) | 423 if (selectorMatches(m_selectors[i], *element, rootNode)) |
| 426 return element; | 424 return element; |
| 427 } | 425 } |
| 428 } | 426 } |
| 429 return 0; | 427 return 0; |
| 430 } | 428 } |
| 431 | 429 |
| 432 Element* SelectorDataList::executeQueryFirst(Node* rootNode) const | 430 Element* SelectorDataList::executeQueryFirst(Node& rootNode) const |
| 433 { | 431 { |
| 434 if (!canUseFastQuery(rootNode)) | 432 if (!canUseFastQuery(rootNode)) |
| 435 return executeSlowQueryFirst(rootNode); | 433 return executeSlowQueryFirst(rootNode); |
| 436 | 434 |
| 437 | 435 |
| 438 const CSSSelector* selector = m_selectors[0].selector; | 436 const CSSSelector* selector = m_selectors[0].selector; |
| 439 ASSERT(selector); | 437 ASSERT(selector); |
| 440 | 438 |
| 441 if (!selector->tagHistory()) { | 439 if (!selector->tagHistory()) { |
| 442 // Fast path for querySelector('#id'), querySelector('.foo'), and queryS
elector('div'). | 440 // Fast path for querySelector('#id'), querySelector('.foo'), and queryS
elector('div'). |
| 443 // Many web developers uses querySelector with these simple selectors. | 441 // Many web developers uses querySelector with these simple selectors. |
| 444 switch (selector->m_match) { | 442 switch (selector->m_match) { |
| 445 case CSSSelector::Id: | 443 case CSSSelector::Id: |
| 446 { | 444 { |
| 447 if (rootNode->document().containsMultipleElementsWithId(selector
->value())) | 445 if (rootNode.document().containsMultipleElementsWithId(selector-
>value())) |
| 448 break; | 446 break; |
| 449 Element* element = rootNode->treeScope().getElementById(selector
->value()); | 447 Element* element = rootNode.treeScope().getElementById(selector-
>value()); |
| 450 return element && (isTreeScopeRoot(rootNode) || element->isDesce
ndantOf(rootNode)) ? element : 0; | 448 return element && (isTreeScopeRoot(rootNode) || element->isDesce
ndantOf(&rootNode)) ? element : 0; |
| 451 } | 449 } |
| 452 case CSSSelector::Class: | 450 case CSSSelector::Class: |
| 453 return findElementByClassName(rootNode, selector->value()); | 451 return findElementByClassName(rootNode, selector->value()); |
| 454 case CSSSelector::Tag: | 452 case CSSSelector::Tag: |
| 455 return findElementByTagName(rootNode, selector->tagQName()); | 453 return findElementByTagName(rootNode, selector->tagQName()); |
| 456 default: | 454 default: |
| 457 break; // If we need another fast path, add here. | 455 break; // If we need another fast path, add here. |
| 458 } | 456 } |
| 459 } | 457 } |
| 460 | 458 |
| 461 bool matchTraverseRoot; | 459 bool matchTraverseRoot; |
| 462 Node* traverseRootNode = findTraverseRoot(rootNode, matchTraverseRoot); | 460 Node* traverseRootNode = findTraverseRoot(rootNode, matchTraverseRoot); |
| 463 if (!traverseRootNode) | 461 if (!traverseRootNode) |
| 464 return 0; | 462 return 0; |
| 465 if (matchTraverseRoot) { | 463 if (matchTraverseRoot) { |
| 466 ASSERT(m_selectors.size() == 1); | 464 ASSERT(m_selectors.size() == 1); |
| 467 ASSERT(traverseRootNode->isElementNode()); | 465 ASSERT(traverseRootNode->isElementNode()); |
| 468 Element* element = toElement(traverseRootNode); | 466 Element& element = toElement(*traverseRootNode); |
| 469 return selectorMatches(m_selectors[0], element, rootNode) ? element : 0; | 467 return selectorMatches(m_selectors[0], element, rootNode) ? &element : 0
; |
| 470 } | 468 } |
| 471 | 469 |
| 472 for (Element* element = ElementTraversal::firstWithin(traverseRootNode); ele
ment; element = ElementTraversal::next(element, traverseRootNode)) { | 470 for (Element* element = ElementTraversal::firstWithin(traverseRootNode); ele
ment; element = ElementTraversal::next(element, traverseRootNode)) { |
| 473 if (selectorMatches(m_selectors[0], element, rootNode)) | 471 if (selectorMatches(m_selectors[0], *element, rootNode)) |
| 474 return element; | 472 return element; |
| 475 } | 473 } |
| 476 return 0; | 474 return 0; |
| 477 } | 475 } |
| 478 | 476 |
| 479 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList) | 477 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList) |
| 480 : m_selectorList(selectorList) | 478 : m_selectorList(selectorList) |
| 481 { | 479 { |
| 482 m_selectors.initialize(m_selectorList); | 480 m_selectors.initialize(m_selectorList); |
| 483 } | 481 } |
| 484 | 482 |
| 485 bool SelectorQuery::matches(Element* element) const | 483 bool SelectorQuery::matches(Element& element) const |
| 486 { | 484 { |
| 487 return m_selectors.matches(element); | 485 return m_selectors.matches(element); |
| 488 } | 486 } |
| 489 | 487 |
| 490 PassRefPtr<NodeList> SelectorQuery::queryAll(Node* rootNode) const | 488 PassRefPtr<NodeList> SelectorQuery::queryAll(Node& rootNode) const |
| 491 { | 489 { |
| 492 return m_selectors.queryAll(rootNode); | 490 return m_selectors.queryAll(rootNode); |
| 493 } | 491 } |
| 494 | 492 |
| 495 PassRefPtr<Element> SelectorQuery::queryFirst(Node* rootNode) const | 493 PassRefPtr<Element> SelectorQuery::queryFirst(Node& rootNode) const |
| 496 { | 494 { |
| 497 return m_selectors.queryFirst(rootNode); | 495 return m_selectors.queryFirst(rootNode); |
| 498 } | 496 } |
| 499 | 497 |
| 500 SelectorQuery* SelectorQueryCache::add(const AtomicString& selectors, const Docu
ment& document, ExceptionState& es) | 498 SelectorQuery* SelectorQueryCache::add(const AtomicString& selectors, const Docu
ment& document, ExceptionState& es) |
| 501 { | 499 { |
| 502 HashMap<AtomicString, OwnPtr<SelectorQuery> >::iterator it = m_entries.find(
selectors); | 500 HashMap<AtomicString, OwnPtr<SelectorQuery> >::iterator it = m_entries.find(
selectors); |
| 503 if (it != m_entries.end()) | 501 if (it != m_entries.end()) |
| 504 return it->value.get(); | 502 return it->value.get(); |
| 505 | 503 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 527 m_entries.add(selectors, selectorQuery.release()); | 525 m_entries.add(selectors, selectorQuery.release()); |
| 528 return rawSelectorQuery; | 526 return rawSelectorQuery; |
| 529 } | 527 } |
| 530 | 528 |
| 531 void SelectorQueryCache::invalidate() | 529 void SelectorQueryCache::invalidate() |
| 532 { | 530 { |
| 533 m_entries.clear(); | 531 m_entries.clear(); |
| 534 } | 532 } |
| 535 | 533 |
| 536 } | 534 } |
| OLD | NEW |