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 |