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

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

Issue 2875673006: Allow using SelectorQuery fast paths in quirks mode and disconnected subtrees. (Closed)
Patch Set: Created 3 years, 7 months 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, 2013 Apple Inc. All rights reserved. 2 * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
3 * Copyright (C) 2014 Samsung Electronics. All rights reserved. 3 * Copyright (C) 2014 Samsung Electronics. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 8 *
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 23 matching lines...) Expand all
34 #include "core/dom/Document.h" 34 #include "core/dom/Document.h"
35 #include "core/dom/ElementTraversal.h" 35 #include "core/dom/ElementTraversal.h"
36 #include "core/dom/ExceptionCode.h" 36 #include "core/dom/ExceptionCode.h"
37 #include "core/dom/Node.h" 37 #include "core/dom/Node.h"
38 #include "core/dom/NthIndexCache.h" 38 #include "core/dom/NthIndexCache.h"
39 #include "core/dom/StaticNodeList.h" 39 #include "core/dom/StaticNodeList.h"
40 #include "core/dom/shadow/ElementShadow.h" 40 #include "core/dom/shadow/ElementShadow.h"
41 #include "core/dom/shadow/ShadowRoot.h" 41 #include "core/dom/shadow/ShadowRoot.h"
42 #include "platform/wtf/PtrUtil.h" 42 #include "platform/wtf/PtrUtil.h"
43 43
44 // Uncomment to run the SelectorQueryTests for stats in a release build.
45 // #define RELEASE_QUERY_STATS
46
44 namespace blink { 47 namespace blink {
45 48
46 using namespace HTMLNames; 49 using namespace HTMLNames;
47 50
48 #if DCHECK_IS_ON() 51 #if DCHECK_IS_ON() || defined(RELEASE_QUERY_STATS)
49 static SelectorQuery::QueryStats& CurrentQueryStats() { 52 static SelectorQuery::QueryStats& CurrentQueryStats() {
50 DEFINE_STATIC_LOCAL(SelectorQuery::QueryStats, stats, ()); 53 DEFINE_STATIC_LOCAL(SelectorQuery::QueryStats, stats, ());
51 return stats; 54 return stats;
52 } 55 }
53 56
54 SelectorQuery::QueryStats SelectorQuery::LastQueryStats() { 57 SelectorQuery::QueryStats SelectorQuery::LastQueryStats() {
55 return CurrentQueryStats(); 58 return CurrentQueryStats();
56 } 59 }
57 60
58 #define QUERY_STATS_INCREMENT(name) \ 61 #define QUERY_STATS_INCREMENT(name) \
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
190 for (Element& element : ElementTraversal::DescendantsOf(root_node)) { 193 for (Element& element : ElementTraversal::DescendantsOf(root_node)) {
191 QUERY_STATS_INCREMENT(fast_tag_name); 194 QUERY_STATS_INCREMENT(fast_tag_name);
192 if (MatchesTagName(tag_name, element)) { 195 if (MatchesTagName(tag_name, element)) {
193 SelectorQueryTrait::AppendElement(output, element); 196 SelectorQueryTrait::AppendElement(output, element);
194 if (SelectorQueryTrait::kShouldOnlyMatchFirstElement) 197 if (SelectorQueryTrait::kShouldOnlyMatchFirstElement)
195 return; 198 return;
196 } 199 }
197 } 200 }
198 } 201 }
199 202
200 inline bool SelectorQuery::CanUseFastQuery(
201 const ContainerNode& root_node) const {
202 if (uses_deep_combinator_or_shadow_pseudo_)
203 return false;
204 if (needs_updated_distribution_)
205 return false;
206 if (root_node.GetDocument().InQuirksMode())
207 return false;
208 if (!root_node.isConnected())
209 return false;
210 return selectors_.size() == 1;
211 }
212
213 inline bool AncestorHasClassName(ContainerNode& root_node, 203 inline bool AncestorHasClassName(ContainerNode& root_node,
214 const AtomicString& class_name) { 204 const AtomicString& class_name) {
215 if (!root_node.IsElementNode()) 205 if (!root_node.IsElementNode())
216 return false; 206 return false;
217 207
218 for (Element* element = &ToElement(root_node); element; 208 for (Element* element = &ToElement(root_node); element;
219 element = element->parentElement()) { 209 element = element->parentElement()) {
220 if (HasClassName(*element, class_name)) 210 if (HasClassName(*element, class_name))
221 return true; 211 return true;
222 } 212 }
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 SelectorQueryTrait::AppendElement(output, *element); 370 SelectorQueryTrait::AppendElement(output, *element);
381 if (SelectorQueryTrait::kShouldOnlyMatchFirstElement) 371 if (SelectorQueryTrait::kShouldOnlyMatchFirstElement)
382 return; 372 return;
383 } 373 }
384 } 374 }
385 375
386 template <typename SelectorQueryTrait> 376 template <typename SelectorQueryTrait>
387 void SelectorQuery::ExecuteWithId( 377 void SelectorQuery::ExecuteWithId(
388 ContainerNode& root_node, 378 ContainerNode& root_node,
389 typename SelectorQueryTrait::OutputType& output) const { 379 typename SelectorQueryTrait::OutputType& output) const {
380 DCHECK_EQ(selectors_.size(), 1u);
381 DCHECK(!root_node.GetDocument().InQuirksMode());
382
390 const CSSSelector& first_selector = *selectors_[0]; 383 const CSSSelector& first_selector = *selectors_[0];
391 const TreeScope& scope = root_node.ContainingTreeScope(); 384 const TreeScope& scope = root_node.ContainingTreeScope();
392 385
393 if (scope.ContainsMultipleElementsWithId(selector_id_)) { 386 if (scope.ContainsMultipleElementsWithId(selector_id_)) {
394 // We don't currently handle cases where there's multiple elements with the 387 // We don't currently handle cases where there's multiple elements with the
395 // id and it's not in the rightmost selector. 388 // id and it's not in the rightmost selector.
396 if (!selector_id_is_rightmost_) { 389 if (!selector_id_is_rightmost_) {
397 FindTraverseRootsAndExecute<SelectorQueryTrait>(root_node, output); 390 FindTraverseRootsAndExecute<SelectorQueryTrait>(root_node, output);
398 return; 391 return;
399 } 392 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 ExecuteForTraverseRoot<SelectorQueryTrait>(*start, root_node, output); 426 ExecuteForTraverseRoot<SelectorQueryTrait>(*start, root_node, output);
434 } 427 }
435 428
436 template <typename SelectorQueryTrait> 429 template <typename SelectorQueryTrait>
437 void SelectorQuery::Execute( 430 void SelectorQuery::Execute(
438 ContainerNode& root_node, 431 ContainerNode& root_node,
439 typename SelectorQueryTrait::OutputType& output) const { 432 typename SelectorQueryTrait::OutputType& output) const {
440 if (selectors_.IsEmpty()) 433 if (selectors_.IsEmpty())
441 return; 434 return;
442 435
443 if (!CanUseFastQuery(root_node)) { 436 if (use_slow_scan_) {
444 if (needs_updated_distribution_) 437 if (needs_updated_distribution_)
445 root_node.UpdateDistribution(); 438 root_node.UpdateDistribution();
446 if (uses_deep_combinator_or_shadow_pseudo_) { 439 if (uses_deep_combinator_or_shadow_pseudo_) {
447 ExecuteSlowTraversingShadowTree<SelectorQueryTrait>(root_node, output); 440 ExecuteSlowTraversingShadowTree<SelectorQueryTrait>(root_node, output);
448 } else { 441 } else {
449 ExecuteSlow<SelectorQueryTrait>(root_node, output); 442 ExecuteSlow<SelectorQueryTrait>(root_node, output);
450 } 443 }
451 return; 444 return;
452 } 445 }
453 446
454 DCHECK_EQ(selectors_.size(), 1u); 447 DCHECK_EQ(selectors_.size(), 1u);
455 DCHECK(!root_node.GetDocument().InQuirksMode()); 448 DCHECK(!needs_updated_distribution_);
449 DCHECK(!uses_deep_combinator_or_shadow_pseudo_);
456 450
457 if (selector_id_) { 451 // In quirks mode getElementById("a") is case sensitive and should only
452 // match elements with lowercase id "a", but querySelector is case-insensitive
453 // so querySelector("#a") == querySelector("#A"), which means we can only use
454 // the id fast path when we're in a standards mode document.
455 if (selector_id_ && root_node.IsInTreeScope() &&
456 !root_node.GetDocument().InQuirksMode()) {
458 ExecuteWithId<SelectorQueryTrait>(root_node, output); 457 ExecuteWithId<SelectorQueryTrait>(root_node, output);
459 return; 458 return;
460 } 459 }
461 460
462 const CSSSelector& first_selector = *selectors_[0]; 461 const CSSSelector& first_selector = *selectors_[0];
463 if (!first_selector.TagHistory()) { 462 if (!first_selector.TagHistory()) {
464 // Fast path for querySelector*('.foo'), and querySelector*('div'). 463 // Fast path for querySelector*('.foo'), and querySelector*('div').
465 switch (first_selector.Match()) { 464 switch (first_selector.Match()) {
466 case CSSSelector::kClass: 465 case CSSSelector::kClass:
467 CollectElementsByClassName<SelectorQueryTrait>( 466 CollectElementsByClassName<SelectorQueryTrait>(
(...skipping 21 matching lines...) Expand all
489 std::unique_ptr<SelectorQuery> SelectorQuery::Adopt( 488 std::unique_ptr<SelectorQuery> SelectorQuery::Adopt(
490 CSSSelectorList selector_list) { 489 CSSSelectorList selector_list) {
491 return WTF::WrapUnique(new SelectorQuery(std::move(selector_list))); 490 return WTF::WrapUnique(new SelectorQuery(std::move(selector_list)));
492 } 491 }
493 492
494 SelectorQuery::SelectorQuery(CSSSelectorList selector_list) 493 SelectorQuery::SelectorQuery(CSSSelectorList selector_list)
495 : selector_list_(std::move(selector_list)), 494 : selector_list_(std::move(selector_list)),
496 selector_id_is_rightmost_(true), 495 selector_id_is_rightmost_(true),
497 selector_id_affected_by_sibling_combinator_(false), 496 selector_id_affected_by_sibling_combinator_(false),
498 uses_deep_combinator_or_shadow_pseudo_(false), 497 uses_deep_combinator_or_shadow_pseudo_(false),
499 needs_updated_distribution_(false) { 498 needs_updated_distribution_(false),
499 use_slow_scan_(true) {
500 selectors_.ReserveInitialCapacity(selector_list_.ComputeLength()); 500 selectors_.ReserveInitialCapacity(selector_list_.ComputeLength());
501 for (const CSSSelector* selector = selector_list_.First(); selector; 501 for (const CSSSelector* selector = selector_list_.First(); selector;
502 selector = CSSSelectorList::Next(*selector)) { 502 selector = CSSSelectorList::Next(*selector)) {
503 if (selector->MatchesPseudoElement()) 503 if (selector->MatchesPseudoElement())
504 continue; 504 continue;
505 selectors_.UncheckedAppend(selector); 505 selectors_.UncheckedAppend(selector);
506 uses_deep_combinator_or_shadow_pseudo_ |= 506 uses_deep_combinator_or_shadow_pseudo_ |=
507 selector->HasDeepCombinatorOrShadowPseudo(); 507 selector->HasDeepCombinatorOrShadowPseudo();
508 needs_updated_distribution_ |= selector->NeedsUpdatedDistribution(); 508 needs_updated_distribution_ |= selector->NeedsUpdatedDistribution();
509 } 509 }
510 510
511 if (selectors_.size() == 1 && !uses_deep_combinator_or_shadow_pseudo_ && 511 if (selectors_.size() == 1 && !uses_deep_combinator_or_shadow_pseudo_ &&
512 !needs_updated_distribution_) { 512 !needs_updated_distribution_) {
513 use_slow_scan_ = false;
513 for (const CSSSelector* current = selectors_[0]; current; 514 for (const CSSSelector* current = selectors_[0]; current;
514 current = current->TagHistory()) { 515 current = current->TagHistory()) {
515 if (current->Match() == CSSSelector::kId) { 516 if (current->Match() == CSSSelector::kId) {
516 selector_id_ = current->Value(); 517 selector_id_ = current->Value();
517 break; 518 break;
518 } 519 }
519 // We only use the fast path when in standards mode where #id selectors 520 // We only use the fast path when in standards mode where #id selectors
520 // are case sensitive, so we need the same behavior for [id=value]. 521 // are case sensitive, so we need the same behavior for [id=value].
521 if (current->Match() == CSSSelector::kAttributeExact && 522 if (current->Match() == CSSSelector::kAttributeExact &&
522 current->Attribute() == idAttr && 523 current->Attribute() == idAttr &&
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
567 return entries_ 568 return entries_
568 .insert(selectors, SelectorQuery::Adopt(std::move(selector_list))) 569 .insert(selectors, SelectorQuery::Adopt(std::move(selector_list)))
569 .stored_value->value.get(); 570 .stored_value->value.get();
570 } 571 }
571 572
572 void SelectorQueryCache::Invalidate() { 573 void SelectorQueryCache::Invalidate() {
573 entries_.clear(); 574 entries_.clear();
574 } 575 }
575 576
576 } // namespace blink 577 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/dom/SelectorQuery.h ('k') | third_party/WebKit/Source/core/dom/SelectorQueryTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698