| OLD | NEW |
| 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 27 matching lines...) Expand all Loading... |
| 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 "wtf/PtrUtil.h" | 42 #include "wtf/PtrUtil.h" |
| 43 | 43 |
| 44 namespace blink { | 44 namespace blink { |
| 45 | 45 |
| 46 using namespace HTMLNames; | 46 using namespace HTMLNames; |
| 47 | 47 |
| 48 #if DCHECK_IS_ON() |
| 49 static SelectorQuery::QueryStats& currentQueryStats() { |
| 50 DEFINE_STATIC_LOCAL(SelectorQuery::QueryStats, stats, ()); |
| 51 return stats; |
| 52 } |
| 53 |
| 54 SelectorQuery::QueryStats SelectorQuery::lastQueryStats() { |
| 55 return currentQueryStats(); |
| 56 } |
| 57 |
| 58 #define QUERY_STATS_INCREMENT(name) \ |
| 59 (void)(currentQueryStats().totalCount++, currentQueryStats().name++); |
| 60 #define QUERY_STATS_RESET() (void)(currentQueryStats() = {}); |
| 61 |
| 62 #else |
| 63 |
| 64 #define QUERY_STATS_INCREMENT(name) |
| 65 #define QUERY_STATS_RESET() |
| 66 |
| 67 #endif |
| 68 |
| 48 struct SingleElementSelectorQueryTrait { | 69 struct SingleElementSelectorQueryTrait { |
| 49 typedef Element* OutputType; | 70 typedef Element* OutputType; |
| 50 static const bool shouldOnlyMatchFirstElement = true; | 71 static const bool shouldOnlyMatchFirstElement = true; |
| 51 ALWAYS_INLINE static void appendElement(OutputType& output, | 72 ALWAYS_INLINE static void appendElement(OutputType& output, |
| 52 Element& element) { | 73 Element& element) { |
| 53 DCHECK(!output); | 74 DCHECK(!output); |
| 54 output = &element; | 75 output = &element; |
| 55 } | 76 } |
| 56 }; | 77 }; |
| 57 | 78 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 77 init.mode = SelectorChecker::QueryingRules; | 98 init.mode = SelectorChecker::QueryingRules; |
| 78 SelectorChecker checker(init); | 99 SelectorChecker checker(init); |
| 79 SelectorChecker::SelectorCheckingContext context( | 100 SelectorChecker::SelectorCheckingContext context( |
| 80 &element, SelectorChecker::VisitedMatchDisabled); | 101 &element, SelectorChecker::VisitedMatchDisabled); |
| 81 context.selector = &selector; | 102 context.selector = &selector; |
| 82 context.scope = &rootNode; | 103 context.scope = &rootNode; |
| 83 return checker.match(context); | 104 return checker.match(context); |
| 84 } | 105 } |
| 85 | 106 |
| 86 bool SelectorQuery::matches(Element& targetElement) const { | 107 bool SelectorQuery::matches(Element& targetElement) const { |
| 108 QUERY_STATS_RESET(); |
| 87 if (m_needsUpdatedDistribution) | 109 if (m_needsUpdatedDistribution) |
| 88 targetElement.updateDistribution(); | 110 targetElement.updateDistribution(); |
| 89 return selectorListMatches(targetElement, targetElement); | 111 return selectorListMatches(targetElement, targetElement); |
| 90 } | 112 } |
| 91 | 113 |
| 92 Element* SelectorQuery::closest(Element& targetElement) const { | 114 Element* SelectorQuery::closest(Element& targetElement) const { |
| 115 QUERY_STATS_RESET(); |
| 93 if (m_selectors.isEmpty()) | 116 if (m_selectors.isEmpty()) |
| 94 return nullptr; | 117 return nullptr; |
| 95 if (m_needsUpdatedDistribution) | 118 if (m_needsUpdatedDistribution) |
| 96 targetElement.updateDistribution(); | 119 targetElement.updateDistribution(); |
| 97 | 120 |
| 98 for (Element* currentElement = &targetElement; currentElement; | 121 for (Element* currentElement = &targetElement; currentElement; |
| 99 currentElement = currentElement->parentElement()) { | 122 currentElement = currentElement->parentElement()) { |
| 100 if (selectorListMatches(targetElement, *currentElement)) | 123 if (selectorListMatches(targetElement, *currentElement)) |
| 101 return currentElement; | 124 return currentElement; |
| 102 } | 125 } |
| 103 return nullptr; | 126 return nullptr; |
| 104 } | 127 } |
| 105 | 128 |
| 106 StaticElementList* SelectorQuery::queryAll(ContainerNode& rootNode) const { | 129 StaticElementList* SelectorQuery::queryAll(ContainerNode& rootNode) const { |
| 130 QUERY_STATS_RESET(); |
| 107 NthIndexCache nthIndexCache(rootNode.document()); | 131 NthIndexCache nthIndexCache(rootNode.document()); |
| 108 HeapVector<Member<Element>> result; | 132 HeapVector<Member<Element>> result; |
| 109 execute<AllElementsSelectorQueryTrait>(rootNode, result); | 133 execute<AllElementsSelectorQueryTrait>(rootNode, result); |
| 110 return StaticElementList::adopt(result); | 134 return StaticElementList::adopt(result); |
| 111 } | 135 } |
| 112 | 136 |
| 113 Element* SelectorQuery::queryFirst(ContainerNode& rootNode) const { | 137 Element* SelectorQuery::queryFirst(ContainerNode& rootNode) const { |
| 138 QUERY_STATS_RESET(); |
| 114 NthIndexCache nthIndexCache(rootNode.document()); | 139 NthIndexCache nthIndexCache(rootNode.document()); |
| 115 Element* matchedElement = nullptr; | 140 Element* matchedElement = nullptr; |
| 116 execute<SingleElementSelectorQueryTrait>(rootNode, matchedElement); | 141 execute<SingleElementSelectorQueryTrait>(rootNode, matchedElement); |
| 117 return matchedElement; | 142 return matchedElement; |
| 118 } | 143 } |
| 119 | 144 |
| 120 template <typename SelectorQueryTrait> | 145 template <typename SelectorQueryTrait> |
| 121 static void collectElementsByClassName( | 146 static void collectElementsByClassName( |
| 122 ContainerNode& rootNode, | 147 ContainerNode& rootNode, |
| 123 const AtomicString& className, | 148 const AtomicString& className, |
| 124 const CSSSelector* selector, | 149 const CSSSelector* selector, |
| 125 typename SelectorQueryTrait::OutputType& output) { | 150 typename SelectorQueryTrait::OutputType& output) { |
| 126 for (Element& element : ElementTraversal::descendantsOf(rootNode)) { | 151 for (Element& element : ElementTraversal::descendantsOf(rootNode)) { |
| 152 QUERY_STATS_INCREMENT(fastClass); |
| 127 if (!hasClassName(element, className)) | 153 if (!hasClassName(element, className)) |
| 128 continue; | 154 continue; |
| 129 if (selector && !selectorMatches(*selector, element, rootNode)) | 155 if (selector && !selectorMatches(*selector, element, rootNode)) |
| 130 continue; | 156 continue; |
| 131 SelectorQueryTrait::appendElement(output, element); | 157 SelectorQueryTrait::appendElement(output, element); |
| 132 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) | 158 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) |
| 133 return; | 159 return; |
| 134 } | 160 } |
| 135 } | 161 } |
| 136 | 162 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 149 return false; | 175 return false; |
| 150 } | 176 } |
| 151 | 177 |
| 152 template <typename SelectorQueryTrait> | 178 template <typename SelectorQueryTrait> |
| 153 static void collectElementsByTagName( | 179 static void collectElementsByTagName( |
| 154 ContainerNode& rootNode, | 180 ContainerNode& rootNode, |
| 155 const QualifiedName& tagName, | 181 const QualifiedName& tagName, |
| 156 typename SelectorQueryTrait::OutputType& output) { | 182 typename SelectorQueryTrait::OutputType& output) { |
| 157 DCHECK_EQ(tagName.namespaceURI(), starAtom); | 183 DCHECK_EQ(tagName.namespaceURI(), starAtom); |
| 158 for (Element& element : ElementTraversal::descendantsOf(rootNode)) { | 184 for (Element& element : ElementTraversal::descendantsOf(rootNode)) { |
| 185 QUERY_STATS_INCREMENT(fastTagName); |
| 159 if (matchesTagName(tagName, element)) { | 186 if (matchesTagName(tagName, element)) { |
| 160 SelectorQueryTrait::appendElement(output, element); | 187 SelectorQueryTrait::appendElement(output, element); |
| 161 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) | 188 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) |
| 162 return; | 189 return; |
| 163 } | 190 } |
| 164 } | 191 } |
| 165 } | 192 } |
| 166 | 193 |
| 167 inline bool SelectorQuery::canUseFastQuery( | 194 inline bool SelectorQuery::canUseFastQuery( |
| 168 const ContainerNode& rootNode) const { | 195 const ContainerNode& rootNode) const { |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 template <typename SelectorQueryTrait> | 296 template <typename SelectorQueryTrait> |
| 270 void SelectorQuery::executeForTraverseRoot( | 297 void SelectorQuery::executeForTraverseRoot( |
| 271 ContainerNode& traverseRoot, | 298 ContainerNode& traverseRoot, |
| 272 ContainerNode& rootNode, | 299 ContainerNode& rootNode, |
| 273 typename SelectorQueryTrait::OutputType& output) const { | 300 typename SelectorQueryTrait::OutputType& output) const { |
| 274 DCHECK_EQ(m_selectors.size(), 1u); | 301 DCHECK_EQ(m_selectors.size(), 1u); |
| 275 | 302 |
| 276 const CSSSelector& selector = *m_selectors[0]; | 303 const CSSSelector& selector = *m_selectors[0]; |
| 277 | 304 |
| 278 for (Element& element : ElementTraversal::descendantsOf(traverseRoot)) { | 305 for (Element& element : ElementTraversal::descendantsOf(traverseRoot)) { |
| 306 QUERY_STATS_INCREMENT(fastScan); |
| 279 if (selectorMatches(selector, element, rootNode)) { | 307 if (selectorMatches(selector, element, rootNode)) { |
| 280 SelectorQueryTrait::appendElement(output, element); | 308 SelectorQueryTrait::appendElement(output, element); |
| 281 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) | 309 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) |
| 282 return; | 310 return; |
| 283 } | 311 } |
| 284 } | 312 } |
| 285 } | 313 } |
| 286 | 314 |
| 287 bool SelectorQuery::selectorListMatches(ContainerNode& rootNode, | 315 bool SelectorQuery::selectorListMatches(ContainerNode& rootNode, |
| 288 Element& element) const { | 316 Element& element) const { |
| 289 for (const auto& selector : m_selectors) { | 317 for (const auto& selector : m_selectors) { |
| 290 if (selectorMatches(*selector, element, rootNode)) | 318 if (selectorMatches(*selector, element, rootNode)) |
| 291 return true; | 319 return true; |
| 292 } | 320 } |
| 293 return false; | 321 return false; |
| 294 } | 322 } |
| 295 | 323 |
| 296 template <typename SelectorQueryTrait> | 324 template <typename SelectorQueryTrait> |
| 297 void SelectorQuery::executeSlow( | 325 void SelectorQuery::executeSlow( |
| 298 ContainerNode& rootNode, | 326 ContainerNode& rootNode, |
| 299 typename SelectorQueryTrait::OutputType& output) const { | 327 typename SelectorQueryTrait::OutputType& output) const { |
| 300 for (Element& element : ElementTraversal::descendantsOf(rootNode)) { | 328 for (Element& element : ElementTraversal::descendantsOf(rootNode)) { |
| 329 QUERY_STATS_INCREMENT(slowScan); |
| 301 if (!selectorListMatches(rootNode, element)) | 330 if (!selectorListMatches(rootNode, element)) |
| 302 continue; | 331 continue; |
| 303 SelectorQueryTrait::appendElement(output, element); | 332 SelectorQueryTrait::appendElement(output, element); |
| 304 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) | 333 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) |
| 305 return; | 334 return; |
| 306 } | 335 } |
| 307 } | 336 } |
| 308 | 337 |
| 309 // FIXME: Move the following helper functions, authorShadowRootOf, | 338 // FIXME: Move the following helper functions, authorShadowRootOf, |
| 310 // firstWithinTraversingShadowTree, nextTraversingShadowTree to the best place, | 339 // firstWithinTraversingShadowTree, nextTraversingShadowTree to the best place, |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 351 } | 380 } |
| 352 | 381 |
| 353 template <typename SelectorQueryTrait> | 382 template <typename SelectorQueryTrait> |
| 354 void SelectorQuery::executeSlowTraversingShadowTree( | 383 void SelectorQuery::executeSlowTraversingShadowTree( |
| 355 ContainerNode& rootNode, | 384 ContainerNode& rootNode, |
| 356 typename SelectorQueryTrait::OutputType& output) const { | 385 typename SelectorQueryTrait::OutputType& output) const { |
| 357 for (ContainerNode* node = nextTraversingShadowTree(rootNode, &rootNode); | 386 for (ContainerNode* node = nextTraversingShadowTree(rootNode, &rootNode); |
| 358 node; node = nextTraversingShadowTree(*node, &rootNode)) { | 387 node; node = nextTraversingShadowTree(*node, &rootNode)) { |
| 359 if (!node->isElementNode()) | 388 if (!node->isElementNode()) |
| 360 continue; | 389 continue; |
| 390 QUERY_STATS_INCREMENT(slowTraversingShadowTreeScan); |
| 361 Element* element = toElement(node); | 391 Element* element = toElement(node); |
| 362 if (!selectorListMatches(rootNode, *element)) | 392 if (!selectorListMatches(rootNode, *element)) |
| 363 continue; | 393 continue; |
| 364 SelectorQueryTrait::appendElement(output, *element); | 394 SelectorQueryTrait::appendElement(output, *element); |
| 365 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) | 395 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) |
| 366 return; | 396 return; |
| 367 } | 397 } |
| 368 } | 398 } |
| 369 | 399 |
| 370 static const CSSSelector* selectorForIdLookup( | 400 static const CSSSelector* selectorForIdLookup( |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 // Fast path for querySelector*('#id'), querySelector*('tag#id'), | 442 // Fast path for querySelector*('#id'), querySelector*('tag#id'), |
| 413 // querySelector*('tag[id=example]'). | 443 // querySelector*('tag[id=example]'). |
| 414 if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { | 444 if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { |
| 415 const AtomicString& idToMatch = idSelector->value(); | 445 const AtomicString& idToMatch = idSelector->value(); |
| 416 if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) { | 446 if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) { |
| 417 const HeapVector<Member<Element>>& elements = | 447 const HeapVector<Member<Element>>& elements = |
| 418 rootNode.treeScope().getAllElementsById(idToMatch); | 448 rootNode.treeScope().getAllElementsById(idToMatch); |
| 419 for (const auto& element : elements) { | 449 for (const auto& element : elements) { |
| 420 if (!element->isDescendantOf(&rootNode)) | 450 if (!element->isDescendantOf(&rootNode)) |
| 421 continue; | 451 continue; |
| 452 QUERY_STATS_INCREMENT(fastId); |
| 422 if (selectorMatches(selector, *element, rootNode)) { | 453 if (selectorMatches(selector, *element, rootNode)) { |
| 423 SelectorQueryTrait::appendElement(output, *element); | 454 SelectorQueryTrait::appendElement(output, *element); |
| 424 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) | 455 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) |
| 425 return; | 456 return; |
| 426 } | 457 } |
| 427 } | 458 } |
| 428 return; | 459 return; |
| 429 } | 460 } |
| 430 Element* element = rootNode.treeScope().getElementById(idToMatch); | 461 Element* element = rootNode.treeScope().getElementById(idToMatch); |
| 431 if (!element) | 462 if (!element) |
| 432 return; | 463 return; |
| 433 if (!element->isDescendantOf(&rootNode)) | 464 if (!element->isDescendantOf(&rootNode)) |
| 434 return; | 465 return; |
| 466 QUERY_STATS_INCREMENT(fastId); |
| 435 if (selectorMatches(selector, *element, rootNode)) | 467 if (selectorMatches(selector, *element, rootNode)) |
| 436 SelectorQueryTrait::appendElement(output, *element); | 468 SelectorQueryTrait::appendElement(output, *element); |
| 437 return; | 469 return; |
| 438 } | 470 } |
| 439 | 471 |
| 440 if (!firstSelector.tagHistory()) { | 472 if (!firstSelector.tagHistory()) { |
| 441 // Fast path for querySelector*('.foo'), and querySelector*('div'). | 473 // Fast path for querySelector*('.foo'), and querySelector*('div'). |
| 442 switch (firstSelector.match()) { | 474 switch (firstSelector.match()) { |
| 443 case CSSSelector::Class: | 475 case CSSSelector::Class: |
| 444 collectElementsByClassName<SelectorQueryTrait>( | 476 collectElementsByClassName<SelectorQueryTrait>( |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 return m_entries | 549 return m_entries |
| 518 .insert(selectors, SelectorQuery::adopt(std::move(selectorList))) | 550 .insert(selectors, SelectorQuery::adopt(std::move(selectorList))) |
| 519 .storedValue->value.get(); | 551 .storedValue->value.get(); |
| 520 } | 552 } |
| 521 | 553 |
| 522 void SelectorQueryCache::invalidate() { | 554 void SelectorQueryCache::invalidate() { |
| 523 m_entries.clear(); | 555 m_entries.clear(); |
| 524 } | 556 } |
| 525 | 557 |
| 526 } // namespace blink | 558 } // namespace blink |
| OLD | NEW |