Element* SelectorDataList::executeQueryFirst(Node* rootNode) const { if (!canUseFastQuery(rootNode)) return executeSlowQueryFirst(rootNode); const CSSSelector* selector = m_selectors[0].selector; ASSERT(selector); if (!selector->tagHistory()) { // Fast path for querySelector('#id'), querySelector('.foo'), and querySelector('div'). // Many web developers uses querySelector with these simple selectors. switch (selector->m_match) { case CSSSelector::Id: { if (rootNode->document()->containsMultipleElementsWithId(selector->value())) break; Element* element = rootNode->treeScope()->getElementById(selector->value()); return element && (isTreeScopeRoot(rootNode) || element->isDescendantOf(rootNode)) ? element : 0; } case CSSSelector::Class: return findElementByClassName(rootNode, selector->value()); case CSSSelector::Tag: return findElementByTagName(rootNode, selector->tagQName()); default: break; // If we need another fast path, add here. } } bool matchTraverseRoot; Node* traverseRootNode = findTraverseRoot(rootNode, matchTraverseRoot); if (!traverseRootNode) return 0; if (matchTraverseRoot) { ASSERT(m_selectors.size() == 1); ASSERT(traverseRootNode->isElementNode()); Element* element = toElement(traverseRootNode); return selectorMatches(m_selectors[0], element, rootNode) ? element : 0; } for (Element* element = ElementTraversal::firstWithin(traverseRootNode); element; element = ElementTraversal::next(element, traverseRootNode)) { if (selectorMatches(m_selectors[0], element, rootNode)) return element; } return 0; }
void SelectorDataList::execute(Node* rootNode, Vector<RefPtr<Node> >& matchedElements) const { std::pair<bool, Node*> traverseRoot = findTraverseRoot(rootNode); if (!traverseRoot.second) return; Node* traverseRootNode = traverseRoot.second; if (traverseRoot.first) { ASSERT(m_selectors.size() == 1); ASSERT(traverseRootNode->isElementNode()); Element* element = toElement(traverseRootNode); 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; } } return; } for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(element, rootNode)) { for (unsigned i = 0; i < selectorCount; ++i) { if (selectorMatches(m_selectors[i], element, rootNode)) { matchedElements.append(element); if (firstMatchOnly) return; break; } } } }