| 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 12 matching lines...) Expand all Loading... |
| 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 */ | 25 */ |
| 26 | 26 |
| 27 #include "config.h" | 27 #include "config.h" |
| 28 #include "core/dom/SelectorQuery.h" | 28 #include "core/dom/SelectorQuery.h" |
| 29 | 29 |
| 30 #include "bindings/v8/ExceptionState.h" | 30 #include "bindings/v8/ExceptionState.h" |
| 31 #include "core/css/parser/BisonCSSParser.h" | 31 #include "core/css/parser/BisonCSSParser.h" |
| 32 #include "core/css/SelectorChecker.h" | 32 #include "core/css/SelectorChecker.h" |
| 33 #include "core/css/SelectorCheckerFastPath.h" | |
| 34 #include "core/css/SiblingTraversalStrategies.h" | 33 #include "core/css/SiblingTraversalStrategies.h" |
| 35 #include "core/dom/Document.h" | 34 #include "core/dom/Document.h" |
| 36 #include "core/dom/ElementTraversal.h" | 35 #include "core/dom/ElementTraversal.h" |
| 37 #include "core/dom/Node.h" | 36 #include "core/dom/Node.h" |
| 38 #include "core/dom/StaticNodeList.h" | 37 #include "core/dom/StaticNodeList.h" |
| 39 #include "core/dom/shadow/ElementShadow.h" | 38 #include "core/dom/shadow/ElementShadow.h" |
| 40 #include "core/dom/shadow/ShadowRoot.h" | 39 #include "core/dom/shadow/ShadowRoot.h" |
| 41 | 40 |
| 42 namespace WebCore { | 41 namespace WebCore { |
| 43 | 42 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 ASSERT(m_selectors.isEmpty()); | 102 ASSERT(m_selectors.isEmpty()); |
| 104 | 103 |
| 105 unsigned selectorCount = 0; | 104 unsigned selectorCount = 0; |
| 106 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(*selector)) | 105 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(*selector)) |
| 107 selectorCount++; | 106 selectorCount++; |
| 108 | 107 |
| 109 m_crossesTreeBoundary = false; | 108 m_crossesTreeBoundary = false; |
| 110 m_selectors.reserveInitialCapacity(selectorCount); | 109 m_selectors.reserveInitialCapacity(selectorCount); |
| 111 unsigned index = 0; | 110 unsigned index = 0; |
| 112 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(*selector), ++index) { | 111 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(*selector), ++index) { |
| 113 m_selectors.uncheckedAppend(SelectorData(*selector, SelectorCheckerFastP
ath::canUse(*selector))); | 112 m_selectors.uncheckedAppend(selector); |
| 114 m_crossesTreeBoundary |= selectorList.hasCombinatorCrossingTreeBoundaryA
t(index); | 113 m_crossesTreeBoundary |= selectorList.hasCombinatorCrossingTreeBoundaryA
t(index); |
| 115 } | 114 } |
| 116 } | 115 } |
| 117 | 116 |
| 118 inline bool SelectorDataList::selectorMatches(const SelectorData& selectorData,
Element& element, const ContainerNode& rootNode) const | 117 inline bool SelectorDataList::selectorMatches(const CSSSelector& selector, Eleme
nt& element, const ContainerNode& rootNode) const |
| 119 { | 118 { |
| 120 if (selectorData.isFastCheckable && !element.isSVGElement()) { | |
| 121 SelectorCheckerFastPath selectorCheckerFastPath(selectorData.selector, e
lement); | |
| 122 if (!selectorCheckerFastPath.matchesRightmostSelector(SelectorChecker::V
isitedMatchDisabled)) | |
| 123 return false; | |
| 124 return selectorCheckerFastPath.matches(); | |
| 125 } | |
| 126 | |
| 127 SelectorChecker selectorChecker(element.document(), SelectorChecker::Queryin
gRules); | 119 SelectorChecker selectorChecker(element.document(), SelectorChecker::Queryin
gRules); |
| 128 SelectorChecker::SelectorCheckingContext selectorCheckingContext(selectorDat
a.selector, &element, SelectorChecker::VisitedMatchDisabled); | 120 SelectorChecker::SelectorCheckingContext selectorCheckingContext(selector, &
element, SelectorChecker::VisitedMatchDisabled); |
| 129 selectorCheckingContext.behaviorAtBoundary = SelectorChecker::StaysWithinTre
eScope; | 121 selectorCheckingContext.behaviorAtBoundary = SelectorChecker::StaysWithinTre
eScope; |
| 130 selectorCheckingContext.scope = !rootNode.isDocumentNode() ? &rootNode : 0; | 122 selectorCheckingContext.scope = !rootNode.isDocumentNode() ? &rootNode : 0; |
| 131 return selectorChecker.match(selectorCheckingContext, DOMSiblingTraversalStr
ategy()) == SelectorChecker::SelectorMatches; | 123 return selectorChecker.match(selectorCheckingContext, DOMSiblingTraversalStr
ategy()) == SelectorChecker::SelectorMatches; |
| 132 } | 124 } |
| 133 | 125 |
| 134 bool SelectorDataList::matches(Element& targetElement) const | 126 bool SelectorDataList::matches(Element& targetElement) const |
| 135 { | 127 { |
| 136 unsigned selectorCount = m_selectors.size(); | 128 unsigned selectorCount = m_selectors.size(); |
| 137 for (unsigned i = 0; i < selectorCount; ++i) { | 129 for (unsigned i = 0; i < selectorCount; ++i) { |
| 138 if (selectorMatches(m_selectors[i], targetElement, targetElement)) | 130 if (selectorMatches(*m_selectors[i], targetElement, targetElement)) |
| 139 return true; | 131 return true; |
| 140 } | 132 } |
| 141 | 133 |
| 142 return false; | 134 return false; |
| 143 } | 135 } |
| 144 | 136 |
| 145 PassRefPtr<NodeList> SelectorDataList::queryAll(ContainerNode& rootNode) const | 137 PassRefPtr<NodeList> SelectorDataList::queryAll(ContainerNode& rootNode) const |
| 146 { | 138 { |
| 147 Vector<RefPtr<Node> > result; | 139 Vector<RefPtr<Node> > result; |
| 148 execute<AllElementsSelectorQueryTrait>(rootNode, result); | 140 execute<AllElementsSelectorQueryTrait>(rootNode, result); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 template <typename SelectorQueryTrait> | 200 template <typename SelectorQueryTrait> |
| 209 void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type
name SelectorQueryTrait::OutputType& output) const | 201 void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type
name SelectorQueryTrait::OutputType& output) const |
| 210 { | 202 { |
| 211 // We need to return the matches in document order. To use id lookup while t
here is possiblity of multiple matches | 203 // We need to return the matches in document order. To use id lookup while t
here is possiblity of multiple matches |
| 212 // we would need to sort the results. For now, just traverse the document in
that case. | 204 // we would need to sort the results. For now, just traverse the document in
that case. |
| 213 ASSERT(m_selectors.size() == 1); | 205 ASSERT(m_selectors.size() == 1); |
| 214 | 206 |
| 215 bool isRightmostSelector = true; | 207 bool isRightmostSelector = true; |
| 216 bool startFromParent = false; | 208 bool startFromParent = false; |
| 217 | 209 |
| 218 for (const CSSSelector* selector = &m_selectors[0].selector; selector; selec
tor = selector->tagHistory()) { | 210 for (const CSSSelector* selector = m_selectors[0]; selector; selector = sele
ctor->tagHistory()) { |
| 219 if (selector->m_match == CSSSelector::Id && !rootNode.document().contain
sMultipleElementsWithId(selector->value())) { | 211 if (selector->m_match == CSSSelector::Id && !rootNode.document().contain
sMultipleElementsWithId(selector->value())) { |
| 220 Element* element = rootNode.treeScope().getElementById(selector->val
ue()); | 212 Element* element = rootNode.treeScope().getElementById(selector->val
ue()); |
| 221 ContainerNode* adjustedNode = &rootNode; | 213 ContainerNode* adjustedNode = &rootNode; |
| 222 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf
(&rootNode))) | 214 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf
(&rootNode))) |
| 223 adjustedNode = element; | 215 adjustedNode = element; |
| 224 else if (!element || isRightmostSelector) | 216 else if (!element || isRightmostSelector) |
| 225 adjustedNode = 0; | 217 adjustedNode = 0; |
| 226 if (isRightmostSelector) { | 218 if (isRightmostSelector) { |
| 227 executeForTraverseRoot<SelectorQueryTrait>(m_selectors[0], adjus
tedNode, MatchesTraverseRoots, rootNode, output); | 219 executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], adju
stedNode, MatchesTraverseRoots, rootNode, output); |
| 228 return; | 220 return; |
| 229 } | 221 } |
| 230 | 222 |
| 231 if (startFromParent && adjustedNode) | 223 if (startFromParent && adjustedNode) |
| 232 adjustedNode = adjustedNode->parentNode(); | 224 adjustedNode = adjustedNode->parentNode(); |
| 233 | 225 |
| 234 executeForTraverseRoot<SelectorQueryTrait>(m_selectors[0], adjustedN
ode, DoesNotMatchTraverseRoots, rootNode, output); | 226 executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], adjusted
Node, DoesNotMatchTraverseRoots, rootNode, output); |
| 235 return; | 227 return; |
| 236 } | 228 } |
| 237 | 229 |
| 238 // If we have both CSSSelector::Id and CSSSelector::Class at the same ti
me, we should use Id | 230 // If we have both CSSSelector::Id and CSSSelector::Class at the same ti
me, we should use Id |
| 239 // to find traverse root. | 231 // to find traverse root. |
| 240 if (!SelectorQueryTrait::shouldOnlyMatchFirstElement && !startFromParent
&& selector->m_match == CSSSelector::Class) { | 232 if (!SelectorQueryTrait::shouldOnlyMatchFirstElement && !startFromParent
&& selector->m_match == CSSSelector::Class) { |
| 241 if (isRightmostSelector) { | 233 if (isRightmostSelector) { |
| 242 ClassElementList<AllElements> traverseRoots(rootNode, selector->
value()); | 234 ClassElementList<AllElements> traverseRoots(rootNode, selector->
value()); |
| 243 executeForTraverseRoots<SelectorQueryTrait>(m_selectors[0], trav
erseRoots, MatchesTraverseRoots, rootNode, output); | 235 executeForTraverseRoots<SelectorQueryTrait>(*m_selectors[0], tra
verseRoots, MatchesTraverseRoots, rootNode, output); |
| 244 return; | 236 return; |
| 245 } | 237 } |
| 246 // Since there exists some ancestor element which has the class name
, we need to see all children of rootNode. | 238 // Since there exists some ancestor element which has the class name
, we need to see all children of rootNode. |
| 247 if (ancestorHasClassName(rootNode, selector->value())) { | 239 if (ancestorHasClassName(rootNode, selector->value())) { |
| 248 executeForTraverseRoot<SelectorQueryTrait>(m_selectors[0], &root
Node, DoesNotMatchTraverseRoots, rootNode, output); | 240 executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], &roo
tNode, DoesNotMatchTraverseRoots, rootNode, output); |
| 249 return; | 241 return; |
| 250 } | 242 } |
| 251 | 243 |
| 252 ClassElementList<OnlyRoots> traverseRoots(rootNode, selector->value(
)); | 244 ClassElementList<OnlyRoots> traverseRoots(rootNode, selector->value(
)); |
| 253 executeForTraverseRoots<SelectorQueryTrait>(m_selectors[0], traverse
Roots, DoesNotMatchTraverseRoots, rootNode, output); | 245 executeForTraverseRoots<SelectorQueryTrait>(*m_selectors[0], travers
eRoots, DoesNotMatchTraverseRoots, rootNode, output); |
| 254 return; | 246 return; |
| 255 } | 247 } |
| 256 | 248 |
| 257 if (selector->relation() == CSSSelector::SubSelector) | 249 if (selector->relation() == CSSSelector::SubSelector) |
| 258 continue; | 250 continue; |
| 259 isRightmostSelector = false; | 251 isRightmostSelector = false; |
| 260 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel
ation() == CSSSelector::IndirectAdjacent) | 252 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel
ation() == CSSSelector::IndirectAdjacent) |
| 261 startFromParent = true; | 253 startFromParent = true; |
| 262 else | 254 else |
| 263 startFromParent = false; | 255 startFromParent = false; |
| 264 } | 256 } |
| 265 | 257 |
| 266 executeForTraverseRoot<SelectorQueryTrait>(m_selectors[0], &rootNode, DoesNo
tMatchTraverseRoots, rootNode, output); | 258 executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], &rootNode, DoesN
otMatchTraverseRoots, rootNode, output); |
| 267 } | 259 } |
| 268 | 260 |
| 269 template <typename SelectorQueryTrait> | 261 template <typename SelectorQueryTrait> |
| 270 void SelectorDataList::executeForTraverseRoot(const SelectorData& selector, Cont
ainerNode* traverseRoot, MatchTraverseRootState matchTraverseRoot, ContainerNode
& rootNode, typename SelectorQueryTrait::OutputType& output) const | 262 void SelectorDataList::executeForTraverseRoot(const CSSSelector& selector, Conta
inerNode* traverseRoot, MatchTraverseRootState matchTraverseRoot, ContainerNode&
rootNode, typename SelectorQueryTrait::OutputType& output) const |
| 271 { | 263 { |
| 272 if (!traverseRoot) | 264 if (!traverseRoot) |
| 273 return; | 265 return; |
| 274 | 266 |
| 275 if (matchTraverseRoot) { | 267 if (matchTraverseRoot) { |
| 276 if (selectorMatches(selector, toElement(*traverseRoot), rootNode)) | 268 if (selectorMatches(selector, toElement(*traverseRoot), rootNode)) |
| 277 SelectorQueryTrait::appendElement(output, toElement(*traverseRoot)); | 269 SelectorQueryTrait::appendElement(output, toElement(*traverseRoot)); |
| 278 return; | 270 return; |
| 279 } | 271 } |
| 280 | 272 |
| 281 for (Element* element = ElementTraversal::firstWithin(*traverseRoot); elemen
t; element = ElementTraversal::next(*element, traverseRoot)) { | 273 for (Element* element = ElementTraversal::firstWithin(*traverseRoot); elemen
t; element = ElementTraversal::next(*element, traverseRoot)) { |
| 282 if (selectorMatches(selector, *element, rootNode)) { | 274 if (selectorMatches(selector, *element, rootNode)) { |
| 283 SelectorQueryTrait::appendElement(output, *element); | 275 SelectorQueryTrait::appendElement(output, *element); |
| 284 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) | 276 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) |
| 285 return; | 277 return; |
| 286 } | 278 } |
| 287 } | 279 } |
| 288 } | 280 } |
| 289 | 281 |
| 290 template <typename SelectorQueryTrait, typename SimpleElementListType> | 282 template <typename SelectorQueryTrait, typename SimpleElementListType> |
| 291 void SelectorDataList::executeForTraverseRoots(const SelectorData& selector, Sim
pleElementListType& traverseRoots, MatchTraverseRootState matchTraverseRoots, Co
ntainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const | 283 void SelectorDataList::executeForTraverseRoots(const CSSSelector& selector, Simp
leElementListType& traverseRoots, MatchTraverseRootState matchTraverseRoots, Con
tainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const |
| 292 { | 284 { |
| 293 if (traverseRoots.isEmpty()) | 285 if (traverseRoots.isEmpty()) |
| 294 return; | 286 return; |
| 295 | 287 |
| 296 if (matchTraverseRoots) { | 288 if (matchTraverseRoots) { |
| 297 while (!traverseRoots.isEmpty()) { | 289 while (!traverseRoots.isEmpty()) { |
| 298 Element& element = *traverseRoots.next(); | 290 Element& element = *traverseRoots.next(); |
| 299 if (selectorMatches(selector, element, rootNode)) { | 291 if (selectorMatches(selector, element, rootNode)) { |
| 300 SelectorQueryTrait::appendElement(output, element); | 292 SelectorQueryTrait::appendElement(output, element); |
| 301 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) | 293 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) |
| (...skipping 12 matching lines...) Expand all Loading... |
| 314 return; | 306 return; |
| 315 } | 307 } |
| 316 } | 308 } |
| 317 } | 309 } |
| 318 } | 310 } |
| 319 | 311 |
| 320 template <typename SelectorQueryTrait> | 312 template <typename SelectorQueryTrait> |
| 321 bool SelectorDataList::selectorListMatches(ContainerNode& rootNode, Element& ele
ment, typename SelectorQueryTrait::OutputType& output) const | 313 bool SelectorDataList::selectorListMatches(ContainerNode& rootNode, Element& ele
ment, typename SelectorQueryTrait::OutputType& output) const |
| 322 { | 314 { |
| 323 for (unsigned i = 0; i < m_selectors.size(); ++i) { | 315 for (unsigned i = 0; i < m_selectors.size(); ++i) { |
| 324 if (selectorMatches(m_selectors[i], element, rootNode)) { | 316 if (selectorMatches(*m_selectors[i], element, rootNode)) { |
| 325 SelectorQueryTrait::appendElement(output, element); | 317 SelectorQueryTrait::appendElement(output, element); |
| 326 return true; | 318 return true; |
| 327 } | 319 } |
| 328 } | 320 } |
| 329 return false; | 321 return false; |
| 330 } | 322 } |
| 331 | 323 |
| 332 template <typename SelectorQueryTrait> | 324 template <typename SelectorQueryTrait> |
| 333 void SelectorDataList::executeSlow(ContainerNode& rootNode, typename SelectorQue
ryTrait::OutputType& output) const | 325 void SelectorDataList::executeSlow(ContainerNode& rootNode, typename SelectorQue
ryTrait::OutputType& output) const |
| 334 { | 326 { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 if (!canUseFastQuery(rootNode)) { | 405 if (!canUseFastQuery(rootNode)) { |
| 414 if (m_crossesTreeBoundary) | 406 if (m_crossesTreeBoundary) |
| 415 executeSlowTraversingShadowTree<SelectorQueryTrait>(rootNode, output
); | 407 executeSlowTraversingShadowTree<SelectorQueryTrait>(rootNode, output
); |
| 416 else | 408 else |
| 417 executeSlow<SelectorQueryTrait>(rootNode, output); | 409 executeSlow<SelectorQueryTrait>(rootNode, output); |
| 418 return; | 410 return; |
| 419 } | 411 } |
| 420 | 412 |
| 421 ASSERT(m_selectors.size() == 1); | 413 ASSERT(m_selectors.size() == 1); |
| 422 | 414 |
| 423 const SelectorData& selector = m_selectors[0]; | 415 const CSSSelector& selector = *m_selectors[0]; |
| 424 const CSSSelector& firstSelector = selector.selector; | 416 const CSSSelector& firstSelector = selector; |
| 425 | 417 |
| 426 // Fast path for querySelector*('#id'), querySelector*('tag#id'). | 418 // Fast path for querySelector*('#id'), querySelector*('tag#id'). |
| 427 if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { | 419 if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { |
| 428 const AtomicString& idToMatch = idSelector->value(); | 420 const AtomicString& idToMatch = idSelector->value(); |
| 429 if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) { | 421 if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) { |
| 430 const Vector<Element*>& elements = rootNode.treeScope().getAllElemen
tsById(idToMatch); | 422 const Vector<Element*>& elements = rootNode.treeScope().getAllElemen
tsById(idToMatch); |
| 431 size_t count = elements.size(); | 423 size_t count = elements.size(); |
| 432 for (size_t i = 0; i < count; ++i) { | 424 for (size_t i = 0; i < count; ++i) { |
| 433 Element& element = *elements[i]; | 425 Element& element = *elements[i]; |
| 434 if (!(isTreeScopeRoot(rootNode) || element.isDescendantOf(&rootN
ode))) | 426 if (!(isTreeScopeRoot(rootNode) || element.isDescendantOf(&rootN
ode))) |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 m_entries.add(selectors, selectorQuery.release()); | 509 m_entries.add(selectors, selectorQuery.release()); |
| 518 return rawSelectorQuery; | 510 return rawSelectorQuery; |
| 519 } | 511 } |
| 520 | 512 |
| 521 void SelectorQueryCache::invalidate() | 513 void SelectorQueryCache::invalidate() |
| 522 { | 514 { |
| 523 m_entries.clear(); | 515 m_entries.clear(); |
| 524 } | 516 } |
| 525 | 517 |
| 526 } | 518 } |
| OLD | NEW |