Diff
Modified: trunk/Source/WebCore/CMakeLists.txt (143685 => 143686)
--- trunk/Source/WebCore/CMakeLists.txt 2013-02-22 04:03:41 UTC (rev 143685)
+++ trunk/Source/WebCore/CMakeLists.txt 2013-02-22 05:15:35 UTC (rev 143686)
@@ -1087,6 +1087,7 @@
css/RuleSet.h
css/RuleSet.cpp
css/SelectorChecker.cpp
+ css/SelectorCheckerFastPath.cpp
css/SelectorFilter.cpp
css/ShadowValue.cpp
css/StyleBuilder.cpp
Modified: trunk/Source/WebCore/ChangeLog (143685 => 143686)
--- trunk/Source/WebCore/ChangeLog 2013-02-22 04:03:41 UTC (rev 143685)
+++ trunk/Source/WebCore/ChangeLog 2013-02-22 05:15:35 UTC (rev 143686)
@@ -1,3 +1,31 @@
+2013-02-21 Dimitri Glazkov <[email protected]>
+
+ Split SelectorChecker's fast-checking logic into its own class.
+ https://bugs.webkit.org/show_bug.cgi?id=106860
+
+ Reviewed by Antti Koivisto.
+
+ No functional changes, covered by existing tests.
+
+ * CMakeLists.txt: Added new class to existing build system.
+ * GNUmakefile.list.am: Ditto.
+ * Target.pri: Ditto.
+ * WebCore.gypi: Ditto.
+ * WebCore.xcodeproj/project.pbxproj: Ditto.
+ * css/CSSAllInOne.cpp: Ditto.
+ * css/RuleSet.cpp:
+ (WebCore::RuleData::RuleData): Changed to use SelectorCheckerFastPath.
+ * css/SelectorChecker.cpp:
+ (WebCore::SelectorChecker::matches): Ditto.
+ * css/SelectorChecker.h:
+ (SelectorChecker): Move fast path code into SelectorCheckerFastPath.
+ * css/SelectorCheckerFastPath.cpp: Added.
+ * css/SelectorCheckerFastPath.h: Added.
+ * css/StyleResolver.cpp:
+ (WebCore::StyleResolver::ruleMatches): Changed to use SelectorCheckerFastPath.
+ * dom/SelectorQuery.cpp:
+ (WebCore::SelectorDataList::initialize): Ditto.
+
2013-02-21 Tony Gentilcore <[email protected]>
Invalidate outstanding checkpoints for the background input stream and preload scanner
Modified: trunk/Source/WebCore/GNUmakefile.list.am (143685 => 143686)
--- trunk/Source/WebCore/GNUmakefile.list.am 2013-02-22 04:03:41 UTC (rev 143685)
+++ trunk/Source/WebCore/GNUmakefile.list.am 2013-02-22 05:15:35 UTC (rev 143686)
@@ -2690,6 +2690,8 @@
Source/WebCore/css/RuleSet.h \
Source/WebCore/css/SelectorChecker.cpp \
Source/WebCore/css/SelectorChecker.h \
+ Source/WebCore/css/SelectorCheckerFastPath.cpp \
+ Source/WebCore/css/SelectorCheckerFastPath.h \
Source/WebCore/css/SelectorFilter.cpp \
Source/WebCore/css/SelectorFilter.h \
Source/WebCore/css/ShadowValue.cpp \
Modified: trunk/Source/WebCore/Target.pri (143685 => 143686)
--- trunk/Source/WebCore/Target.pri 2013-02-22 04:03:41 UTC (rev 143685)
+++ trunk/Source/WebCore/Target.pri 2013-02-22 05:15:35 UTC (rev 143686)
@@ -324,6 +324,7 @@
css/RuleFeature.cpp \
css/RuleSet.cpp \
css/SelectorChecker.cpp \
+ css/SelectorCheckerFastPath.cpp \
css/SelectorFilter.cpp \
css/ShadowValue.cpp \
css/StyleBuilder.cpp \
Modified: trunk/Source/WebCore/WebCore.gypi (143685 => 143686)
--- trunk/Source/WebCore/WebCore.gypi 2013-02-22 04:03:41 UTC (rev 143685)
+++ trunk/Source/WebCore/WebCore.gypi 2013-02-22 05:15:35 UTC (rev 143686)
@@ -1590,6 +1590,8 @@
'css/SVGCSSStyleSelector.cpp',
'css/SelectorChecker.cpp',
'css/SelectorChecker.h',
+ 'css/SelectorCheckerFastPath.cpp',
+ 'css/SelectorCheckerFastPath.h',
'css/SelectorFilter.cpp',
'css/SelectorFilter.h',
'css/ShadowValue.cpp',
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (143685 => 143686)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2013-02-22 04:03:41 UTC (rev 143685)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2013-02-22 05:15:35 UTC (rev 143686)
@@ -1099,6 +1099,8 @@
419BC2DF1685329900D64D6D /* VisitedLinkState.h in Headers */ = {isa = PBXBuildFile; fileRef = 419BC2DD1685329900D64D6D /* VisitedLinkState.h */; };
41A3D58E101C152D00316D07 /* DedicatedWorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41A3D58C101C152D00316D07 /* DedicatedWorkerThread.cpp */; };
41A3D58F101C152D00316D07 /* DedicatedWorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 41A3D58D101C152D00316D07 /* DedicatedWorkerThread.h */; };
+ 41B8CD4516D04591000E8CC0 /* SelectorCheckerFastPath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41B8CD4316D04591000E8CC0 /* SelectorCheckerFastPath.cpp */; };
+ 41B8CD4616D04591000E8CC0 /* SelectorCheckerFastPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 41B8CD4416D04591000E8CC0 /* SelectorCheckerFastPath.h */; };
41BF700B0FE86F49005E8DEC /* MessagePortChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41BF70090FE86F49005E8DEC /* MessagePortChannel.cpp */; };
41BF700C0FE86F49005E8DEC /* MessagePortChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 41BF700A0FE86F49005E8DEC /* MessagePortChannel.h */; settings = {ATTRIBUTES = (Private, ); }; };
41BF700F0FE86F61005E8DEC /* PlatformMessagePortChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41BF700D0FE86F61005E8DEC /* PlatformMessagePortChannel.cpp */; };
@@ -8478,6 +8480,8 @@
419BC2DD1685329900D64D6D /* VisitedLinkState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VisitedLinkState.h; sourceTree = "<group>"; };
41A3D58C101C152D00316D07 /* DedicatedWorkerThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DedicatedWorkerThread.cpp; path = workers/DedicatedWorkerThread.cpp; sourceTree = "<group>"; };
41A3D58D101C152D00316D07 /* DedicatedWorkerThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DedicatedWorkerThread.h; path = workers/DedicatedWorkerThread.h; sourceTree = "<group>"; };
+ 41B8CD4316D04591000E8CC0 /* SelectorCheckerFastPath.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SelectorCheckerFastPath.cpp; sourceTree = "<group>"; };
+ 41B8CD4416D04591000E8CC0 /* SelectorCheckerFastPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectorCheckerFastPath.h; sourceTree = "<group>"; };
41BF70090FE86F49005E8DEC /* MessagePortChannel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MessagePortChannel.cpp; sourceTree = "<group>"; };
41BF700A0FE86F49005E8DEC /* MessagePortChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessagePortChannel.h; sourceTree = "<group>"; };
41BF700D0FE86F61005E8DEC /* PlatformMessagePortChannel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformMessagePortChannel.cpp; path = default/PlatformMessagePortChannel.cpp; sourceTree = "<group>"; };
@@ -22104,6 +22108,8 @@
A79BADA0161E7F3F00C2E652 /* RuleSet.h */,
E44B4BB1141650D7002B1D8B /* SelectorChecker.cpp */,
E44B4BB2141650D7002B1D8B /* SelectorChecker.h */,
+ 41B8CD4316D04591000E8CC0 /* SelectorCheckerFastPath.cpp */,
+ 41B8CD4416D04591000E8CC0 /* SelectorCheckerFastPath.h */,
415071551685067300C3C7B3 /* SelectorFilter.cpp */,
415071561685067300C3C7B3 /* SelectorFilter.h */,
A80E6CCA0A1989CA007FB8C5 /* ShadowValue.cpp */,
@@ -26601,6 +26607,7 @@
977E2E0F12F0FC9C00C13379 /* XSSAuditor.h in Headers */,
977E2E0F12F0FC9C00C13380 /* XSSAuditorDelegate.h in Headers */,
FD537353137B651800008DCE /* ZeroPole.h in Headers */,
+ 41B8CD4616D04591000E8CC0 /* SelectorCheckerFastPath.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -29795,6 +29802,7 @@
977E2E0E12F0FC9C00C13379 /* XSSAuditor.cpp in Sources */,
977E2E0E12F0FC9C00C13380 /* XSSAuditorDelegate.cpp in Sources */,
FD537352137B651800008DCE /* ZeroPole.cpp in Sources */,
+ 41B8CD4516D04591000E8CC0 /* SelectorCheckerFastPath.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Modified: trunk/Source/WebCore/css/CSSAllInOne.cpp (143685 => 143686)
--- trunk/Source/WebCore/css/CSSAllInOne.cpp 2013-02-22 04:03:41 UTC (rev 143685)
+++ trunk/Source/WebCore/css/CSSAllInOne.cpp 2013-02-22 05:15:35 UTC (rev 143686)
@@ -74,6 +74,7 @@
#include "InspectorCSSOMWrappers.cpp"
#include "RuleFeature.cpp"
#include "RuleSet.cpp"
+#include "SelectorCheckerFastPath.cpp"
#include "SelectorFilter.cpp"
#include "StyleBuilder.cpp"
#include "StylePropertySet.cpp"
Modified: trunk/Source/WebCore/css/RuleSet.cpp (143685 => 143686)
--- trunk/Source/WebCore/css/RuleSet.cpp 2013-02-22 04:03:41 UTC (rev 143685)
+++ trunk/Source/WebCore/css/RuleSet.cpp 2013-02-22 05:15:35 UTC (rev 143686)
@@ -36,6 +36,7 @@
#include "MediaQueryEvaluator.h"
#include "SecurityOrigin.h"
#include "SelectorChecker.h"
+#include "SelectorCheckerFastPath.h"
#include "SelectorFilter.h"
#include "StyleResolver.h"
#include "StyleRule.h"
@@ -135,7 +136,7 @@
: m_rule(rule)
, m_selectorIndex(selectorIndex)
, m_position(position)
- , m_hasFastCheckableSelector((addRuleFlags & RuleCanUseFastCheckSelector) && SelectorChecker::isFastCheckableSelector(selector()))
+ , m_hasFastCheckableSelector((addRuleFlags & RuleCanUseFastCheckSelector) && SelectorCheckerFastPath::canUse(selector()))
, m_specificity(selector()->specificity())
, m_hasMultipartSelector(!!selector()->tagHistory())
, m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash(isSelectorMatchingHTMLBasedOnRuleHash(selector()))
Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (143685 => 143686)
--- trunk/Source/WebCore/css/SelectorChecker.cpp 2013-02-22 04:03:41 UTC (rev 143685)
+++ trunk/Source/WebCore/css/SelectorChecker.cpp 2013-02-22 05:15:35 UTC (rev 143686)
@@ -50,6 +50,7 @@
#include "RenderStyle.h"
#include "ScrollableArea.h"
#include "ScrollbarTheme.h"
+#include "SelectorCheckerFastPath.h"
#include "ShadowRoot.h"
#include "SiblingTraversalStrategies.h"
#include "StyledElement.h"
@@ -73,173 +74,16 @@
bool SelectorChecker::matches(const CSSSelector* selector, Element* element, bool isFastCheckableSelector) const
{
if (isFastCheckableSelector && !element->isSVGElement()) {
- if (!fastCheckRightmostSelector(selector, element, VisitedMatchDisabled))
+ SelectorCheckerFastPath selectorCheckerFastPath(selector, element);
+ if (!selectorCheckerFastPath.matchesRightmostSelector(VisitedMatchDisabled))
return false;
- return fastCheck(selector, element);
+ return selectorCheckerFastPath.matches();
}
PseudoId ignoreDynamicPseudo = NOPSEUDO;
return match(SelectorCheckingContext(selector, element, SelectorChecker::VisitedMatchDisabled), ignoreDynamicPseudo, DOMSiblingTraversalStrategy()) == SelectorMatches;
}
-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() && static_cast<const StyledElement*>(element)->classNames().contains(selector->value().impl());
-}
-
-inline bool checkIDValue(const Element* element, const CSSSelector* selector)
-{
- return element->hasID() && element->idForStyleResolution().impl() == selector->value().impl();
-}
-
-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());
-}
-
-}
-
-bool SelectorChecker::fastCheckRightmostSelector(const CSSSelector* selector, const Element* element, SelectorChecker::VisitedMatchType visitedMatchType)
-{
- ASSERT(SelectorChecker::isFastCheckableSelector(selector));
-
- switch (selector->m_match) {
- case CSSSelector::Tag:
- return checkTagValue(element, selector);
- case CSSSelector::Class:
- return checkClassValue(element, selector);
- case CSSSelector::Id:
- return checkIDValue(element, selector);
- case CSSSelector::Exact:
- case CSSSelector::Set:
- return checkExactAttributeValue(element, selector);
- case CSSSelector::PseudoClass:
- return commonPseudoClassSelectorMatches(element, selector, visitedMatchType);
- default:
- ASSERT_NOT_REACHED();
- }
- return false;
-}
-
-bool SelectorChecker::fastCheck(const CSSSelector* selector, const Element* element)
-{
- ASSERT(fastCheckRightmostSelector(selector, element, VisitedMatchEnabled));
-
- 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 SelectorChecker::isFastCheckableSelector(const CSSSelector* selector)
-{
- if (!isFastCheckableRightmostSelector(selector))
- return false;
- for (selector = selector->tagHistory(); selector; selector = selector->tagHistory()) {
- if (!isFastCheckableRelation(selector->relation()))
- return false;
- if (!isFastCheckableMatch(selector))
- return false;
- }
- return true;
-}
-
// Recursive check of selectors and combinators
// It can return 4 different values:
// * SelectorMatches - the selector matches the element e
@@ -1023,23 +867,6 @@
}
}
-bool SelectorChecker::commonPseudoClassSelectorMatches(const Element* element, const CSSSelector* selector, VisitedMatchType visitedMatchType)
-{
- ASSERT(isCommonPseudoClassSelector(selector));
- switch (selector->pseudoType()) {
- case CSSSelector::PseudoLink:
- case CSSSelector::PseudoAnyLink:
- return element->isLink();
- case CSSSelector::PseudoVisited:
- return element->isLink() && visitedMatchType == VisitedMatchEnabled;
- case CSSSelector::PseudoFocus:
- return matchesFocusPseudoClass(element);
- default:
- ASSERT_NOT_REACHED();
- }
- return true;
-}
-
unsigned SelectorChecker::determineLinkMatchType(const CSSSelector* selector)
{
unsigned linkMatchType = MatchAll;
Modified: trunk/Source/WebCore/css/SelectorChecker.h (143685 => 143686)
--- trunk/Source/WebCore/css/SelectorChecker.h 2013-02-22 04:03:41 UTC (rev 143685)
+++ trunk/Source/WebCore/css/SelectorChecker.h 2013-02-22 05:15:35 UTC (rev 143686)
@@ -83,9 +83,6 @@
template<typename SiblingTraversalStrategy>
bool checkOne(const SelectorCheckingContext&, const SiblingTraversalStrategy&) const;
- static bool isFastCheckableSelector(const CSSSelector*);
- static bool fastCheck(const CSSSelector*, const Element*);
-
bool strictParsing() const { return m_strictParsing; }
Mode mode() const { return m_mode; }
@@ -93,7 +90,6 @@
static bool tagMatches(const Element*, const QualifiedName&);
static bool isCommonPseudoClassSelector(const CSSSelector*);
static bool matchesFocusPseudoClass(const Element*);
- static bool fastCheckRightmostAttributeSelector(const Element*, const CSSSelector*);
static bool checkExactAttribute(const Element*, const QualifiedName& selectorAttributeName, const AtomicStringImpl* value);
enum LinkMatchMask { MatchLink = 1, MatchVisited = 2, MatchAll = MatchLink | MatchVisited };
@@ -104,9 +100,6 @@
static bool isFrameFocused(const Element*);
- static bool fastCheckRightmostSelector(const CSSSelector*, const Element*, VisitedMatchType);
- static bool commonPseudoClassSelectorMatches(const Element*, const CSSSelector*, VisitedMatchType);
-
bool m_strictParsing;
bool m_documentIsHTML;
Mode m_mode;
@@ -147,14 +140,6 @@
return false;
}
-inline bool SelectorChecker::fastCheckRightmostAttributeSelector(const Element* element, const CSSSelector* selector)
-{
- if (selector->m_match == CSSSelector::Exact || selector->m_match == CSSSelector::Set)
- return checkExactAttribute(element, selector->attribute(), selector->value().impl());
- ASSERT(!selector->isAttributeSelector());
- return true;
}
-}
-
#endif
Added: trunk/Source/WebCore/css/SelectorCheckerFastPath.cpp (0 => 143686)
--- trunk/Source/WebCore/css/SelectorCheckerFastPath.cpp (rev 0)
+++ trunk/Source/WebCore/css/SelectorCheckerFastPath.cpp 2013-02-22 05:15:35 UTC (rev 143686)
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 1999 Lars Knoll ([email protected])
+ * (C) 2004-2005 Allan Sandfeld Jensen ([email protected])
+ * Copyright (C) 2006, 2007 Nicholas Shanks ([email protected])
+ * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Alexey Proskuryakov <[email protected]>
+ * Copyright (C) 2007, 2008 Eric Seidel <[email protected]>
+ * 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 "SelectorCheckerFastPath.h"
+
+#include "HTMLDocument.h"
+#include "HTMLNames.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() && static_cast<const StyledElement*>(element)->classNames().contains(selector->value().impl());
+}
+
+inline bool checkIDValue(const Element* element, const CSSSelector* selector)
+{
+ return element->hasID() && element->idForStyleResolution().impl() == selector->value().impl();
+}
+
+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 (selector = selector->tagHistory(); selector; selector = selector->tagHistory()) {
+ if (!isFastCheckableRelation(selector->relation()))
+ return false;
+ if (!isFastCheckableMatch(selector))
+ 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;
+}
+
+
+}
Added: trunk/Source/WebCore/css/SelectorCheckerFastPath.h (0 => 143686)
--- trunk/Source/WebCore/css/SelectorCheckerFastPath.h (rev 0)
+++ trunk/Source/WebCore/css/SelectorCheckerFastPath.h 2013-02-22 05:15:35 UTC (rev 143686)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 1999 Lars Knoll ([email protected])
+ * (C) 2004-2005 Allan Sandfeld Jensen ([email protected])
+ * Copyright (C) 2006, 2007 Nicholas Shanks ([email protected])
+ * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Alexey Proskuryakov <[email protected]>
+ * Copyright (C) 2007, 2008 Eric Seidel <[email protected]>
+ * 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 "CSSSelector.h"
+#include "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
Modified: trunk/Source/WebCore/css/StyleResolver.cpp (143685 => 143686)
--- trunk/Source/WebCore/css/StyleResolver.cpp 2013-02-22 04:03:41 UTC (rev 143685)
+++ trunk/Source/WebCore/css/StyleResolver.cpp 2013-02-22 05:15:35 UTC (rev 143686)
@@ -103,6 +103,7 @@
#include "SVGFontFaceElement.h"
#include "ScaleTransformOperation.h"
#include "SecurityOrigin.h"
+#include "SelectorCheckerFastPath.h"
#include "Settings.h"
#include "ShadowData.h"
#include "ShadowRoot.h"
@@ -2084,10 +2085,11 @@
}
if (ruleData.selector()->m_match == CSSSelector::Tag && !SelectorChecker::tagMatches(state.element(), ruleData.selector()->tagQName()))
return false;
- if (!SelectorChecker::fastCheckRightmostAttributeSelector(state.element(), ruleData.selector()))
+ SelectorCheckerFastPath selectorCheckerFastPath(ruleData.selector(), state.element());
+ if (!selectorCheckerFastPath.matchesRightmostAttributeSelector())
return false;
- return SelectorChecker::fastCheck(ruleData.selector(), state.element());
+ return selectorCheckerFastPath.matches();
}
// Slow path.
Modified: trunk/Source/WebCore/dom/SelectorQuery.cpp (143685 => 143686)
--- trunk/Source/WebCore/dom/SelectorQuery.cpp 2013-02-22 04:03:41 UTC (rev 143685)
+++ trunk/Source/WebCore/dom/SelectorQuery.cpp 2013-02-22 05:15:35 UTC (rev 143686)
@@ -30,6 +30,7 @@
#include "CSSSelectorList.h"
#include "Document.h"
#include "SelectorChecker.h"
+#include "SelectorCheckerFastPath.h"
#include "StaticNodeList.h"
#include "StyledElement.h"
@@ -45,7 +46,7 @@
m_selectors.reserveInitialCapacity(selectorCount);
for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector))
- m_selectors.uncheckedAppend(SelectorData(selector, SelectorChecker::isFastCheckableSelector(selector)));
+ m_selectors.uncheckedAppend(SelectorData(selector, SelectorCheckerFastPath::canUse(selector)));
}
bool SelectorDataList::matches(Element* targetElement) const