Title: [107911] trunk
Revision
107911
Author
[email protected]
Date
2012-02-16 01:31:17 -0800 (Thu, 16 Feb 2012)

Log Message

<style scoped>: Implement scoped selector matching in the slow path
https://bugs.webkit.org/show_bug.cgi?id=77528

Source/WebCore:

Added scope information to SelectorCheckingContext, SelectorChecker methods and CSSStyleSelector methods.
Added matchOptions struct to CSSStyleSelector similar to SelectorCheckingContext in SelectorChecker.
Adapted the calling sites.

Reviewed by Antti Koivisto.

No new tests. (extended existing tests)

* css/CSSStyleSelector.cpp:
(RuleData):
(RuleSet):
(WebCore::CSSStyleSelector::determineScopingElement):
(WebCore::CSSStyleSelector::collectMatchingRules):
(WebCore::CSSStyleSelector::collectMatchingRulesForRegion):
(WebCore::CSSStyleSelector::matchScopedAuthorRules):
(WebCore::CSSStyleSelector::matchAuthorRules):
(WebCore::CSSStyleSelector::collectMatchingRulesForList):
* css/CSSStyleSelector.h:
(CSSStyleSelector):
(MatchOptions):
(WebCore::CSSStyleSelector::MatchOptions::MatchOptions):
* css/SelectorChecker.cpp:
(WebCore::SelectorChecker::checkSelector):
* css/SelectorChecker.h:
(WebCore::SelectorChecker::SelectorCheckingContext::SelectorCheckingContext):
(SelectorCheckingContext):
(SelectorChecker):

LayoutTests:

Extended existing <style scoped> tests to also verify that selector matching doesn't exceed the scoping element.

Reviewed by Antti Koivisto.

* fast/css/style-scoped/style-scoped-basic-expected.txt:
* fast/css/style-scoped/style-scoped-basic.html:
* fast/css/style-scoped/style-scoped-remove-scoped-expected.txt:
* fast/css/style-scoped/style-scoped-remove-scoped.html:
* fast/css/style-scoped/style-scoped-set-scoped-expected.txt:
* fast/css/style-scoped/style-scoped-set-scoped.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (107910 => 107911)


--- trunk/LayoutTests/ChangeLog	2012-02-16 09:15:53 UTC (rev 107910)
+++ trunk/LayoutTests/ChangeLog	2012-02-16 09:31:17 UTC (rev 107911)
@@ -1,3 +1,19 @@
+2012-02-16  Roland Steiner  <[email protected]>
+
+        <style scoped>: Implement scoped selector matching in the slow path
+        https://bugs.webkit.org/show_bug.cgi?id=77528
+
+        Extended existing <style scoped> tests to also verify that selector matching doesn't exceed the scoping element.
+
+        Reviewed by Antti Koivisto.
+
+        * fast/css/style-scoped/style-scoped-basic-expected.txt:
+        * fast/css/style-scoped/style-scoped-basic.html:
+        * fast/css/style-scoped/style-scoped-remove-scoped-expected.txt:
+        * fast/css/style-scoped/style-scoped-remove-scoped.html:
+        * fast/css/style-scoped/style-scoped-set-scoped-expected.txt:
+        * fast/css/style-scoped/style-scoped-set-scoped.html:
+
 2012-02-16  Noel Gordon  <[email protected]>
 
         [chromium] Rebaseline JPEG image results after r107389

Modified: trunk/LayoutTests/fast/css/style-scoped/style-scoped-basic-expected.txt (107910 => 107911)


--- trunk/LayoutTests/fast/css/style-scoped/style-scoped-basic-expected.txt	2012-02-16 09:15:53 UTC (rev 107910)
+++ trunk/LayoutTests/fast/css/style-scoped/style-scoped-basic-expected.txt	2012-02-16 09:31:17 UTC (rev 107911)
@@ -11,6 +11,7 @@
 Text
 Text
 Text
+Text
 
 Text
 Text
@@ -28,6 +29,7 @@
 S2: rgb(255, 0, 0)
 P2: rgb(0, 128, 0)
 R2: rgb(0, 0, 255)
+E2: rgb(255, 0, 0)
 
 S3: rgb(0, 0, 0)
 P3: rgb(0, 0, 0)

Modified: trunk/LayoutTests/fast/css/style-scoped/style-scoped-basic.html (107910 => 107911)


--- trunk/LayoutTests/fast/css/style-scoped/style-scoped-basic.html	2012-02-16 09:15:53 UTC (rev 107910)
+++ trunk/LayoutTests/fast/css/style-scoped/style-scoped-basic.html	2012-02-16 09:31:17 UTC (rev 107911)
@@ -28,6 +28,7 @@
             test('S2');
             test('P2');
             test('R2');
+            test('E2');
             log('');
             test('S3');
             test('P3');
@@ -51,29 +52,35 @@
     <div class="foo">
         <span id="S1">Text</span>
         <p id="P1">Text</p>
-        <pre id = "R1" class="bar">Text</pre>
+        <pre id="R1" class="bar">Text</pre>
         <pre id="E1" class="baz">Text</pre>
     </div>
-    <div>
+    <div id="foo">
+        <div id="sib"></div>
         <div>
             <style type="text/css" scoped>
                 div { color: red; }
                 p { color: green; }
                 div .bar { color: blue; }
+                #foo .baz { color: rgb(10, 10, 10); } /* should NOT apply! */
+                sib + * { color: rgb(20, 20, 20); } /* should NOT apply! */
+                sib ~ * { color: rgb(30, 30, 30); } /* should NOT apply! */
+                div div { color: rgb(40, 40, 40); } /* should NOT apply! */ 
             </style>
             <span id="S2">Text</span>
             <p id="P2">Text</p>
             <pre id="R2" class="bar">Text</pre>
+            <pre id="E2" class="baz">Text</pre>
         </div>
         <span id="S3">Text</span>
         <p id="P3">Text</p>
-        <pre id = "R3" class="bar">Text</pre>
+        <pre id="R3" class="bar">Text</pre>
         <pre id="E3" class="baz">Text</pre>
     </div>
     <div class="foo">
         <span id="S4">Text</span>
         <p id="P4">Text</p>
-        <pre id = "R4" class="bar">Text</pre>
+        <pre id="R4" class="bar">Text</pre>
         <pre id="E4" class="baz">Text</pre>
     </div>
     <pre id="console"></pre>

Modified: trunk/LayoutTests/fast/css/style-scoped/style-scoped-remove-scoped-expected.txt (107910 => 107911)


--- trunk/LayoutTests/fast/css/style-scoped/style-scoped-remove-scoped-expected.txt	2012-02-16 09:15:53 UTC (rev 107910)
+++ trunk/LayoutTests/fast/css/style-scoped/style-scoped-remove-scoped-expected.txt	2012-02-16 09:31:17 UTC (rev 107911)
@@ -4,24 +4,39 @@
 Text
 
 Text
+
+    
 Text
+Text
 
 Text
+
+    
 Text
+Text
 
+Text
+
+    
 --- ORIGINAL ---
 S1: rgb(0, 0, 0)
 P1: rgb(0, 0, 0)
+R1: rgb(0, 0, 0)
 S2: rgb(255, 0, 0)
 P2: rgb(0, 128, 0)
+R2: rgb(255, 0, 0)
 S3: rgb(0, 0, 0)
 P3: rgb(0, 0, 0)
+R3: rgb(0, 0, 0)
 --- AFTER UN-SETTING @SCOPED ---
 S1: rgb(255, 0, 0)
 P1: rgb(0, 128, 0)
+R1: rgb(0, 0, 255)
 S2: rgb(255, 0, 0)
 P2: rgb(0, 128, 0)
+R2: rgb(0, 0, 255)
 S3: rgb(255, 0, 0)
 P3: rgb(0, 128, 0)
+R3: rgb(0, 0, 255)
 --- FINISHED ---
 

Modified: trunk/LayoutTests/fast/css/style-scoped/style-scoped-remove-scoped.html (107910 => 107911)


--- trunk/LayoutTests/fast/css/style-scoped/style-scoped-remove-scoped.html	2012-02-16 09:15:53 UTC (rev 107910)
+++ trunk/LayoutTests/fast/css/style-scoped/style-scoped-remove-scoped.html	2012-02-16 09:31:17 UTC (rev 107911)
@@ -17,10 +17,13 @@
         {
             test('S1');
             test('P1');
+            test('R1');
             test('S2');
             test('P2');
+            test('R2');
             test('S3');
             test('P3');
+            test('R3');
         }
 
         function runTests()
@@ -52,18 +55,22 @@
     <div>
         <span id="S1">Text</span>
         <p id="P1">Text</p>
+        <pre id="R1">Text</p>
     </div>
     <div>
         <style id="STYLE" type="text/css" scoped>
             div { color: red; }
             p { color: green; }
+            p ~ div pre { color: blue; } /* should NOT apply while scoped! */
         </style>
         <span id="S2">Text</span>
         <p id="P2">Text</p>
+        <pre id="R2">Text</p>
     </div>
     <div>
         <span id="S3">Text</span>
         <p id="P3">Text</p>
+        <pre id="R3">Text</p>
     </div>
     <pre id="console"></pre>
 </body>

Modified: trunk/LayoutTests/fast/css/style-scoped/style-scoped-set-scoped-expected.txt (107910 => 107911)


--- trunk/LayoutTests/fast/css/style-scoped/style-scoped-set-scoped-expected.txt	2012-02-16 09:15:53 UTC (rev 107910)
+++ trunk/LayoutTests/fast/css/style-scoped/style-scoped-set-scoped-expected.txt	2012-02-16 09:31:17 UTC (rev 107911)
@@ -4,24 +4,39 @@
 Text
 
 Text
+
+    
 Text
+Text
 
 Text
+
+    
 Text
+Text
 
+Text
+
+    
 --- ORIGINAL ---
 S1: rgb(255, 0, 0)
 P1: rgb(0, 128, 0)
+R1: rgb(0, 0, 255)
 S2: rgb(255, 0, 0)
 P2: rgb(0, 128, 0)
+R2: rgb(0, 0, 255)
 S3: rgb(255, 0, 0)
 P3: rgb(0, 128, 0)
+R3: rgb(0, 0, 255)
 --- AFTER SETTING @SCOPED ---
 S1: rgb(0, 0, 0)
 P1: rgb(0, 0, 0)
+R1: rgb(0, 0, 0)
 S2: rgb(255, 0, 0)
 P2: rgb(0, 128, 0)
+R2: rgb(255, 0, 0)
 S3: rgb(0, 0, 0)
 P3: rgb(0, 0, 0)
+R3: rgb(0, 0, 0)
 --- FINISHED ---
 

Modified: trunk/LayoutTests/fast/css/style-scoped/style-scoped-set-scoped.html (107910 => 107911)


--- trunk/LayoutTests/fast/css/style-scoped/style-scoped-set-scoped.html	2012-02-16 09:15:53 UTC (rev 107910)
+++ trunk/LayoutTests/fast/css/style-scoped/style-scoped-set-scoped.html	2012-02-16 09:31:17 UTC (rev 107911)
@@ -17,10 +17,13 @@
         {
             test('S1');
             test('P1');
+            test('R1');
             test('S2');
             test('P2');
+            test('R2');
             test('S3');
             test('P3');
+            test('R3');
         }
 
         function runTests()
@@ -52,18 +55,22 @@
     <div>
         <span id="S1">Text</span>
         <p id="P1">Text</p>
+        <pre id="R1">Text</p>
     </div>
     <div>
         <style id="STYLE" type="text/css">
             div { color: red; }
             p { color: green; }
+            p ~ div pre { color: blue; } /* should NOT apply while scoped! */
         </style>
         <span id="S2">Text</span>
         <p id="P2">Text</p>
+        <pre id="R2">Text</p>
     </div>
     <div>
         <span id="S3">Text</span>
         <p id="P3">Text</p>
+        <pre id="R3">Text</p>
     </div>
     <pre id="console"></pre>
 </body>

Modified: trunk/Source/WebCore/ChangeLog (107910 => 107911)


--- trunk/Source/WebCore/ChangeLog	2012-02-16 09:15:53 UTC (rev 107910)
+++ trunk/Source/WebCore/ChangeLog	2012-02-16 09:31:17 UTC (rev 107911)
@@ -1,3 +1,36 @@
+2012-02-16  Roland Steiner  <[email protected]>
+
+        <style scoped>: Implement scoped selector matching in the slow path
+        https://bugs.webkit.org/show_bug.cgi?id=77528
+
+        Added scope information to SelectorCheckingContext, SelectorChecker methods and CSSStyleSelector methods.
+        Added matchOptions struct to CSSStyleSelector similar to SelectorCheckingContext in SelectorChecker.
+        Adapted the calling sites.
+
+        Reviewed by Antti Koivisto.
+
+        No new tests. (extended existing tests)
+
+        * css/CSSStyleSelector.cpp:
+        (RuleData):
+        (RuleSet):
+        (WebCore::CSSStyleSelector::determineScopingElement):
+        (WebCore::CSSStyleSelector::collectMatchingRules):
+        (WebCore::CSSStyleSelector::collectMatchingRulesForRegion):
+        (WebCore::CSSStyleSelector::matchScopedAuthorRules):
+        (WebCore::CSSStyleSelector::matchAuthorRules):
+        (WebCore::CSSStyleSelector::collectMatchingRulesForList):
+        * css/CSSStyleSelector.h:
+        (CSSStyleSelector):
+        (MatchOptions):
+        (WebCore::CSSStyleSelector::MatchOptions::MatchOptions):
+        * css/SelectorChecker.cpp:
+        (WebCore::SelectorChecker::checkSelector):
+        * css/SelectorChecker.h:
+        (WebCore::SelectorChecker::SelectorCheckingContext::SelectorCheckingContext):
+        (SelectorCheckingContext):
+        (SelectorChecker):
+
 2012-02-15  Patrick Gansterer  <[email protected]>
 
         Windows build fix for !ENABLE(CSS_FILTERS) after r106593.

Modified: trunk/Source/WebCore/css/CSSStyleSelector.cpp (107910 => 107911)


--- trunk/Source/WebCore/css/CSSStyleSelector.cpp	2012-02-16 09:15:53 UTC (rev 107910)
+++ trunk/Source/WebCore/css/CSSStyleSelector.cpp	2012-02-16 09:31:17 UTC (rev 107911)
@@ -173,7 +173,7 @@
 
 class RuleData {
 public:
-    RuleData(CSSStyleRule*, CSSSelector*, unsigned position);
+    RuleData(CSSStyleRule*, CSSSelector*, unsigned position, bool canUseFastCheckSelector = true);
 
     unsigned position() const { return m_position; }
     CSSStyleRule* rule() const { return m_rule; }
@@ -225,8 +225,8 @@
 
     void addRulesFromSheet(CSSStyleSheet*, const MediaQueryEvaluator&, CSSStyleSelector* = 0, const Element* = 0);
 
-    void addStyleRule(CSSStyleRule*);
-    void addRule(CSSStyleRule*, CSSSelector*);
+    void addStyleRule(CSSStyleRule*, bool canUseFastCheckSelector = true);
+    void addRule(CSSStyleRule*, CSSSelector*, bool canUseFastCheckSelector = true);
     void addPageRule(CSSPageRule*);
     void addToRuleSet(AtomicStringImpl* key, AtomRuleMap&, const RuleData&);
     void addRegionRule(WebKitCSSRegionRule*);
@@ -443,7 +443,7 @@
 }
 
 #if ENABLE(STYLE_SCOPED)
-Element* CSSStyleSelector::determineScopingElement(const CSSStyleSheet* sheet)
+const Element* CSSStyleSelector::determineScopingElement(const CSSStyleSheet* sheet)
 {
     ASSERT(sheet);
 
@@ -756,7 +756,7 @@
     matchResult.matchedRules.append(rule);
 }
 
-void CSSStyleSelector::collectMatchingRules(RuleSet* rules, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules)
+void CSSStyleSelector::collectMatchingRules(RuleSet* rules, int& firstRuleIndex, int& lastRuleIndex, const MatchOptions& options)
 {
     ASSERT(rules);
     ASSERT(m_element);
@@ -764,28 +764,28 @@
     // We need to collect the rules for id, class, tag, and everything else into a buffer and
     // then sort the buffer.
     if (m_element->hasID())
-        collectMatchingRulesForList(rules->idRules(m_element->idForStyleResolution().impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules);
+        collectMatchingRulesForList(rules->idRules(m_element->idForStyleResolution().impl()), firstRuleIndex, lastRuleIndex, options);
     if (m_element->hasClass()) {
         ASSERT(m_styledElement);
         const SpaceSplitString& classNames = m_styledElement->classNames();
         size_t size = classNames.size();
         for (size_t i = 0; i < size; ++i)
-            collectMatchingRulesForList(rules->classRules(classNames[i].impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules);
+            collectMatchingRulesForList(rules->classRules(classNames[i].impl()), firstRuleIndex, lastRuleIndex, options);
     }
     const AtomicString& pseudoId = m_element->shadowPseudoId();
     if (!pseudoId.isEmpty()) {
         ASSERT(m_styledElement);
-        collectMatchingRulesForList(rules->shadowPseudoElementRules(pseudoId.impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules);
+        collectMatchingRulesForList(rules->shadowPseudoElementRules(pseudoId.impl()), firstRuleIndex, lastRuleIndex, options);
     }
     if (m_element->isLink())
-        collectMatchingRulesForList(rules->linkPseudoClassRules(), firstRuleIndex, lastRuleIndex, includeEmptyRules);
+        collectMatchingRulesForList(rules->linkPseudoClassRules(), firstRuleIndex, lastRuleIndex, options);
     if (m_checker.matchesFocusPseudoClass(m_element))
-        collectMatchingRulesForList(rules->focusPseudoClassRules(), firstRuleIndex, lastRuleIndex, includeEmptyRules);
-    collectMatchingRulesForList(rules->tagRules(m_element->localName().impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules);
-    collectMatchingRulesForList(rules->universalRules(), firstRuleIndex, lastRuleIndex, includeEmptyRules);
+        collectMatchingRulesForList(rules->focusPseudoClassRules(), firstRuleIndex, lastRuleIndex, options);
+    collectMatchingRulesForList(rules->tagRules(m_element->localName().impl()), firstRuleIndex, lastRuleIndex, options);
+    collectMatchingRulesForList(rules->universalRules(), firstRuleIndex, lastRuleIndex, options);
 }
 
-void CSSStyleSelector::collectMatchingRulesForRegion(RuleSet* rules, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules)
+void CSSStyleSelector::collectMatchingRulesForRegion(RuleSet* rules, int& firstRuleIndex, int& lastRuleIndex, const MatchOptions& options)
 {
     if (!m_regionForStyling)
         return;
@@ -796,7 +796,7 @@
         if (checkRegionSelector(regionSelector, static_cast<Element*>(m_regionForStyling->node()))) {
             RuleSet* regionRules = rules->m_regionSelectorsAndRuleSets.at(i).ruleSet.get();
             ASSERT(regionRules);
-            collectMatchingRules(regionRules, firstRuleIndex, lastRuleIndex, includeEmptyRules);
+            collectMatchingRules(regionRules, firstRuleIndex, lastRuleIndex, options);
         }
     }
 }
@@ -835,19 +835,24 @@
     if (m_scopedAuthorStyles.isEmpty())
         return;
 
+    MatchOptions options(includeEmptyRules);
+
     // Match scoped author rules by traversing the scoped element stack (rebuild it if it got inconsistent).
     const Element* parent = m_element->parentOrHostElement();
     if (!scopingElementStackIsConsistent(parent))
         setupScopingElementStack(parent);
     for (size_t i = m_scopingElementStack.size(); i; --i) {
-        collectMatchingRules(m_scopingElementStack[i - 1].m_ruleSet, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, includeEmptyRules);
-        collectMatchingRulesForRegion(m_scopingElementStack[i - 1].m_ruleSet, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, includeEmptyRules);
+        const ScopeStackFrame& frame = m_scopingElementStack[i - 1];
+        options.scope = frame.m_element;
+        collectMatchingRules(frame.m_ruleSet, result.ranges.firstAuthorRule, result.ranges.lastAuthorRule, options);
+        collectMatchingRulesForRegion(frame.m_ruleSet, result.ranges.firstAuthorRule, result.ranges.lastAuthorRule, options);
     }
     // Also include the current element.
     RuleSet* ruleSet = scopedRuleSetForElement(m_element);
     if (ruleSet) {
-        collectMatchingRules(ruleSet, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, includeEmptyRules);
-        collectMatchingRulesForRegion(ruleSet, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, includeEmptyRules);
+        options.scope = m_element;
+        collectMatchingRules(ruleSet, result.ranges.firstAuthorRule, result.ranges.lastAuthorRule, options);
+        collectMatchingRulesForRegion(ruleSet, result.ranges.firstAuthorRule, result.ranges.lastAuthorRule, options);
     }
 #else
     UNUSED_PARAM(result);
@@ -858,11 +863,16 @@
 void CSSStyleSelector::matchAuthorRules(MatchResult& result, bool includeEmptyRules)
 {
     m_matchedRules.clear();
-
     result.ranges.lastAuthorRule = result.matchedProperties.size() - 1;
-    collectMatchingRules(m_authorStyle.get(), result.ranges.firstAuthorRule, result.ranges.lastAuthorRule, includeEmptyRules);
-    collectMatchingRulesForRegion(m_authorStyle.get(), result.ranges.firstAuthorRule, result.ranges.lastAuthorRule, includeEmptyRules);
 
+    if (!m_element)
+        return;
+
+    // Match global author rules.
+    MatchOptions options(includeEmptyRules);
+    collectMatchingRules(m_authorStyle.get(), result.ranges.firstAuthorRule, result.ranges.lastAuthorRule, options);
+    collectMatchingRulesForRegion(m_authorStyle.get(), result.ranges.firstAuthorRule, result.ranges.lastAuthorRule, options);
+
     matchScopedAuthorRules(result, includeEmptyRules);
 
     sortAndTransferMatchedRules(result);
@@ -921,13 +931,8 @@
 
 bool MatchingUARulesScope::m_matchingUARules = false;
 
-inline static bool matchesInTreeScope(TreeScope* treeScope, bool ruleReachesIntoShadowDOM)
+void CSSStyleSelector::collectMatchingRulesForList(const Vector<RuleData>* rules, int& firstRuleIndex, int& lastRuleIndex, const MatchOptions& options)
 {
-    return MatchingUARulesScope::isMatchingUARules() || treeScope->applyAuthorSheets() || ruleReachesIntoShadowDOM;
-}
-
-void CSSStyleSelector::collectMatchingRulesForList(const Vector<RuleData>* rules, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules)
-{
     if (!rules)
         return;
     // In some cases we may end up looking up style for random elements in the middle of a recursive tree resolve.
@@ -942,14 +947,30 @@
 
         CSSStyleRule* rule = ruleData.rule();
         InspectorInstrumentationCookie cookie = InspectorInstrumentation::willMatchRule(document(), rule);
+#if ENABLE(STYLE_SCOPED)
+        if (checkSelector(ruleData, options.scope)) {
+#else
         if (checkSelector(ruleData)) {
-            if (!matchesInTreeScope(m_element->treeScope(), m_checker.hasUnknownPseudoElements())) {
+#endif
+            // Check whether the rule is applicable in the current tree scope. Criteria for this:
+            // a) it's a UA rule
+            // b) the tree scope allows author rules
+            // c) the rules comes from a scoped style sheet within the same tree scope
+            // d) the rule contains shadow-ID pseudo elements
+            TreeScope* treeScope = m_element->treeScope();
+            if (!MatchingUARulesScope::isMatchingUARules()
+                && !treeScope->applyAuthorSheets()
+#if ENABLE(STYLE_SCOPED)
+                && (!options.scope || options.scope->treeScope() != treeScope)
+#endif
+                && !m_checker.hasUnknownPseudoElements()) {
+
                 InspectorInstrumentation::didMatchRule(cookie, false);
                 continue;
             }
             // If the rule has no properties to apply, then ignore it in the non-debug mode.
             StylePropertySet* decl = rule->declaration();
-            if (!decl || (decl->isEmpty() && !includeEmptyRules)) {
+            if (!decl || (decl->isEmpty() && !options.includeEmptyRules)) {
                 InspectorInstrumentation::didMatchRule(cookie, false);
                 continue;
             }
@@ -2081,7 +2102,7 @@
     return m_ruleList.release();
 }
 
-inline bool CSSStyleSelector::checkSelector(const RuleData& ruleData)
+inline bool CSSStyleSelector::checkSelector(const RuleData& ruleData, const Element* scope)
 {
     m_dynamicPseudo = NOPSEUDO;
     m_checker.clearHasUnknownPseudoElements();
@@ -2104,7 +2125,10 @@
     }
 
     // Slow path.
-    SelectorChecker::SelectorCheckingContext context(ruleData.selector(), m_element, SelectorChecker::VisitedMatchEnabled, style(), m_parentNode ? m_parentNode->renderStyle() : 0);
+    SelectorChecker::SelectorCheckingContext context(ruleData.selector(), m_element, SelectorChecker::VisitedMatchEnabled);
+    context.elementStyle = style();
+    context.elementParentStyle = m_parentNode ? m_parentNode->renderStyle() : 0;
+    context.scope = scope;
     SelectorChecker::SelectorMatch match = m_checker.checkSelector(context, m_dynamicPseudo);
     if (match != SelectorChecker::SelectorMatches)
         return false;
@@ -2211,12 +2235,12 @@
     return false;
 }
 
-RuleData::RuleData(CSSStyleRule* rule, CSSSelector* selector, unsigned position)
+RuleData::RuleData(CSSStyleRule* rule, CSSSelector* selector, unsigned position, bool canUseFastCheckSelector)
     : m_rule(rule)
     , m_selector(selector)
     , m_specificity(selector->specificity())
     , m_position(position)
-    , m_hasFastCheckableSelector(SelectorChecker::isFastCheckableSelector(selector))
+    , m_hasFastCheckableSelector(canUseFastCheckSelector && SelectorChecker::isFastCheckableSelector(selector))
     , m_hasMultipartSelector(!!selector->tagHistory())
     , m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash(isSelectorMatchingHTMLBasedOnRuleHash(selector))
     , m_containsUncommonAttributeSelector(WebCore::containsUncommonAttributeSelector(selector))
@@ -2285,9 +2309,9 @@
     rules->append(ruleData);
 }
 
-void RuleSet::addRule(CSSStyleRule* rule, CSSSelector* selector)
+void RuleSet::addRule(CSSStyleRule* rule, CSSSelector* selector, bool canUseFastCheckSelector)
 {
-    RuleData ruleData(rule, selector, m_ruleCount++);
+    RuleData ruleData(rule, selector, m_ruleCount++, canUseFastCheckSelector);
     collectFeaturesFromRuleData(m_features, ruleData);
 
     if (selector->m_match == CSSSelector::Id) {
@@ -2364,7 +2388,7 @@
     for (int i = 0; i < len; i++) {
         CSSRule* rule = sheet->item(i);
         if (rule->isStyleRule())
-            addStyleRule(static_cast<CSSStyleRule*>(rule));
+            addStyleRule(static_cast<CSSStyleRule*>(rule), !scope);
         else if (rule->isPageRule())
             addPageRule(static_cast<CSSPageRule*>(rule));
         else if (rule->isImportRule()) {
@@ -2381,7 +2405,7 @@
                 for (unsigned j = 0; j < rules->length(); j++) {
                     CSSRule *childItem = rules->item(j);
                     if (childItem->isStyleRule())
-                        addStyleRule(static_cast<CSSStyleRule*>(childItem));
+                        addStyleRule(static_cast<CSSStyleRule*>(childItem), !scope);
                     else if (childItem->isPageRule())
                         addPageRule(static_cast<CSSPageRule*>(childItem));
                     else if (childItem->isFontFaceRule() && styleSelector) {
@@ -2425,10 +2449,10 @@
         shrinkToFit();
 }
 
-void RuleSet::addStyleRule(CSSStyleRule* rule)
+void RuleSet::addStyleRule(CSSStyleRule* rule, bool canUseFastCheckSelector)
 {
     for (CSSSelector* s = rule->selectorList().first(); s; s = CSSSelectorList::next(s))
-        addRule(rule, s);
+        addRule(rule, s, canUseFastCheckSelector);
 }
 
 static inline void shrinkMapVectorsToFit(RuleSet::AtomRuleMap& map)

Modified: trunk/Source/WebCore/css/CSSStyleSelector.h (107910 => 107911)


--- trunk/Source/WebCore/css/CSSStyleSelector.h	2012-02-16 09:15:53 UTC (rev 107910)
+++ trunk/Source/WebCore/css/CSSStyleSelector.h	2012-02-16 09:31:17 UTC (rev 107911)
@@ -106,10 +106,6 @@
                      bool strictParsing, bool matchAuthorAndUserStyles);
     ~CSSStyleSelector();
 
-#if ENABLE(STYLE_SCOPED)
-    static Element* determineScopingElement(const CSSStyleSheet*);
-#endif
-
     // Using these during tree walk will allow style selector to optimize child and descendant selector lookups.
     void pushParent(Element* parent);
     void popParent(Element* parent);
@@ -288,6 +284,13 @@
         MatchRanges ranges;
         bool isCacheable;
     };
+
+    struct MatchOptions {
+        MatchOptions(bool includeEmptyRules, const Element* scope = 0) : scope(scope), includeEmptyRules(includeEmptyRules) { }
+        const Element* scope;
+        bool includeEmptyRules;
+    };
+
     static void addMatchedProperties(MatchResult& matchResult, StylePropertySet* properties, CSSStyleRule* rule = 0, unsigned linkMatchType =  SelectorChecker::MatchAll);
 
     void matchAllRules(MatchResult&);
@@ -296,14 +299,14 @@
     void matchAuthorRules(MatchResult&, bool includeEmptyRules);
     void matchUserRules(MatchResult&, bool includeEmptyRules);
     void matchScopedAuthorRules(MatchResult&, bool includeEmptyRules);
-    void collectMatchingRules(RuleSet*, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules);
-    void collectMatchingRulesForRegion(RuleSet*, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules);
-    void collectMatchingRulesForList(const Vector<RuleData>*, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules);
+    void collectMatchingRules(RuleSet*, int& firstRuleIndex, int& lastRuleIndex, const MatchOptions&);
+    void collectMatchingRulesForRegion(RuleSet*, int& firstRuleIndex, int& lastRuleIndex, const MatchOptions&);
+    void collectMatchingRulesForList(const Vector<RuleData>*, int& firstRuleIndex, int& lastRuleIndex, const MatchOptions&);
     bool fastRejectSelector(const RuleData&) const;
     void sortMatchedRules();
     void sortAndTransferMatchedRules(MatchResult&);
 
-    bool checkSelector(const RuleData&);
+    bool checkSelector(const RuleData&, const Element* scope = 0);
     bool checkRegionSelector(CSSSelector* regionSelector, Element* regionElement);
     void applyMatchedProperties(const MatchResult&);
     template <bool firstPass>
@@ -446,6 +449,8 @@
 #endif
 
 #if ENABLE(STYLE_SCOPED)
+    static const Element* determineScopingElement(const CSSStyleSheet*);
+
     typedef HashMap<const Element*, OwnPtr<RuleSet> > ScopedRuleSetMap;
 
     RuleSet* scopedRuleSetForElement(const Element*) const;

Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (107910 => 107911)


--- trunk/Source/WebCore/css/SelectorChecker.cpp	2012-02-16 09:15:53 UTC (rev 107910)
+++ trunk/Source/WebCore/css/SelectorChecker.cpp	2012-02-16 09:31:17 UTC (rev 107911)
@@ -468,6 +468,10 @@
     nextContext.selector = historySelector;
 
     if (relation != CSSSelector::SubSelector) {
+        // Abort if the next selector would exceed the scope.
+        if (context.element == context.scope)
+            return SelectorFailsCompletely;
+
         // Bail-out if this selector is irrelevant for the pseudoStyle
         if (m_pseudoStyle != NOPSEUDO && m_pseudoStyle != dynamicPseudo)
             return SelectorFailsCompletely;
@@ -487,6 +491,8 @@
             SelectorMatch match = checkSelector(nextContext, dynamicPseudo);
             if (match == SelectorMatches || match == SelectorFailsCompletely)
                 return match;
+            if (nextContext.element == nextContext.scope)
+                return SelectorFailsCompletely;
         }
         return SelectorFailsCompletely;
 
@@ -542,6 +548,9 @@
 
     case CSSSelector::ShadowDescendant:
         {
+            // If we're in the same tree-scope as the scoping element, then following a shadow descendant combinator would escape that and thus the scope.
+            if (context.scope && context.scope->treeScope() == context.element->treeScope())
+                return SelectorFailsCompletely;
             Node* shadowHostNode = context.element->shadowAncestorNode();
             if (shadowHostNode == context.element || !shadowHostNode->isElementNode())
                 return SelectorFailsCompletely;

Modified: trunk/Source/WebCore/css/SelectorChecker.h (107910 => 107911)


--- trunk/Source/WebCore/css/SelectorChecker.h	2012-02-16 09:15:53 UTC (rev 107910)
+++ trunk/Source/WebCore/css/SelectorChecker.h	2012-02-16 09:31:17 UTC (rev 107911)
@@ -54,17 +54,19 @@
 
     struct SelectorCheckingContext {
         // Initial selector constructor
-        SelectorCheckingContext(CSSSelector* selector, Element* element, VisitedMatchType visitedMatchType, RenderStyle* elementStyle = 0, RenderStyle* elementParentStyle = 0)
+        SelectorCheckingContext(CSSSelector* selector, Element* element, VisitedMatchType visitedMatchType)
             : selector(selector)
             , element(element)
+            , scope(0)
             , visitedMatchType(visitedMatchType)
-            , elementStyle(elementStyle)
-            , elementParentStyle(elementParentStyle)
+            , elementStyle(0)
+            , elementParentStyle(0)
             , isSubSelector(false)
         { }
 
         CSSSelector* selector;
         Element* element;
+        const Element* scope;
         VisitedMatchType visitedMatchType;
         RenderStyle* elementStyle;
         RenderStyle* elementParentStyle;
@@ -143,7 +145,7 @@
         Vector<unsigned, 4> identifierHashes;
     };
     Vector<ParentStackFrame> m_parentStack;
-    
+
     // With 100 unique strings in the filter, 2^12 slot table has false positive rate of ~0.2%.
     static const unsigned bloomFilterKeyBits = 12;
     OwnPtr<BloomFilter<bloomFilterKeyBits> > m_ancestorIdentifierFilter;
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to