Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: Source/core/dom/SelectorQuery.cpp

Issue 92083002: Add fast path for tag#id selector queries (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698