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