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

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: Take feedback into consideration 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 288 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698