| 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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 const AtomicString& m_className; | 94 const AtomicString& m_className; |
| 95 ContainerNode& m_rootNode; | 95 ContainerNode& m_rootNode; |
| 96 Element* m_currentElement; | 96 Element* m_currentElement; |
| 97 }; | 97 }; |
| 98 | 98 |
| 99 void SelectorDataList::initialize(const CSSSelectorList& selectorList) | 99 void SelectorDataList::initialize(const CSSSelectorList& selectorList) |
| 100 { | 100 { |
| 101 ASSERT(m_selectors.isEmpty()); | 101 ASSERT(m_selectors.isEmpty()); |
| 102 | 102 |
| 103 unsigned selectorCount = 0; | 103 unsigned selectorCount = 0; |
| 104 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(selector)) | 104 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(*selector)) |
| 105 selectorCount++; | 105 selectorCount++; |
| 106 | 106 |
| 107 m_selectors.reserveInitialCapacity(selectorCount); | 107 m_selectors.reserveInitialCapacity(selectorCount); |
| 108 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(selector)) | 108 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(*selector)) |
| 109 m_selectors.uncheckedAppend(SelectorData(selector, SelectorCheckerFastPa
th::canUse(selector))); | 109 m_selectors.uncheckedAppend(SelectorData(*selector, SelectorCheckerFastP
ath::canUse(*selector))); |
| 110 } | 110 } |
| 111 | 111 |
| 112 inline bool SelectorDataList::selectorMatches(const SelectorData& selectorData,
Element& element, const ContainerNode& rootNode) const | 112 inline bool SelectorDataList::selectorMatches(const SelectorData& selectorData,
Element& element, const ContainerNode& rootNode) const |
| 113 { | 113 { |
| 114 if (selectorData.isFastCheckable && !element.isSVGElement()) { | 114 if (selectorData.isFastCheckable && !element.isSVGElement()) { |
| 115 SelectorCheckerFastPath selectorCheckerFastPath(selectorData.selector, e
lement); | 115 SelectorCheckerFastPath selectorCheckerFastPath(selectorData.selector, e
lement); |
| 116 if (!selectorCheckerFastPath.matchesRightmostSelector(SelectorChecker::V
isitedMatchDisabled)) | 116 if (!selectorCheckerFastPath.matchesRightmostSelector(SelectorChecker::V
isitedMatchDisabled)) |
| 117 return false; | 117 return false; |
| 118 return selectorCheckerFastPath.matches(); | 118 return selectorCheckerFastPath.matches(); |
| 119 } | 119 } |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 // the subtree for which we can limit the querySelector traversal. | 198 // the subtree for which we can limit the querySelector traversal. |
| 199 // | 199 // |
| 200 // The travseralRoots may be empty, regardless of the returned bool value, if th
is method finds that the selectors won't | 200 // The travseralRoots may be empty, regardless of the returned bool value, if th
is method finds that the selectors won't |
| 201 // match any element. | 201 // match any element. |
| 202 template <typename SelectorQueryTrait> | 202 template <typename SelectorQueryTrait> |
| 203 void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type
name SelectorQueryTrait::OutputType& output) const | 203 void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type
name SelectorQueryTrait::OutputType& output) const |
| 204 { | 204 { |
| 205 // We need to return the matches in document order. To use id lookup while t
here is possiblity of multiple matches | 205 // We need to return the matches in document order. To use id lookup while t
here is possiblity of multiple matches |
| 206 // we would need to sort the results. For now, just traverse the document in
that case. | 206 // we would need to sort the results. For now, just traverse the document in
that case. |
| 207 ASSERT(m_selectors.size() == 1); | 207 ASSERT(m_selectors.size() == 1); |
| 208 ASSERT(m_selectors[0].selector); | |
| 209 | 208 |
| 210 bool isRightmostSelector = true; | 209 bool isRightmostSelector = true; |
| 211 bool startFromParent = false; | 210 bool startFromParent = false; |
| 212 | 211 |
| 213 for (const CSSSelector* selector = m_selectors[0].selector; selector; select
or = selector->tagHistory()) { | 212 for (const CSSSelector* selector = &m_selectors[0].selector; selector; selec
tor = selector->tagHistory()) { |
| 214 if (selector->m_match == CSSSelector::Id && !rootNode.document().contain
sMultipleElementsWithId(selector->value())) { | 213 if (selector->m_match == CSSSelector::Id && !rootNode.document().contain
sMultipleElementsWithId(selector->value())) { |
| 215 Element* element = rootNode.treeScope().getElementById(selector->val
ue()); | 214 Element* element = rootNode.treeScope().getElementById(selector->val
ue()); |
| 216 ContainerNode* adjustedNode = &rootNode; | 215 ContainerNode* adjustedNode = &rootNode; |
| 217 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf
(&rootNode))) | 216 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf
(&rootNode))) |
| 218 adjustedNode = element; | 217 adjustedNode = element; |
| 219 else if (!element || isRightmostSelector) | 218 else if (!element || isRightmostSelector) |
| 220 adjustedNode = 0; | 219 adjustedNode = 0; |
| 221 if (isRightmostSelector) { | 220 if (isRightmostSelector) { |
| 222 executeForTraverseRoot<SelectorQueryTrait>(m_selectors[0], adjus
tedNode, MatchesTraverseRoots, rootNode, output); | 221 executeForTraverseRoot<SelectorQueryTrait>(m_selectors[0], adjus
tedNode, MatchesTraverseRoots, rootNode, output); |
| 223 return; | 222 return; |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 322 if (selectorMatches(m_selectors[i], *element, rootNode)) { | 321 if (selectorMatches(m_selectors[i], *element, rootNode)) { |
| 323 SelectorQueryTrait::appendElement(output, *element); | 322 SelectorQueryTrait::appendElement(output, *element); |
| 324 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) | 323 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) |
| 325 return; | 324 return; |
| 326 break; | 325 break; |
| 327 } | 326 } |
| 328 } | 327 } |
| 329 } | 328 } |
| 330 } | 329 } |
| 331 | 330 |
| 332 const CSSSelector* SelectorDataList::selectorForIdLookup(const CSSSelector* firs
tSelector) const | 331 const CSSSelector* SelectorDataList::selectorForIdLookup(const CSSSelector& firs
tSelector) const |
| 333 { | 332 { |
| 334 for (const CSSSelector* selector = firstSelector; selector; selector = selec
tor->tagHistory()) { | 333 for (const CSSSelector* selector = &firstSelector; selector; selector = sele
ctor->tagHistory()) { |
| 335 if (selector->m_match == CSSSelector::Id) | 334 if (selector->m_match == CSSSelector::Id) |
| 336 return selector; | 335 return selector; |
| 337 if (selector->relation() != CSSSelector::SubSelector) | 336 if (selector->relation() != CSSSelector::SubSelector) |
| 338 break; | 337 break; |
| 339 } | 338 } |
| 340 return 0; | 339 return 0; |
| 341 } | 340 } |
| 342 | 341 |
| 343 template <typename SelectorQueryTrait> | 342 template <typename SelectorQueryTrait> |
| 344 void SelectorDataList::execute(ContainerNode& rootNode, typename SelectorQueryTr
ait::OutputType& output) const | 343 void SelectorDataList::execute(ContainerNode& rootNode, typename SelectorQueryTr
ait::OutputType& output) const |
| 345 { | 344 { |
| 346 if (!canUseFastQuery(rootNode)) { | 345 if (!canUseFastQuery(rootNode)) { |
| 347 executeSlow<SelectorQueryTrait>(rootNode, output); | 346 executeSlow<SelectorQueryTrait>(rootNode, output); |
| 348 return; | 347 return; |
| 349 } | 348 } |
| 350 | 349 |
| 351 ASSERT(m_selectors.size() == 1); | 350 ASSERT(m_selectors.size() == 1); |
| 352 ASSERT(m_selectors[0].selector); | |
| 353 | 351 |
| 354 const SelectorData& selector = m_selectors[0]; | 352 const SelectorData& selector = m_selectors[0]; |
| 355 const CSSSelector* firstSelector = selector.selector; | 353 const CSSSelector& firstSelector = selector.selector; |
| 356 | 354 |
| 357 // Fast path for querySelector*('#id'), querySelector*('tag#id'). | 355 // Fast path for querySelector*('#id'), querySelector*('tag#id'). |
| 358 if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { | 356 if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { |
| 359 const AtomicString& idToMatch = idSelector->value(); | 357 const AtomicString& idToMatch = idSelector->value(); |
| 360 if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) { | 358 if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) { |
| 361 const Vector<Element*>& elements = rootNode.treeScope().getAllElemen
tsById(idToMatch); | 359 const Vector<Element*>& elements = rootNode.treeScope().getAllElemen
tsById(idToMatch); |
| 362 size_t count = elements.size(); | 360 size_t count = elements.size(); |
| 363 for (size_t i = 0; i < count; ++i) { | 361 for (size_t i = 0; i < count; ++i) { |
| 364 Element& element = *elements[i]; | 362 Element& element = *elements[i]; |
| 365 if (!(isTreeScopeRoot(rootNode) || element.isDescendantOf(&rootN
ode))) | 363 if (!(isTreeScopeRoot(rootNode) || element.isDescendantOf(&rootN
ode))) |
| 366 continue; | 364 continue; |
| 367 if (selectorMatches(selector, element, rootNode)) { | 365 if (selectorMatches(selector, element, rootNode)) { |
| 368 SelectorQueryTrait::appendElement(output, element); | 366 SelectorQueryTrait::appendElement(output, element); |
| 369 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) | 367 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) |
| 370 return; | 368 return; |
| 371 } | 369 } |
| 372 } | 370 } |
| 373 return; | 371 return; |
| 374 } | 372 } |
| 375 Element* element = rootNode.treeScope().getElementById(idToMatch); | 373 Element* element = rootNode.treeScope().getElementById(idToMatch); |
| 376 if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(&
rootNode))) | 374 if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(&
rootNode))) |
| 377 return; | 375 return; |
| 378 if (selectorMatches(selector, *element, rootNode)) | 376 if (selectorMatches(selector, *element, rootNode)) |
| 379 SelectorQueryTrait::appendElement(output, *element); | 377 SelectorQueryTrait::appendElement(output, *element); |
| 380 return; | 378 return; |
| 381 } | 379 } |
| 382 | 380 |
| 383 if (!firstSelector->tagHistory()) { | 381 if (!firstSelector.tagHistory()) { |
| 384 // Fast path for querySelector*('.foo'), and querySelector*('div'). | 382 // Fast path for querySelector*('.foo'), and querySelector*('div'). |
| 385 switch (firstSelector->m_match) { | 383 switch (firstSelector.m_match) { |
| 386 case CSSSelector::Class: | 384 case CSSSelector::Class: |
| 387 collectElementsByClassName<SelectorQueryTrait>(rootNode, firstSelect
or->value(), output); | 385 collectElementsByClassName<SelectorQueryTrait>(rootNode, firstSelect
or.value(), output); |
| 388 return; | 386 return; |
| 389 case CSSSelector::Tag: | 387 case CSSSelector::Tag: |
| 390 collectElementsByTagName<SelectorQueryTrait>(rootNode, firstSelector
->tagQName(), output); | 388 collectElementsByTagName<SelectorQueryTrait>(rootNode, firstSelector
.tagQName(), output); |
| 391 return; | 389 return; |
| 392 default: | 390 default: |
| 393 break; // If we need another fast path, add here. | 391 break; // If we need another fast path, add here. |
| 394 } | 392 } |
| 395 } | 393 } |
| 396 | 394 |
| 397 findTraverseRootsAndExecute<SelectorQueryTrait>(rootNode, output); | 395 findTraverseRootsAndExecute<SelectorQueryTrait>(rootNode, output); |
| 398 } | 396 } |
| 399 | 397 |
| 400 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList) | 398 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList) |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 448 m_entries.add(selectors, selectorQuery.release()); | 446 m_entries.add(selectors, selectorQuery.release()); |
| 449 return rawSelectorQuery; | 447 return rawSelectorQuery; |
| 450 } | 448 } |
| 451 | 449 |
| 452 void SelectorQueryCache::invalidate() | 450 void SelectorQueryCache::invalidate() |
| 453 { | 451 { |
| 454 m_entries.clear(); | 452 m_entries.clear(); |
| 455 } | 453 } |
| 456 | 454 |
| 457 } | 455 } |
| OLD | NEW |