From 7c36a82129ac1ff302ea19c5cee59d23f8e4c214 Mon Sep 17 00:00:00 2001 From: Psychpsyo Date: Sat, 3 May 2025 21:05:11 +0200 Subject: [PATCH] LibWeb: Improve parsing for the CSS contain property This makes us actually respect the grammar and nets us a couple extra WPT passes in the parsing section. --- Libraries/LibWeb/CSS/Parser/Parser.h | 1 + .../LibWeb/CSS/Parser/PropertyParsing.cpp | 75 +++++++++++++++++++ Libraries/LibWeb/CSS/Properties.json | 1 - .../css-contain/parsing/contain-computed.txt | 14 ++-- .../css/css-contain/parsing/contain-valid.txt | 6 +- 5 files changed, 86 insertions(+), 11 deletions(-) diff --git a/Libraries/LibWeb/CSS/Parser/Parser.h b/Libraries/LibWeb/CSS/Parser/Parser.h index c9e336160ce..34b5b0a5600 100644 --- a/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Libraries/LibWeb/CSS/Parser/Parser.h @@ -345,6 +345,7 @@ private: }; RefPtr parse_position_value(TokenStream&, PositionParsingMode = PositionParsingMode::Normal); RefPtr parse_filter_value_list_value(TokenStream&); + RefPtr parse_contain_value(TokenStream&); RefPtr parse_opentype_tag_value(TokenStream&); RefPtr parse_font_source_value(TokenStream&); diff --git a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp index fca8e79bd29..2d8ed9cc640 100644 --- a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp +++ b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp @@ -700,6 +700,10 @@ Parser::ParseErrorOr> Parser::parse_css_value if (auto parsed_value = parse_scale_value(tokens); parsed_value && !tokens.has_next_token()) return parsed_value.release_nonnull(); return ParseError::SyntaxError; + case PropertyID::Contain: + if (auto parsed_value = parse_contain_value(tokens); parsed_value && !tokens.has_next_token()) + return parsed_value.release_nonnull(); + return ParseError::SyntaxError; default: break; } @@ -4609,4 +4613,75 @@ RefPtr Parser::parse_filter_value_list_value(TokenStream Parser::parse_contain_value(TokenStream& tokens) +{ + // none | strict | content | [ [size | inline-size] || layout || style || paint ] + auto transaction = tokens.begin_transaction(); + tokens.discard_whitespace(); + + // none + if (auto none = parse_all_as_single_keyword_value(tokens, Keyword::None)) { + transaction.commit(); + return none; + } + + // strict + if (auto strict = parse_all_as_single_keyword_value(tokens, Keyword::Strict)) { + transaction.commit(); + return strict; + } + + // content + if (auto content = parse_all_as_single_keyword_value(tokens, Keyword::Content)) { + transaction.commit(); + return content; + } + + // [ [size | inline-size] || layout || style || paint ] + if (!tokens.has_next_token()) + return {}; + + bool has_size = false; + bool has_layout = false; + bool has_style = false; + bool has_paint = false; + + StyleValueVector containments; + while (tokens.has_next_token()) { + tokens.discard_whitespace(); + auto keyword = parse_keyword_value(tokens); + if (!keyword) + return {}; + switch (keyword->to_keyword()) { + case Keyword::Size: + case Keyword::InlineSize: + if (has_size) + return {}; + has_size = true; + break; + case Keyword::Layout: + if (has_layout) + return {}; + has_layout = true; + break; + case Keyword::Style: + if (has_style) + return {}; + has_style = true; + break; + case Keyword::Paint: + if (has_paint) + return {}; + has_paint = true; + break; + default: + return {}; + } + containments.append(*keyword); + } + transaction.commit(); + + return StyleValueList::create(move(containments), StyleValueList::Separator::Space); +} + } diff --git a/Libraries/LibWeb/CSS/Properties.json b/Libraries/LibWeb/CSS/Properties.json index ee187e40a8d..52543c26784 100644 --- a/Libraries/LibWeb/CSS/Properties.json +++ b/Libraries/LibWeb/CSS/Properties.json @@ -1110,7 +1110,6 @@ ] }, "contain": { - "__comment": "FIXME: Some values of contain need to be mutually exclusive. The grammar this should adhere to is 'none | strict | content | [ [size | inline-size] || layout || style || paint ]'.", "affects-stacking-context": true, "animation-type": "none", "inherited": false, diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-contain/parsing/contain-computed.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-contain/parsing/contain-computed.txt index 0c7b8c2998c..0bab7018899 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-contain/parsing/contain-computed.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-contain/parsing/contain-computed.txt @@ -2,8 +2,8 @@ Harness status: OK Found 15 tests -8 Pass -7 Fail +13 Pass +2 Fail Pass Property contain value 'none' Pass Property contain value 'strict' Pass Property contain value 'content' @@ -11,11 +11,11 @@ Pass Property contain value 'size' Pass Property contain value 'layout' Pass Property contain value 'style' Pass Property contain value 'paint' -Fail Property contain value 'size layout' -Fail Property contain value 'style paint' +Pass Property contain value 'size layout' +Pass Property contain value 'style paint' Fail Property contain value 'style layout paint' Fail Property contain value 'size style layout paint' -Fail Property contain value 'size layout paint' -Fail Property contain value 'layout paint' +Pass Property contain value 'size layout paint' +Pass Property contain value 'layout paint' Pass Property contain value 'inline-size' -Fail Property contain value 'inline-size layout style paint' \ No newline at end of file +Pass Property contain value 'inline-size layout style paint' \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-contain/parsing/contain-valid.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-contain/parsing/contain-valid.txt index dfd31da478e..6729db0e42e 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-contain/parsing/contain-valid.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-contain/parsing/contain-valid.txt @@ -2,8 +2,8 @@ Harness status: OK Found 13 tests -8 Pass -5 Fail +9 Pass +4 Fail Pass e.style['contain'] = "none" should set the property value Pass e.style['contain'] = "strict" should set the property value Pass e.style['contain'] = "content" should set the property value @@ -13,7 +13,7 @@ Pass e.style['contain'] = "style" should set the property value Pass e.style['contain'] = "paint" should set the property value Fail e.style['contain'] = "layout size" should set the property value Fail e.style['contain'] = "paint style" should set the property value -Fail e.style['contain'] = "layout style paint" should set the property value +Pass e.style['contain'] = "layout style paint" should set the property value Fail e.style['contain'] = "layout paint style size" should set the property value Pass e.style['contain'] = "inline-size" should set the property value Fail e.style['contain'] = "layout inline-size" should set the property value \ No newline at end of file