void SelectorDataList::executeForTraverseRoots(const SelectorData& selector, SimpleElementListType& traverseRoots, MatchTraverseRootState matchTraverseRoots, ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const { if (traverseRoots.isEmpty()) return; if (matchTraverseRoots) { while (!traverseRoots.isEmpty()) { Element& element = *traverseRoots.next(); if (selectorMatches(selector, element, rootNode)) { SelectorQueryTrait::appendElement(output, element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; } } return; } while (!traverseRoots.isEmpty()) { Element& traverseRoot = *traverseRoots.next(); for (Element* element = ElementTraversal::firstWithin(traverseRoot); element; element = ElementTraversal::next(*element, &traverseRoot)) { if (selectorMatches(selector, *element, rootNode)) { SelectorQueryTrait::appendElement(output, *element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; } } } }
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); }
ALWAYS_INLINE void SelectorDataList::executeFastPathForIdSelector(const Node* rootNode, const SelectorData& selectorData, const CSSSelector* idSelector, typename SelectorQueryTrait::OutputType& output) const { ASSERT(m_selectors.size() == 1); ASSERT(idSelector); const AtomicString& idToMatch = idSelector->value(); if (UNLIKELY(rootNode->treeScope()->containsMultipleElementsWithId(idToMatch))) { const Vector<Element*>* elements = rootNode->treeScope()->getAllElementsById(idToMatch); ASSERT(elements); size_t count = elements->size(); bool rootNodeIsTreeScopeRoot = isTreeScopeRoot(rootNode); for (size_t i = 0; i < count; ++i) { Element* element = elements->at(i); if ((rootNodeIsTreeScopeRoot || element->isDescendantOf(rootNode)) && selectorMatches(selectorData, element, rootNode)) { SelectorQueryTrait::appendOutputForElement(output, element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; } } return; } Element* element = rootNode->treeScope()->getElementById(idToMatch); if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(rootNode))) return; if (selectorMatches(selectorData, element, rootNode)) SelectorQueryTrait::appendOutputForElement(output, element); }
ALWAYS_INLINE void SelectorDataList::executeFastPathForIdSelector(const Node* rootNode, const SelectorData& selectorData, const CSSSelector* idSelector, Vector<RefPtr<Node> >& matchedElements) const { ASSERT(m_selectors.size() == 1); ASSERT(idSelector); const AtomicString& idToMatch = idSelector->value(); if (UNLIKELY(rootNode->treeScope()->containsMultipleElementsWithId(idToMatch))) { const Vector<Element*>* elements = rootNode->treeScope()->getAllElementsById(idToMatch); ASSERT(elements); size_t count = elements->size(); bool rootNodeIsTreeScopeRoot = isTreeScopeRoot(rootNode); for (size_t i = 0; i < count; ++i) { Element* element = elements->at(i); if ((rootNodeIsTreeScopeRoot || element->isDescendantOf(rootNode)) && selectorMatches(selectorData, element, rootNode)) { matchedElements.append(element); if (firstMatchOnly) return; } } return; } Element* element = rootNode->treeScope()->getElementById(idToMatch); if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(rootNode))) return; if (selectorMatches(selectorData, element, rootNode)) matchedElements.append(element); }
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); }
void SelectorDataList::execute(Node* rootNode, Vector<RefPtr<Node> >& matchedElements) const { if (const CSSSelector* idSelector = selectorForIdLookup(rootNode)) { ASSERT(m_selectors.size() == 1); const AtomicString& idToMatch = idSelector->value(); if (UNLIKELY(rootNode->treeScope()->containsMultipleElementsWithId(idToMatch))) { const Vector<Element*>* elements = rootNode->treeScope()->getAllElementsById(idToMatch); ASSERT(elements); size_t count = elements->size(); for (size_t i = 0; i < count; ++i) { Element* element = elements->at(i); if (selectorMatches(m_selectors[0], element, rootNode)) { matchedElements.append(element); if (firstMatchOnly) return; } } return; } Element* element = rootNode->treeScope()->getElementById(idToMatch); if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(rootNode))) return; 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; } } } }
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; }
bool SelectorDataList::matches(Element& targetElement) const { for (auto& selctor : m_selectors) { if (selectorMatches(selctor, targetElement, targetElement)) return true; } return false; }
bool SelectorDataList::matches(Element& targetElement) const { unsigned selectorCount = m_selectors.size(); for (unsigned i = 0; i < selectorCount; ++i) { if (selectorMatches(m_selectors[i], targetElement, targetElement)) return true; } return false; }
Element* SelectorDataList::executeSlowQueryFirst(Node* rootNode) const { for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(element, rootNode)) { for (unsigned i = 0; i < m_selectors.size(); ++i) { if (selectorMatches(m_selectors[i], element, rootNode)) return element; } } return 0; }
bool SelectorDataList::selectorListMatches(ContainerNode& rootNode, Element& element, typename SelectorQueryTrait::OutputType& output) const { for (unsigned i = 0; i < m_selectors.size(); ++i) { if (selectorMatches(*m_selectors[i], element, rootNode)) { SelectorQueryTrait::appendElement(output, element); return true; } } return false; }
void SelectorDataList::executeForTraverseRoot(const CSSSelector& selector, ContainerNode* traverseRoot, MatchTraverseRootState matchTraverseRoot, ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const { if (!traverseRoot) return; if (matchTraverseRoot) { if (selectorMatches(selector, toElement(*traverseRoot), rootNode)) SelectorQueryTrait::appendElement(output, toElement(*traverseRoot)); return; } for (Element& element : ElementTraversal::descendantsOf(*traverseRoot)) { if (selectorMatches(selector, element, rootNode)) { SelectorQueryTrait::appendElement(output, element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; } } }
void SelectorDataList::executeForTraverseRoot(const SelectorData& selector, ContainerNode* traverseRoot, MatchTraverseRootState matchTraverseRoot, ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const { if (!traverseRoot) return; if (matchTraverseRoot) { if (selectorMatches(selector, toElement(*traverseRoot), rootNode)) SelectorQueryTrait::appendElement(output, toElement(*traverseRoot)); return; } for (Element* element = ElementTraversal::firstWithin(*traverseRoot); element; element = ElementTraversal::next(*element, traverseRoot)) { if (selectorMatches(selector, *element, rootNode)) { SelectorQueryTrait::appendElement(output, *element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; } } }
void SelectorDataList::executeSlowQueryAll(Node* rootNode, Vector<RefPtr<Node> >& matchedElements) const { for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(element, rootNode)) { for (unsigned i = 0; i < m_selectors.size(); ++i) { if (selectorMatches(m_selectors[i], element, rootNode)) { matchedElements.append(element); break; } } } }
ALWAYS_INLINE void SelectorDataList::executeSingleSelectorData(const Node* rootNode, const SelectorData& selectorData, Vector<RefPtr<Node> >& matchedElements) const { ASSERT(m_selectors.size() == 1); for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(element, rootNode)) { if (selectorMatches(selectorData, element, rootNode)) { matchedElements.append(element); if (firstMatchOnly) return; } } }
ALWAYS_INLINE void SelectorDataList::executeSingleSelectorData(const ContainerNode& rootNode, const SelectorData& selectorData, typename SelectorQueryTrait::OutputType& output) const { ASSERT(m_selectors.size() == 1); for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) { if (selectorMatches(selectorData, element, rootNode)) { SelectorQueryTrait::appendOutputForElement(output, &element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; } } }
ALWAYS_INLINE void SelectorDataList::executeSingleSelectorData(const Node* rootNode, const SelectorData& selectorData, typename SelectorQueryTrait::OutputType& output) const { ASSERT(m_selectors.size() == 1); for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(element, rootNode)) { if (selectorMatches(selectorData, element, rootNode)) { SelectorQueryTrait::appendOutputForElement(output, element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; } } }
void SelectorDataList::execute(Node* rootNode, Vector<RefPtr<Node> >& matchedElements) const { if (canUseIdLookup(rootNode)) { ASSERT(m_selectors.size() == 1); const CSSSelector* selector = m_selectors[0].selector; Element* element = rootNode->treeScope()->getElementById(selector->value()); if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(rootNode))) return; if (selectorMatches(m_selectors[0], element, rootNode)) matchedElements.append(element); return; } unsigned selectorCount = m_selectors.size(); Node* n = rootNode->firstChild(); while (n) { if (n->isElementNode()) { Element* element = toElement(n); for (unsigned i = 0; i < selectorCount; ++i) { if (selectorMatches(m_selectors[i], element, rootNode)) { matchedElements.append(element); if (firstMatchOnly) return; break; } } if (element->firstChild()) { n = element->firstChild(); continue; } } while (!n->nextSibling()) { n = n->parentNode(); if (n == rootNode) return; } n = n->nextSibling(); } }
void SelectorDataList::executeSlow(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const { for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(*element, &rootNode)) { for (unsigned i = 0; i < m_selectors.size(); ++i) { if (selectorMatches(m_selectors[i], *element, rootNode)) { SelectorQueryTrait::appendElement(output, *element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; break; } } } }
bool SelectorDataList::matches(Element& targetElement) const { if (m_needsUpdatedDistribution) targetElement.updateDistribution(); unsigned selectorCount = m_selectors.size(); for (unsigned i = 0; i < selectorCount; ++i) { if (selectorMatches(*m_selectors[i], targetElement, targetElement)) return true; } return false; }
ALWAYS_INLINE void SelectorDataList::executeSingleMultiSelectorData(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const { for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) { for (auto& selector : m_selectors) { if (selectorMatches(selector, element, rootNode)) { SelectorQueryTrait::appendOutputForElement(output, &element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; break; } } } }
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; } } } }
ALWAYS_INLINE void SelectorDataList::executeSingleMultiSelectorData(const Node* rootNode, Vector<RefPtr<Node> >& matchedElements) const { unsigned selectorCount = m_selectors.size(); 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; } } } }
ALWAYS_INLINE void SelectorDataList::executeSingleMultiSelectorData(const Node* rootNode, typename SelectorQueryTrait::OutputType& output) const { unsigned selectorCount = m_selectors.size(); 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)) { SelectorQueryTrait::appendOutputForElement(output, element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; break; } } } }
Element* SelectorDataList::closest(Element& targetElement) const { if (m_needsUpdatedDistribution) targetElement.updateDistribution(); unsigned selectorCount = m_selectors.size(); for (Element* currentElement = &targetElement; currentElement; currentElement = currentElement->parentElement()) { for (unsigned i = 0; i < selectorCount; ++i) { if (selectorMatches(*m_selectors[i], *currentElement, targetElement)) return currentElement; } } return nullptr; }
ALWAYS_INLINE void SelectorDataList::executeSingleMultiSelectorData(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const { unsigned selectorCount = m_selectors.size(); for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) { for (unsigned i = 0; i < selectorCount; ++i) { if (selectorMatches(m_selectors[i], element, rootNode)) { SelectorQueryTrait::appendOutputForElement(output, &element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; break; } } } }