| 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 26 matching lines...) Expand all Loading... |
| 37 #include "core/dom/shadow/ElementShadow.h" | 37 #include "core/dom/shadow/ElementShadow.h" |
| 38 #include "core/dom/shadow/ShadowRoot.h" | 38 #include "core/dom/shadow/ShadowRoot.h" |
| 39 | 39 |
| 40 namespace blink { | 40 namespace blink { |
| 41 | 41 |
| 42 struct SingleElementSelectorQueryTrait { | 42 struct SingleElementSelectorQueryTrait { |
| 43 typedef Element* OutputType; | 43 typedef Element* OutputType; |
| 44 static const bool shouldOnlyMatchFirstElement = true; | 44 static const bool shouldOnlyMatchFirstElement = true; |
| 45 ALWAYS_INLINE static void appendElement(OutputType& output, Element& element
) | 45 ALWAYS_INLINE static void appendElement(OutputType& output, Element& element
) |
| 46 { | 46 { |
| 47 ASSERT(!output); | 47 DCHECK(!output); |
| 48 output = &element; | 48 output = &element; |
| 49 } | 49 } |
| 50 }; | 50 }; |
| 51 | 51 |
| 52 struct AllElementsSelectorQueryTrait { | 52 struct AllElementsSelectorQueryTrait { |
| 53 typedef HeapVector<Member<Element>> OutputType; | 53 typedef HeapVector<Member<Element>> OutputType; |
| 54 static const bool shouldOnlyMatchFirstElement = false; | 54 static const bool shouldOnlyMatchFirstElement = false; |
| 55 ALWAYS_INLINE static void appendElement(OutputType& output, Element& element
) | 55 ALWAYS_INLINE static void appendElement(OutputType& output, Element& element
) |
| 56 { | 56 { |
| 57 output.append(&element); | 57 output.append(&element); |
| 58 } | 58 } |
| 59 }; | 59 }; |
| 60 | 60 |
| 61 enum ClassElementListBehavior { AllElements, OnlyRoots }; | 61 enum ClassElementListBehavior { AllElements, OnlyRoots }; |
| 62 | 62 |
| 63 template <ClassElementListBehavior onlyRoots> | 63 template <ClassElementListBehavior onlyRoots> |
| 64 class ClassElementList { | 64 class ClassElementList { |
| 65 STACK_ALLOCATED(); | 65 STACK_ALLOCATED(); |
| 66 public: | 66 public: |
| 67 ClassElementList(ContainerNode& rootNode, const AtomicString& className) | 67 ClassElementList(ContainerNode& rootNode, const AtomicString& className) |
| 68 : m_className(className) | 68 : m_className(className) |
| 69 , m_rootNode(&rootNode) | 69 , m_rootNode(&rootNode) |
| 70 , m_currentElement(nextInternal(ElementTraversal::firstWithin(rootNode))
) { } | 70 , m_currentElement(nextInternal(ElementTraversal::firstWithin(rootNode))
) { } |
| 71 | 71 |
| 72 bool isEmpty() const { return !m_currentElement; } | 72 bool isEmpty() const { return !m_currentElement; } |
| 73 | 73 |
| 74 Element* next() | 74 Element* next() |
| 75 { | 75 { |
| 76 Element* current = m_currentElement; | 76 Element* current = m_currentElement; |
| 77 ASSERT(current); | 77 DCHECK(current); |
| 78 if (onlyRoots) | 78 if (onlyRoots) |
| 79 m_currentElement = nextInternal(ElementTraversal::nextSkippingChildr
en(*m_currentElement, m_rootNode)); | 79 m_currentElement = nextInternal(ElementTraversal::nextSkippingChildr
en(*m_currentElement, m_rootNode)); |
| 80 else | 80 else |
| 81 m_currentElement = nextInternal(ElementTraversal::next(*m_currentEle
ment, m_rootNode)); | 81 m_currentElement = nextInternal(ElementTraversal::next(*m_currentEle
ment, m_rootNode)); |
| 82 return current; | 82 return current; |
| 83 } | 83 } |
| 84 | 84 |
| 85 private: | 85 private: |
| 86 Element* nextInternal(Element* element) | 86 Element* nextInternal(Element* element) |
| 87 { | 87 { |
| 88 for (; element; element = ElementTraversal::next(*element, m_rootNode))
{ | 88 for (; element; element = ElementTraversal::next(*element, m_rootNode))
{ |
| 89 if (element->hasClass() && element->classNames().contains(m_classNam
e)) | 89 if (element->hasClass() && element->classNames().contains(m_classNam
e)) |
| 90 return element; | 90 return element; |
| 91 } | 91 } |
| 92 return nullptr; | 92 return nullptr; |
| 93 } | 93 } |
| 94 | 94 |
| 95 const AtomicString& m_className; | 95 const AtomicString& m_className; |
| 96 Member<ContainerNode> m_rootNode; | 96 Member<ContainerNode> m_rootNode; |
| 97 Member<Element> m_currentElement; | 97 Member<Element> m_currentElement; |
| 98 }; | 98 }; |
| 99 | 99 |
| 100 void SelectorDataList::initialize(const CSSSelectorList& selectorList) | 100 void SelectorDataList::initialize(const CSSSelectorList& selectorList) |
| 101 { | 101 { |
| 102 ASSERT(m_selectors.isEmpty()); | 102 DCHECK(m_selectors.isEmpty()); |
| 103 | 103 |
| 104 unsigned selectorCount = 0; | 104 unsigned selectorCount = 0; |
| 105 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(*selector)) | 105 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(*selector)) |
| 106 selectorCount++; | 106 selectorCount++; |
| 107 | 107 |
| 108 m_usesDeepCombinatorOrShadowPseudo = false; | 108 m_usesDeepCombinatorOrShadowPseudo = false; |
| 109 m_needsUpdatedDistribution = false; | 109 m_needsUpdatedDistribution = false; |
| 110 m_selectors.reserveInitialCapacity(selectorCount); | 110 m_selectors.reserveInitialCapacity(selectorCount); |
| 111 unsigned index = 0; | 111 unsigned index = 0; |
| 112 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(*selector), ++index) { | 112 for (const CSSSelector* selector = selectorList.first(); selector; selector
= CSSSelectorList::next(*selector), ++index) { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 return element.tagQName().localNameUpper() == tagName.localNameUpper(); | 201 return element.tagQName().localNameUpper() == tagName.localNameUpper(); |
| 202 return false; | 202 return false; |
| 203 } | 203 } |
| 204 | 204 |
| 205 template <typename SelectorQueryTrait> | 205 template <typename SelectorQueryTrait> |
| 206 void SelectorDataList::collectElementsByTagName(ContainerNode& rootNode, const Q
ualifiedName& tagName, typename SelectorQueryTrait::OutputType& output) const | 206 void SelectorDataList::collectElementsByTagName(ContainerNode& rootNode, const Q
ualifiedName& tagName, typename SelectorQueryTrait::OutputType& output) const |
| 207 { | 207 { |
| 208 for (Element& element : ElementTraversal::descendantsOf(rootNode)) { | 208 for (Element& element : ElementTraversal::descendantsOf(rootNode)) { |
| 209 // querySelector*() doesn't allow namespaces and throws before it gets | 209 // querySelector*() doesn't allow namespaces and throws before it gets |
| 210 // here so we can ignore them. | 210 // here so we can ignore them. |
| 211 ASSERT(tagName.namespaceURI() == starAtom); | 211 DCHECK_EQ(tagName.namespaceURI(), starAtom); |
| 212 if (matchesTagName(tagName, element)) { | 212 if (matchesTagName(tagName, element)) { |
| 213 SelectorQueryTrait::appendElement(output, element); | 213 SelectorQueryTrait::appendElement(output, element); |
| 214 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) | 214 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) |
| 215 return; | 215 return; |
| 216 } | 216 } |
| 217 } | 217 } |
| 218 } | 218 } |
| 219 | 219 |
| 220 inline bool SelectorDataList::canUseFastQuery(const ContainerNode& rootNode) con
st | 220 inline bool SelectorDataList::canUseFastQuery(const ContainerNode& rootNode) con
st |
| 221 { | 221 { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 248 // If returns false, traversalRoots has the rootNode parameter or descendants of
rootNode representing | 248 // If returns false, traversalRoots has the rootNode parameter or descendants of
rootNode representing |
| 249 // the subtree for which we can limit the querySelector traversal. | 249 // the subtree for which we can limit the querySelector traversal. |
| 250 // | 250 // |
| 251 // The travseralRoots may be empty, regardless of the returned bool value, if th
is method finds that the selectors won't | 251 // The travseralRoots may be empty, regardless of the returned bool value, if th
is method finds that the selectors won't |
| 252 // match any element. | 252 // match any element. |
| 253 template <typename SelectorQueryTrait> | 253 template <typename SelectorQueryTrait> |
| 254 void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type
name SelectorQueryTrait::OutputType& output) const | 254 void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type
name SelectorQueryTrait::OutputType& output) const |
| 255 { | 255 { |
| 256 // We need to return the matches in document order. To use id lookup while t
here is possiblity of multiple matches | 256 // We need to return the matches in document order. To use id lookup while t
here is possiblity of multiple matches |
| 257 // we would need to sort the results. For now, just traverse the document in
that case. | 257 // we would need to sort the results. For now, just traverse the document in
that case. |
| 258 ASSERT(m_selectors.size() == 1); | 258 DCHECK_EQ(m_selectors.size(), 1u); |
| 259 | 259 |
| 260 bool isRightmostSelector = true; | 260 bool isRightmostSelector = true; |
| 261 bool startFromParent = false; | 261 bool startFromParent = false; |
| 262 | 262 |
| 263 for (const CSSSelector* selector = m_selectors[0]; selector; selector = sele
ctor->tagHistory()) { | 263 for (const CSSSelector* selector = m_selectors[0]; selector; selector = sele
ctor->tagHistory()) { |
| 264 if (selector->match() == CSSSelector::Id && !rootNode.document().contain
sMultipleElementsWithId(selector->value())) { | 264 if (selector->match() == CSSSelector::Id && !rootNode.document().contain
sMultipleElementsWithId(selector->value())) { |
| 265 Element* element = rootNode.treeScope().getElementById(selector->val
ue()); | 265 Element* element = rootNode.treeScope().getElementById(selector->val
ue()); |
| 266 ContainerNode* adjustedNode = &rootNode; | 266 ContainerNode* adjustedNode = &rootNode; |
| 267 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf
(&rootNode))) | 267 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf
(&rootNode))) |
| 268 adjustedNode = element; | 268 adjustedNode = element; |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 } | 383 } |
| 384 | 384 |
| 385 // FIXME: Move the following helper functions, authorShadowRootOf, firstWithinTr
aversingShadowTree, | 385 // FIXME: Move the following helper functions, authorShadowRootOf, firstWithinTr
aversingShadowTree, |
| 386 // nextTraversingShadowTree to the best place, e.g. NodeTraversal. | 386 // nextTraversingShadowTree to the best place, e.g. NodeTraversal. |
| 387 static ShadowRoot* authorShadowRootOf(const ContainerNode& node) | 387 static ShadowRoot* authorShadowRootOf(const ContainerNode& node) |
| 388 { | 388 { |
| 389 if (!node.isElementNode() || !isShadowHost(&node)) | 389 if (!node.isElementNode() || !isShadowHost(&node)) |
| 390 return nullptr; | 390 return nullptr; |
| 391 | 391 |
| 392 ElementShadow* shadow = toElement(node).shadow(); | 392 ElementShadow* shadow = toElement(node).shadow(); |
| 393 ASSERT(shadow); | 393 DCHECK(shadow); |
| 394 for (ShadowRoot* shadowRoot = shadow->oldestShadowRoot(); shadowRoot; shadow
Root = shadowRoot->youngerShadowRoot()) { | 394 for (ShadowRoot* shadowRoot = shadow->oldestShadowRoot(); shadowRoot; shadow
Root = shadowRoot->youngerShadowRoot()) { |
| 395 if (shadowRoot->type() == ShadowRootType::V0 || shadowRoot->type() == Sh
adowRootType::Open) | 395 if (shadowRoot->type() == ShadowRootType::V0 || shadowRoot->type() == Sh
adowRootType::Open) |
| 396 return shadowRoot; | 396 return shadowRoot; |
| 397 } | 397 } |
| 398 return nullptr; | 398 return nullptr; |
| 399 } | 399 } |
| 400 | 400 |
| 401 static ContainerNode* firstWithinTraversingShadowTree(const ContainerNode& rootN
ode) | 401 static ContainerNode* firstWithinTraversingShadowTree(const ContainerNode& rootN
ode) |
| 402 { | 402 { |
| 403 if (ShadowRoot* shadowRoot = authorShadowRootOf(rootNode)) | 403 if (ShadowRoot* shadowRoot = authorShadowRootOf(rootNode)) |
| (...skipping 12 matching lines...) Expand all Loading... |
| 416 return next; | 416 return next; |
| 417 | 417 |
| 418 if (!current->isInShadowTree()) | 418 if (!current->isInShadowTree()) |
| 419 return nullptr; | 419 return nullptr; |
| 420 | 420 |
| 421 ShadowRoot* shadowRoot = current->containingShadowRoot(); | 421 ShadowRoot* shadowRoot = current->containingShadowRoot(); |
| 422 if (shadowRoot == rootNode) | 422 if (shadowRoot == rootNode) |
| 423 return nullptr; | 423 return nullptr; |
| 424 if (ShadowRoot* youngerShadowRoot = shadowRoot->youngerShadowRoot()) { | 424 if (ShadowRoot* youngerShadowRoot = shadowRoot->youngerShadowRoot()) { |
| 425 // Should not obtain any elements in closed or user-agent shadow roo
t. | 425 // Should not obtain any elements in closed or user-agent shadow roo
t. |
| 426 ASSERT(youngerShadowRoot->type() == ShadowRootType::V0 || youngerSha
dowRoot->type() == ShadowRootType::Open); | 426 DCHECK(youngerShadowRoot->type() == ShadowRootType::V0 || youngerSha
dowRoot->type() == ShadowRootType::Open); |
| 427 return youngerShadowRoot; | 427 return youngerShadowRoot; |
| 428 } | 428 } |
| 429 | 429 |
| 430 current = shadowRoot->host(); | 430 current = shadowRoot->host(); |
| 431 } | 431 } |
| 432 return nullptr; | 432 return nullptr; |
| 433 } | 433 } |
| 434 | 434 |
| 435 template <typename SelectorQueryTrait> | 435 template <typename SelectorQueryTrait> |
| 436 void SelectorDataList::executeSlowTraversingShadowTree(ContainerNode& rootNode,
typename SelectorQueryTrait::OutputType& output) const | 436 void SelectorDataList::executeSlowTraversingShadowTree(ContainerNode& rootNode,
typename SelectorQueryTrait::OutputType& output) const |
| (...skipping 28 matching lines...) Expand all Loading... |
| 465 if (m_needsUpdatedDistribution) | 465 if (m_needsUpdatedDistribution) |
| 466 rootNode.updateDistribution(); | 466 rootNode.updateDistribution(); |
| 467 if (m_usesDeepCombinatorOrShadowPseudo) { | 467 if (m_usesDeepCombinatorOrShadowPseudo) { |
| 468 executeSlowTraversingShadowTree<SelectorQueryTrait>(rootNode, output
); | 468 executeSlowTraversingShadowTree<SelectorQueryTrait>(rootNode, output
); |
| 469 } else { | 469 } else { |
| 470 executeSlow<SelectorQueryTrait>(rootNode, output); | 470 executeSlow<SelectorQueryTrait>(rootNode, output); |
| 471 } | 471 } |
| 472 return; | 472 return; |
| 473 } | 473 } |
| 474 | 474 |
| 475 ASSERT(m_selectors.size() == 1); | 475 DCHECK_EQ(m_selectors.size(), 1u); |
| 476 | 476 |
| 477 const CSSSelector& selector = *m_selectors[0]; | 477 const CSSSelector& selector = *m_selectors[0]; |
| 478 const CSSSelector& firstSelector = selector; | 478 const CSSSelector& firstSelector = selector; |
| 479 | 479 |
| 480 // Fast path for querySelector*('#id'), querySelector*('tag#id'). | 480 // Fast path for querySelector*('#id'), querySelector*('tag#id'). |
| 481 if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { | 481 if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { |
| 482 const AtomicString& idToMatch = idSelector->value(); | 482 const AtomicString& idToMatch = idSelector->value(); |
| 483 if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) { | 483 if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) { |
| 484 const HeapVector<Member<Element>>& elements = rootNode.treeScope().g
etAllElementsById(idToMatch); | 484 const HeapVector<Member<Element>>& elements = rootNode.treeScope().g
etAllElementsById(idToMatch); |
| 485 size_t count = elements.size(); | 485 size_t count = elements.size(); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 570 | 570 |
| 571 return m_entries.add(selectors, SelectorQuery::adopt(std::move(selectorList)
)).storedValue->value.get(); | 571 return m_entries.add(selectors, SelectorQuery::adopt(std::move(selectorList)
)).storedValue->value.get(); |
| 572 } | 572 } |
| 573 | 573 |
| 574 void SelectorQueryCache::invalidate() | 574 void SelectorQueryCache::invalidate() |
| 575 { | 575 { |
| 576 m_entries.clear(); | 576 m_entries.clear(); |
| 577 } | 577 } |
| 578 | 578 |
| 579 } // namespace blink | 579 } // namespace blink |
| OLD | NEW |