Index: Source/core/dom/SelectorQuery.cpp |
diff --git a/Source/core/dom/SelectorQuery.cpp b/Source/core/dom/SelectorQuery.cpp |
index 589a0f27c6d275aab90b9610a4abe3db6071bfe8..603f4844bbd13b303c91fefd1183e8f33aa41a79 100644 |
--- a/Source/core/dom/SelectorQuery.cpp |
+++ b/Source/core/dom/SelectorQuery.cpp |
@@ -98,38 +98,67 @@ PassRefPtr<Element> SelectorDataList::queryFirst(Node* rootNode) const |
return toElement(result.first().get()); |
} |
-bool SelectorDataList::canUseIdLookup(Node* rootNode) const |
+static inline bool isTreeScopeRoot(Node* node) |
+{ |
+ ASSERT(node); |
+ return node->isDocumentNode() || node->isShadowRoot(); |
+} |
+ |
+// If the first pair value is true, the returned Node is the single Element that may match the selector query. |
+// |
+// If the first value is false, the returned Node is the rootNode parameter or a descendant of rootNode representing |
+// the subtree for which we can limit the querySelector traversal. |
+// |
+// The returned Node may be 0, regardless of the returned bool value, if this method finds that the selectors won't |
+// match any element. |
+std::pair<bool, Node*> SelectorDataList::findTraverseRoot(Node* rootNode) const |
{ |
// We need to return the matches in document order. To use id lookup while there is possiblity of multiple matches |
// we would need to sort the results. For now, just traverse the document in that case. |
if (m_selectors.size() != 1) |
- return false; |
- if (m_selectors[0].selector->m_match != CSSSelector::Id) |
- return false; |
+ return std::make_pair(false, rootNode); |
if (!rootNode->inDocument()) |
- return false; |
+ return std::make_pair(false, rootNode); |
if (rootNode->document()->inQuirksMode()) |
- return false; |
- if (rootNode->document()->containsMultipleElementsWithId(m_selectors[0].selector->value())) |
- return false; |
- return true; |
-} |
- |
-static inline bool isTreeScopeRoot(Node* node) |
-{ |
- ASSERT(node); |
- return node->isDocumentNode() || node->isShadowRoot(); |
+ return std::make_pair(false, rootNode); |
+ |
+ bool matchSingleNode = true; |
+ bool startFromParent = false; |
+ for (const CSSSelector* selector = m_selectors[0].selector; selector; selector = selector->tagHistory()) { |
+ if (selector->m_match == CSSSelector::Id && !rootNode->document()->containsMultipleElementsWithId(selector->value())) { |
+ Element* element = rootNode->treeScope()->getElementById(selector->value()); |
+ if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf(rootNode))) |
+ rootNode = element; |
+ else if (!element || matchSingleNode) |
+ rootNode = 0; |
+ if (matchSingleNode) |
+ return std::make_pair(true, rootNode); |
+ if (startFromParent && rootNode) |
+ rootNode = rootNode->parentNode(); |
+ return std::make_pair(false, rootNode); |
+ } |
+ if (selector->relation() == CSSSelector::SubSelector) |
+ continue; |
+ matchSingleNode = false; |
+ if (selector->relation() == CSSSelector::DirectAdjacent || selector->relation() == CSSSelector::IndirectAdjacent) |
+ startFromParent = true; |
+ else |
+ startFromParent = false; |
+ } |
+ return std::make_pair(false, rootNode); |
} |
template <bool firstMatchOnly> |
void SelectorDataList::execute(Node* rootNode, Vector<RefPtr<Node> >& matchedElements) const |
{ |
- if (canUseIdLookup(rootNode)) { |
+ std::pair<bool, Node*> traverseRoot = findTraverseRoot(rootNode); |
+ if (!traverseRoot.second) |
+ return; |
+ Node* traverseRootNode = traverseRoot.second; |
+ if (traverseRoot.first) { |
ASSERT(m_selectors.size() == 1); |
- const CSSSelector* selector = m_selectors[0].selector; |
- Element* element = rootNode->treeScope()->getElementById(selector->value()); |
- if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(rootNode))) |
- return; |
+ ASSERT(traverseRootNode->isElementNode()); |
+ Element* element = toElement(traverseRootNode); |
if (selectorMatches(m_selectors[0], element, rootNode)) |
matchedElements.append(element); |
return; |
@@ -137,7 +166,7 @@ void SelectorDataList::execute(Node* rootNode, Vector<RefPtr<Node> >& matchedEle |
unsigned selectorCount = m_selectors.size(); |
- Node* n = rootNode->firstChild(); |
+ Node* n = traverseRootNode->firstChild(); |
while (n) { |
if (n->isElementNode()) { |
Element* element = toElement(n); |
@@ -156,7 +185,7 @@ void SelectorDataList::execute(Node* rootNode, Vector<RefPtr<Node> >& matchedEle |
} |
while (!n->nextSibling()) { |
n = n->parentNode(); |
- if (n == rootNode) |
+ if (n == traverseRootNode) |
return; |
} |
n = n->nextSibling(); |