void SelectorDataList::execute(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const { if (!canUseFastQuery(rootNode)) { if (m_needsUpdatedDistribution) rootNode.updateDistribution(); if (m_crossesTreeBoundary) { executeSlowTraversingShadowTree<SelectorQueryTrait>(rootNode, output); } else { executeSlow<SelectorQueryTrait>(rootNode, output); } return; } ASSERT(m_selectors.size() == 1); const CSSSelector& selector = *m_selectors[0]; const CSSSelector& firstSelector = selector; // Fast path for querySelector*('#id'), querySelector*('tag#id'). if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { const AtomicString& idToMatch = idSelector->value(); if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) { const WillBeHeapVector<RawPtrWillBeMember<Element>>& elements = rootNode.treeScope().getAllElementsById(idToMatch); size_t count = elements.size(); for (size_t i = 0; i < count; ++i) { Element& element = *elements[i]; if (!(isTreeScopeRoot(rootNode) || element.isDescendantOf(&rootNode))) continue; if (selectorMatches(selector, element, rootNode)) { SelectorQueryTrait::appendElement(output, element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; } } return; } Element* element = rootNode.treeScope().getElementById(idToMatch); if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode))) return; if (selectorMatches(selector, *element, rootNode)) SelectorQueryTrait::appendElement(output, *element); return; } if (!firstSelector.tagHistory()) { // Fast path for querySelector*('.foo'), and querySelector*('div'). switch (firstSelector.match()) { case CSSSelector::Class: collectElementsByClassName<SelectorQueryTrait>(rootNode, firstSelector.value(), output); return; case CSSSelector::Tag: collectElementsByTagName<SelectorQueryTrait>(rootNode, firstSelector.tagQName(), output); return; default: break; // If we need another fast path, add here. } } findTraverseRootsAndExecute<SelectorQueryTrait>(rootNode, output); }
void SelectorDataList::executeQueryAll(Node* rootNode, Vector<RefPtr<Node> >& matchedElements) const { if (!canUseFastQuery(rootNode)) return executeSlowQueryAll(rootNode, matchedElements); ASSERT(m_selectors.size() == 1); ASSERT(m_selectors[0].selector); const CSSSelector* firstSelector = m_selectors[0].selector; if (!firstSelector->tagHistory()) { // Fast path for querySelectorAll('#id'), querySelectorAl('.foo'), and querySelectorAll('div'). switch (firstSelector->m_match) { case CSSSelector::Id: { if (rootNode->document()->containsMultipleElementsWithId(firstSelector->value())) break; // Just the same as getElementById. Element* element = rootNode->treeScope()->getElementById(firstSelector->value()); if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf(rootNode))) matchedElements.append(element); return; } case CSSSelector::Class: return collectElementsByClassName(rootNode, firstSelector->value(), matchedElements); case CSSSelector::Tag: return collectElementsByTagName(rootNode, firstSelector->tagQName(), matchedElements); default: break; // If we need another fast path, add here. } } bool matchTraverseRoots; OwnPtr<SimpleNodeList> traverseRoots = findTraverseRoots(rootNode, matchTraverseRoots); if (traverseRoots->isEmpty()) return; const SelectorData& selector = m_selectors[0]; if (matchTraverseRoots) { while (!traverseRoots->isEmpty()) { Node* node = traverseRoots->next(); Element* element = toElement(node); if (selectorMatches(selector, element, rootNode)) matchedElements.append(element); } return; } while (!traverseRoots->isEmpty()) { Node* traverseRoot = traverseRoots->next(); for (Element* element = ElementTraversal::firstWithin(traverseRoot); element; element = ElementTraversal::next(element, traverseRoot)) { if (selectorMatches(selector, element, rootNode)) matchedElements.append(element); } } }
void SelectorDataList::execute(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const { if (!canUseFastQuery(rootNode)) { executeSlow<SelectorQueryTrait>(rootNode, output); return; } ASSERT(m_selectors.size() == 1); const SelectorData& selector = m_selectors[0]; const CSSSelector& firstSelector = selector.selector; // Fast path for querySelector*('#id'), querySelector*('tag#id'). if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { const AtomicString& idToMatch = idSelector->value(); Element* singleMatchingElement = 0; if (rootNode.treeScope().getNumberOfElementsWithId(idToMatch, singleMatchingElement) > 1) { const Vector<Element*>& elements = rootNode.treeScope().getAllElementsById(idToMatch); size_t count = elements.size(); for (size_t i = 0; i < count; ++i) { Element& element = *elements[i]; if (!(isTreeScopeRoot(rootNode) || element.isDescendantOf(&rootNode))) continue; if (selectorMatches(selector, element, rootNode)) { SelectorQueryTrait::appendElement(output, element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; } } return; } if (!singleMatchingElement || !(isTreeScopeRoot(rootNode) || singleMatchingElement->isDescendantOf(&rootNode))) return; if (selectorMatches(selector, *singleMatchingElement, rootNode)) SelectorQueryTrait::appendElement(output, *singleMatchingElement); return; } if (!firstSelector.tagHistory()) { // Fast path for querySelector*('.foo'), and querySelector*('div'). switch (firstSelector.m_match) { case CSSSelector::Class: collectElementsByClassName<SelectorQueryTrait>(rootNode, firstSelector.value(), output); return; case CSSSelector::Tag: collectElementsByTagName<SelectorQueryTrait>(rootNode, firstSelector.tagQName(), output); return; default: break; // If we need another fast path, add here. } } findTraverseRootsAndExecute<SelectorQueryTrait>(rootNode, output); }
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; }