Skip to content

Commit

Permalink
[css-nesting] Make selectors dropped during forgiving parsing still
Browse files Browse the repository at this point in the history
count towards nest-containment.

Also add a test. We keep track of this using a simple boolean,
and since we make CSSParser from scratch every time we start parsing
a new top-level selector, we don't need to worry about resetting it.

In line with CSSWG resolution at
w3c/csswg-drafts#7972.

Bug: 1095675
Change-Id: I869e6859e32284167ef4e1e8c60b64e770b9e945
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4200218
Reviewed-by: Rune Lillesveen <futhark@chromium.org>
Commit-Queue: Steinar H Gunderson <sesse@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1098520}
  • Loading branch information
Steinar H. Gunderson authored and Chromium LUCI CQ committed Jan 30, 2023
1 parent 40c9879 commit c0c2114
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,12 @@ CSSSelectorList* CSSSelectorParser::ConsumeForgivingComplexSelectorList(
ConsumeComplexSelector(argument, /*in_nested_style_rule=*/false,
/*first_in_complex_selector_list=*/false);
if (selector.empty() || failed_parsing_ || !argument.AtEnd()) {
for (const CSSParserToken& token : argument) {
if (token.GetType() == kDelimiterToken && token.Delimiter() == '&') {
dropped_nest_token_during_forgiving_parsing_ = true;
break;
}
}
if (in_supports_parsing_) {
at_supports_drop_invalid_counter.Count();
}
Expand Down Expand Up @@ -766,7 +772,8 @@ base::span<CSSSelector> CSSSelectorParser::ConsumeComplexSelector(
// of SelectorListIsNestContaining().
wtf_size_t last_index = output_.size() - 1;
output_[last_index].SetLastInSelectorList(true);
if (!SelectorListIsNestContaining(reset_vector.AddedElements().data())) {
if (!dropped_nest_token_during_forgiving_parsing_ &&
!SelectorListIsNestContaining(reset_vector.AddedElements().data())) {
output_.back().SetRelation(CSSSelector::kDescendant);
output_.push_back(
CSSSelector(parent_rule_for_nesting_, /*is_implicit=*/true));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ class CORE_EXPORT CSSSelectorParser {
// PseudoType of the pseudo-element causing the restriction.
CSSSelector::PseudoType restricting_pseudo_element_ =
CSSSelector::kPseudoUnknown;
// Whether at any point we dropped an & token during forgiving parsing
// (e.g. in :is(!&, .foo)); such selectors are still considered as
// nest-containing. Since every top-level selector gets a new CSSParser
// instance, we don't need to worry about resetting it.
bool dropped_nest_token_during_forgiving_parsing_ = false;
// If we're _resisting_ the default namespace, it means that we are inside
// a nested selector (:is(), :where(), etc) where we should _consider_
// ignoring the default namespace (depending on circumstance). See the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<title>Nest-containing in forgiving parsing</title>
<style>
.test {
background-color: green;
width: 100px;
height: 100px;
display: grid;
}

body * + * {
margin-top: 8px;
}
</style>
<body>
<p>Tests pass if <strong>block is green</strong></p>
<div class="test"></div>
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<title>Nest-containing in forgiving parsing</title>
<link rel="author" title="Steinar H. Gunderson" href="mailto:sesse@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
<link rel="match" href="nest-containing-forgiving-ref.html">
<style>
.test {
background-color: red;
width: 100px;
height: 100px;
display: grid;
}

.does-not-exist {
:is(.test-1, !&) {
background-color: green;
}
}

body * + * {
margin-top: 8px;
}
</style>
<body>
<p>Tests pass if <strong>block is green</strong></p>
<div class="test test-1"></div>
</body>

0 comments on commit c0c2114

Please sign in to comment.