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

Side by Side Diff: Source/core/dom/SelectorQuery.cpp

Issue 14581013: Optimized querySelector(All) when selector contains #id. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Fixed review issues in Patch Set 2 Created 7 years, 7 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 unified diff | Download patch
« no previous file with comments | « Source/core/dom/SelectorQuery.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2011 Apple Inc. All rights reserved. 2 * Copyright (C) 2011 Apple Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 { 91 {
92 Vector<RefPtr<Node> > result; 92 Vector<RefPtr<Node> > result;
93 execute<true>(rootNode, result); 93 execute<true>(rootNode, result);
94 if (result.isEmpty()) 94 if (result.isEmpty())
95 return 0; 95 return 0;
96 ASSERT(result.size() == 1); 96 ASSERT(result.size() == 1);
97 ASSERT(result.first()->isElementNode()); 97 ASSERT(result.first()->isElementNode());
98 return toElement(result.first().get()); 98 return toElement(result.first().get());
99 } 99 }
100 100
101 bool SelectorDataList::canUseIdLookup(Node* rootNode) const
102 {
103 // We need to return the matches in document order. To use id lookup while t here is possiblity of multiple matches
104 // we would need to sort the results. For now, just traverse the document in that case.
105 if (m_selectors.size() != 1)
106 return false;
107 if (m_selectors[0].selector->m_match != CSSSelector::Id)
108 return false;
109 if (!rootNode->inDocument())
110 return false;
111 if (rootNode->document()->inQuirksMode())
112 return false;
113 if (rootNode->document()->containsMultipleElementsWithId(m_selectors[0].sele ctor->value()))
114 return false;
115 return true;
116 }
117
118 static inline bool isTreeScopeRoot(Node* node) 101 static inline bool isTreeScopeRoot(Node* node)
119 { 102 {
120 ASSERT(node); 103 ASSERT(node);
121 return node->isDocumentNode() || node->isShadowRoot(); 104 return node->isDocumentNode() || node->isShadowRoot();
122 } 105 }
123 106
107 // If the first pair value is true, the returned Node is the single Element that may match the selector query.
108 //
109 // If the first value is false, the returned Node is the rootNode parameter or a descendant of rootNode representing
110 // the subtree for which we can limit the querySelector traversal.
111 //
112 // The returned Node may be 0, regardless of the returned bool value, if this me thod finds that the selectors won't
113 // match any element.
114 std::pair<bool, Node*> SelectorDataList::findTraverseRoot(Node* rootNode) const
115 {
116 // We need to return the matches in document order. To use id lookup while t here is possiblity of multiple matches
117 // we would need to sort the results. For now, just traverse the document in that case.
118 if (m_selectors.size() != 1)
119 return std::make_pair(false, rootNode);
120 if (!rootNode->inDocument())
121 return std::make_pair(false, rootNode);
122 if (rootNode->document()->inQuirksMode())
123 return std::make_pair(false, rootNode);
124
125 bool matchSingleNode = true;
126 bool startFromParent = false;
127 for (const CSSSelector* selector = m_selectors[0].selector; selector; select or = selector->tagHistory()) {
128 if (selector->m_match == CSSSelector::Id && !rootNode->document()->conta insMultipleElementsWithId(selector->value())) {
129 Element* element = rootNode->treeScope()->getElementById(selector->v alue());
130 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf (rootNode)))
131 rootNode = element;
132 else if (!element || matchSingleNode)
133 rootNode = 0;
134 if (matchSingleNode)
135 return std::make_pair(true, rootNode);
136 if (startFromParent && rootNode)
137 rootNode = rootNode->parentNode();
138 return std::make_pair(false, rootNode);
139 }
140 if (selector->relation() == CSSSelector::SubSelector)
141 continue;
142 matchSingleNode = false;
143 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel ation() == CSSSelector::IndirectAdjacent)
144 startFromParent = true;
145 else
146 startFromParent = false;
147 }
148 return std::make_pair(false, rootNode);
149 }
150
124 template <bool firstMatchOnly> 151 template <bool firstMatchOnly>
125 void SelectorDataList::execute(Node* rootNode, Vector<RefPtr<Node> >& matchedEle ments) const 152 void SelectorDataList::execute(Node* rootNode, Vector<RefPtr<Node> >& matchedEle ments) const
126 { 153 {
127 if (canUseIdLookup(rootNode)) { 154 std::pair<bool, Node*> traverseRoot = findTraverseRoot(rootNode);
155 if (!traverseRoot.second)
156 return;
157 Node* traverseRootNode = traverseRoot.second;
158 if (traverseRoot.first) {
128 ASSERT(m_selectors.size() == 1); 159 ASSERT(m_selectors.size() == 1);
129 const CSSSelector* selector = m_selectors[0].selector; 160 ASSERT(traverseRootNode->isElementNode());
130 Element* element = rootNode->treeScope()->getElementById(selector->value ()); 161 Element* element = toElement(traverseRootNode);
131 if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(r ootNode)))
132 return;
133 if (selectorMatches(m_selectors[0], element, rootNode)) 162 if (selectorMatches(m_selectors[0], element, rootNode))
134 matchedElements.append(element); 163 matchedElements.append(element);
135 return; 164 return;
136 } 165 }
137 166
138 unsigned selectorCount = m_selectors.size(); 167 unsigned selectorCount = m_selectors.size();
139 168
140 Node* n = rootNode->firstChild(); 169 Node* n = traverseRootNode->firstChild();
141 while (n) { 170 while (n) {
142 if (n->isElementNode()) { 171 if (n->isElementNode()) {
143 Element* element = toElement(n); 172 Element* element = toElement(n);
144 for (unsigned i = 0; i < selectorCount; ++i) { 173 for (unsigned i = 0; i < selectorCount; ++i) {
145 if (selectorMatches(m_selectors[i], element, rootNode)) { 174 if (selectorMatches(m_selectors[i], element, rootNode)) {
146 matchedElements.append(element); 175 matchedElements.append(element);
147 if (firstMatchOnly) 176 if (firstMatchOnly)
148 return; 177 return;
149 break; 178 break;
150 } 179 }
151 } 180 }
152 if (element->firstChild()) { 181 if (element->firstChild()) {
153 n = element->firstChild(); 182 n = element->firstChild();
154 continue; 183 continue;
155 } 184 }
156 } 185 }
157 while (!n->nextSibling()) { 186 while (!n->nextSibling()) {
158 n = n->parentNode(); 187 n = n->parentNode();
159 if (n == rootNode) 188 if (n == traverseRootNode)
160 return; 189 return;
161 } 190 }
162 n = n->nextSibling(); 191 n = n->nextSibling();
163 } 192 }
164 } 193 }
165 194
166 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList) 195 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList)
167 : m_selectorList(selectorList) 196 : m_selectorList(selectorList)
168 { 197 {
169 m_selectors.initialize(m_selectorList); 198 m_selectors.initialize(m_selectorList);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 m_entries.add(selectors, selectorQuery.release()); 243 m_entries.add(selectors, selectorQuery.release());
215 return rawSelectorQuery; 244 return rawSelectorQuery;
216 } 245 }
217 246
218 void SelectorQueryCache::invalidate() 247 void SelectorQueryCache::invalidate()
219 { 248 {
220 m_entries.clear(); 249 m_entries.clear();
221 } 250 }
222 251
223 } 252 }
OLDNEW
« 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