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;