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 |