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

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: 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
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 bool SelectorDataList::findTraverseRoot(Node*& rootNode) const
Hajime Morrita 2013/05/14 00:51:39 Using in-out parameter is almost bad idea. This co
108 {
109 // We need to return the matches in document order. To use id lookup while t here is possiblity of multiple matches
110 // we would need to sort the results. For now, just traverse the document in that case.
111 if (m_selectors.size() != 1)
112 return false;
113 if (!rootNode->inDocument())
114 return false;
115 if (rootNode->document()->inQuirksMode())
116 return false;
117
118 bool matchSingleNode = true;
119 bool startFromParent = false;
120 for (const CSSSelector* selector = m_selectors[0].selector; selector; select or = selector->tagHistory()) {
121 if (selector->m_match == CSSSelector::Id && !rootNode->document()->conta insMultipleElementsWithId(selector->value())) {
122 Element* element = rootNode->treeScope()->getElementById(selector->v alue());
123 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf (rootNode)))
124 rootNode = element;
125 else if (!element || matchSingleNode)
126 rootNode = 0;
127 if (matchSingleNode)
128 return true;
129 if (startFromParent && rootNode)
130 rootNode = rootNode->parentNode();
131 return false;
132 }
133 if (selector->relation() == CSSSelector::SubSelector)
134 continue;
135 matchSingleNode = false;
136 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel ation() == CSSSelector::IndirectAdjacent)
137 startFromParent = true;
138 else
139 startFromParent = false;
140 }
141 return false;
142 }
143
124 template <bool firstMatchOnly> 144 template <bool firstMatchOnly>
125 void SelectorDataList::execute(Node* rootNode, Vector<RefPtr<Node> >& matchedEle ments) const 145 void SelectorDataList::execute(Node* rootNode, Vector<RefPtr<Node> >& matchedEle ments) const
126 { 146 {
127 if (canUseIdLookup(rootNode)) { 147 Node* traverseRoot = rootNode;
148 bool matchSingleNode = findTraverseRoot(traverseRoot);
149 if (!traverseRoot)
haraken 2013/05/14 00:32:58 You can put this above the findTraverseRoot() line
150 return;
151 if (matchSingleNode) {
128 ASSERT(m_selectors.size() == 1); 152 ASSERT(m_selectors.size() == 1);
129 const CSSSelector* selector = m_selectors[0].selector; 153 Element* element = toElement(traverseRoot);
haraken 2013/05/14 00:32:58 Don't you need to check if traverseRoot is an Elem
130 Element* element = rootNode->treeScope()->getElementById(selector->value ());
131 if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(r ootNode)))
132 return;
133 if (selectorMatches(m_selectors[0], element, rootNode)) 154 if (selectorMatches(m_selectors[0], element, rootNode))
134 matchedElements.append(element); 155 matchedElements.append(element);
135 return; 156 return;
136 } 157 }
137 158
138 unsigned selectorCount = m_selectors.size(); 159 unsigned selectorCount = m_selectors.size();
139 160
140 Node* n = rootNode->firstChild(); 161 Node* n = traverseRoot->firstChild();
141 while (n) { 162 while (n) {
142 if (n->isElementNode()) { 163 if (n->isElementNode()) {
143 Element* element = toElement(n); 164 Element* element = toElement(n);
144 for (unsigned i = 0; i < selectorCount; ++i) { 165 for (unsigned i = 0; i < selectorCount; ++i) {
145 if (selectorMatches(m_selectors[i], element, rootNode)) { 166 if (selectorMatches(m_selectors[i], element, rootNode)) {
146 matchedElements.append(element); 167 matchedElements.append(element);
147 if (firstMatchOnly) 168 if (firstMatchOnly)
148 return; 169 return;
149 break; 170 break;
150 } 171 }
151 } 172 }
152 if (element->firstChild()) { 173 if (element->firstChild()) {
153 n = element->firstChild(); 174 n = element->firstChild();
154 continue; 175 continue;
155 } 176 }
156 } 177 }
157 while (!n->nextSibling()) { 178 while (!n->nextSibling()) {
158 n = n->parentNode(); 179 n = n->parentNode();
159 if (n == rootNode) 180 if (n == traverseRoot)
160 return; 181 return;
161 } 182 }
162 n = n->nextSibling(); 183 n = n->nextSibling();
163 } 184 }
164 } 185 }
165 186
166 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList) 187 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList)
167 : m_selectorList(selectorList) 188 : m_selectorList(selectorList)
168 { 189 {
169 m_selectors.initialize(m_selectorList); 190 m_selectors.initialize(m_selectorList);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 m_entries.add(selectors, selectorQuery.release()); 235 m_entries.add(selectors, selectorQuery.release());
215 return rawSelectorQuery; 236 return rawSelectorQuery;
216 } 237 }
217 238
218 void SelectorQueryCache::invalidate() 239 void SelectorQueryCache::invalidate()
219 { 240 {
220 m_entries.clear(); 241 m_entries.clear();
221 } 242 }
222 243
223 } 244 }
OLDNEW
« PerformanceTests/Parser/query-selector-id-last.html ('K') | « Source/core/dom/SelectorQuery.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698