| Index: Source/core/dom/SelectorQuery.cpp
|
| diff --git a/Source/core/dom/SelectorQuery.cpp b/Source/core/dom/SelectorQuery.cpp
|
| index 9334ca52f0f986e2c164c37396d4cebb1c56e24e..f3370cccffc118be04e35c9e8b292fa0f3e091c6 100644
|
| --- a/Source/core/dom/SelectorQuery.cpp
|
| +++ b/Source/core/dom/SelectorQuery.cpp
|
| @@ -1,5 +1,6 @@
|
| /*
|
| - * Copyright (C) 2011 Apple Inc. All rights reserved.
|
| + * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
|
| + * Copyright (C) 2014 Samsung Electronics. All rights reserved.
|
| *
|
| * Redistribution and use in source and binary forms, with or without
|
| * modification, are permitted provided that the following conditions
|
| @@ -38,76 +39,45 @@
|
|
|
| namespace WebCore {
|
|
|
| -class SimpleNodeList {
|
| -public:
|
| - virtual ~SimpleNodeList() { }
|
| - virtual bool isEmpty() const = 0;
|
| - virtual Node* next() = 0;
|
| -};
|
| -
|
| -class SingleNodeList FINAL : public SimpleNodeList {
|
| -public:
|
| - explicit SingleNodeList(Node* rootNode) : m_currentNode(rootNode) { }
|
| -
|
| - virtual bool isEmpty() const OVERRIDE { return !m_currentNode; }
|
| -
|
| - virtual Node* next() OVERRIDE
|
| +struct SingleElementSelectorQueryTrait {
|
| + typedef Element* OutputType;
|
| + static const bool shouldOnlyMatchFirstElement = true;
|
| + ALWAYS_INLINE static void appendElement(OutputType& output, Element& element)
|
| {
|
| - Node* current = m_currentNode;
|
| - m_currentNode = 0;
|
| - return current;
|
| + ASSERT(!output);
|
| + output = &element;
|
| }
|
| -
|
| -private:
|
| - Node* m_currentNode;
|
| };
|
|
|
| -class ClassRootNodeList FINAL : public SimpleNodeList {
|
| -public:
|
| - ClassRootNodeList(Node& rootNode, const AtomicString& className)
|
| - : m_className(className)
|
| - , m_rootNode(rootNode)
|
| - , m_currentElement(nextInternal(ElementTraversal::firstWithin(m_rootNode))) { }
|
| -
|
| - virtual bool isEmpty() const OVERRIDE { return !m_currentElement; }
|
| -
|
| - virtual Node* next() OVERRIDE
|
| +struct AllElementsSelectorQueryTrait {
|
| + typedef Vector<RefPtr<Node> > OutputType;
|
| + static const bool shouldOnlyMatchFirstElement = false;
|
| + ALWAYS_INLINE static void appendElement(OutputType& output, Node& element)
|
| {
|
| - Node* current = m_currentElement;
|
| - ASSERT(current);
|
| - m_currentElement = nextInternal(ElementTraversal::nextSkippingChildren(*m_currentElement, &m_rootNode));
|
| - return current;
|
| + output.append(RefPtr<Node>(element));
|
| }
|
| -
|
| -private:
|
| - Element* nextInternal(Element* element)
|
| - {
|
| - for (; element; element = ElementTraversal::next(*element, &m_rootNode)) {
|
| - if (element->hasClass() && element->classNames().contains(m_className))
|
| - return element;
|
| - }
|
| - return 0;
|
| - }
|
| -
|
| - const AtomicString& m_className;
|
| - Node& m_rootNode;
|
| - Element* m_currentElement;
|
| };
|
|
|
| -class ClassElementList FINAL : public SimpleNodeList {
|
| +enum ClassElementListBehavior { AllElements, OnlyRoots };
|
| +
|
| +template <ClassElementListBehavior onlyRoots>
|
| +class ClassElementList {
|
| public:
|
| ClassElementList(Node& rootNode, const AtomicString& className)
|
| : m_className(className)
|
| , m_rootNode(rootNode)
|
| , m_currentElement(nextInternal(ElementTraversal::firstWithin(rootNode))) { }
|
|
|
| - virtual bool isEmpty() const OVERRIDE { return !m_currentElement; }
|
| + bool isEmpty() const { return !m_currentElement; }
|
|
|
| - virtual Node* next() OVERRIDE
|
| + Node* next()
|
| {
|
| Node* current = m_currentElement;
|
| ASSERT(current);
|
| - m_currentElement = nextInternal(ElementTraversal::next(*m_currentElement, &m_rootNode));
|
| + if (onlyRoots)
|
| + m_currentElement = nextInternal(ElementTraversal::nextSkippingChildren(*m_currentElement, &m_rootNode));
|
| + else
|
| + m_currentElement = nextInternal(ElementTraversal::next(*m_currentElement, &m_rootNode));
|
| return current;
|
| }
|
|
|
| @@ -169,47 +139,39 @@ bool SelectorDataList::matches(Element& targetElement) const
|
| PassRefPtr<NodeList> SelectorDataList::queryAll(Node& rootNode) const
|
| {
|
| Vector<RefPtr<Node> > result;
|
| - executeQueryAll(rootNode, result);
|
| + execute<AllElementsSelectorQueryTrait>(rootNode, result);
|
| return StaticNodeList::adopt(result);
|
| }
|
|
|
| PassRefPtr<Element> SelectorDataList::queryFirst(Node& rootNode) const
|
| {
|
| - return executeQueryFirst(rootNode);
|
| -}
|
| -
|
| -void SelectorDataList::collectElementsByClassName(Node& rootNode, const AtomicString& className, Vector<RefPtr<Node> >& traversalRoots) const
|
| -{
|
| - for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(*element, &rootNode)) {
|
| - if (element->hasClass() && element->classNames().contains(className))
|
| - traversalRoots.append(element);
|
| - }
|
| -}
|
| -
|
| -void SelectorDataList::collectElementsByTagName(Node& rootNode, const QualifiedName& tagName, Vector<RefPtr<Node> >& traversalRoots) const
|
| -{
|
| - for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(*element, &rootNode)) {
|
| - if (SelectorChecker::tagMatches(*element, tagName))
|
| - traversalRoots.append(element);
|
| - }
|
| + Element* matchedElement = 0;
|
| + execute<SingleElementSelectorQueryTrait>(rootNode, matchedElement);
|
| + return matchedElement;
|
| }
|
|
|
| -Element* SelectorDataList::findElementByClassName(Node& rootNode, const AtomicString& className) const
|
| +template <typename SelectorQueryTrait>
|
| +void SelectorDataList::collectElementsByClassName(Node& rootNode, const AtomicString& className, typename SelectorQueryTrait::OutputType& output) const
|
| {
|
| for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(*element, &rootNode)) {
|
| - if (element->hasClass() && element->classNames().contains(className))
|
| - return element;
|
| + if (element->hasClass() && element->classNames().contains(className)) {
|
| + SelectorQueryTrait::appendElement(output, *element);
|
| + if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
|
| + return;
|
| + }
|
| }
|
| - return 0;
|
| }
|
|
|
| -Element* SelectorDataList::findElementByTagName(Node& rootNode, const QualifiedName& tagName) const
|
| +template <typename SelectorQueryTrait>
|
| +void SelectorDataList::collectElementsByTagName(Node& rootNode, const QualifiedName& tagName, typename SelectorQueryTrait::OutputType& output) const
|
| {
|
| for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(*element, &rootNode)) {
|
| - if (SelectorChecker::tagMatches(*element, tagName))
|
| - return element;
|
| + if (SelectorChecker::tagMatches(*element, tagName)) {
|
| + SelectorQueryTrait::appendElement(output, *element);
|
| + if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
|
| + return;
|
| + }
|
| }
|
| - return 0;
|
| }
|
|
|
| inline bool SelectorDataList::canUseFastQuery(const Node& rootNode) const
|
| @@ -237,7 +199,8 @@ inline bool ancestorHasClassName(Node& rootNode, const AtomicString& className)
|
| //
|
| // The travseralRoots may be empty, regardless of the returned bool value, if this method finds that the selectors won't
|
| // match any element.
|
| -PassOwnPtr<SimpleNodeList> SelectorDataList::findTraverseRoots(Node& rootNode, bool& matchTraverseRoots) const
|
| +template <typename SelectorQueryTrait>
|
| +void SelectorDataList::findTraverseRootsAndExecute(Node& rootNode, typename SelectorQueryTrait::OutputType& output) const
|
| {
|
| // We need to return the matches in document order. To use id lookup while there is possiblity of multiple matches
|
| // we would need to sort the results. For now, just traverse the document in that case.
|
| @@ -256,29 +219,34 @@ PassOwnPtr<SimpleNodeList> SelectorDataList::findTraverseRoots(Node& rootNode, b
|
| else if (!element || isRightmostSelector)
|
| adjustedNode = 0;
|
| if (isRightmostSelector) {
|
| - matchTraverseRoots = true;
|
| - return adoptPtr(new SingleNodeList(adjustedNode));
|
| + executeForTraverseRoot<SelectorQueryTrait>(m_selectors[0], adjustedNode, MatchesTraverseRoots, rootNode, output);
|
| + return;
|
| }
|
| +
|
| if (startFromParent && adjustedNode)
|
| adjustedNode = adjustedNode->parentNode();
|
|
|
| - matchTraverseRoots = false;
|
| - return adoptPtr(new SingleNodeList(adjustedNode));
|
| + executeForTraverseRoot<SelectorQueryTrait>(m_selectors[0], adjustedNode, DoesNotMatchTraverseRoots, rootNode, output);
|
| + return;
|
| }
|
|
|
| // If we have both CSSSelector::Id and CSSSelector::Class at the same time, we should use Id
|
| // to find traverse root.
|
| - if (!startFromParent && selector->m_match == CSSSelector::Class) {
|
| + if (!SelectorQueryTrait::shouldOnlyMatchFirstElement && !startFromParent && selector->m_match == CSSSelector::Class) {
|
| if (isRightmostSelector) {
|
| - matchTraverseRoots = true;
|
| - return adoptPtr(new ClassElementList(rootNode, selector->value()));
|
| + ClassElementList<AllElements> traverseRoots(rootNode, selector->value());
|
| + executeForTraverseRoots<SelectorQueryTrait>(m_selectors[0], traverseRoots, MatchesTraverseRoots, rootNode, output);
|
| + return;
|
| }
|
| - matchTraverseRoots = false;
|
| // Since there exists some ancestor element which has the class name, we need to see all children of rootNode.
|
| - if (ancestorHasClassName(rootNode, selector->value()))
|
| - return adoptPtr(new SingleNodeList(&rootNode));
|
| + if (ancestorHasClassName(rootNode, selector->value())) {
|
| + executeForTraverseRoot<SelectorQueryTrait>(m_selectors[0], &rootNode, DoesNotMatchTraverseRoots, rootNode, output);
|
| + return;
|
| + }
|
|
|
| - return adoptPtr(new ClassRootNodeList(rootNode, selector->value()));
|
| + ClassElementList<OnlyRoots> traverseRoots(rootNode, selector->value());
|
| + executeForTraverseRoots<SelectorQueryTrait>(m_selectors[0], traverseRoots, DoesNotMatchTraverseRoots, rootNode, output);
|
| + return;
|
| }
|
|
|
| if (selector->relation() == CSSSelector::SubSelector)
|
| @@ -290,165 +258,95 @@ PassOwnPtr<SimpleNodeList> SelectorDataList::findTraverseRoots(Node& rootNode, b
|
| startFromParent = false;
|
| }
|
|
|
| - matchTraverseRoots = false;
|
| - return adoptPtr(new SingleNodeList(&rootNode));
|
| + executeForTraverseRoot<SelectorQueryTrait>(m_selectors[0], &rootNode, DoesNotMatchTraverseRoots, rootNode, output);
|
| }
|
|
|
| -void SelectorDataList::executeSlowQueryAll(Node& rootNode, Vector<RefPtr<Node> >& matchedElements) const
|
| +template <typename SelectorQueryTrait>
|
| +void SelectorDataList::executeForTraverseRoot(const SelectorData& selector, Node* traverseRoot, MatchTraverseRootState matchTraverseRoot, Node& 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)) {
|
| - matchedElements.append(element);
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -const CSSSelector* SelectorDataList::selectorForIdLookup(const CSSSelector* firstSelector) const
|
| -{
|
| - for (const CSSSelector* selector = firstSelector; selector; selector = selector->tagHistory()) {
|
| - if (selector->m_match == CSSSelector::Id)
|
| - return selector;
|
| - if (selector->relation() != CSSSelector::SubSelector)
|
| - break;
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -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 SelectorData& selector = m_selectors[0];
|
| - const CSSSelector* firstSelector = selector.selector;
|
| + if (!traverseRoot)
|
| + return;
|
|
|
| - // Fast path for querySelectorAll('#id'), querySelectorAll('tag#id').
|
| - if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) {
|
| - const AtomicString& idToMatch = idSelector->value();
|
| - if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) {
|
| - 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];
|
| - ASSERT(element);
|
| - if (!(isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode)))
|
| - continue;
|
| - if (selectorMatches(selector, *element, rootNode))
|
| - matchedElements.append(element);
|
| - }
|
| - return;
|
| - }
|
| - Element* element = rootNode.treeScope().getElementById(idToMatch);
|
| - if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode)))
|
| - return;
|
| - if (selectorMatches(selector, *element, rootNode))
|
| - matchedElements.append(element);
|
| + if (matchTraverseRoot) {
|
| + if (selectorMatches(selector, toElement(*traverseRoot), rootNode))
|
| + SelectorQueryTrait::appendElement(output, toElement(*traverseRoot));
|
| return;
|
| }
|
|
|
| - if (!firstSelector->tagHistory()) {
|
| - // Fast path for querySelectorAl('.foo'), and querySelectorAll('div').
|
| - switch (firstSelector->m_match) {
|
| - 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.
|
| + 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;
|
| }
|
| }
|
| +}
|
|
|
| - bool matchTraverseRoots;
|
| - OwnPtr<SimpleNodeList> traverseRoots = findTraverseRoots(rootNode, matchTraverseRoots);
|
| - if (traverseRoots->isEmpty())
|
| +template <typename SelectorQueryTrait, typename SimpleNodeListType>
|
| +void SelectorDataList::executeForTraverseRoots(const SelectorData& selector, SimpleNodeListType& traverseRoots, MatchTraverseRootState matchTraverseRoots, Node& rootNode, typename SelectorQueryTrait::OutputType& output) const
|
| +{
|
| + if (traverseRoots.isEmpty())
|
| return;
|
|
|
| if (matchTraverseRoots) {
|
| - while (!traverseRoots->isEmpty()) {
|
| - Node& node = *traverseRoots->next();
|
| + while (!traverseRoots.isEmpty()) {
|
| + Node& node = *traverseRoots.next();
|
| Element& element = toElement(node);
|
| - if (selectorMatches(selector, element, rootNode))
|
| - matchedElements.append(&element);
|
| + if (selectorMatches(selector, element, rootNode)) {
|
| + SelectorQueryTrait::appendElement(output, element);
|
| + if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
|
| + return;
|
| + }
|
| }
|
| return;
|
| }
|
|
|
| - while (!traverseRoots->isEmpty()) {
|
| - Node* traverseRoot = traverseRoots->next();
|
| + while (!traverseRoots.isEmpty()) {
|
| + Node* traverseRoot = traverseRoots.next();
|
| ASSERT(traverseRoot);
|
| for (Element* element = ElementTraversal::firstWithin(*traverseRoot); element; element = ElementTraversal::next(*element, traverseRoot)) {
|
| - if (selectorMatches(selector, *element, rootNode))
|
| - matchedElements.append(element);
|
| + if (selectorMatches(selector, *element, rootNode)) {
|
| + SelectorQueryTrait::appendElement(output, *element);
|
| + if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
|
| + return;
|
| + }
|
| }
|
| }
|
| }
|
|
|
| -// If matchTraverseRoot is true, the returned Node is the single Element that may match the selector query.
|
| -//
|
| -// If matchTraverseRoot is false, the returned Node is the rootNode parameter or a descendant of rootNode representing
|
| -// the subtree for which we can limit the querySelector traversal.
|
| -//
|
| -// The returned Node may be 0, regardless of matchTraverseRoot, if this method finds that the selectors won't
|
| -// match any element.
|
| -Node* SelectorDataList::findTraverseRoot(Node& rootNode, bool& matchTraverseRoot) const
|
| +template <typename SelectorQueryTrait>
|
| +void SelectorDataList::executeSlow(Node& rootNode, typename SelectorQueryTrait::OutputType& output) const
|
| {
|
| - // We need to return the matches in document order. To use id lookup while there is possiblity of multiple matches
|
| - // we would need to sort the results. For now, just traverse the document in that case.
|
| - ASSERT(m_selectors.size() == 1);
|
| - ASSERT(m_selectors[0].selector);
|
| -
|
| - bool matchSingleNode = true;
|
| - bool startFromParent = false;
|
| - for (const CSSSelector* selector = m_selectors[0].selector; selector; selector = selector->tagHistory()) {
|
| - if (selector->m_match == CSSSelector::Id && !rootNode.document().containsMultipleElementsWithId(selector->value())) {
|
| - Element* element = rootNode.treeScope().getElementById(selector->value());
|
| - Node* adjustedRootNode = &rootNode;
|
| - if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode)))
|
| - adjustedRootNode = element;
|
| - else if (!element || matchSingleNode)
|
| - adjustedRootNode = 0;
|
| - if (matchSingleNode) {
|
| - matchTraverseRoot = true;
|
| - return adjustedRootNode;
|
| + 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;
|
| }
|
| - if (startFromParent && adjustedRootNode)
|
| - adjustedRootNode = adjustedRootNode->parentNode();
|
| - matchTraverseRoot = false;
|
| - return adjustedRootNode;
|
| }
|
| - if (selector->relation() == CSSSelector::SubSelector)
|
| - continue;
|
| - matchSingleNode = false;
|
| - if (selector->relation() == CSSSelector::DirectAdjacent || selector->relation() == CSSSelector::IndirectAdjacent)
|
| - startFromParent = true;
|
| - else
|
| - startFromParent = false;
|
| }
|
| - matchTraverseRoot = false;
|
| - return &rootNode;
|
| }
|
|
|
| -Element* SelectorDataList::executeSlowQueryFirst(Node& rootNode) const
|
| +const CSSSelector* SelectorDataList::selectorForIdLookup(const CSSSelector* firstSelector) 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;
|
| - }
|
| + for (const CSSSelector* selector = firstSelector; selector; selector = selector->tagHistory()) {
|
| + if (selector->m_match == CSSSelector::Id)
|
| + return selector;
|
| + if (selector->relation() != CSSSelector::SubSelector)
|
| + break;
|
| }
|
| return 0;
|
| }
|
|
|
| -Element* SelectorDataList::executeQueryFirst(Node& rootNode) const
|
| +template <typename SelectorQueryTrait>
|
| +void SelectorDataList::execute(Node& rootNode, typename SelectorQueryTrait::OutputType& output) const
|
| {
|
| - if (!canUseFastQuery(rootNode))
|
| - return executeSlowQueryFirst(rootNode);
|
| + if (!canUseFastQuery(rootNode)) {
|
| + executeSlow<SelectorQueryTrait>(rootNode, output);
|
| + return;
|
| + }
|
|
|
| ASSERT(m_selectors.size() == 1);
|
| ASSERT(m_selectors[0].selector);
|
| @@ -456,56 +354,47 @@ Element* SelectorDataList::executeQueryFirst(Node& rootNode) const
|
| const SelectorData& selector = m_selectors[0];
|
| const CSSSelector* firstSelector = selector.selector;
|
|
|
| - // Fast path for querySelectorAll('#id'), querySelectorAll('tag#id').
|
| + // 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 Vector<Element*>& elements = rootNode.treeScope().getAllElementsById(idToMatch);
|
| size_t count = elements.size();
|
| for (size_t i = 0; i < count; ++i) {
|
| - Element* element = elements[i];
|
| - ASSERT(element);
|
| - if (!(isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode)))
|
| + Element& element = *elements[i];
|
| + if (!(isTreeScopeRoot(rootNode) || element.isDescendantOf(&rootNode)))
|
| continue;
|
| - if (selectorMatches(selector, *element, rootNode))
|
| - return element;
|
| + if (selectorMatches(selector, element, rootNode)) {
|
| + SelectorQueryTrait::appendElement(output, element);
|
| + if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
|
| + return;
|
| + }
|
| }
|
| - return 0;
|
| + return;
|
| }
|
| Element* element = rootNode.treeScope().getElementById(idToMatch);
|
| if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode)))
|
| - return 0;
|
| - return selectorMatches(selector, *element, rootNode) ? element : 0;
|
| + return;
|
| + if (selectorMatches(selector, *element, rootNode))
|
| + SelectorQueryTrait::appendElement(output, *element);
|
| + return;
|
| }
|
|
|
| if (!firstSelector->tagHistory()) {
|
| - // Fast path for querySelector('.foo'), and querySelector('div').
|
| - // Many web developers uses querySelector with these simple selectors.
|
| + // Fast path for querySelector*('.foo'), and querySelector*('div').
|
| switch (firstSelector->m_match) {
|
| case CSSSelector::Class:
|
| - return findElementByClassName(rootNode, firstSelector->value());
|
| + collectElementsByClassName<SelectorQueryTrait>(rootNode, firstSelector->value(), output);
|
| + return;
|
| case CSSSelector::Tag:
|
| - return findElementByTagName(rootNode, firstSelector->tagQName());
|
| + collectElementsByTagName<SelectorQueryTrait>(rootNode, firstSelector->tagQName(), output);
|
| + return;
|
| default:
|
| break; // If we need another fast path, add here.
|
| }
|
| }
|
|
|
| - bool matchTraverseRoot;
|
| - Node* traverseRootNode = findTraverseRoot(rootNode, matchTraverseRoot);
|
| - if (!traverseRootNode)
|
| - return 0;
|
| - if (matchTraverseRoot) {
|
| - ASSERT(traverseRootNode->isElementNode());
|
| - Element& element = toElement(*traverseRootNode);
|
| - return selectorMatches(selector, element, rootNode) ? &element : 0;
|
| - }
|
| -
|
| - for (Element* element = ElementTraversal::firstWithin(*traverseRootNode); element; element = ElementTraversal::next(*element, traverseRootNode)) {
|
| - if (selectorMatches(selector, *element, rootNode))
|
| - return element;
|
| - }
|
| - return 0;
|
| + findTraverseRootsAndExecute<SelectorQueryTrait>(rootNode, output);
|
| }
|
|
|
| SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList)
|
|
|