Chromium Code Reviews| 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 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 220 return false; | 220 return false; |
| 221 | 221 |
| 222 for (Element* element = &toElement(rootNode); element; | 222 for (Element* element = &toElement(rootNode); element; |
| 223 element = element->parentElement()) { | 223 element = element->parentElement()) { |
| 224 if (element->hasClass() && element->classNames().contains(className)) | 224 if (element->hasClass() && element->classNames().contains(className)) |
| 225 return true; | 225 return true; |
| 226 } | 226 } |
| 227 return false; | 227 return false; |
| 228 } | 228 } |
| 229 | 229 |
| 230 // If returns true, traversalRoots has the elements that may match the selector | |
| 231 // query. | |
| 232 // | |
| 233 // If returns false, traversalRoots has the rootNode parameter or descendants of | |
| 234 // rootNode representing the subtree for which we can limit the querySelector | |
| 235 // traversal. | |
| 236 // | |
| 237 // The travseralRoots may be empty, regardless of the returned bool value, if | |
| 238 // this method finds that the selectors won't match any element. | |
|
esprehn
2017/03/23 01:09:33
This comment was ancient, from when we used to ret
sashab
2017/03/23 05:40:21
Wanna add an updated comment to explain how it wor
esprehn
2017/03/23 05:48:51
I'd prefer to do that in a separate patch.
| |
| 239 template <typename SelectorQueryTrait> | 230 template <typename SelectorQueryTrait> |
| 240 void SelectorQuery::findTraverseRootsAndExecute( | 231 void SelectorQuery::findTraverseRootsAndExecute( |
| 241 ContainerNode& rootNode, | 232 ContainerNode& rootNode, |
| 242 typename SelectorQueryTrait::OutputType& output) const { | 233 typename SelectorQueryTrait::OutputType& output) const { |
| 243 // We need to return the matches in document order. To use id lookup while | 234 // We need to return the matches in document order. To use id lookup while |
| 244 // there is possiblity of multiple matches we would need to sort the | 235 // there is possiblity of multiple matches we would need to sort the |
| 245 // results. For now, just traverse the document in that case. | 236 // results. For now, just traverse the document in that case. |
| 246 DCHECK_EQ(m_selectors.size(), 1u); | 237 DCHECK_EQ(m_selectors.size(), 1u); |
| 247 | 238 |
| 248 bool isRightmostSelector = true; | 239 bool isRightmostSelector = true; |
| 249 bool startFromParent = false; | 240 bool startFromParent = false; |
| 250 | 241 |
| 251 for (const CSSSelector* selector = m_selectors[0]; selector; | 242 for (const CSSSelector* selector = m_selectors[0]; selector; |
| 252 selector = selector->tagHistory()) { | 243 selector = selector->tagHistory()) { |
| 253 if (selector->match() == CSSSelector::Id && rootNode.isInTreeScope() && | 244 if (selector->match() == CSSSelector::Id && rootNode.isInTreeScope() && |
| 254 !rootNode.containingTreeScope().containsMultipleElementsWithId( | 245 !rootNode.containingTreeScope().containsMultipleElementsWithId( |
| 255 selector->value())) { | 246 selector->value())) { |
| 256 Element* element = | 247 Element* element = |
| 257 rootNode.containingTreeScope().getElementById(selector->value()); | 248 rootNode.containingTreeScope().getElementById(selector->value()); |
| 258 ContainerNode* adjustedNode = &rootNode; | 249 ContainerNode* adjustedNode = &rootNode; |
| 259 if (element && | 250 if (element && |
| 260 (isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode))) | 251 (isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode))) |
| 261 adjustedNode = element; | 252 adjustedNode = element; |
| 262 else if (!element || isRightmostSelector) | 253 else if (!element || isRightmostSelector) |
| 263 adjustedNode = nullptr; | 254 adjustedNode = nullptr; |
| 264 if (isRightmostSelector) { | 255 if (isRightmostSelector) { |
| 265 executeForTraverseRoot<SelectorQueryTrait>( | 256 if (!adjustedNode) |
| 266 *m_selectors[0], adjustedNode, MatchesTraverseRoots, rootNode, | 257 return; |
| 267 output); | 258 element = toElement(adjustedNode); |
| 259 if (selectorMatches(*m_selectors[0], *element, rootNode)) | |
| 260 SelectorQueryTrait::appendElement(output, *element); | |
|
sashab
2017/03/23 06:26:32
I don't really understand this part of the change,
esprehn
2017/03/23 06:31:58
The code used to pass MatchedTraverseRoot as the e
sashab
2017/03/23 23:19:05
Can you remove it from the function then? Do other
esprehn
2017/03/24 00:02:31
I did remove it from that function. There's a anot
| |
| 268 return; | 261 return; |
| 269 } | 262 } |
| 270 | 263 |
| 271 if (startFromParent && adjustedNode) | 264 if (startFromParent && adjustedNode) |
| 272 adjustedNode = adjustedNode->parentNode(); | 265 adjustedNode = adjustedNode->parentNode(); |
| 273 | 266 |
| 274 executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], adjustedNode, | 267 executeForTraverseRoot<SelectorQueryTrait>(adjustedNode, rootNode, |
| 275 DoesNotMatchTraverseRoots, | 268 output); |
| 276 rootNode, output); | |
| 277 return; | 269 return; |
| 278 } | 270 } |
| 279 | 271 |
| 280 // If we have both CSSSelector::Id and CSSSelector::Class at the same time, | 272 // If we have both CSSSelector::Id and CSSSelector::Class at the same time, |
| 281 // we should use Id to find traverse root. | 273 // we should use Id to find traverse root. |
| 282 if (!SelectorQueryTrait::shouldOnlyMatchFirstElement && !startFromParent && | 274 if (!SelectorQueryTrait::shouldOnlyMatchFirstElement && !startFromParent && |
| 283 selector->match() == CSSSelector::Class) { | 275 selector->match() == CSSSelector::Class) { |
| 284 if (isRightmostSelector) { | 276 if (isRightmostSelector) { |
| 285 ClassElementList<AllElements> traverseRoots(rootNode, | 277 ClassElementList<AllElements> traverseRoots(rootNode, |
| 286 selector->value()); | 278 selector->value()); |
| 287 executeForTraverseRoots<SelectorQueryTrait>( | 279 executeForTraverseRoots<SelectorQueryTrait>( |
| 288 *m_selectors[0], traverseRoots, MatchesTraverseRoots, rootNode, | 280 traverseRoots, MatchesTraverseRoots, rootNode, output); |
| 289 output); | |
| 290 return; | 281 return; |
| 291 } | 282 } |
| 292 // Since there exists some ancestor element which has the class name, we | 283 // Since there exists some ancestor element which has the class name, we |
| 293 // need to see all children of rootNode. | 284 // need to see all children of rootNode. |
| 294 if (ancestorHasClassName(rootNode, selector->value())) { | 285 if (ancestorHasClassName(rootNode, selector->value())) { |
| 295 executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], &rootNode, | 286 executeForTraverseRoot<SelectorQueryTrait>(&rootNode, rootNode, output); |
| 296 DoesNotMatchTraverseRoots, | |
| 297 rootNode, output); | |
| 298 return; | 287 return; |
| 299 } | 288 } |
| 300 | 289 |
| 301 ClassElementList<OnlyRoots> traverseRoots(rootNode, selector->value()); | 290 ClassElementList<OnlyRoots> traverseRoots(rootNode, selector->value()); |
| 302 executeForTraverseRoots<SelectorQueryTrait>( | 291 executeForTraverseRoots<SelectorQueryTrait>( |
| 303 *m_selectors[0], traverseRoots, DoesNotMatchTraverseRoots, rootNode, | 292 traverseRoots, DoesNotMatchTraverseRoots, rootNode, output); |
| 304 output); | |
| 305 return; | 293 return; |
| 306 } | 294 } |
| 307 | 295 |
| 308 if (selector->relation() == CSSSelector::SubSelector) | 296 if (selector->relation() == CSSSelector::SubSelector) |
| 309 continue; | 297 continue; |
| 310 isRightmostSelector = false; | 298 isRightmostSelector = false; |
| 311 if (selector->relation() == CSSSelector::DirectAdjacent || | 299 if (selector->relation() == CSSSelector::DirectAdjacent || |
| 312 selector->relation() == CSSSelector::IndirectAdjacent) | 300 selector->relation() == CSSSelector::IndirectAdjacent) |
| 313 startFromParent = true; | 301 startFromParent = true; |
| 314 else | 302 else |
| 315 startFromParent = false; | 303 startFromParent = false; |
| 316 } | 304 } |
| 317 | 305 |
| 318 executeForTraverseRoot<SelectorQueryTrait>( | 306 executeForTraverseRoot<SelectorQueryTrait>(&rootNode, rootNode, output); |
| 319 *m_selectors[0], &rootNode, DoesNotMatchTraverseRoots, rootNode, output); | |
| 320 } | 307 } |
| 321 | 308 |
| 322 template <typename SelectorQueryTrait> | 309 template <typename SelectorQueryTrait> |
| 323 void SelectorQuery::executeForTraverseRoot( | 310 void SelectorQuery::executeForTraverseRoot( |
| 324 const CSSSelector& selector, | |
| 325 ContainerNode* traverseRoot, | 311 ContainerNode* traverseRoot, |
| 326 MatchTraverseRootState matchTraverseRoot, | |
| 327 ContainerNode& rootNode, | 312 ContainerNode& rootNode, |
| 328 typename SelectorQueryTrait::OutputType& output) const { | 313 typename SelectorQueryTrait::OutputType& output) const { |
| 314 DCHECK_EQ(m_selectors.size(), 1u); | |
| 315 | |
| 329 if (!traverseRoot) | 316 if (!traverseRoot) |
| 330 return; | 317 return; |
| 331 | 318 const CSSSelector& selector = *m_selectors[0]; |
| 332 if (matchTraverseRoot) { | |
| 333 if (selectorMatches(selector, toElement(*traverseRoot), rootNode)) | |
| 334 SelectorQueryTrait::appendElement(output, toElement(*traverseRoot)); | |
| 335 return; | |
| 336 } | |
| 337 | 319 |
| 338 for (Element& element : ElementTraversal::descendantsOf(*traverseRoot)) { | 320 for (Element& element : ElementTraversal::descendantsOf(*traverseRoot)) { |
| 339 if (selectorMatches(selector, element, rootNode)) { | 321 if (selectorMatches(selector, element, rootNode)) { |
| 340 SelectorQueryTrait::appendElement(output, element); | 322 SelectorQueryTrait::appendElement(output, element); |
| 341 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) | 323 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) |
| 342 return; | 324 return; |
| 343 } | 325 } |
| 344 } | 326 } |
| 345 } | 327 } |
| 346 | 328 |
| 347 template <typename SelectorQueryTrait, typename SimpleElementListType> | 329 template <typename SelectorQueryTrait, typename SimpleElementListType> |
| 348 void SelectorQuery::executeForTraverseRoots( | 330 void SelectorQuery::executeForTraverseRoots( |
| 349 const CSSSelector& selector, | |
| 350 SimpleElementListType& traverseRoots, | 331 SimpleElementListType& traverseRoots, |
| 351 MatchTraverseRootState matchTraverseRoots, | 332 MatchTraverseRootState matchTraverseRoots, |
| 352 ContainerNode& rootNode, | 333 ContainerNode& rootNode, |
| 353 typename SelectorQueryTrait::OutputType& output) const { | 334 typename SelectorQueryTrait::OutputType& output) const { |
| 335 DCHECK_EQ(m_selectors.size(), 1u); | |
| 336 | |
| 354 if (traverseRoots.isEmpty()) | 337 if (traverseRoots.isEmpty()) |
| 355 return; | 338 return; |
| 356 | 339 |
| 340 const CSSSelector& selector = *m_selectors[0]; | |
| 341 | |
| 357 if (matchTraverseRoots) { | 342 if (matchTraverseRoots) { |
| 358 while (!traverseRoots.isEmpty()) { | 343 while (!traverseRoots.isEmpty()) { |
| 359 Element& element = *traverseRoots.next(); | 344 Element& element = *traverseRoots.next(); |
| 360 if (selectorMatches(selector, element, rootNode)) { | 345 if (selectorMatches(selector, element, rootNode)) { |
| 361 SelectorQueryTrait::appendElement(output, element); | 346 SelectorQueryTrait::appendElement(output, element); |
| 362 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) | 347 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) |
| 363 return; | 348 return; |
| 364 } | 349 } |
| 365 } | 350 } |
| 366 return; | 351 return; |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 620 return m_entries | 605 return m_entries |
| 621 .insert(selectors, SelectorQuery::adopt(std::move(selectorList))) | 606 .insert(selectors, SelectorQuery::adopt(std::move(selectorList))) |
| 622 .storedValue->value.get(); | 607 .storedValue->value.get(); |
| 623 } | 608 } |
| 624 | 609 |
| 625 void SelectorQueryCache::invalidate() { | 610 void SelectorQueryCache::invalidate() { |
| 626 m_entries.clear(); | 611 m_entries.clear(); |
| 627 } | 612 } |
| 628 | 613 |
| 629 } // namespace blink | 614 } // namespace blink |
| OLD | NEW |