Chromium Code Reviews| 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 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 301 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el ement = ElementTraversal::next(*element, &rootNode)) { | 301 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el ement = ElementTraversal::next(*element, &rootNode)) { |
| 302 for (unsigned i = 0; i < m_selectors.size(); ++i) { | 302 for (unsigned i = 0; i < m_selectors.size(); ++i) { |
| 303 if (selectorMatches(m_selectors[i], *element, rootNode)) { | 303 if (selectorMatches(m_selectors[i], *element, rootNode)) { |
| 304 matchedElements.append(element); | 304 matchedElements.append(element); |
| 305 break; | 305 break; |
| 306 } | 306 } |
| 307 } | 307 } |
| 308 } | 308 } |
| 309 } | 309 } |
| 310 | 310 |
| 311 const CSSSelector* SelectorDataList::selectorForIdLookup(const CSSSelector* firs tSelector) const | |
| 312 { | |
| 313 for (const CSSSelector* selector = firstSelector; selector; selector = selec tor->tagHistory()) { | |
| 314 if (selector->m_match == CSSSelector::Id) | |
| 315 return selector; | |
| 316 if (selector->relation() != CSSSelector::SubSelector) | |
| 317 break; | |
| 318 } | |
| 319 return 0; | |
| 320 } | |
| 321 | |
| 311 void SelectorDataList::executeQueryAll(Node& rootNode, Vector<RefPtr<Node> >& ma tchedElements) const | 322 void SelectorDataList::executeQueryAll(Node& rootNode, Vector<RefPtr<Node> >& ma tchedElements) const |
| 312 { | 323 { |
| 313 if (!canUseFastQuery(rootNode)) | 324 if (!canUseFastQuery(rootNode)) |
| 314 return executeSlowQueryAll(rootNode, matchedElements); | 325 return executeSlowQueryAll(rootNode, matchedElements); |
| 315 | 326 |
| 316 ASSERT(m_selectors.size() == 1); | 327 ASSERT(m_selectors.size() == 1); |
| 317 ASSERT(m_selectors[0].selector); | 328 ASSERT(m_selectors[0].selector); |
| 318 | 329 |
| 319 const CSSSelector* firstSelector = m_selectors[0].selector; | 330 const SelectorData& selector = m_selectors[0]; |
| 331 const CSSSelector* firstSelector = selector.selector; | |
| 332 | |
| 333 // Fast path for querySelectorAll('#id'), querySelectorAll('tag#id'). | |
| 334 if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { | |
| 335 const AtomicString& idToMatch = idSelector->value(); | |
| 336 if (UNLIKELY(rootNode.treeScope().containsMultipleElementsWithId(idToMat ch))) { | |
| 337 const Vector<Element*>* elements = rootNode.treeScope().getAllElemen tsById(idToMatch); | |
| 338 ASSERT(elements); | |
| 339 size_t count = elements->size(); | |
| 340 for (size_t i = 0; i < count; ++i) { | |
| 341 Element* element = elements->at(i); | |
| 342 ASSERT(element); | |
| 343 if (selectorMatches(selector, *element, rootNode)) | |
| 344 matchedElements.append(element); | |
| 345 } | |
| 346 return; | |
| 347 } | |
| 348 Element* element = rootNode.treeScope().getElementById(idToMatch); | |
| 349 if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(& rootNode))) | |
| 350 return; | |
| 351 if (selectorMatches(selector, *element, rootNode)) | |
| 352 matchedElements.append(element); | |
| 353 return; | |
| 354 } | |
| 320 | 355 |
| 321 if (!firstSelector->tagHistory()) { | 356 if (!firstSelector->tagHistory()) { |
| 322 // Fast path for querySelectorAll('#id'), querySelectorAl('.foo'), and q uerySelectorAll('div'). | 357 // Fast path for querySelectorAl('.foo'), and querySelectorAll('div'). |
| 323 switch (firstSelector->m_match) { | 358 switch (firstSelector->m_match) { |
| 324 case CSSSelector::Id: | |
| 325 { | |
| 326 if (rootNode.document().containsMultipleElementsWithId(firstSele ctor->value())) | |
| 327 break; | |
| 328 | |
| 329 // Just the same as getElementById. | |
| 330 Element* element = rootNode.treeScope().getElementById(firstSele ctor->value()); | |
| 331 if (element && (isTreeScopeRoot(rootNode) || element->isDescenda ntOf(&rootNode))) | |
| 332 matchedElements.append(element); | |
| 333 return; | |
| 334 } | |
| 335 case CSSSelector::Class: | 359 case CSSSelector::Class: |
| 336 return collectElementsByClassName(rootNode, firstSelector->value(), matchedElements); | 360 return collectElementsByClassName(rootNode, firstSelector->value(), matchedElements); |
| 337 case CSSSelector::Tag: | 361 case CSSSelector::Tag: |
| 338 return collectElementsByTagName(rootNode, firstSelector->tagQName(), matchedElements); | 362 return collectElementsByTagName(rootNode, firstSelector->tagQName(), matchedElements); |
| 339 default: | 363 default: |
| 340 break; // If we need another fast path, add here. | 364 break; // If we need another fast path, add here. |
| 341 } | 365 } |
| 342 } | 366 } |
| 343 | 367 |
| 344 bool matchTraverseRoots; | 368 bool matchTraverseRoots; |
| 345 OwnPtr<SimpleNodeList> traverseRoots = findTraverseRoots(rootNode, matchTrav erseRoots); | 369 OwnPtr<SimpleNodeList> traverseRoots = findTraverseRoots(rootNode, matchTrav erseRoots); |
| 346 if (traverseRoots->isEmpty()) | 370 if (traverseRoots->isEmpty()) |
| 347 return; | 371 return; |
| 348 | 372 |
| 349 const SelectorData& selector = m_selectors[0]; | |
| 350 if (matchTraverseRoots) { | 373 if (matchTraverseRoots) { |
| 351 while (!traverseRoots->isEmpty()) { | 374 while (!traverseRoots->isEmpty()) { |
| 352 Node& node = *traverseRoots->next(); | 375 Node& node = *traverseRoots->next(); |
| 353 Element& element = toElement(node); | 376 Element& element = toElement(node); |
| 354 if (selectorMatches(selector, element, rootNode)) | 377 if (selectorMatches(selector, element, rootNode)) |
| 355 matchedElements.append(&element); | 378 matchedElements.append(&element); |
| 356 } | 379 } |
| 357 return; | 380 return; |
| 358 } | 381 } |
| 359 | 382 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 421 } | 444 } |
| 422 } | 445 } |
| 423 return 0; | 446 return 0; |
| 424 } | 447 } |
| 425 | 448 |
| 426 Element* SelectorDataList::executeQueryFirst(Node& rootNode) const | 449 Element* SelectorDataList::executeQueryFirst(Node& rootNode) const |
| 427 { | 450 { |
| 428 if (!canUseFastQuery(rootNode)) | 451 if (!canUseFastQuery(rootNode)) |
| 429 return executeSlowQueryFirst(rootNode); | 452 return executeSlowQueryFirst(rootNode); |
| 430 | 453 |
| 454 ASSERT(m_selectors.size() == 1); | |
| 455 ASSERT(m_selectors[0].selector); | |
| 431 | 456 |
| 432 const CSSSelector* selector = m_selectors[0].selector; | 457 const SelectorData& selector = m_selectors[0]; |
| 433 ASSERT(selector); | 458 const CSSSelector* firstSelector = selector.selector; |
| 434 | 459 |
| 435 if (!selector->tagHistory()) { | 460 // Fast path for querySelectorAll('#id'), querySelectorAll('tag#id'). |
| 436 // Fast path for querySelector('#id'), querySelector('.foo'), and queryS elector('div'). | 461 if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { |
| 462 const AtomicString& idToMatch = idSelector->value(); | |
| 463 if (UNLIKELY(rootNode.treeScope().containsMultipleElementsWithId(idToMat ch))) { | |
| 464 const Vector<Element*>* elements = rootNode.treeScope().getAllElemen tsById(idToMatch); | |
| 465 ASSERT(elements); | |
| 466 size_t count = elements->size(); | |
| 467 for (size_t i = 0; i < count; ++i) { | |
| 468 Element* element = elements->at(i); | |
| 469 ASSERT(element); | |
| 470 if (selectorMatches(selector, *element, rootNode)) | |
| 471 return element; | |
| 472 } | |
| 473 return 0; | |
| 474 } | |
| 475 Element* element = rootNode.treeScope().getElementById(idToMatch); | |
| 476 if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(& rootNode))) | |
| 477 return 0; | |
| 478 return selectorMatches(selector, *element, rootNode) ? element : 0; | |
|
esprehn
2013/12/02 20:38:04
Woah looks like copy pasta?
Inactive
2013/12/02 20:47:26
Yes, SelectorDataList::executeQueryFirst() and Sel
| |
| 479 } | |
| 480 | |
| 481 if (!firstSelector->tagHistory()) { | |
| 482 // Fast path for querySelector('.foo'), and querySelector('div'). | |
| 437 // Many web developers uses querySelector with these simple selectors. | 483 // Many web developers uses querySelector with these simple selectors. |
| 438 switch (selector->m_match) { | 484 switch (firstSelector->m_match) { |
| 439 case CSSSelector::Id: | |
| 440 { | |
| 441 if (rootNode.document().containsMultipleElementsWithId(selector- >value())) | |
| 442 break; | |
| 443 Element* element = rootNode.treeScope().getElementById(selector- >value()); | |
| 444 return element && (isTreeScopeRoot(rootNode) || element->isDesce ndantOf(&rootNode)) ? element : 0; | |
| 445 } | |
| 446 case CSSSelector::Class: | 485 case CSSSelector::Class: |
| 447 return findElementByClassName(rootNode, selector->value()); | 486 return findElementByClassName(rootNode, firstSelector->value()); |
| 448 case CSSSelector::Tag: | 487 case CSSSelector::Tag: |
| 449 return findElementByTagName(rootNode, selector->tagQName()); | 488 return findElementByTagName(rootNode, firstSelector->tagQName()); |
| 450 default: | 489 default: |
| 451 break; // If we need another fast path, add here. | 490 break; // If we need another fast path, add here. |
| 452 } | 491 } |
| 453 } | 492 } |
| 454 | 493 |
| 455 bool matchTraverseRoot; | 494 bool matchTraverseRoot; |
| 456 Node* traverseRootNode = findTraverseRoot(rootNode, matchTraverseRoot); | 495 Node* traverseRootNode = findTraverseRoot(rootNode, matchTraverseRoot); |
| 457 if (!traverseRootNode) | 496 if (!traverseRootNode) |
| 458 return 0; | 497 return 0; |
| 459 if (matchTraverseRoot) { | 498 if (matchTraverseRoot) { |
| 460 ASSERT(m_selectors.size() == 1); | |
| 461 ASSERT(traverseRootNode->isElementNode()); | 499 ASSERT(traverseRootNode->isElementNode()); |
| 462 Element& element = toElement(*traverseRootNode); | 500 Element& element = toElement(*traverseRootNode); |
| 463 return selectorMatches(m_selectors[0], element, rootNode) ? &element : 0 ; | 501 return selectorMatches(selector, element, rootNode) ? &element : 0; |
| 464 } | 502 } |
| 465 | 503 |
| 466 for (Element* element = ElementTraversal::firstWithin(*traverseRootNode); el ement; element = ElementTraversal::next(*element, traverseRootNode)) { | 504 for (Element* element = ElementTraversal::firstWithin(*traverseRootNode); el ement; element = ElementTraversal::next(*element, traverseRootNode)) { |
| 467 if (selectorMatches(m_selectors[0], *element, rootNode)) | 505 if (selectorMatches(selector, *element, rootNode)) |
| 468 return element; | 506 return element; |
| 469 } | 507 } |
| 470 return 0; | 508 return 0; |
| 471 } | 509 } |
| 472 | 510 |
| 473 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList) | 511 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList) |
| 474 : m_selectorList(selectorList) | 512 : m_selectorList(selectorList) |
| 475 { | 513 { |
| 476 m_selectors.initialize(m_selectorList); | 514 m_selectors.initialize(m_selectorList); |
| 477 } | 515 } |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 521 m_entries.add(selectors, selectorQuery.release()); | 559 m_entries.add(selectors, selectorQuery.release()); |
| 522 return rawSelectorQuery; | 560 return rawSelectorQuery; |
| 523 } | 561 } |
| 524 | 562 |
| 525 void SelectorQueryCache::invalidate() | 563 void SelectorQueryCache::invalidate() |
| 526 { | 564 { |
| 527 m_entries.clear(); | 565 m_entries.clear(); |
| 528 } | 566 } |
| 529 | 567 |
| 530 } | 568 } |
| OLD | NEW |