Title: [175772] trunk/Source/WebCore
Revision
175772
Author
[email protected]
Date
2014-11-07 18:05:36 -0800 (Fri, 07 Nov 2014)

Log Message

Make the Selector's specificity part of Selector matching
https://bugs.webkit.org/show_bug.cgi?id=138486

Reviewed by Andreas Kling.

In CSS Selectors Level 4, the specificity of selectors is computed dynamically
based on which element is being matched.

For example, a selector:
    :matches(#foo, .bar, baz)
has a specificity of
    (1, 0, 0) on <baz id=foo class=bar>
    (0, 1, 0) on <baz class=bar>
    (0, 0, 1) on <baz>

Previously, the specificity of each selector was computed statically when populating
RuleSet. With more recent CSS, this gives us the wrong specificity because we do not know
how the selectors applies to the target.

This patch moves one tiny step in the direction of dynamic specificity. The specificity
is removed from RuleSet and is moved inside Selector Matching.

There is one bit worth keeping static: matching based on rule hash. This path is important
to avoid spending time compiling trivial selectors.
In order to keep rule hash matching working, the RuleData store which specificity class
the rule has in addition to the information about matching/not-matching. When going through
the fast path in ElementCollector, we compute the right specificity based on the type
of rule-hash matching.

* css/CSSSelector.cpp:
(WebCore::CSSSelector::specificityForOneSelector):
* css/CSSSelector.h:
* css/ElementRuleCollector.cpp:
(WebCore::ElementRuleCollector::addMatchedRule):
(WebCore::ElementRuleCollector::sortAndTransferMatchedRules):
(WebCore::ElementRuleCollector::ruleMatches):
(WebCore::ElementRuleCollector::collectMatchingRulesForList):
(WebCore::compareRules):
* css/ElementRuleCollector.h:
* css/RuleSet.cpp:
(WebCore::computeMatchBasedOnRuleHash):
(WebCore::RuleData::RuleData):
(WebCore::isSelectorMatchingHTMLBasedOnRuleHash): Deleted.
* css/RuleSet.h:
(WebCore::RuleData::matchBasedOnRuleHash):
(WebCore::RuleData::hasRightmostSelectorMatchingHTMLBasedOnRuleHash): Deleted.
(WebCore::RuleData::specificity): Deleted.
* css/SelectorChecker.cpp:
(WebCore::SelectorChecker::match):
* css/SelectorChecker.h:
* css/StyleResolver.h:
(WebCore::checkRegionSelector):
* cssjit/SelectorCompiler.cpp:
(WebCore::SelectorCompiler::SelectorCodeGenerator::SelectorCodeGenerator):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateSelectorChecker):
* cssjit/SelectorCompiler.h:
(WebCore::SelectorCompiler::ruleCollectorSimpleSelectorCheckerFunction):
(WebCore::SelectorCompiler::querySelectorSimpleSelectorCheckerFunction):
(WebCore::SelectorCompiler::ruleCollectorSelectorCheckerFunctionWithCheckingContext):
(WebCore::SelectorCompiler::querySelectorSelectorCheckerFunctionWithCheckingContext):
(WebCore::SelectorCompiler::simpleSelectorCheckerFunction): Deleted.
(WebCore::SelectorCompiler::selectorCheckerFunctionWithCheckingContext): Deleted.
* dom/SelectorQuery.cpp:
(WebCore::SelectorDataList::selectorMatches):
(WebCore::SelectorDataList::selectorClosest):
(WebCore::SelectorDataList::executeCompiledSimpleSelectorChecker):
(WebCore::SelectorDataList::executeCompiledSelectorCheckerWithCheckingContext):
(WebCore::SelectorDataList::executeCompiledSingleMultiSelectorData):
(WebCore::SelectorDataList::execute):
* dom/SelectorQuery.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (175771 => 175772)


--- trunk/Source/WebCore/ChangeLog	2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/ChangeLog	2014-11-08 02:05:36 UTC (rev 175772)
@@ -1,3 +1,76 @@
+2014-11-07  Benjamin Poulain  <[email protected]>
+
+        Make the Selector's specificity part of Selector matching
+        https://bugs.webkit.org/show_bug.cgi?id=138486
+
+        Reviewed by Andreas Kling.
+
+        In CSS Selectors Level 4, the specificity of selectors is computed dynamically
+        based on which element is being matched.
+
+        For example, a selector:
+            :matches(#foo, .bar, baz)
+        has a specificity of
+            (1, 0, 0) on <baz id=foo class=bar>
+            (0, 1, 0) on <baz class=bar>
+            (0, 0, 1) on <baz>
+
+        Previously, the specificity of each selector was computed statically when populating
+        RuleSet. With more recent CSS, this gives us the wrong specificity because we do not know
+        how the selectors applies to the target.
+
+        This patch moves one tiny step in the direction of dynamic specificity. The specificity
+        is removed from RuleSet and is moved inside Selector Matching.
+
+        There is one bit worth keeping static: matching based on rule hash. This path is important
+        to avoid spending time compiling trivial selectors.
+        In order to keep rule hash matching working, the RuleData store which specificity class
+        the rule has in addition to the information about matching/not-matching. When going through
+        the fast path in ElementCollector, we compute the right specificity based on the type
+        of rule-hash matching.
+
+        * css/CSSSelector.cpp:
+        (WebCore::CSSSelector::specificityForOneSelector):
+        * css/CSSSelector.h:
+        * css/ElementRuleCollector.cpp:
+        (WebCore::ElementRuleCollector::addMatchedRule):
+        (WebCore::ElementRuleCollector::sortAndTransferMatchedRules):
+        (WebCore::ElementRuleCollector::ruleMatches):
+        (WebCore::ElementRuleCollector::collectMatchingRulesForList):
+        (WebCore::compareRules):
+        * css/ElementRuleCollector.h:
+        * css/RuleSet.cpp:
+        (WebCore::computeMatchBasedOnRuleHash):
+        (WebCore::RuleData::RuleData):
+        (WebCore::isSelectorMatchingHTMLBasedOnRuleHash): Deleted.
+        * css/RuleSet.h:
+        (WebCore::RuleData::matchBasedOnRuleHash):
+        (WebCore::RuleData::hasRightmostSelectorMatchingHTMLBasedOnRuleHash): Deleted.
+        (WebCore::RuleData::specificity): Deleted.
+        * css/SelectorChecker.cpp:
+        (WebCore::SelectorChecker::match):
+        * css/SelectorChecker.h:
+        * css/StyleResolver.h:
+        (WebCore::checkRegionSelector):
+        * cssjit/SelectorCompiler.cpp:
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::SelectorCodeGenerator):
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateSelectorChecker):
+        * cssjit/SelectorCompiler.h:
+        (WebCore::SelectorCompiler::ruleCollectorSimpleSelectorCheckerFunction):
+        (WebCore::SelectorCompiler::querySelectorSimpleSelectorCheckerFunction):
+        (WebCore::SelectorCompiler::ruleCollectorSelectorCheckerFunctionWithCheckingContext):
+        (WebCore::SelectorCompiler::querySelectorSelectorCheckerFunctionWithCheckingContext):
+        (WebCore::SelectorCompiler::simpleSelectorCheckerFunction): Deleted.
+        (WebCore::SelectorCompiler::selectorCheckerFunctionWithCheckingContext): Deleted.
+        * dom/SelectorQuery.cpp:
+        (WebCore::SelectorDataList::selectorMatches):
+        (WebCore::SelectorDataList::selectorClosest):
+        (WebCore::SelectorDataList::executeCompiledSimpleSelectorChecker):
+        (WebCore::SelectorDataList::executeCompiledSelectorCheckerWithCheckingContext):
+        (WebCore::SelectorDataList::executeCompiledSingleMultiSelectorData):
+        (WebCore::SelectorDataList::execute):
+        * dom/SelectorQuery.h:
+
 2014-11-07  Alexey Proskuryakov  <[email protected]>
 
         CSP is enforced for eval in report-only mode on first page load

Modified: trunk/Source/WebCore/css/CSSSelector.cpp (175771 => 175772)


--- trunk/Source/WebCore/css/CSSSelector.cpp	2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/CSSSelector.cpp	2014-11-08 02:05:36 UTC (rev 175772)
@@ -94,7 +94,7 @@
 {
     switch (match()) {
     case Id:
-        return 0x10000;
+        return static_cast<unsigned>(SelectorSpecificityIncrement::ClassA);
 
     case PagePseudoClass:
         break;
@@ -125,11 +125,11 @@
     case Contain:
     case Begin:
     case End:
-        return 0x100;
+        return static_cast<unsigned>(SelectorSpecificityIncrement::ClassB);
     case Tag:
-        return (tagQName().localName() != starAtom) ? 1 : 0;
+        return (tagQName().localName() != starAtom) ? static_cast<unsigned>(SelectorSpecificityIncrement::ClassC) : 0;
     case PseudoElement:
-        return 1;
+        return static_cast<unsigned>(SelectorSpecificityIncrement::ClassC);
     case Unknown:
         return 0;
     }

Modified: trunk/Source/WebCore/css/CSSSelector.h (175771 => 175772)


--- trunk/Source/WebCore/css/CSSSelector.h	2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/CSSSelector.h	2014-11-08 02:05:36 UTC (rev 175772)
@@ -29,6 +29,12 @@
 namespace WebCore {
     class CSSSelectorList;
 
+    enum class SelectorSpecificityIncrement {
+        ClassA = 0x10000,
+        ClassB = 0x100,
+        ClassC = 1
+    };
+
     // this class represents a selector for a StyleRule
     class CSSSelector {
         WTF_MAKE_FAST_ALLOCATED;

Modified: trunk/Source/WebCore/css/ElementRuleCollector.cpp (175771 => 175772)


--- trunk/Source/WebCore/css/ElementRuleCollector.cpp	2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/ElementRuleCollector.cpp	2014-11-08 02:05:36 UTC (rev 175772)
@@ -86,11 +86,11 @@
     return m_matchedRuleList;
 }
 
-inline void ElementRuleCollector::addMatchedRule(const RuleData* rule)
+inline void ElementRuleCollector::addMatchedRule(const MatchedRule& matchedRule)
 {
     if (!m_matchedRules)
-        m_matchedRules = std::make_unique<Vector<const RuleData*, 32>>();
-    m_matchedRules->append(rule);
+        m_matchedRules = std::make_unique<Vector<MatchedRule, 32>>();
+    m_matchedRules->append(matchedRule);
 }
 
 void ElementRuleCollector::clearMatchedRules()
@@ -202,18 +202,18 @@
 
     sortMatchedRules();
 
-    Vector<const RuleData*, 32>& matchedRules = *m_matchedRules;
+    Vector<MatchedRule, 32>& matchedRules = *m_matchedRules;
     if (m_mode == SelectorChecker::Mode::CollectingRules) {
-        for (unsigned i = 0; i < matchedRules.size(); ++i)
-            m_matchedRuleList.append(matchedRules[i]->rule());
+        for (const MatchedRule& matchedRule : matchedRules)
+            m_matchedRuleList.append(matchedRule.ruleData->rule());
         return;
     }
 
     // Now transfer the set of matched rules over to our list of declarations.
-    for (unsigned i = 0; i < matchedRules.size(); i++) {
-        if (m_style && matchedRules[i]->containsUncommonAttributeSelector())
+    for (const MatchedRule& matchedRule : matchedRules) {
+        if (m_style && matchedRule.ruleData->containsUncommonAttributeSelector())
             m_style->setUnique();
-        m_result.addMatchedProperties(matchedRules[i]->rule()->properties(), matchedRules[i]->rule(), matchedRules[i]->linkMatchType(), matchedRules[i]->propertyWhitelistType(MatchingUARulesScope::isMatchingUARules()));
+        m_result.addMatchedProperties(matchedRule.ruleData->rule()->properties(), matchedRule.ruleData->rule(), matchedRule.ruleData->linkMatchType(), matchedRule.ruleData->propertyWhitelistType(MatchingUARulesScope::isMatchingUARules()));
     }
 }
 
@@ -274,12 +274,31 @@
     sortAndTransferMatchedRules();
 }
 
-inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData)
+inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, unsigned& specificity)
 {
     // We know a sufficiently simple single part selector matches simply because we found it from the rule hash when filtering the RuleSet.
     // This is limited to HTML only so we don't need to check the namespace (because of tag name match).
-    if (ruleData.hasRightmostSelectorMatchingHTMLBasedOnRuleHash() && m_element.isHTMLElement()) {
+    MatchBasedOnRuleHash matchBasedOnRuleHash = ruleData.matchBasedOnRuleHash();
+    if (matchBasedOnRuleHash != MatchBasedOnRuleHash::None && m_element.isHTMLElement()) {
         ASSERT_WITH_MESSAGE(m_pseudoStyleRequest.pseudoId == NOPSEUDO, "If we match based on the rule hash while collecting for a particular pseudo element ID, we would add incorrect rules for that pseudo element ID. We should never end in ruleMatches() with a pseudo element if the ruleData cannot match any pseudo element.");
+
+        switch (matchBasedOnRuleHash) {
+        case MatchBasedOnRuleHash::None:
+            ASSERT_NOT_REACHED();
+            break;
+        case MatchBasedOnRuleHash::Universal:
+            specificity = 0;
+            break;
+        case MatchBasedOnRuleHash::ClassA:
+            specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassA);
+            break;
+        case MatchBasedOnRuleHash::ClassB:
+            specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassB);
+            break;
+        case MatchBasedOnRuleHash::ClassC:
+            specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassC);
+            break;
+        }
         return true;
     }
 
@@ -296,12 +315,15 @@
     }
 
     if (compiledSelectorChecker && ruleData.compilationStatus() == SelectorCompilationStatus::SimpleSelectorChecker) {
-        SelectorCompiler::SimpleSelectorChecker selectorChecker = SelectorCompiler::simpleSelectorCheckerFunction(compiledSelectorChecker, ruleData.compilationStatus());
-        ASSERT_WITH_MESSAGE(!selectorChecker(&m_element) || m_pseudoStyleRequest.pseudoId == NOPSEUDO, "When matching pseudo elements, we should never compile a selector checker without context unless it cannot match anything.");
+        SelectorCompiler::RuleCollectorSimpleSelectorChecker selectorChecker = SelectorCompiler::ruleCollectorSimpleSelectorCheckerFunction(compiledSelectorChecker, ruleData.compilationStatus());
+#if !ASSERT_MSG_DISABLED
+        unsigned ignoreSpecificity;
+        ASSERT_WITH_MESSAGE(!selectorChecker(&m_element, &ignoreSpecificity) || m_pseudoStyleRequest.pseudoId == NOPSEUDO, "When matching pseudo elements, we should never compile a selector checker without context unless it cannot match anything.");
+#endif
 #if CSS_SELECTOR_JIT_PROFILING
         ruleData.compiledSelectorUsed();
 #endif
-        return selectorChecker(&m_element);
+        return selectorChecker(&m_element, &specificity);
     }
 #endif // ENABLE(CSS_SELECTOR_JIT)
 
@@ -315,18 +337,18 @@
     if (compiledSelectorChecker) {
         ASSERT(ruleData.compilationStatus() == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
 
-        SelectorCompiler::SelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::selectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, ruleData.compilationStatus());
+        SelectorCompiler::RuleCollectorSelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::ruleCollectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, ruleData.compilationStatus());
 
 #if CSS_SELECTOR_JIT_PROFILING
         ruleData.compiledSelectorUsed();
 #endif
-        return selectorChecker(&m_element, &context);
+        return selectorChecker(&m_element, &context, &specificity);
     }
 #endif // ENABLE(CSS_SELECTOR_JIT)
 
     // Slow path.
     SelectorChecker selectorChecker(m_element.document());
-    return selectorChecker.match(ruleData.selector(), &m_element, context);
+    return selectorChecker.match(ruleData.selector(), &m_element, context, specificity);
 }
 
 void ElementRuleCollector::collectMatchingRulesForList(const Vector<RuleData>* rules, const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange)
@@ -354,23 +376,24 @@
         if (m_sameOriginOnly && !ruleData.hasDocumentSecurityOrigin())
             continue;
 
-        if (ruleMatches(ruleData)) {
+        unsigned specificity;
+        if (ruleMatches(ruleData, specificity)) {
             // Update our first/last rule indices in the matched rules array.
             ++ruleRange.lastRuleIndex;
             if (ruleRange.firstRuleIndex == -1)
                 ruleRange.firstRuleIndex = ruleRange.lastRuleIndex;
 
             // Add this rule to our list of matched rules.
-            addMatchedRule(&ruleData);
+            addMatchedRule({&ruleData, specificity});
         }
     }
 }
 
-static inline bool compareRules(const RuleData* r1, const RuleData* r2)
+static inline bool compareRules(MatchedRule r1, MatchedRule r2)
 {
-    unsigned specificity1 = r1->specificity();
-    unsigned specificity2 = r2->specificity();
-    return (specificity1 == specificity2) ? r1->position() < r2->position() : specificity1 < specificity2;
+    unsigned specificity1 = r1.specificity;
+    unsigned specificity2 = r2.specificity;
+    return (specificity1 == specificity2) ? r1.ruleData->position() < r2.ruleData->position() : specificity1 < specificity2;
 }
 
 void ElementRuleCollector::sortMatchedRules()

Modified: trunk/Source/WebCore/css/ElementRuleCollector.h (175771 => 175772)


--- trunk/Source/WebCore/css/ElementRuleCollector.h	2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/ElementRuleCollector.h	2014-11-08 02:05:36 UTC (rev 175772)
@@ -38,6 +38,11 @@
 class RuleSet;
 class SelectorFilter;
 
+struct MatchedRule {
+    const RuleData* ruleData;
+    unsigned specificity;
+};
+
 class ElementRuleCollector {
 public:
     ElementRuleCollector(Element& element, RenderStyle* style, const DocumentRuleSets& ruleSets, const SelectorFilter& selectorFilter)
@@ -81,12 +86,12 @@
     void collectMatchingRules(const MatchRequest&, StyleResolver::RuleRange&);
     void collectMatchingRulesForRegion(const MatchRequest&, StyleResolver::RuleRange&);
     void collectMatchingRulesForList(const Vector<RuleData>*, const MatchRequest&, StyleResolver::RuleRange&);
-    bool ruleMatches(const RuleData&);
+    bool ruleMatches(const RuleData&, unsigned &specificity);
 
     void sortMatchedRules();
     void sortAndTransferMatchedRules();
 
-    void addMatchedRule(const RuleData*);
+    void addMatchedRule(const MatchedRule&);
 
     Element& m_element;
     RenderStyle* m_style;
@@ -100,7 +105,7 @@
     SelectorChecker::Mode m_mode;
     bool m_canUseFastReject;
 
-    std::unique_ptr<Vector<const RuleData*, 32>> m_matchedRules;
+    std::unique_ptr<Vector<MatchedRule, 32>> m_matchedRules;
 
     // Output.
     Vector<RefPtr<StyleRule>> m_matchedRuleList;

Modified: trunk/Source/WebCore/css/RuleSet.cpp (175771 => 175772)


--- trunk/Source/WebCore/css/RuleSet.cpp	2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/RuleSet.cpp	2014-11-08 02:05:36 UTC (rev 175772)
@@ -53,18 +53,28 @@
 
 // -----------------------------------------------------------------
 
-static inline bool isSelectorMatchingHTMLBasedOnRuleHash(const CSSSelector& selector)
+static inline MatchBasedOnRuleHash computeMatchBasedOnRuleHash(const CSSSelector& selector)
 {
     if (selector.tagHistory())
-        return false;
+        return MatchBasedOnRuleHash::None;
 
     if (selector.match() == CSSSelector::Tag) {
-        const AtomicString& selectorNamespace = selector.tagQName().namespaceURI();
-        return selectorNamespace == starAtom || selectorNamespace == xhtmlNamespaceURI;
+        const QualifiedName& tagQualifiedName = selector.tagQName();
+        const AtomicString& selectorNamespace = tagQualifiedName.namespaceURI();
+        if (selectorNamespace == starAtom || selectorNamespace == xhtmlNamespaceURI) {
+            if (tagQualifiedName == anyQName())
+                return MatchBasedOnRuleHash::Universal;
+            return MatchBasedOnRuleHash::ClassC;
+        }
+        return MatchBasedOnRuleHash::None;
     }
     if (SelectorChecker::isCommonPseudoClassSelector(&selector))
-        return true;
-    return selector.match() == CSSSelector::Id || selector.match() == CSSSelector::Class;
+        return MatchBasedOnRuleHash::ClassB;
+    if (selector.match() == CSSSelector::Id)
+        return MatchBasedOnRuleHash::ClassA;
+    if (selector.match() == CSSSelector::Class)
+        return MatchBasedOnRuleHash::ClassB;
+    return MatchBasedOnRuleHash::None;
 }
 
 static bool selectorCanMatchPseudoElement(const CSSSelector& rootSelector)
@@ -149,8 +159,7 @@
     , m_selectorIndex(selectorIndex)
     , m_hasDocumentSecurityOrigin(addRuleFlags & RuleHasDocumentSecurityOrigin)
     , m_position(position)
-    , m_specificity(selector()->specificity())
-    , m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash(isSelectorMatchingHTMLBasedOnRuleHash(*selector()))
+    , m_matchBasedOnRuleHash(static_cast<unsigned>(computeMatchBasedOnRuleHash(*selector())))
     , m_canMatchPseudoElement(selectorCanMatchPseudoElement(*selector()))
     , m_containsUncommonAttributeSelector(WebCore::containsUncommonAttributeSelector(selector()))
     , m_linkMatchType(SelectorChecker::determineLinkMatchType(selector()))

Modified: trunk/Source/WebCore/css/RuleSet.h (175771 => 175772)


--- trunk/Source/WebCore/css/RuleSet.h	2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/RuleSet.h	2014-11-08 02:05:36 UTC (rev 175772)
@@ -54,6 +54,14 @@
 class StyleRuleRegion;
 class StyleSheetContents;
 
+enum class MatchBasedOnRuleHash : unsigned {
+    None,
+    Universal,
+    ClassA,
+    ClassB,
+    ClassC
+};
+
 class RuleData {
 public:
     static const unsigned maximumSelectorComponentCount = 8192;
@@ -66,9 +74,8 @@
     unsigned selectorIndex() const { return m_selectorIndex; }
 
     bool canMatchPseudoElement() const { return m_canMatchPseudoElement; }
-    bool hasRightmostSelectorMatchingHTMLBasedOnRuleHash() const { return m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash; }
+    MatchBasedOnRuleHash matchBasedOnRuleHash() const { return static_cast<MatchBasedOnRuleHash>(m_matchBasedOnRuleHash); }
     bool containsUncommonAttributeSelector() const { return m_containsUncommonAttributeSelector; }
-    unsigned specificity() const { return m_specificity; }
     unsigned linkMatchType() const { return m_linkMatchType; }
     bool hasDocumentSecurityOrigin() const { return m_hasDocumentSecurityOrigin; }
     PropertyWhitelistType propertyWhitelistType(bool isMatchingUARules = false) const { return isMatchingUARules ? PropertyWhitelistNone : static_cast<PropertyWhitelistType>(m_propertyWhitelistType); }
@@ -101,8 +108,7 @@
     // 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.
     unsigned m_position : 18;
-    unsigned m_specificity : 24;
-    unsigned m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash : 1;
+    unsigned m_matchBasedOnRuleHash : 3;
     unsigned m_canMatchPseudoElement : 1;
     unsigned m_containsUncommonAttributeSelector : 1;
     unsigned m_linkMatchType : 2; //  SelectorChecker::LinkMatchMask

Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (175771 => 175772)


--- trunk/Source/WebCore/css/SelectorChecker.cpp	2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/SelectorChecker.cpp	2014-11-08 02:05:36 UTC (rev 175772)
@@ -168,7 +168,7 @@
 {
 }
 
-bool SelectorChecker::match(const CSSSelector* selector, Element* element, const CheckingContext& providedContext) const
+bool SelectorChecker::match(const CSSSelector* selector, Element* element, const CheckingContext& providedContext, unsigned& specificity) const
 {
     CheckingContextWithStatus context(providedContext, selector, element);
     PseudoId pseudoId = NOPSEUDO;
@@ -176,6 +176,8 @@
         return false;
     if (context.pseudoId != NOPSEUDO && context.pseudoId != pseudoId)
         return false;
+
+    specificity = selector->specificity();
     if (context.pseudoId == NOPSEUDO && pseudoId != NOPSEUDO) {
         if (context.resolvingMode == Mode::ResolvingStyle && pseudoId < FIRST_INTERNAL_PSEUDOID)
             context.elementStyle->setHasPseudoStyle(pseudoId);

Modified: trunk/Source/WebCore/css/SelectorChecker.h (175771 => 175772)


--- trunk/Source/WebCore/css/SelectorChecker.h	2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/SelectorChecker.h	2014-11-08 02:05:36 UTC (rev 175772)
@@ -72,7 +72,7 @@
 
     struct CheckingContextWithStatus;
 
-    bool match(const CSSSelector*, Element*, const CheckingContext&) const;
+    bool match(const CSSSelector*, Element*, const CheckingContext&, unsigned& specificity) const;
 
     static bool tagMatches(const Element*, const QualifiedName&);
     static bool isCommonPseudoClassSelector(const CSSSelector*);

Modified: trunk/Source/WebCore/css/StyleResolver.h (175771 => 175772)


--- trunk/Source/WebCore/css/StyleResolver.h	2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/StyleResolver.h	2014-11-08 02:05:36 UTC (rev 175772)
@@ -572,7 +572,8 @@
     SelectorChecker selectorChecker(regionElement->document());
     for (const CSSSelector* s = regionSelector; s; s = CSSSelectorList::next(s)) {
         SelectorChecker::CheckingContext selectorCheckingContext(SelectorChecker::Mode::QueryingRules);
-        if (selectorChecker.match(s, regionElement, selectorCheckingContext))
+        unsigned ignoredSpecificity;
+        if (selectorChecker.match(s, regionElement, selectorCheckingContext, ignoredSpecificity))
             return true;
     }
     return false;

Modified: trunk/Source/WebCore/cssjit/SelectorCompiler.cpp (175771 => 175772)


--- trunk/Source/WebCore/cssjit/SelectorCompiler.cpp	2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/cssjit/SelectorCompiler.cpp	2014-11-08 02:05:36 UTC (rev 175772)
@@ -357,9 +357,7 @@
     StackAllocator::StackReference m_lastVisitedElement;
     StackAllocator::StackReference m_startElement;
 
-#if CSS_SELECTOR_JIT_DEBUGGING
     const CSSSelector* m_originalSelector;
-#endif
 };
 
 const Assembler::RegisterID SelectorCodeGenerator::returnRegister = JSC::GPRInfo::returnValueGPR;
@@ -798,9 +796,7 @@
     , m_functionType(FunctionType::SimpleSelectorChecker)
     , m_visitedMode(VisitedMode::None)
     , m_descendantBacktrackingStartInUse(false)
-#if CSS_SELECTOR_JIT_DEBUGGING
     , m_originalSelector(rootSelector)
-#endif
 {
 #if CSS_SELECTOR_JIT_DEBUGGING
     dataLogF("Compiling \"%s\"\n", m_originalSelector->selectorText().utf8().data());
@@ -1609,6 +1605,14 @@
         generateRequestedPseudoElementEqualsToSelectorPseudoElement(failureOnFunctionEntry, m_selectorFragments.first(), checkingContextRegister);
     }
 
+    if (m_selectorContext == SelectorContext::RuleCollector) {
+        unsigned specificity = m_originalSelector->specificity();
+        if (m_functionType == FunctionType::SelectorCheckerWithCheckingContext)
+            m_assembler.store32(Assembler::TrustedImm32(specificity), JSC::GPRInfo::argumentGPR2);
+        else
+            m_assembler.store32(Assembler::TrustedImm32(specificity), JSC::GPRInfo::argumentGPR1);
+    }
+
     computeBacktrackingMemoryRequirements(m_selectorFragments);
     unsigned availableRegisterCount = m_registerAllocator.reserveCallerSavedRegisters(m_selectorFragments.registerRequirements);
 

Modified: trunk/Source/WebCore/cssjit/SelectorCompiler.h (175771 => 175772)


--- trunk/Source/WebCore/cssjit/SelectorCompiler.h	2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/cssjit/SelectorCompiler.h	2014-11-08 02:05:36 UTC (rev 175772)
@@ -77,22 +77,37 @@
     QuerySelector
 };
 
-typedef unsigned (*SimpleSelectorChecker)(Element*);
-typedef unsigned (*SelectorCheckerWithCheckingContext)(Element*, const SelectorChecker::CheckingContext*);
+typedef unsigned (*RuleCollectorSimpleSelectorChecker)(Element*, unsigned*);
+typedef unsigned (*QuerySelectorSimpleSelectorChecker)(Element*);
+
+typedef unsigned (*RuleCollectorSelectorCheckerWithCheckingContext)(Element*, const SelectorChecker::CheckingContext*, unsigned*);
+typedef unsigned (*QuerySelectorSelectorCheckerWithCheckingContext)(Element*, const SelectorChecker::CheckingContext*);
+
 SelectorCompilationStatus compileSelector(const CSSSelector*, JSC::VM*, SelectorContext, JSC::MacroAssemblerCodeRef& outputCodeRef);
 
-inline SimpleSelectorChecker simpleSelectorCheckerFunction(void* executableAddress, SelectorCompilationStatus compilationStatus)
+inline RuleCollectorSimpleSelectorChecker ruleCollectorSimpleSelectorCheckerFunction(void* executableAddress, SelectorCompilationStatus compilationStatus)
 {
     ASSERT_UNUSED(compilationStatus, compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker);
-    return reinterpret_cast<SimpleSelectorChecker>(executableAddress);
+    return reinterpret_cast<RuleCollectorSimpleSelectorChecker>(executableAddress);
 }
 
-inline SelectorCheckerWithCheckingContext selectorCheckerFunctionWithCheckingContext(void* executableAddress, SelectorCompilationStatus compilationStatus)
+inline QuerySelectorSimpleSelectorChecker querySelectorSimpleSelectorCheckerFunction(void* executableAddress, SelectorCompilationStatus compilationStatus)
 {
+    ASSERT_UNUSED(compilationStatus, compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker);
+    return reinterpret_cast<QuerySelectorSimpleSelectorChecker>(executableAddress);
+}
+
+inline RuleCollectorSelectorCheckerWithCheckingContext ruleCollectorSelectorCheckerFunctionWithCheckingContext(void* executableAddress, SelectorCompilationStatus compilationStatus)
+{
     ASSERT_UNUSED(compilationStatus, compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
-    return reinterpret_cast<SelectorCheckerWithCheckingContext>(executableAddress);
+    return reinterpret_cast<RuleCollectorSelectorCheckerWithCheckingContext>(executableAddress);
 }
 
+inline QuerySelectorSelectorCheckerWithCheckingContext querySelectorSelectorCheckerFunctionWithCheckingContext(void* executableAddress, SelectorCompilationStatus compilationStatus)
+{
+    ASSERT_UNUSED(compilationStatus, compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
+    return reinterpret_cast<QuerySelectorSelectorCheckerWithCheckingContext>(executableAddress);
+}
 
 } // namespace SelectorCompiler
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/SelectorQuery.cpp (175771 => 175772)


--- trunk/Source/WebCore/dom/SelectorQuery.cpp	2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/dom/SelectorQuery.cpp	2014-11-08 02:05:36 UTC (rev 175772)
@@ -117,7 +117,8 @@
     SelectorChecker selectorChecker(element.document());
     SelectorChecker::CheckingContext selectorCheckingContext(SelectorChecker::Mode::QueryingRules);
     selectorCheckingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
-    return selectorChecker.match(selectorData.selector, &element, selectorCheckingContext);
+    unsigned ignoredSpecificity;
+    return selectorChecker.match(selectorData.selector, &element, selectorCheckingContext, ignoredSpecificity);
 }
 
 inline Element* SelectorDataList::selectorClosest(const SelectorData& selectorData, Element& element, const ContainerNode& rootNode) const
@@ -126,7 +127,8 @@
     SelectorChecker::CheckingContext selectorCheckingContext(SelectorChecker::Mode::QueryingRules);
     selectorCheckingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
     Element* currentNode = &element;
-    if (!selectorChecker.match(selectorData.selector, currentNode, selectorCheckingContext))
+    unsigned ignoredSpecificity;
+    if (!selectorChecker.match(selectorData.selector, currentNode, selectorCheckingContext, ignoredSpecificity))
         return nullptr;
     return currentNode;
 }
@@ -381,7 +383,7 @@
 
 #if ENABLE(CSS_SELECTOR_JIT)
 template <typename SelectorQueryTrait>
-ALWAYS_INLINE void SelectorDataList::executeCompiledSimpleSelectorChecker(const ContainerNode& searchRootNode, SelectorCompiler::SimpleSelectorChecker selectorChecker, typename SelectorQueryTrait::OutputType& output, const SelectorData& selectorData) const
+ALWAYS_INLINE void SelectorDataList::executeCompiledSimpleSelectorChecker(const ContainerNode& searchRootNode, SelectorCompiler::QuerySelectorSimpleSelectorChecker selectorChecker, typename SelectorQueryTrait::OutputType& output, const SelectorData& selectorData) const
 {
     for (auto& element : elementDescendants(const_cast<ContainerNode&>(searchRootNode))) {
 #if CSS_SELECTOR_JIT_PROFILING
@@ -398,7 +400,7 @@
 }
 
 template <typename SelectorQueryTrait>
-ALWAYS_INLINE void SelectorDataList::executeCompiledSelectorCheckerWithCheckingContext(const ContainerNode& rootNode, const ContainerNode& searchRootNode, SelectorCompiler::SelectorCheckerWithCheckingContext selectorChecker, typename SelectorQueryTrait::OutputType& output, const SelectorData& selectorData) const
+ALWAYS_INLINE void SelectorDataList::executeCompiledSelectorCheckerWithCheckingContext(const ContainerNode& rootNode, const ContainerNode& searchRootNode, SelectorCompiler::QuerySelectorSelectorCheckerWithCheckingContext selectorChecker, typename SelectorQueryTrait::OutputType& output, const SelectorData& selectorData) const
 {
     SelectorChecker::CheckingContext checkingContext(SelectorChecker::Mode::QueryingRules);
     checkingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
@@ -431,11 +433,11 @@
             bool matched = false;
             void* compiledSelectorChecker = m_selectors[i].compiledSelectorCodeRef.code().executableAddress();
             if (m_selectors[i].compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker) {
-                SelectorCompiler::SimpleSelectorChecker selectorChecker = SelectorCompiler::simpleSelectorCheckerFunction(compiledSelectorChecker, m_selectors[i].compilationStatus);
+                SelectorCompiler::QuerySelectorSimpleSelectorChecker selectorChecker = SelectorCompiler::querySelectorSimpleSelectorCheckerFunction(compiledSelectorChecker, m_selectors[i].compilationStatus);
                 matched = selectorChecker(&element);
             } else {
                 ASSERT(m_selectors[i].compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
-                SelectorCompiler::SelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::selectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, m_selectors[i].compilationStatus);
+                SelectorCompiler::QuerySelectorSelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::querySelectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, m_selectors[i].compilationStatus);
                 matched = selectorChecker(&element, &checkingContext);
             }
             if (matched) {
@@ -524,11 +526,11 @@
         const SelectorData& selectorData = m_selectors.first();
         void* compiledSelectorChecker = selectorData.compiledSelectorCodeRef.code().executableAddress();
         if (selectorData.compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker) {
-            SelectorCompiler::SimpleSelectorChecker selectorChecker = SelectorCompiler::simpleSelectorCheckerFunction(compiledSelectorChecker, selectorData.compilationStatus);
+            SelectorCompiler::QuerySelectorSimpleSelectorChecker selectorChecker = SelectorCompiler::querySelectorSimpleSelectorCheckerFunction(compiledSelectorChecker, selectorData.compilationStatus);
             executeCompiledSimpleSelectorChecker<SelectorQueryTrait>(*searchRootNode, selectorChecker, output, selectorData);
         } else {
             ASSERT(selectorData.compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
-            SelectorCompiler::SelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::selectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, selectorData.compilationStatus);
+            SelectorCompiler::QuerySelectorSelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::querySelectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, selectorData.compilationStatus);
             executeCompiledSelectorCheckerWithCheckingContext<SelectorQueryTrait>(rootNode, *searchRootNode, selectorChecker, output, selectorData);
         }
         break;

Modified: trunk/Source/WebCore/dom/SelectorQuery.h (175771 => 175772)


--- trunk/Source/WebCore/dom/SelectorQuery.h	2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/dom/SelectorQuery.h	2014-11-08 02:05:36 UTC (rev 175772)
@@ -89,8 +89,8 @@
     template <typename SelectorQueryTrait> void executeSingleSelectorData(const ContainerNode& rootNode, const SelectorData&, typename SelectorQueryTrait::OutputType&) const;
     template <typename SelectorQueryTrait> void executeSingleMultiSelectorData(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType&) const;
 #if ENABLE(CSS_SELECTOR_JIT)
-    template <typename SelectorQueryTrait> void executeCompiledSimpleSelectorChecker(const ContainerNode& searchRootNode, SelectorCompiler::SimpleSelectorChecker, typename SelectorQueryTrait::OutputType&, const SelectorData&) const;
-    template <typename SelectorQueryTrait> void executeCompiledSelectorCheckerWithCheckingContext(const ContainerNode& rootNode, const ContainerNode& searchRootNode, SelectorCompiler::SelectorCheckerWithCheckingContext, typename SelectorQueryTrait::OutputType&, const SelectorData&) const;
+    template <typename SelectorQueryTrait> void executeCompiledSimpleSelectorChecker(const ContainerNode& searchRootNode, SelectorCompiler::QuerySelectorSimpleSelectorChecker, typename SelectorQueryTrait::OutputType&, const SelectorData&) const;
+    template <typename SelectorQueryTrait> void executeCompiledSelectorCheckerWithCheckingContext(const ContainerNode& rootNode, const ContainerNode& searchRootNode, SelectorCompiler::QuerySelectorSelectorCheckerWithCheckingContext, typename SelectorQueryTrait::OutputType&, const SelectorData&) const;
     template <typename SelectorQueryTrait> void executeCompiledSingleMultiSelectorData(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType&) const;
     static bool compileSelector(const SelectorData&, const ContainerNode& rootNode);
 #endif // ENABLE(CSS_SELECTOR_JIT)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to