Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(887)

Unified Diff: Source/core/dom/SelectorQuery.cpp

Issue 18732004: Add fast path for querySelector(All) (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/dom/SelectorQuery.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/dom/SelectorQuery.cpp
diff --git a/Source/core/dom/SelectorQuery.cpp b/Source/core/dom/SelectorQuery.cpp
index 32ed0f30b0b86c7608837975df3f1f731ab591d6..be97d8f6b52014082cb66f02d769b37113a30cac 100644
--- a/Source/core/dom/SelectorQuery.cpp
+++ b/Source/core/dom/SelectorQuery.cpp
@@ -104,74 +104,142 @@ static inline bool isTreeScopeRoot(Node* 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.
+static bool hasNodeContains(DocumentOrderedList& rootNodes, Node* node)
+{
+ for (DocumentOrderedList::iterator it = rootNodes.begin(); it != rootNodes.end(); ++it) {
+ Node* rootNode = *it;
+ if (rootNode->contains(node))
+ return true;
+ }
+ return false;
+}
+
+static void addWithRemoveNodesContainedBy(DocumentOrderedList& rootNodes, Node* rootNode)
+{
+ rootNodes.add(rootNode);
+
+ // Remove nodes contained by a given rootNode, because rootNode is not given in document order.
+ DocumentOrderedList::iterator it = rootNodes.end();
+ do {
+ --it;
+ if (rootNode == *it)
+ break;
+ if (rootNode->contains(*it))
+ rootNodes.remove(*it);
+ } while (it != rootNodes.begin());
+}
+
+// If returns true, traversalRoots has the elements 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
+// If returns false, traversalRoots has the rootNode parameter or descendants 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
+// The travseralRoots may be empty, 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
+bool SelectorDataList::findTraverseRoot(Node* rootNode, DocumentOrderedList& traversalRoots) 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 std::make_pair(false, rootNode);
- if (!rootNode->inDocument())
- return std::make_pair(false, rootNode);
- if (rootNode->document()->inQuirksMode())
- return std::make_pair(false, rootNode);
-
- bool matchSingleNode = true;
+ if (m_selectors.size() != 1 || !rootNode->inDocument() || rootNode->document()->inQuirksMode()) {
+ traversalRoots.parserAdd(rootNode);
+ return false;
+ }
+
+ bool matchTraverseRoots = 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)
+ else if (!element || matchTraverseRoots)
rootNode = 0;
- if (matchSingleNode)
- return std::make_pair(true, rootNode);
+ if (matchTraverseRoots) {
+ if (rootNode)
+ traversalRoots.parserAdd(rootNode);
+ return true;
+ }
if (startFromParent && rootNode)
rootNode = rootNode->parentNode();
- return std::make_pair(false, rootNode);
+ if (rootNode)
+ traversalRoots.parserAdd(rootNode);
+ return false;
+ }
+ if (selector->m_match == CSSSelector::Class) {
+ RefPtr<NodeList> nodeList = rootNode->getElementsByClassName(selector->value());
haraken 2013/07/08 11:33:47 oh, this will create unexpected NodeList cache in
+ if (startFromParent) {
+ // Looking at parent nodes, we need to sort in document order.
+ for (unsigned i = 0; i < nodeList->length(); ++i) {
+ Node* node = nodeList->item(i);
+ if (!node || (!isTreeScopeRoot(rootNode) && !node->isDescendantOf(rootNode)))
+ continue;
+ if (Node* parent = node->parentNode()) {
+ if (!hasNodeContains(traversalRoots, parent))
+ addWithRemoveNodesContainedBy(traversalRoots, parent);
+ }
+ }
+ } else if (matchTraverseRoots) {
+ for (unsigned i = 0; i < nodeList->length(); ++i) {
+ Node* node = nodeList->item(i);
+ if (node && (isTreeScopeRoot(rootNode) || node->isDescendantOf(rootNode)))
+ traversalRoots.parserAdd(node);
+ }
+ return true;
+ } else {
+ for (unsigned i = 0; i < nodeList->length(); ++i) {
+ Node* node = nodeList->item(i);
+ if (!node || (!isTreeScopeRoot(rootNode) && !node->isDescendantOf(rootNode)))
+ continue;
+ // Need to check whether the new node is contained by other nodes.
+ if (!hasNodeContains(traversalRoots, node))
+ traversalRoots.add(node);
+ }
+ }
+ return false;
}
+
if (selector->relation() == CSSSelector::SubSelector)
continue;
- matchSingleNode = false;
+ matchTraverseRoots = false;
if (selector->relation() == CSSSelector::DirectAdjacent || selector->relation() == CSSSelector::IndirectAdjacent)
startFromParent = true;
else
startFromParent = false;
}
- return std::make_pair(false, rootNode);
+ if (rootNode)
+ traversalRoots.parserAdd(rootNode);
+ return false;
}
template <bool firstMatchOnly>
void SelectorDataList::execute(Node* rootNode, Vector<RefPtr<Node> >& matchedElements) const
{
- std::pair<bool, Node*> traverseRoot = findTraverseRoot(rootNode);
- if (!traverseRoot.second)
+ DocumentOrderedList traverseRoots;
+ bool matchTraverseRoots = findTraverseRoot(rootNode, traverseRoots);
+
+ if (traverseRoots.isEmpty())
return;
- Node* traverseRootNode = traverseRoot.second;
- if (traverseRoot.first) {
+ if (matchTraverseRoots) {
ASSERT(m_selectors.size() == 1);
- ASSERT(traverseRootNode->isElementNode());
- Element* element = toElement(traverseRootNode);
- if (selectorMatches(m_selectors[0], element, rootNode))
- matchedElements.append(element);
+ for (DocumentOrderedList::iterator it = traverseRoots.begin(); it != traverseRoots.end(); ++it) {
+ Element* element = toElement(*it);
+ if (selectorMatches(m_selectors[0], element, rootNode))
+ matchedElements.append(element);
+ }
return;
}
unsigned selectorCount = m_selectors.size();
if (selectorCount == 1) {
const SelectorData& selector = m_selectors[0];
- for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(element, rootNode)) {
- if (selectorMatches(selector, element, rootNode)) {
- matchedElements.append(element);
- if (firstMatchOnly)
- return;
+ for (DocumentOrderedList::iterator it = traverseRoots.begin(); it != traverseRoots.end(); ++it) {
+ Node* traverseRoot = *it;
+ for (Element* element = ElementTraversal::firstWithin(traverseRoot); element; element = ElementTraversal::next(element, traverseRoot)) {
+ if (selectorMatches(selector, element, rootNode)) {
+ matchedElements.append(element);
+ if (firstMatchOnly)
+ return;
+ }
}
}
return;
« no previous file with comments | « Source/core/dom/SelectorQuery.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698