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;
}
예제 #2
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;
            }
        }
    }
}