Commit bcffd352 authored by esprehn@chromium.org's avatar esprehn@chromium.org

Remove SelectorCheckerFastPath

There's no evidence that this fast path actually matters, the only difference 
seems to be the number of if and switch statements. If it does we should look 
into how we can make the regular SelectorChecker faster instead of having two modes.

Review URL: https://codereview.chromium.org/208423010

git-svn-id: svn://svn.chromium.org/blink/trunk@169993 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 01a449a5
...@@ -828,8 +828,6 @@ ...@@ -828,8 +828,6 @@
'css/SVGCSSComputedStyleDeclaration.cpp', 'css/SVGCSSComputedStyleDeclaration.cpp',
'css/SelectorChecker.cpp', 'css/SelectorChecker.cpp',
'css/SelectorChecker.h', 'css/SelectorChecker.h',
'css/SelectorCheckerFastPath.cpp',
'css/SelectorCheckerFastPath.h',
'css/SelectorFilter.cpp', 'css/SelectorFilter.cpp',
'css/SelectorFilter.h', 'css/SelectorFilter.h',
'css/SiblingTraversalStrategies.h', 'css/SiblingTraversalStrategies.h',
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include "core/css/CSSStyleRule.h" #include "core/css/CSSStyleRule.h"
#include "core/css/CSSStyleSheet.h" #include "core/css/CSSStyleSheet.h"
#include "core/css/CSSSupportsRule.h" #include "core/css/CSSSupportsRule.h"
#include "core/css/SelectorCheckerFastPath.h"
#include "core/css/SiblingTraversalStrategies.h" #include "core/css/SiblingTraversalStrategies.h"
#include "core/css/StylePropertySet.h" #include "core/css/StylePropertySet.h"
#include "core/css/resolver/StyleResolver.h" #include "core/css/resolver/StyleResolver.h"
...@@ -259,29 +258,6 @@ void ElementRuleCollector::sortAndTransferMatchedRules() ...@@ -259,29 +258,6 @@ void ElementRuleCollector::sortAndTransferMatchedRules()
inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, const ContainerNode* scope, SelectorChecker::BehaviorAtBoundary behaviorAtBoundary, SelectorChecker::MatchResult* result) inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, const ContainerNode* scope, SelectorChecker::BehaviorAtBoundary behaviorAtBoundary, SelectorChecker::MatchResult* result)
{ {
// Scoped rules can't match because the fast path uses a pool of tag/class/ids, collected from
// elements in that tree and those will never match the host, since it's in a different pool.
if (ruleData.hasFastCheckableSelector() && !scope) {
// We know this selector does not include any pseudo elements.
if (m_pseudoStyleRequest.pseudoId != NOPSEUDO)
return false;
// We know a sufficiently simple single part selector matches simply because we found it from the rule hash.
// This is limited to HTML only so we don't need to check the namespace.
ASSERT(m_context.element());
if (ruleData.hasRightmostSelectorMatchingHTMLBasedOnRuleHash() && m_context.element()->isHTMLElement()) {
if (!ruleData.hasMultipartSelector())
return true;
}
if (ruleData.selector().m_match == CSSSelector::Tag && !SelectorChecker::tagMatches(*m_context.element(), ruleData.selector().tagQName()))
return false;
SelectorCheckerFastPath selectorCheckerFastPath(ruleData.selector(), *m_context.element());
if (!selectorCheckerFastPath.matchesRightmostAttributeSelector())
return false;
return selectorCheckerFastPath.matches();
}
// Slow path.
SelectorChecker selectorChecker(m_context.element()->document(), m_mode); SelectorChecker selectorChecker(m_context.element()->document(), m_mode);
SelectorChecker::SelectorCheckingContext context(ruleData.selector(), m_context.element(), SelectorChecker::VisitedMatchEnabled); SelectorChecker::SelectorCheckingContext context(ruleData.selector(), m_context.element(), SelectorChecker::VisitedMatchEnabled);
context.elementStyle = m_style.get(); context.elementStyle = m_style.get();
......
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
#include "core/css/CSSSelector.h" #include "core/css/CSSSelector.h"
#include "core/css/CSSSelectorList.h" #include "core/css/CSSSelectorList.h"
#include "core/css/SelectorChecker.h" #include "core/css/SelectorChecker.h"
#include "core/css/SelectorCheckerFastPath.h"
#include "core/css/SelectorFilter.h" #include "core/css/SelectorFilter.h"
#include "core/css/StyleRuleImport.h" #include "core/css/StyleRuleImport.h"
#include "core/css/StyleSheetContents.h" #include "core/css/StyleSheetContents.h"
...@@ -127,7 +126,6 @@ RuleData::RuleData(StyleRule* rule, unsigned selectorIndex, unsigned position, A ...@@ -127,7 +126,6 @@ RuleData::RuleData(StyleRule* rule, unsigned selectorIndex, unsigned position, A
, m_selectorIndex(selectorIndex) , m_selectorIndex(selectorIndex)
, m_isLastInArray(false) , m_isLastInArray(false)
, m_position(position) , m_position(position)
, m_hasFastCheckableSelector((addRuleFlags & RuleCanUseFastCheckSelector) && SelectorCheckerFastPath::canUse(selector()))
, m_specificity(selector().specificity()) , m_specificity(selector().specificity())
, m_hasMultipartSelector(!!selector().tagHistory()) , m_hasMultipartSelector(!!selector().tagHistory())
, m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash(isSelectorMatchingHTMLBasedOnRuleHash(selector())) , m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash(isSelectorMatchingHTMLBasedOnRuleHash(selector()))
......
...@@ -81,7 +81,6 @@ public: ...@@ -81,7 +81,6 @@ public:
bool isLastInArray() const { return m_isLastInArray; } bool isLastInArray() const { return m_isLastInArray; }
void setLastInArray(bool flag) { m_isLastInArray = flag; } void setLastInArray(bool flag) { m_isLastInArray = flag; }
bool hasFastCheckableSelector() const { return m_hasFastCheckableSelector; }
bool hasMultipartSelector() const { return m_hasMultipartSelector; } bool hasMultipartSelector() const { return m_hasMultipartSelector; }
bool hasRightmostSelectorMatchingHTMLBasedOnRuleHash() const { return m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash; } bool hasRightmostSelectorMatchingHTMLBasedOnRuleHash() const { return m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash; }
bool containsUncommonAttributeSelector() const { return m_containsUncommonAttributeSelector; } bool containsUncommonAttributeSelector() const { return m_containsUncommonAttributeSelector; }
...@@ -102,7 +101,6 @@ private: ...@@ -102,7 +101,6 @@ private:
// This number was picked fairly arbitrarily. We can probably lower it if we need to. // This number was picked fairly arbitrarily. We can probably lower it if we need to.
// Some simple testing showed <100,000 RuleData's on large sites. // Some simple testing showed <100,000 RuleData's on large sites.
unsigned m_position : 18; unsigned m_position : 18;
unsigned m_hasFastCheckableSelector : 1;
unsigned m_specificity : 24; unsigned m_specificity : 24;
unsigned m_hasMultipartSelector : 1; unsigned m_hasMultipartSelector : 1;
unsigned m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash : 1; unsigned m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash : 1;
......
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
* Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
* Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
* Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (C) Research In Motion Limited 2011. All rights reserved.
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "core/css/SelectorCheckerFastPath.h"
#include "HTMLNames.h"
#include "core/dom/Element.h"
#include "core/html/HTMLDocument.h"
namespace WebCore {
using namespace HTMLNames;
namespace {
template <bool checkValue(const Element&, const CSSSelector&)>
inline bool fastCheckSingleSelector(const CSSSelector*& selector, const Element*& element, const CSSSelector*& topChildOrSubselector, const Element*& topChildOrSubselectorMatchElement)
{
for (; element; element = element->parentElement()) {
if (checkValue(*element, *selector)) {
if (selector->relation() == CSSSelector::Descendant)
topChildOrSubselector = 0;
else if (!topChildOrSubselector) {
ASSERT(selector->relation() == CSSSelector::Child || selector->relation() == CSSSelector::SubSelector);
topChildOrSubselector = selector;
topChildOrSubselectorMatchElement = element;
}
if (selector->relation() != CSSSelector::SubSelector)
element = element->parentElement();
selector = selector->tagHistory();
return true;
}
if (topChildOrSubselector) {
// Child or subselector check failed.
// If the match element is null, topChildOrSubselector was also the very topmost selector and had to match
// the original element we were checking.
if (!topChildOrSubselectorMatchElement)
return false;
// There may be other matches down the ancestor chain.
// Rewind to the topmost child or subselector and the element it matched, continue checking ancestors.
selector = topChildOrSubselector;
element = topChildOrSubselectorMatchElement->parentElement();
topChildOrSubselector = 0;
return true;
}
}
return false;
}
inline bool checkClassValue(const Element& element, const CSSSelector& selector)
{
return element.hasClass() && element.classNames().contains(selector.value());
}
inline bool checkIDValue(const Element& element, const CSSSelector& selector)
{
return element.hasID() && element.idForStyleResolution() == selector.value();
}
inline bool checkExactAttributeValue(const Element& element, const CSSSelector& selector)
{
return SelectorChecker::checkExactAttribute(element, selector.attribute(), selector.value().impl());
}
inline bool checkTagValue(const Element& element, const CSSSelector& selector)
{
return SelectorChecker::tagMatches(element, selector.tagQName());
}
}
SelectorCheckerFastPath::SelectorCheckerFastPath(const CSSSelector& selector, const Element& element)
: m_selector(selector)
, m_element(element)
{
}
bool SelectorCheckerFastPath::matchesRightmostSelector(SelectorChecker::VisitedMatchType visitedMatchType) const
{
ASSERT(SelectorCheckerFastPath::canUse(m_selector));
switch (m_selector.m_match) {
case CSSSelector::Tag:
return checkTagValue(m_element, m_selector);
case CSSSelector::Class:
return checkClassValue(m_element, m_selector);
case CSSSelector::Id:
return checkIDValue(m_element, m_selector);
case CSSSelector::Exact:
case CSSSelector::Set:
return checkExactAttributeValue(m_element, m_selector);
case CSSSelector::PseudoClass:
return commonPseudoClassSelectorMatches(visitedMatchType);
default:
ASSERT_NOT_REACHED();
}
return false;
}
bool SelectorCheckerFastPath::matches() const
{
ASSERT(matchesRightmostSelector(SelectorChecker::VisitedMatchEnabled));
const CSSSelector* selector = &m_selector;
const Element* element = &m_element;
const CSSSelector* topChildOrSubselector = 0;
const Element* topChildOrSubselectorMatchElement = 0;
if (selector->relation() == CSSSelector::Child || selector->relation() == CSSSelector::SubSelector)
topChildOrSubselector = selector;
if (selector->relation() != CSSSelector::SubSelector)
element = element->parentElement();
selector = selector->tagHistory();
// We know this compound selector has descendant, child and subselector combinators only and all components are simple.
while (selector) {
switch (selector->m_match) {
case CSSSelector::Class:
if (!fastCheckSingleSelector<checkClassValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
return false;
break;
case CSSSelector::Id:
if (!fastCheckSingleSelector<checkIDValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
return false;
break;
case CSSSelector::Tag:
if (!fastCheckSingleSelector<checkTagValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
return false;
break;
case CSSSelector::Set:
case CSSSelector::Exact:
if (!fastCheckSingleSelector<checkExactAttributeValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
return false;
break;
default:
ASSERT_NOT_REACHED();
}
}
return true;
}
static inline bool isFastCheckableRelation(CSSSelector::Relation relation)
{
return relation == CSSSelector::Descendant || relation == CSSSelector::Child || relation == CSSSelector::SubSelector;
}
static inline bool isFastCheckableMatch(const CSSSelector& selector)
{
if (selector.m_match == CSSSelector::Set) {
// Style attribute is generated lazily but the fast path doesn't trigger it.
// Disallow them here rather than making the fast path more branchy.
return selector.attribute() != styleAttr;
}
if (selector.m_match == CSSSelector::Exact)
return selector.attribute() != styleAttr && HTMLDocument::isCaseSensitiveAttribute(selector.attribute());
return selector.m_match == CSSSelector::Tag || selector.m_match == CSSSelector::Id || selector.m_match == CSSSelector::Class;
}
static inline bool isFastCheckableRightmostSelector(const CSSSelector& selector)
{
if (!isFastCheckableRelation(selector.relation()))
return false;
return isFastCheckableMatch(selector) || SelectorChecker::isCommonPseudoClassSelector(selector);
}
bool SelectorCheckerFastPath::canUse(const CSSSelector& selector)
{
if (!isFastCheckableRightmostSelector(selector))
return false;
for (const CSSSelector* current = selector.tagHistory(); current; current = current->tagHistory()) {
if (!isFastCheckableRelation(current->relation()))
return false;
if (!isFastCheckableMatch(*current))
return false;
}
return true;
}
bool SelectorCheckerFastPath::commonPseudoClassSelectorMatches(SelectorChecker::VisitedMatchType visitedMatchType) const
{
ASSERT(SelectorChecker::isCommonPseudoClassSelector(m_selector));
switch (m_selector.pseudoType()) {
case CSSSelector::PseudoLink:
case CSSSelector::PseudoAnyLink:
return m_element.isLink();
case CSSSelector::PseudoVisited:
return m_element.isLink() && visitedMatchType == SelectorChecker::VisitedMatchEnabled;
case CSSSelector::PseudoFocus:
return SelectorChecker::matchesFocusPseudoClass(m_element);
default:
ASSERT_NOT_REACHED();
}
return true;
}
}
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
* Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
* Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
* Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (C) Research In Motion Limited 2011. All rights reserved.
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef SelectorCheckerFastPath_h
#define SelectorCheckerFastPath_h
#include "core/css/CSSSelector.h"
#include "core/css/SelectorChecker.h"
namespace WebCore {
class SelectorCheckerFastPath {
public:
SelectorCheckerFastPath(const CSSSelector&, const Element&);
bool matches() const;
bool matchesRightmostSelector(SelectorChecker::VisitedMatchType) const;
bool matchesRightmostAttributeSelector() const;
static bool canUse(const CSSSelector&);
private:
bool commonPseudoClassSelectorMatches(SelectorChecker::VisitedMatchType) const;
const CSSSelector& m_selector;
const Element& m_element;
};
inline bool SelectorCheckerFastPath::matchesRightmostAttributeSelector() const
{
if (m_selector.m_match == CSSSelector::Exact || m_selector.m_match == CSSSelector::Set)
return SelectorChecker::checkExactAttribute(m_element, m_selector.attribute(), m_selector.value().impl());
ASSERT(!m_selector.isAttributeSelector());
return true;
}
}
#endif
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include "bindings/v8/ExceptionState.h" #include "bindings/v8/ExceptionState.h"
#include "core/css/parser/BisonCSSParser.h" #include "core/css/parser/BisonCSSParser.h"
#include "core/css/SelectorChecker.h" #include "core/css/SelectorChecker.h"
#include "core/css/SelectorCheckerFastPath.h"
#include "core/css/SiblingTraversalStrategies.h" #include "core/css/SiblingTraversalStrategies.h"
#include "core/dom/Document.h" #include "core/dom/Document.h"
#include "core/dom/ElementTraversal.h" #include "core/dom/ElementTraversal.h"
...@@ -110,22 +109,15 @@ void SelectorDataList::initialize(const CSSSelectorList& selectorList) ...@@ -110,22 +109,15 @@ void SelectorDataList::initialize(const CSSSelectorList& selectorList)
m_selectors.reserveInitialCapacity(selectorCount); m_selectors.reserveInitialCapacity(selectorCount);
unsigned index = 0; unsigned index = 0;
for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector), ++index) { for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector), ++index) {
m_selectors.uncheckedAppend(SelectorData(*selector, SelectorCheckerFastPath::canUse(*selector))); m_selectors.uncheckedAppend(selector);
m_crossesTreeBoundary |= selectorList.hasCombinatorCrossingTreeBoundaryAt(index); m_crossesTreeBoundary |= selectorList.hasCombinatorCrossingTreeBoundaryAt(index);
} }
} }
inline bool SelectorDataList::selectorMatches(const SelectorData& selectorData, Element& element, const ContainerNode& rootNode) const inline bool SelectorDataList::selectorMatches(const CSSSelector& selector, Element& element, const ContainerNode& rootNode) const
{ {
if (selectorData.isFastCheckable && !element.isSVGElement()) {
SelectorCheckerFastPath selectorCheckerFastPath(selectorData.selector, element);
if (!selectorCheckerFastPath.matchesRightmostSelector(SelectorChecker::VisitedMatchDisabled))
return false;
return selectorCheckerFastPath.matches();
}
SelectorChecker selectorChecker(element.document(), SelectorChecker::QueryingRules); SelectorChecker selectorChecker(element.document(), SelectorChecker::QueryingRules);
SelectorChecker::SelectorCheckingContext selectorCheckingContext(selectorData.selector, &element, SelectorChecker::VisitedMatchDisabled); SelectorChecker::SelectorCheckingContext selectorCheckingContext(selector, &element, SelectorChecker::VisitedMatchDisabled);
selectorCheckingContext.behaviorAtBoundary = SelectorChecker::StaysWithinTreeScope; selectorCheckingContext.behaviorAtBoundary = SelectorChecker::StaysWithinTreeScope;
selectorCheckingContext.scope = !rootNode.isDocumentNode() ? &rootNode : 0; selectorCheckingContext.scope = !rootNode.isDocumentNode() ? &rootNode : 0;
return selectorChecker.match(selectorCheckingContext, DOMSiblingTraversalStrategy()) == SelectorChecker::SelectorMatches; return selectorChecker.match(selectorCheckingContext, DOMSiblingTraversalStrategy()) == SelectorChecker::SelectorMatches;
...@@ -135,7 +127,7 @@ bool SelectorDataList::matches(Element& targetElement) const ...@@ -135,7 +127,7 @@ bool SelectorDataList::matches(Element& targetElement) const
{ {
unsigned selectorCount = m_selectors.size(); unsigned selectorCount = m_selectors.size();
for (unsigned i = 0; i < selectorCount; ++i) { for (unsigned i = 0; i < selectorCount; ++i) {
if (selectorMatches(m_selectors[i], targetElement, targetElement)) if (selectorMatches(*m_selectors[i], targetElement, targetElement))
return true; return true;
} }
...@@ -215,7 +207,7 @@ void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type ...@@ -215,7 +207,7 @@ void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type
bool isRightmostSelector = true; bool isRightmostSelector = true;
bool startFromParent = false; bool startFromParent = false;
for (const CSSSelector* selector = &m_selectors[0].selector; selector; selector = selector->tagHistory()) { for (const CSSSelector* selector = m_selectors[0]; selector; selector = selector->tagHistory()) {
if (selector->m_match == CSSSelector::Id && !rootNode.document().containsMultipleElementsWithId(selector->value())) { if (selector->m_match == CSSSelector::Id && !rootNode.document().containsMultipleElementsWithId(selector->value())) {
Element* element = rootNode.treeScope().getElementById(selector->value()); Element* element = rootNode.treeScope().getElementById(selector->value());
ContainerNode* adjustedNode = &rootNode; ContainerNode* adjustedNode = &rootNode;
...@@ -224,14 +216,14 @@ void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type ...@@ -224,14 +216,14 @@ void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type
else if (!element || isRightmostSelector) else if (!element || isRightmostSelector)
adjustedNode = 0; adjustedNode = 0;
if (isRightmostSelector) { if (isRightmostSelector) {
executeForTraverseRoot<SelectorQueryTrait>(m_selectors[0], adjustedNode, MatchesTraverseRoots, rootNode, output); executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], adjustedNode, MatchesTraverseRoots, rootNode, output);
return; return;
} }
if (startFromParent && adjustedNode) if (startFromParent && adjustedNode)
adjustedNode = adjustedNode->parentNode(); adjustedNode = adjustedNode->parentNode();
executeForTraverseRoot<SelectorQueryTrait>(m_selectors[0], adjustedNode, DoesNotMatchTraverseRoots, rootNode, output); executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], adjustedNode, DoesNotMatchTraverseRoots, rootNode, output);
return; return;
} }
...@@ -240,17 +232,17 @@ void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type ...@@ -240,17 +232,17 @@ void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type
if (!SelectorQueryTrait::shouldOnlyMatchFirstElement && !startFromParent && selector->m_match == CSSSelector::Class) { if (!SelectorQueryTrait::shouldOnlyMatchFirstElement && !startFromParent && selector->m_match == CSSSelector::Class) {
if (isRightmostSelector) { if (isRightmostSelector) {
ClassElementList<AllElements> traverseRoots(rootNode, selector->value()); ClassElementList<AllElements> traverseRoots(rootNode, selector->value());
executeForTraverseRoots<SelectorQueryTrait>(m_selectors[0], traverseRoots, MatchesTraverseRoots, rootNode, output); executeForTraverseRoots<SelectorQueryTrait>(*m_selectors[0], traverseRoots, MatchesTraverseRoots, rootNode, output);
return; return;
} }
// Since there exists some ancestor element which has the class name, we need to see all children of rootNode. // Since there exists some ancestor element which has the class name, we need to see all children of rootNode.
if (ancestorHasClassName(rootNode, selector->value())) { if (ancestorHasClassName(rootNode, selector->value())) {
executeForTraverseRoot<SelectorQueryTrait>(m_selectors[0], &rootNode, DoesNotMatchTraverseRoots, rootNode, output); executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], &rootNode, DoesNotMatchTraverseRoots, rootNode, output);
return; return;
} }
ClassElementList<OnlyRoots> traverseRoots(rootNode, selector->value()); ClassElementList<OnlyRoots> traverseRoots(rootNode, selector->value());
executeForTraverseRoots<SelectorQueryTrait>(m_selectors[0], traverseRoots, DoesNotMatchTraverseRoots, rootNode, output); executeForTraverseRoots<SelectorQueryTrait>(*m_selectors[0], traverseRoots, DoesNotMatchTraverseRoots, rootNode, output);
return; return;
} }
...@@ -263,11 +255,11 @@ void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type ...@@ -263,11 +255,11 @@ void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, type
startFromParent = false; startFromParent = false;
} }
executeForTraverseRoot<SelectorQueryTrait>(m_selectors[0], &rootNode, DoesNotMatchTraverseRoots, rootNode, output); executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], &rootNode, DoesNotMatchTraverseRoots, rootNode, output);
} }
template <typename SelectorQueryTrait> template <typename SelectorQueryTrait>
void SelectorDataList::executeForTraverseRoot(const SelectorData& selector, ContainerNode* traverseRoot, MatchTraverseRootState matchTraverseRoot, ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const void SelectorDataList::executeForTraverseRoot(const CSSSelector& selector, ContainerNode* traverseRoot, MatchTraverseRootState matchTraverseRoot, ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
{ {
if (!traverseRoot) if (!traverseRoot)
return; return;
...@@ -288,7 +280,7 @@ void SelectorDataList::executeForTraverseRoot(const SelectorData& selector, Cont ...@@ -288,7 +280,7 @@ void SelectorDataList::executeForTraverseRoot(const SelectorData& selector, Cont
} }
template <typename SelectorQueryTrait, typename SimpleElementListType> template <typename SelectorQueryTrait, typename SimpleElementListType>
void SelectorDataList::executeForTraverseRoots(const SelectorData& selector, SimpleElementListType& traverseRoots, MatchTraverseRootState matchTraverseRoots, ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const void SelectorDataList::executeForTraverseRoots(const CSSSelector& selector, SimpleElementListType& traverseRoots, MatchTraverseRootState matchTraverseRoots, ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
{ {
if (traverseRoots.isEmpty()) if (traverseRoots.isEmpty())
return; return;
...@@ -321,7 +313,7 @@ template <typename SelectorQueryTrait> ...@@ -321,7 +313,7 @@ template <typename SelectorQueryTrait>
bool SelectorDataList::selectorListMatches(ContainerNode& rootNode, Element& element, typename SelectorQueryTrait::OutputType& output) const bool SelectorDataList::selectorListMatches(ContainerNode& rootNode, Element& element, typename SelectorQueryTrait::OutputType& output) const
{ {
for (unsigned i = 0; i < m_selectors.size(); ++i) { for (unsigned i = 0; i < m_selectors.size(); ++i) {
if (selectorMatches(m_selectors[i], element, rootNode)) { if (selectorMatches(*m_selectors[i], element, rootNode)) {
SelectorQueryTrait::appendElement(output, element); SelectorQueryTrait::appendElement(output, element);
return true; return true;
} }
...@@ -420,8 +412,8 @@ void SelectorDataList::execute(ContainerNode& rootNode, typename SelectorQueryTr ...@@ -420,8 +412,8 @@ void SelectorDataList::execute(ContainerNode& rootNode, typename SelectorQueryTr
ASSERT(m_selectors.size() == 1); ASSERT(m_selectors.size() == 1);
const SelectorData& selector = m_selectors[0]; const CSSSelector& selector = *m_selectors[0];
const CSSSelector& firstSelector = selector.selector; const CSSSelector& firstSelector = selector;
// Fast path for querySelector*('#id'), querySelector*('tag#id'). // Fast path for querySelector*('#id'), querySelector*('tag#id').
if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) {
......
...@@ -52,14 +52,8 @@ public: ...@@ -52,14 +52,8 @@ public:
PassRefPtr<Element> queryFirst(ContainerNode& rootNode) const; PassRefPtr<Element> queryFirst(ContainerNode& rootNode) const;
private: private:
struct SelectorData {
SelectorData(const CSSSelector& selector, bool isFastCheckable) : selector(selector), isFastCheckable(isFastCheckable) { }
const CSSSelector& selector;
bool isFastCheckable;
};
bool canUseFastQuery(const ContainerNode& rootNode) const; bool canUseFastQuery(const ContainerNode& rootNode) const;
bool selectorMatches(const SelectorData&, Element&, const ContainerNode&) const; bool selectorMatches(const CSSSelector&, Element&, const ContainerNode&) const;
template <typename SelectorQueryTrait> template <typename SelectorQueryTrait>
void collectElementsByClassName(ContainerNode& rootNode, const AtomicString& className, typename SelectorQueryTrait::OutputType&) const; void collectElementsByClassName(ContainerNode& rootNode, const AtomicString& className, typename SelectorQueryTrait::OutputType&) const;
...@@ -71,9 +65,9 @@ private: ...@@ -71,9 +65,9 @@ private:
enum MatchTraverseRootState { DoesNotMatchTraverseRoots, MatchesTraverseRoots }; enum MatchTraverseRootState { DoesNotMatchTraverseRoots, MatchesTraverseRoots };
template <typename SelectorQueryTrait> template <typename SelectorQueryTrait>
void executeForTraverseRoot(const SelectorData&, ContainerNode* traverseRoot, MatchTraverseRootState, ContainerNode& rootNode, typename SelectorQueryTrait::OutputType&) const; void executeForTraverseRoot(const CSSSelector&, ContainerNode* traverseRoot, MatchTraverseRootState, ContainerNode& rootNode, typename SelectorQueryTrait::OutputType&) const;
template <typename SelectorQueryTrait, typename SimpleElementListType> template <typename SelectorQueryTrait, typename SimpleElementListType>
void executeForTraverseRoots(const SelectorData&, SimpleElementListType& traverseRoots, MatchTraverseRootState, ContainerNode& rootNode, typename SelectorQueryTrait::OutputType&) const; void executeForTraverseRoots(const CSSSelector&, SimpleElementListType& traverseRoots, MatchTraverseRootState, ContainerNode& rootNode, typename SelectorQueryTrait::OutputType&) const;
template <typename SelectorQueryTrait> template <typename SelectorQueryTrait>
bool selectorListMatches(ContainerNode& rootNode, Element&, typename SelectorQueryTrait::OutputType&) const; bool selectorListMatches(ContainerNode& rootNode, Element&, typename SelectorQueryTrait::OutputType&) const;
...@@ -85,7 +79,7 @@ private: ...@@ -85,7 +79,7 @@ private:
void execute(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType&) const; void execute(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType&) const;
const CSSSelector* selectorForIdLookup(const CSSSelector&) const; const CSSSelector* selectorForIdLookup(const CSSSelector&) const;
Vector<SelectorData> m_selectors; Vector<const CSSSelector*> m_selectors;
bool m_crossesTreeBoundary; bool m_crossesTreeBoundary;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment