diff --git a/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp b/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp index f0e0957fde5..bacc40321c2 100644 --- a/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp +++ b/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp @@ -4450,9 +4450,10 @@ bool Parser::expand_unresolved_values(DOM::Element& element, FlyString const& pr // https://drafts.csswg.org/css-values-5/#attr-substitution bool Parser::substitute_attr_function(DOM::Element& element, FlyString const& property_name, Function const& attr_function, Vector& dest) { - // First, parse the arguments to attr(): - // attr() = attr( ? , ?) - // = string | url | ident | color | number | percentage | length | angle | time | frequency | flex | + // attr() = attr( ? , ?) + // = [ ? '|' ]? + // = type( ) | raw-string | + // The production matches any identifier that is an ASCII case-insensitive match for the name of a CSS dimension unit, such as px, or the %. TokenStream attr_contents { attr_function.value }; attr_contents.discard_whitespace(); if (!attr_contents.has_next_token()) @@ -4466,7 +4467,7 @@ bool Parser::substitute_attr_function(DOM::Element& element, FlyString const& pr attr_contents.discard_whitespace(); // - Attribute type (optional) - auto attribute_type = "string"_fly_string; + auto attribute_type = "raw-string"_fly_string; if (attr_contents.next_token().is(Token::Type::Ident)) { attribute_type = attr_contents.consume_a_token().token().ident(); attr_contents.discard_whitespace(); @@ -4493,117 +4494,12 @@ bool Parser::substitute_attr_function(DOM::Element& element, FlyString const& pr }; auto attribute_value = element.get_attribute_value(attribute_name); - if (attribute_type.equals_ignoring_ascii_case("angle"_fly_string)) { - // Parse a component value from the attribute’s value. - auto component_value = parse_string_as_component_value(attribute_value); - // If the result is a whose unit matches the given type, the result is the substitution value. - // Otherwise, there is no substitution value. - if (component_value.has_value() && component_value->is(Token::Type::Dimension)) { - if (Angle::unit_from_name(component_value->token().dimension_unit()).has_value()) { - dest.append(component_value.release_value()); - return true; - } - } - } else if (attribute_type.equals_ignoring_ascii_case("color"_fly_string)) { - // Parse a component value from the attribute’s value. - // If the result is a or a named color ident, the substitution value is that result as a . - // Otherwise there is no substitution value. - auto component_value = parse_string_as_component_value(attribute_value); - if (component_value.has_value()) { - if ((component_value->is(Token::Type::Hash) - && Color::from_string(MUST(String::formatted("#{}", component_value->token().hash_value()))).has_value()) - || (component_value->is(Token::Type::Ident) - && Color::from_string(component_value->token().ident()).has_value())) { - dest.append(component_value.release_value()); - return true; - } - } - } else if (attribute_type.equals_ignoring_ascii_case("flex"_fly_string)) { - // Parse a component value from the attribute’s value. - auto component_value = parse_string_as_component_value(attribute_value); - // If the result is a whose unit matches the given type, the result is the substitution value. - // Otherwise, there is no substitution value. - if (component_value.has_value() && component_value->is(Token::Type::Dimension)) { - if (Flex::unit_from_name(component_value->token().dimension_unit()).has_value()) { - dest.append(component_value.release_value()); - return true; - } - } - } else if (attribute_type.equals_ignoring_ascii_case("frequency"_fly_string)) { - // Parse a component value from the attribute’s value. - auto component_value = parse_string_as_component_value(attribute_value); - // If the result is a whose unit matches the given type, the result is the substitution value. - // Otherwise, there is no substitution value. - if (component_value.has_value() && component_value->is(Token::Type::Dimension)) { - if (Frequency::unit_from_name(component_value->token().dimension_unit()).has_value()) { - dest.append(component_value.release_value()); - return true; - } - } - } else if (attribute_type.equals_ignoring_ascii_case("ident"_fly_string)) { - // The substitution value is a CSS , whose value is the literal value of the attribute, - // with leading and trailing ASCII whitespace stripped. (No CSS parsing of the value is performed.) - // If the attribute value, after trimming, is the empty string, there is instead no substitution value. - // If the ’s value is a CSS-wide keyword or `default`, there is instead no substitution value. - auto substitution_value = MUST(attribute_value.trim(Infra::ASCII_WHITESPACE)); - if (!substitution_value.is_empty() - && !substitution_value.equals_ignoring_ascii_case("default"sv) - && !is_css_wide_keyword(substitution_value)) { - dest.empend(Token::create_ident(substitution_value)); - return true; - } - } else if (attribute_type.equals_ignoring_ascii_case("length"_fly_string)) { - // Parse a component value from the attribute’s value. - auto component_value = parse_string_as_component_value(attribute_value); - // If the result is a whose unit matches the given type, the result is the substitution value. - // Otherwise, there is no substitution value. - if (component_value.has_value() && component_value->is(Token::Type::Dimension)) { - if (Length::unit_from_name(component_value->token().dimension_unit()).has_value()) { - dest.append(component_value.release_value()); - return true; - } - } - } else if (attribute_type.equals_ignoring_ascii_case("number"_fly_string)) { - // Parse a component value from the attribute’s value. - // If the result is a , the result is the substitution value. - // Otherwise, there is no substitution value. - auto component_value = parse_string_as_component_value(attribute_value); - if (component_value.has_value() && component_value->is(Token::Type::Number)) { - dest.append(component_value.release_value()); - return true; - } - } else if (attribute_type.equals_ignoring_ascii_case("percentage"_fly_string)) { - // Parse a component value from the attribute’s value. - auto component_value = parse_string_as_component_value(attribute_value); - // If the result is a , the result is the substitution value. - // Otherwise, there is no substitution value. - if (component_value.has_value() && component_value->is(Token::Type::Percentage)) { - dest.append(component_value.release_value()); - return true; - } - } else if (attribute_type.equals_ignoring_ascii_case("string"_fly_string)) { + if (attribute_type.equals_ignoring_ascii_case("raw-string"_fly_string)) { // The substitution value is a CSS string, whose value is the literal value of the attribute. // (No CSS parsing or "cleanup" of the value is performed.) // No value triggers fallback. dest.empend(Token::create_string(attribute_value)); return true; - } else if (attribute_type.equals_ignoring_ascii_case("time"_fly_string)) { - // Parse a component value from the attribute’s value. - auto component_value = parse_string_as_component_value(attribute_value); - // If the result is a whose unit matches the given type, the result is the substitution value. - // Otherwise, there is no substitution value. - if (component_value.has_value() && component_value->is(Token::Type::Dimension)) { - if (Time::unit_from_name(component_value->token().dimension_unit()).has_value()) { - dest.append(component_value.release_value()); - return true; - } - } - } else if (attribute_type.equals_ignoring_ascii_case("url"_fly_string)) { - // The substitution value is a CSS value, whose url is the literal value of the attribute. - // (No CSS parsing or "cleanup" of the value is performed.) - // No value triggers fallback. - dest.empend(Token::create_url(attribute_value)); - return true; } else { // Dimension units // Parse a component value from the attribute’s value. @@ -4642,7 +4538,7 @@ bool Parser::substitute_attr_function(DOM::Element& element, FlyString const& pr if (has_fallback_values) return expand_unresolved_values(element, property_name, attr_contents, dest); - if (attribute_type.equals_ignoring_ascii_case("string"_fly_string)) { + if (attribute_type.equals_ignoring_ascii_case("raw-string"_fly_string)) { // If the argument is string, defaults to the empty string if omitted dest.empend(Token::create_string({})); return true; diff --git a/Tests/LibWeb/Layout/input/css-attr-typed-fallback.html b/Tests/LibWeb/Layout/input/css-attr-typed-fallback.html index 0fb21c60356..882655c74a1 100644 --- a/Tests/LibWeb/Layout/input/css-attr-typed-fallback.html +++ b/Tests/LibWeb/Layout/input/css-attr-typed-fallback.html @@ -6,10 +6,10 @@ border: 1px solid black; } .string::before { - content: attr(foo string, "WHF!"); + content: attr(foo raw-string, "WHF!"); } .string-no-fallback::before { - content: attr(foo string); + content: attr(foo raw-string); } .px { width: attr(foo px, 200px); diff --git a/Tests/LibWeb/Ref/expected/css-attr-typed-ref.html b/Tests/LibWeb/Ref/expected/css-attr-typed-ref.html index 9e014c47911..a97a30dae7a 100644 --- a/Tests/LibWeb/Ref/expected/css-attr-typed-ref.html +++ b/Tests/LibWeb/Ref/expected/css-attr-typed-ref.html @@ -5,19 +5,10 @@ height: 20px; border: 1px solid black; } - .length { - width: 200px; - } .px { width: 200px; } - .color { - background-color: #00ff00; - }
WHF!
-
-
-
diff --git a/Tests/LibWeb/Ref/input/css-attr-typed-fallback.html b/Tests/LibWeb/Ref/input/css-attr-typed-fallback.html index d1870596912..7df134e9070 100644 --- a/Tests/LibWeb/Ref/input/css-attr-typed-fallback.html +++ b/Tests/LibWeb/Ref/input/css-attr-typed-fallback.html @@ -7,24 +7,15 @@ border: 1px solid black; } .string::before { - content: attr(foo string, "WHF!"); + content: attr(foo raw-string, "WHF!"); } .string-no-fallback::before { - content: attr(foo string); - } - .length { - width: attr(foo length, 200px); + content: attr(foo raw-string); } .px { width: attr(foo px, 200px); } - .color { - background-color: attr(foo color, lime); - }
-
-
-
diff --git a/Tests/LibWeb/Ref/input/css-attr-typed.html b/Tests/LibWeb/Ref/input/css-attr-typed.html index dd92ef810a3..00be2ddda8b 100644 --- a/Tests/LibWeb/Ref/input/css-attr-typed.html +++ b/Tests/LibWeb/Ref/input/css-attr-typed.html @@ -7,21 +7,12 @@ border: 1px solid black; } .string::before { - content: attr(foo string); - } - .length { - width: attr(foo length); + content: attr(foo raw-string); } .px { width: attr(foo px); } - .color { - background-color: attr(foo color); - }
-
-
-
diff --git a/Tests/LibWeb/Text/expected/css/attr-serialization.txt b/Tests/LibWeb/Text/expected/css/attr-serialization.txt index f40cf89058a..27bbea503ca 100644 --- a/Tests/LibWeb/Text/expected/css/attr-serialization.txt +++ b/Tests/LibWeb/Text/expected/css/attr-serialization.txt @@ -2,8 +2,8 @@ attr(foo) attr( foo ) attr(foo, "fallback") attr( foo , "fallback" ) -attr(foo string) -attr( foo string ) -attr(foo string, "fallback") -attr( foo string , "fallback" ) +attr(foo raw-string) +attr( foo raw-string ) +attr(foo raw-string, "fallback") +attr( foo raw-string , "fallback" ) attr(foo) attr(bar) attr(baz) diff --git a/Tests/LibWeb/Text/input/css/attr-serialization.html b/Tests/LibWeb/Text/input/css/attr-serialization.html index 33343d70d56..4b34e26db9f 100644 --- a/Tests/LibWeb/Text/input/css/attr-serialization.html +++ b/Tests/LibWeb/Text/input/css/attr-serialization.html @@ -13,12 +13,12 @@ serialize('attr(foo, "fallback")'); // FIXME: This should produce `attr(foo, "fallback")` but doesn't yet. serialize('attr( foo , "fallback" )'); - serialize('attr(foo string)'); - // FIXME: This should produce `attr(foo string)` but doesn't yet. - serialize('attr( foo string )'); - serialize('attr(foo string, "fallback")'); - // FIXME: This should produce `attr(foo string, "fallback")` but doesn't yet. - serialize('attr( foo string , "fallback" )'); + serialize('attr(foo raw-string)'); + // FIXME: This should produce `attr(foo raw-string)` but doesn't yet. + serialize('attr( foo raw-string )'); + serialize('attr(foo raw-string, "fallback")'); + // FIXME: This should produce `attr(foo raw-string, "fallback")` but doesn't yet. + serialize('attr( foo raw-string , "fallback" )'); serialize(' attr(foo) attr(bar) attr(baz) '); });