Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 76 if (selectorMatches(m_selectors[i], targetElement, targetElement)) | 76 if (selectorMatches(m_selectors[i], targetElement, targetElement)) |
| 77 return true; | 77 return true; |
| 78 } | 78 } |
| 79 | 79 |
| 80 return false; | 80 return false; |
| 81 } | 81 } |
| 82 | 82 |
| 83 PassRefPtr<NodeList> SelectorDataList::queryAll(Node* rootNode) const | 83 PassRefPtr<NodeList> SelectorDataList::queryAll(Node* rootNode) const |
| 84 { | 84 { |
| 85 Vector<RefPtr<Node> > result; | 85 Vector<RefPtr<Node> > result; |
| 86 execute<false>(rootNode, result); | 86 executeQueryAll(rootNode, result); |
| 87 return StaticNodeList::adopt(result); | 87 return StaticNodeList::adopt(result); |
| 88 } | 88 } |
| 89 | 89 |
| 90 PassRefPtr<Element> SelectorDataList::queryFirst(Node* rootNode) const | 90 PassRefPtr<Element> SelectorDataList::queryFirst(Node* rootNode) const |
| 91 { | 91 { |
| 92 Vector<RefPtr<Node> > result; | 92 return executeQueryFirst(rootNode); |
| 93 execute<true>(rootNode, result); | |
| 94 if (result.isEmpty()) | |
| 95 return 0; | |
| 96 ASSERT(result.size() == 1); | |
| 97 ASSERT(result.first()->isElementNode()); | |
| 98 return toElement(result.first().get()); | |
| 99 } | 93 } |
| 100 | 94 |
| 101 static inline bool isTreeScopeRoot(Node* node) | 95 static inline bool isTreeScopeRoot(Node* node) |
| 102 { | 96 { |
| 103 ASSERT(node); | 97 ASSERT(node); |
| 104 return node->isDocumentNode() || node->isShadowRoot(); | 98 return node->isDocumentNode() || node->isShadowRoot(); |
| 105 } | 99 } |
| 106 | 100 |
| 101 template<bool firstMatchOnly> | |
| 102 void SelectorDataList::collectElementsByClassName(Node* rootNode, const SpaceSpl itString& classNames, Vector<Node*>& traversalRoots) const | |
| 103 { | |
| 104 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el ement = ElementTraversal::next(element, rootNode)) { | |
| 105 if (element->hasClass() && element->classNames().containsAll(classNames) ) { | |
| 106 traversalRoots.append(element); | |
| 107 if (firstMatchOnly) | |
|
esprehn
2013/07/12 07:17:17
I'd rather you just created two methods.
Element*
tasak
2013/07/16 07:46:59
I see.
Done.
| |
| 108 return; | |
| 109 } | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 inline bool SelectorDataList::canUseFastQuery(Node* rootNode) const | |
| 114 { | |
| 115 return m_selectors.size() == 1 && rootNode->inDocument() && !rootNode->docum ent()->inQuirksMode(); | |
|
esprehn
2013/07/12 07:17:17
Why does the root need to be inDocument?
tasak
2013/07/16 07:46:59
To use treeScope()->getElementById.
I guess, we h
| |
| 116 } | |
| 117 | |
| 118 // If returns true, traversalRoots has the elements that may match the selector query. | |
| 119 // | |
| 120 // If returns false, traversalRoots has the rootNode parameter or descendants of rootNode representing | |
| 121 // the subtree for which we can limit the querySelector traversal. | |
| 122 // | |
| 123 // The travseralRoots may be empty, regardless of the returned bool value, if th is method finds that the selectors won't | |
|
esprehn
2013/07/12 07:17:17
It seems like you're trying to do too much inside
tasak
2013/07/16 07:46:59
I see. I moved the codes for finding elements with
| |
| 124 // match any element. | |
| 125 bool SelectorDataList::findTraverseRoots(Node* rootNode, Vector<Node*>& traversa lRoots) const | |
| 126 { | |
| 127 // We need to return the matches in document order. To use id lookup while t here is possiblity of multiple matches | |
| 128 // we would need to sort the results. For now, just traverse the document in that case. | |
| 129 if (!canUseFastQuery(rootNode)) { | |
| 130 traversalRoots.append(rootNode); | |
| 131 return false; | |
| 132 } | |
| 133 | |
| 134 bool matchTraverseRoots = true; | |
| 135 bool startFromParent = false; | |
| 136 | |
| 137 for (const CSSSelector* selector = m_selectors[0].selector; selector; select or = selector->tagHistory()) { | |
|
esprehn
2013/07/12 07:17:17
Do you need an ASSERT at the start of this method?
tasak
2013/07/16 07:46:59
I see.
Done.
| |
| 138 if (selector->m_match == CSSSelector::Id && !rootNode->document()->conta insMultipleElementsWithId(selector->value())) { | |
| 139 Element* element = rootNode->treeScope()->getElementById(selector->v alue()); | |
| 140 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf (rootNode))) | |
| 141 rootNode = element; | |
| 142 else if (!element || matchTraverseRoots) | |
| 143 rootNode = 0; | |
| 144 if (matchTraverseRoots) { | |
| 145 if (rootNode) | |
| 146 traversalRoots.append(rootNode); | |
| 147 return true; | |
| 148 } | |
|
esprehn
2013/07/12 07:17:17
This loop is confusing, what is it doing?
tasak
2013/07/16 07:46:59
This loop is:
- looking at each selector from righ
| |
| 149 if (startFromParent && rootNode) | |
| 150 rootNode = rootNode->parentNode(); | |
| 151 if (rootNode) | |
| 152 traversalRoots.append(rootNode); | |
| 153 return false; | |
| 154 } | |
| 155 | |
| 156 // If we have both CSSSelector::Id and CSSSelector::Class at the same ti me, we should use Id | |
| 157 // to find traverse root. | |
| 158 if (!startFromParent && selector->m_match == CSSSelector::Class) { | |
| 159 SpaceSplitString classNames(selector->value(), rootNode->document()- >inQuirksMode()); | |
| 160 if (matchTraverseRoots) { | |
| 161 collectElementsByClassName<false>(rootNode, classNames, traversa lRoots); | |
| 162 } else { | |
| 163 for (Element* element = ElementTraversal::firstWithin(rootNode); element; ) { | |
| 164 if (element->hasClass() && element->classNames().containsAll (classNames)) { | |
| 165 traversalRoots.append(element); | |
| 166 element = ElementTraversal::nextSkippingChildren(element , rootNode); | |
|
esprehn
2013/07/12 07:17:17
Why doesn't this need to be recursive? If this ele
tasak
2013/07/16 07:46:59
Because this is for finding traversal roots (e.g.
| |
| 167 } else { | |
| 168 element = ElementTraversal::next(element, rootNode); | |
| 169 } | |
| 170 } | |
| 171 } | |
| 172 return matchTraverseRoots; | |
| 173 } | |
| 174 | |
| 175 if (selector->relation() == CSSSelector::SubSelector) | |
| 176 continue; | |
| 177 matchTraverseRoots = false; | |
| 178 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel ation() == CSSSelector::IndirectAdjacent) | |
| 179 startFromParent = true; | |
| 180 else | |
| 181 startFromParent = false; | |
| 182 } | |
| 183 if (rootNode) | |
| 184 traversalRoots.append(rootNode); | |
| 185 return false; | |
| 186 } | |
| 187 | |
| 188 void SelectorDataList::executeQueryAll(Node* rootNode, Vector<RefPtr<Node> >& ma tchedElements) const | |
| 189 { | |
| 190 Vector<Node*> traverseRoots; | |
| 191 bool matchTraverseRoots = findTraverseRoots(rootNode, traverseRoots); | |
| 192 | |
| 193 if (traverseRoots.isEmpty()) | |
| 194 return; | |
| 195 if (matchTraverseRoots) { | |
|
esprehn
2013/07/12 07:17:17
This is weird, even if matchTraverseRoots is false
tasak
2013/07/16 07:46:59
The matchTraverseRoots means whether elements foun
| |
| 196 ASSERT(m_selectors.size() == 1); | |
| 197 for (unsigned i = 0; i < traverseRoots.size(); ++i) { | |
| 198 Element* element = toElement(traverseRoots.at(i)); | |
| 199 if (selectorMatches(m_selectors[0], element, rootNode)) | |
| 200 matchedElements.append(element); | |
| 201 } | |
| 202 return; | |
| 203 } | |
| 204 | |
| 205 unsigned selectorCount = m_selectors.size(); | |
|
esprehn
2013/07/12 07:17:17
No need to cache this in a local
tasak
2013/07/16 07:46:59
Done.
| |
| 206 if (selectorCount == 1) { | |
| 207 const SelectorData& selector = m_selectors[0]; | |
| 208 for (unsigned i = 0; i < traverseRoots.size(); ++i) { | |
| 209 Node* traverseRoot = traverseRoots.at(i); | |
| 210 for (Element* element = ElementTraversal::firstWithin(traverseRoot); element; element = ElementTraversal::next(element, traverseRoot)) { | |
| 211 if (selectorMatches(selector, element, rootNode)) | |
| 212 matchedElements.append(element); | |
| 213 } | |
| 214 } | |
| 215 return; | |
| 216 } | |
| 217 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el ement = ElementTraversal::next(element, rootNode)) { | |
| 218 for (unsigned i = 0; i < selectorCount; ++i) { | |
| 219 if (selectorMatches(m_selectors[i], element, rootNode)) { | |
| 220 matchedElements.append(element); | |
| 221 break; | |
| 222 } | |
| 223 } | |
| 224 } | |
| 225 } | |
| 226 | |
| 107 // If the first pair value is true, the returned Node is the single Element that may match the selector query. | 227 // If the first pair value is true, the returned Node is the single Element that may match the selector query. |
| 108 // | 228 // |
| 109 // If the first value is false, the returned Node is the rootNode parameter or a descendant of rootNode representing | 229 // 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. | 230 // the subtree for which we can limit the querySelector traversal. |
| 111 // | 231 // |
| 112 // The returned Node may be 0, regardless of the returned bool value, if this me thod finds that the selectors won't | 232 // 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. | 233 // match any element. |
| 114 std::pair<bool, Node*> SelectorDataList::findTraverseRoot(Node* rootNode) const | 234 std::pair<bool, Node*> SelectorDataList::findTraverseRoot(Node* rootNode) const |
| 115 { | 235 { |
| 116 // We need to return the matches in document order. To use id lookup while t here is possiblity of multiple matches | 236 // 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. | 237 // 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; | 238 bool matchSingleNode = true; |
| 126 bool startFromParent = false; | 239 bool startFromParent = false; |
| 127 for (const CSSSelector* selector = m_selectors[0].selector; selector; select or = selector->tagHistory()) { | 240 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())) { | 241 if (selector->m_match == CSSSelector::Id && !rootNode->document()->conta insMultipleElementsWithId(selector->value())) { |
| 129 Element* element = rootNode->treeScope()->getElementById(selector->v alue()); | 242 Element* element = rootNode->treeScope()->getElementById(selector->v alue()); |
| 130 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf (rootNode))) | 243 if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf (rootNode))) |
| 131 rootNode = element; | 244 rootNode = element; |
| 132 else if (!element || matchSingleNode) | 245 else if (!element || matchSingleNode) |
| 133 rootNode = 0; | 246 rootNode = 0; |
| 134 if (matchSingleNode) | 247 if (matchSingleNode) |
| 135 return std::make_pair(true, rootNode); | 248 return std::make_pair(true, rootNode); |
| 136 if (startFromParent && rootNode) | 249 if (startFromParent && rootNode) |
| 137 rootNode = rootNode->parentNode(); | 250 rootNode = rootNode->parentNode(); |
| 138 return std::make_pair(false, rootNode); | 251 return std::make_pair(false, rootNode); |
| 139 } | 252 } |
| 140 if (selector->relation() == CSSSelector::SubSelector) | 253 if (selector->relation() == CSSSelector::SubSelector) |
| 141 continue; | 254 continue; |
| 142 matchSingleNode = false; | 255 matchSingleNode = false; |
| 143 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel ation() == CSSSelector::IndirectAdjacent) | 256 if (selector->relation() == CSSSelector::DirectAdjacent || selector->rel ation() == CSSSelector::IndirectAdjacent) |
| 144 startFromParent = true; | 257 startFromParent = true; |
| 145 else | 258 else |
| 146 startFromParent = false; | 259 startFromParent = false; |
| 147 } | 260 } |
| 148 return std::make_pair(false, rootNode); | 261 return std::make_pair(false, rootNode); |
| 149 } | 262 } |
| 150 | 263 |
| 151 template <bool firstMatchOnly> | 264 Element* SelectorDataList::executeQueryFirst(Node* rootNode) const |
| 152 void SelectorDataList::execute(Node* rootNode, Vector<RefPtr<Node> >& matchedEle ments) const | |
| 153 { | 265 { |
| 154 std::pair<bool, Node*> traverseRoot = findTraverseRoot(rootNode); | 266 // fast path |
| 155 if (!traverseRoot.second) | 267 if (canUseFastQuery(rootNode)) { |
| 156 return; | 268 if (m_selectors[0].selector && !m_selectors[0].selector->tagHistory()) { |
| 157 Node* traverseRootNode = traverseRoot.second; | 269 const CSSSelector* selector = m_selectors[0].selector; |
| 158 if (traverseRoot.first) { | 270 if (selector->m_match == CSSSelector::Id && !rootNode->document()->c ontainsMultipleElementsWithId(selector->value())) { |
| 159 ASSERT(m_selectors.size() == 1); | 271 // just getElementById |
| 160 ASSERT(traverseRootNode->isElementNode()); | 272 Element* element = rootNode->treeScope()->getElementById(selecto r->value()); |
| 161 Element* element = toElement(traverseRootNode); | 273 return element && (isTreeScopeRoot(rootNode) || element->isDesce ndantOf(rootNode)) ? element : 0; |
|
esprehn
2013/07/12 07:17:17
Remove the isTreeScopeRoot checks, isDescendantOf
tasak
2013/07/16 07:46:59
We need this check, because this doesn't use findT
| |
| 162 if (selectorMatches(m_selectors[0], element, rootNode)) | 274 } |
| 163 matchedElements.append(element); | 275 if (selector->m_match == CSSSelector::Class) { |
| 164 return; | 276 Vector<Node*> nodes; |
| 277 SpaceSplitString classNames(selector->value(), rootNode->documen t()->inQuirksMode()); | |
| 278 collectElementsByClassName<true>(rootNode, classNames, nodes); | |
| 279 return nodes.size() > 0 ? toElement(nodes.at(0)) : 0; | |
|
esprehn
2013/07/12 07:17:17
nodes.isEmpty() ? 0 : nodes.first();
tasak
2013/07/16 07:46:59
I added findElementByClassName and removed this co
| |
| 280 } | |
| 281 } | |
| 282 | |
| 283 std::pair<bool, Node*> traverseRoot = findTraverseRoot(rootNode); | |
|
esprehn
2013/07/12 07:17:17
I think you want to return a Node* and have an out
tasak
2013/07/16 07:46:59
Done.
| |
| 284 if (!traverseRoot.second) | |
| 285 return 0; | |
| 286 Node* traverseRootNode = traverseRoot.second; | |
| 287 if (traverseRoot.first) { | |
| 288 ASSERT(m_selectors.size() == 1); | |
| 289 ASSERT(traverseRootNode->isElementNode()); | |
| 290 Element* element = toElement(traverseRootNode); | |
| 291 return selectorMatches(m_selectors[0], element, rootNode) ? element : 0; | |
| 292 } | |
| 293 rootNode = traverseRootNode; | |
| 165 } | 294 } |
| 166 | 295 |
| 167 unsigned selectorCount = m_selectors.size(); | 296 unsigned selectorCount = m_selectors.size(); |
| 168 if (selectorCount == 1) { | 297 if (selectorCount == 1) { |
| 169 const SelectorData& selector = m_selectors[0]; | 298 const SelectorData& selector = m_selectors[0]; |
| 170 for (Element* element = ElementTraversal::firstWithin(rootNode); element ; element = ElementTraversal::next(element, rootNode)) { | 299 for (Element* element = ElementTraversal::firstWithin(rootNode); element ; element = ElementTraversal::next(element, rootNode)) { |
| 171 if (selectorMatches(selector, element, rootNode)) { | 300 if (selectorMatches(selector, element, rootNode)) |
| 172 matchedElements.append(element); | 301 return element; |
| 173 if (firstMatchOnly) | |
| 174 return; | |
| 175 } | |
| 176 } | 302 } |
| 177 return; | 303 return 0; |
| 178 } | 304 } |
| 305 | |
| 179 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el ement = ElementTraversal::next(element, rootNode)) { | 306 for (Element* element = ElementTraversal::firstWithin(rootNode); element; el ement = ElementTraversal::next(element, rootNode)) { |
| 180 for (unsigned i = 0; i < selectorCount; ++i) { | 307 for (unsigned i = 0; i < selectorCount; ++i) { |
| 181 if (selectorMatches(m_selectors[i], element, rootNode)) { | 308 if (selectorMatches(m_selectors[i], element, rootNode)) |
| 182 matchedElements.append(element); | 309 return element; |
| 183 if (firstMatchOnly) | |
| 184 return; | |
| 185 break; | |
| 186 } | |
| 187 } | 310 } |
| 188 } | 311 } |
| 312 return 0; | |
| 189 } | 313 } |
| 190 | 314 |
| 191 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList) | 315 SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList) |
| 192 : m_selectorList(selectorList) | 316 : m_selectorList(selectorList) |
| 193 { | 317 { |
| 194 m_selectors.initialize(m_selectorList); | 318 m_selectors.initialize(m_selectorList); |
| 195 } | 319 } |
| 196 | 320 |
| 197 bool SelectorQuery::matches(Element* element) const | 321 bool SelectorQuery::matches(Element* element) const |
| 198 { | 322 { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 239 m_entries.add(selectors, selectorQuery.release()); | 363 m_entries.add(selectors, selectorQuery.release()); |
| 240 return rawSelectorQuery; | 364 return rawSelectorQuery; |
| 241 } | 365 } |
| 242 | 366 |
| 243 void SelectorQueryCache::invalidate() | 367 void SelectorQueryCache::invalidate() |
| 244 { | 368 { |
| 245 m_entries.clear(); | 369 m_entries.clear(); |
| 246 } | 370 } |
| 247 | 371 |
| 248 } | 372 } |
| OLD | NEW |