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

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. 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 std::pair<bool, Node*> SelectorDataList::findTraverseRoot(Node* rootNode) const
haraken 2013/05/14 12:50:33 Let's add a comment about what the return values m
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 std::make_pair(false, rootNode);
113 if (!rootNode->inDocument())
114 return std::make_pair(false, rootNode);
115 if (rootNode->document()->inQuirksMode())
116 return std::make_pair(false, rootNode);
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 std::make_pair(true, rootNode);
129 if (startFromParent && rootNode)
130 rootNode = rootNode->parentNode();
131 return std::make_pair(false, rootNode);
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 std::make_pair(false, rootNode);
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 std::pair<bool, Node*> traverseRoot = findTraverseRoot(rootNode);
148 if (!traverseRoot.second)
149 return;
150 Node* traverseRootNode = traverseRoot.second;
151 if (traverseRoot.first) {
128 ASSERT(m_selectors.size() == 1); 152 ASSERT(m_selectors.size() == 1);
129 const CSSSelector* selector = m_selectors[0].selector; 153 ASSERT(traverseRootNode->isElementNode());
130 Element* element = rootNode->treeScope()->getElementById(selector->value ()); 154 if (!traverseRootNode->isElementNode())
haraken 2013/05/14 12:50:33 You can remove this if statement, because it shoul
131 if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(r ootNode)))
132 return; 155 return;
156 Element* element = toElement(traverseRootNode);
133 if (selectorMatches(m_selectors[0], element, rootNode)) 157 if (selectorMatches(m_selectors[0], element, rootNode))
134 matchedElements.append(element); 158 matchedElements.append(element);
135 return; 159 return;
136 } 160 }
137 161
138 unsigned selectorCount = m_selectors.size(); 162 unsigned selectorCount = m_selectors.size();
139 163
140 Node* n = rootNode->firstChild(); 164 Node* n = traverseRootNode->firstChild();
141 while (n) { 165 while (n) {
142 if (n->isElementNode()) { 166 if (n->isElementNode()) {
143 Element* element = toElement(n); 167 Element* element = toElement(n);
144 for (unsigned i = 0; i < selectorCount; ++i) { 168 for (unsigned i = 0; i < selectorCount; ++i) {
145 if (selectorMatches(m_selectors[i], element, rootNode)) { 169 if (selectorMatches(m_selectors[i], element, rootNode)) {
146 matchedElements.append(element); 170 matchedElements.append(element);
147 if (firstMatchOnly) 171 if (firstMatchOnly)
148 return; 172 return;
149 break; 173 break;
150 } 174 }
151 } 175 }
152 if (element->firstChild()) { 176 if (element->firstChild()) {
153 n = element->firstChild(); 177 n = element->firstChild();
154 continue; 178 continue;
155 } 179 }
156 } 180 }
157 while (!n->nextSibling()) { 181 while (!n->nextSibling()) {
158 n = n->parentNode(); 182 n = n->parentNode();
159 if (n == rootNode) 183 if (n == traverseRootNode)
160 return; 184 return;
161 } 185 }
162 n = n->nextSibling(); 186 n = n->nextSibling();
163 } 187 }
164 } 188 }
165 189
166 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList) 190 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList)
167 : m_selectorList(selectorList) 191 : m_selectorList(selectorList)
168 { 192 {
169 m_selectors.initialize(m_selectorList); 193 m_selectors.initialize(m_selectorList);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 m_entries.add(selectors, selectorQuery.release()); 238 m_entries.add(selectors, selectorQuery.release());
215 return rawSelectorQuery; 239 return rawSelectorQuery;
216 } 240 }
217 241
218 void SelectorQueryCache::invalidate() 242 void SelectorQueryCache::invalidate()
219 { 243 {
220 m_entries.clear(); 244 m_entries.clear();
221 } 245 }
222 246
223 } 247 }
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