diff --git a/Tests/LibWeb/Text/expected/css/CSSPropertyRule-invalid-rules.txt b/Tests/LibWeb/Text/expected/css/CSSPropertyRule-invalid-rules.txt new file mode 100644 index 00000000000..cfb6f7b54fe --- /dev/null +++ b/Tests/LibWeb/Text/expected/css/CSSPropertyRule-invalid-rules.txt @@ -0,0 +1 @@ +Number of parsed css rules: 1 (expected: 1) diff --git a/Tests/LibWeb/Text/expected/css/CSSPropertyRule-properties-readonly.txt b/Tests/LibWeb/Text/expected/css/CSSPropertyRule-properties-readonly.txt new file mode 100644 index 00000000000..1957c8d6563 --- /dev/null +++ b/Tests/LibWeb/Text/expected/css/CSSPropertyRule-properties-readonly.txt @@ -0,0 +1,6 @@ +@property rule syntax value: * +@property rule syntax value: * +@property rule inherits value: false +@property rule inherits value: false +@property rule initialValue value: blue +@property rule initialValue value: blue diff --git a/Tests/LibWeb/Text/input/css/CSSPropertyRule-invalid-rules.html b/Tests/LibWeb/Text/input/css/CSSPropertyRule-invalid-rules.html new file mode 100644 index 00000000000..8f40aaa7668 --- /dev/null +++ b/Tests/LibWeb/Text/input/css/CSSPropertyRule-invalid-rules.html @@ -0,0 +1,44 @@ + + +
This text shouldn't be visible
+ + diff --git a/Tests/LibWeb/Text/input/css/CSSPropertyRule-properties-readonly.html b/Tests/LibWeb/Text/input/css/CSSPropertyRule-properties-readonly.html new file mode 100644 index 00000000000..7855480c8fc --- /dev/null +++ b/Tests/LibWeb/Text/input/css/CSSPropertyRule-properties-readonly.html @@ -0,0 +1,26 @@ + + +
This text shouldn't be visible
+ + diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index eee1958cf92..7af3cfcc7b4 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1362,6 +1363,9 @@ JS::GCPtr Parser::convert_to_rule(Rule const& rule, Nested nested) if (at_rule.name.equals_ignoring_ascii_case("supports"sv)) return convert_to_supports_rule(at_rule, nested); + if (at_rule.name.equals_ignoring_ascii_case("property"sv)) + return convert_to_property_rule(at_rule); + // FIXME: More at rules! dbgln_if(CSS_PARSER_DEBUG, "Unrecognized CSS at-rule: @{}", at_rule.name); return {}; @@ -1753,6 +1757,102 @@ JS::GCPtr Parser::convert_to_supports_rule(AtRule const& rule, auto rule_list = CSSRuleList::create(m_context.realm(), child_rules); return CSSSupportsRule::create(m_context.realm(), supports.release_nonnull(), rule_list); } +JS::GCPtr Parser::convert_to_property_rule(AtRule const& rule) +{ + // https://drafts.css-houdini.org/css-properties-values-api-1/#at-ruledef-property + // @property { + // + // } + + if (rule.prelude.is_empty()) { + dbgln_if(CSS_PARSER_DEBUG, "Failed to parse @property rule: Empty prelude."); + return {}; + } + + auto prelude_stream = TokenStream { rule.prelude }; + prelude_stream.discard_whitespace(); + auto const& token = prelude_stream.consume_a_token(); + if (!token.is_token()) { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @property has invalid prelude, prelude = {}; discarding.", rule.prelude); + return {}; + } + + auto name_token = token.token(); + prelude_stream.discard_whitespace(); + + if (prelude_stream.has_next_token()) { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @property has invalid prelude, prelude = {}; discarding.", rule.prelude); + return {}; + } + + if (!name_token.is(Token::Type::Ident)) { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @property name is invalid: {}; discarding.", name_token.to_debug_string()); + return {}; + } + + if (!is_a_custom_property_name_string(name_token.ident())) { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @property name doesn't start with '--': {}; discarding.", name_token.ident()); + return {}; + } + + auto const& name = name_token.ident(); + + Optional syntax_maybe; + Optional inherits_maybe; + Optional initial_value_maybe; + + rule.for_each_as_declaration_list([&](auto& declaration) { + if (declaration.name.equals_ignoring_ascii_case("syntax"sv)) { + TokenStream token_stream { declaration.value }; + token_stream.discard_whitespace(); + + auto const& syntax_token = token_stream.consume_a_token(); + if (syntax_token.is(Token::Type::String)) { + token_stream.discard_whitespace(); + if (token_stream.has_next_token()) { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Unexpected trailing tokens in syntax"); + } else { + syntax_maybe = syntax_token.token().string(); + } + } else { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Unexpected value for @property \"syntax\": {}; discarding.", declaration.to_string()); + } + return; + } + if (declaration.name.equals_ignoring_ascii_case("inherits"sv)) { + TokenStream token_stream { declaration.value }; + token_stream.discard_whitespace(); + + auto const& inherits_token = token_stream.consume_a_token(); + if (inherits_token.is_ident("true"sv) || inherits_token.is_ident("false"sv)) { + auto const& ident = inherits_token.token().ident(); + token_stream.discard_whitespace(); + if (token_stream.has_next_token()) { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Unexpected trailing tokens in inherits"); + } else { + inherits_maybe = (ident == "true"); + } + } else { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Expected true/false for @property \"inherits\" value, got: {}; discarding.", inherits_token.to_debug_string()); + } + return; + } + if (declaration.name.equals_ignoring_ascii_case("initial-value"sv)) { + // FIXME: Ensure that the initial value matches the syntax, and parse the correct CSSValue out + StringBuilder initial_value_sb; + for (auto const& component : declaration.value) { + initial_value_sb.append(component.to_string()); + } + initial_value_maybe = MUST(initial_value_sb.to_string()); + return; + } + }); + + if (syntax_maybe.has_value() && inherits_maybe.has_value()) { + return CSSPropertyRule::create(m_context.realm(), name, syntax_maybe.value(), inherits_maybe.value(), std::move(initial_value_maybe)); + } + return {}; +} Parser::PropertiesAndCustomProperties Parser::extract_properties(Vector const& rules_and_lists_of_declarations) { diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index d5df355d5c4..32c248fb2fa 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -187,6 +187,7 @@ private: JS::GCPtr convert_to_media_rule(AtRule const&, Nested); JS::GCPtr convert_to_namespace_rule(AtRule const&); JS::GCPtr convert_to_supports_rule(AtRule const&, Nested); + JS::GCPtr convert_to_property_rule(AtRule const& rule); PropertyOwningCSSStyleDeclaration* convert_to_style_declaration(Vector const&); Optional convert_to_style_property(Declaration const&);