LibWeb/CSS: Reject trailing unparseable tokens in property values

Without this, we'd happily parse `font-variant-caps: small-caps potato`
as just `small-caps` and ignore the fact that unused tokens were left
over.

This fix gets us some WPT subtest passes, and removes the need for a
bespoke parsing function for font-variant-caps.
This commit is contained in:
Sam Atkins 2025-02-06 15:05:31 +00:00
commit cda3fe7a4b
Notes: github-actions[bot] 2025-02-12 16:02:07 +00:00
11 changed files with 28 additions and 62 deletions

View file

@ -376,7 +376,6 @@ private:
RefPtr<CSSStyleValue> parse_font_variation_settings_value(TokenStream<ComponentValue>&); RefPtr<CSSStyleValue> parse_font_variation_settings_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_variant(TokenStream<ComponentValue>&); RefPtr<CSSStyleValue> parse_font_variant(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_variant_alternates_value(TokenStream<ComponentValue>&); RefPtr<CSSStyleValue> parse_font_variant_alternates_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_variant_caps_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_variant_east_asian_value(TokenStream<ComponentValue>&); RefPtr<CSSStyleValue> parse_font_variant_east_asian_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_variant_emoji(TokenStream<ComponentValue>&); RefPtr<CSSStyleValue> parse_font_variant_emoji(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_variant_ligatures_value(TokenStream<ComponentValue>&); RefPtr<CSSStyleValue> parse_font_variant_ligatures_value(TokenStream<ComponentValue>&);

View file

@ -569,10 +569,6 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue>> Parser::parse_css_value(Prope
if (auto parsed_value = parse_font_variant_alternates_value(tokens); parsed_value && !tokens.has_next_token()) if (auto parsed_value = parse_font_variant_alternates_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull(); return parsed_value.release_nonnull();
return ParseError::SyntaxError; return ParseError::SyntaxError;
case PropertyID::FontVariantCaps:
if (auto parsed_value = parse_font_variant_caps_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::FontVariantEastAsian: case PropertyID::FontVariantEastAsian:
if (auto parsed_value = parse_font_variant_east_asian_value(tokens); parsed_value && !tokens.has_next_token()) if (auto parsed_value = parse_font_variant_east_asian_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull(); return parsed_value.release_nonnull();
@ -735,12 +731,14 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue>> Parser::parse_css_value(Prope
break; break;
} }
// Some types (such as <ratio>) can be made from multiple ComponentValues, so if we only made 1 CSSStyleValue, return it directly. if (!stream.has_next_token()) {
if (parsed_values.size() == 1) // Some types (such as <ratio>) can be made from multiple ComponentValues, so if we only made 1 CSSStyleValue, return it directly.
return *parsed_values.take_first(); if (parsed_values.size() == 1)
return *parsed_values.take_first();
if (!parsed_values.is_empty() && parsed_values.size() <= property_maximum_value_count(property_id)) if (!parsed_values.is_empty() && parsed_values.size() <= property_maximum_value_count(property_id))
return StyleValueList::create(move(parsed_values), StyleValueList::Separator::Space); return StyleValueList::create(move(parsed_values), StyleValueList::Separator::Space);
}
} }
// We have multiple values, but the property claims to accept only a single one, check if it's a shorthand property. // We have multiple values, but the property claims to accept only a single one, check if it's a shorthand property.
@ -2869,30 +2867,6 @@ RefPtr<CSSStyleValue> Parser::parse_font_variant_alternates_value(TokenStream<Co
return nullptr; return nullptr;
} }
// FIXME: This should not be needed, however http://wpt.live/css/css-fonts/font-variant-caps.html fails without it
RefPtr<CSSStyleValue> Parser::parse_font_variant_caps_value(TokenStream<ComponentValue>& tokens)
{
// https://drafts.csswg.org/css-fonts/#propdef-font-variant-caps
// normal | small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps
bool has_token = false;
while (tokens.has_next_token()) {
if (has_token)
break;
auto maybe_value = parse_keyword_value(tokens);
if (!maybe_value)
break;
auto value = maybe_value.release_nonnull();
auto font_variant = keyword_to_font_variant_caps(value->to_keyword());
if (font_variant.has_value()) {
return value;
}
break;
}
return nullptr;
}
RefPtr<CSSStyleValue> Parser::parse_font_variant_east_asian_value(TokenStream<ComponentValue>& tokens) RefPtr<CSSStyleValue> Parser::parse_font_variant_east_asian_value(TokenStream<ComponentValue>& tokens)
{ {
// 6.10 https://drafts.csswg.org/css-fonts/#propdef-font-variant-east-asian // 6.10 https://drafts.csswg.org/css-fonts/#propdef-font-variant-east-asian

View file

@ -2,8 +2,8 @@ Harness status: OK
Found 26 tests Found 26 tests
23 Pass 24 Pass
3 Fail 2 Fail
Pass Default gap is 'normal' Pass Default gap is 'normal'
Pass gap accepts pixels Pass gap accepts pixels
Pass gap accepts pixels 2 Pass gap accepts pixels 2
@ -28,5 +28,5 @@ Pass Angle gap is invalid
Pass Resolution gap is invalid Pass Resolution gap is invalid
Pass Time gap is invalid Pass Time gap is invalid
Pass gap with three values is invalid Pass gap with three values is invalid
Fail gap with slash is invalid Pass gap with slash is invalid
Fail gap with one wrong value is invalid Fail gap with one wrong value is invalid

View file

@ -2,8 +2,8 @@ Harness status: OK
Found 26 tests Found 26 tests
23 Pass 24 Pass
3 Fail 2 Fail
Pass Default grid-gap is 'normal' Pass Default grid-gap is 'normal'
Pass grid-gap accepts pixels Pass grid-gap accepts pixels
Pass grid-gap accepts pixels 2 Pass grid-gap accepts pixels 2
@ -28,5 +28,5 @@ Pass Angle grid-gap is invalid
Pass Resolution grid-gap is invalid Pass Resolution grid-gap is invalid
Pass Time grid-gap is invalid Pass Time grid-gap is invalid
Pass grid-gap with three values is invalid Pass grid-gap with three values is invalid
Fail grid-gap with slash is invalid Pass grid-gap with slash is invalid
Fail grid-gap with one wrong value is invalid Fail grid-gap with one wrong value is invalid

View file

@ -2,9 +2,8 @@ Harness status: OK
Found 4 tests Found 4 tests
3 Pass 4 Pass
1 Fail
Pass e.style['flex-grow'] = "2e3.4" should not set the property value Pass e.style['flex-grow'] = "2e3.4" should not set the property value
Pass e.style['flex-grow'] = "-+5" should not set the property value Pass e.style['flex-grow'] = "-+5" should not set the property value
Pass e.style['flex-grow'] = "6 7" should not set the property value Pass e.style['flex-grow'] = "6 7" should not set the property value
Fail e.style['flex-grow'] = "1." should not set the property value Pass e.style['flex-grow'] = "1." should not set the property value

View file

@ -2,9 +2,8 @@ Harness status: OK
Found 4 tests Found 4 tests
3 Pass 4 Pass
1 Fail
Pass e.style['flex-shrink'] = "2e3.4" should not set the property value Pass e.style['flex-shrink'] = "2e3.4" should not set the property value
Pass e.style['flex-shrink'] = "-+5" should not set the property value Pass e.style['flex-shrink'] = "-+5" should not set the property value
Pass e.style['flex-shrink'] = "6 7" should not set the property value Pass e.style['flex-shrink'] = "6 7" should not set the property value
Fail e.style['flex-shrink'] = "1." should not set the property value Pass e.style['flex-shrink'] = "1." should not set the property value

View file

@ -2,9 +2,8 @@ Harness status: OK
Found 4 tests Found 4 tests
3 Pass 4 Pass
1 Fail
Pass e.style['font-stretch'] = "auto" should not set the property value Pass e.style['font-stretch'] = "auto" should not set the property value
Fail e.style['font-stretch'] = "normal, ultra-condensed" should not set the property value Pass e.style['font-stretch'] = "normal, ultra-condensed" should not set the property value
Pass e.style['font-stretch'] = "condensed expanded" should not set the property value Pass e.style['font-stretch'] = "condensed expanded" should not set the property value
Pass e.style['font-stretch'] = "-50%" should not set the property value Pass e.style['font-stretch'] = "-50%" should not set the property value

View file

@ -2,12 +2,11 @@ Harness status: OK
Found 7 tests Found 7 tests
5 Pass 7 Pass
2 Fail
Pass e.style['font-variant-emoji'] = "auto" should not set the property value Pass e.style['font-variant-emoji'] = "auto" should not set the property value
Pass e.style['font-variant-emoji'] = "none" should not set the property value Pass e.style['font-variant-emoji'] = "none" should not set the property value
Pass e.style['font-variant-emoji'] = "color" should not set the property value Pass e.style['font-variant-emoji'] = "color" should not set the property value
Pass e.style['font-variant-emoji'] = "normal text" should not set the property value Pass e.style['font-variant-emoji'] = "normal text" should not set the property value
Pass e.style['font-variant-emoji'] = "text emoji" should not set the property value Pass e.style['font-variant-emoji'] = "text emoji" should not set the property value
Fail e.style['font-variant-emoji'] = "normal, unicode" should not set the property value Pass e.style['font-variant-emoji'] = "normal, unicode" should not set the property value
Fail e.style['font-variant-emoji'] = "unicode, emoji" should not set the property value Pass e.style['font-variant-emoji'] = "unicode, emoji" should not set the property value

View file

@ -2,12 +2,11 @@ Harness status: OK
Found 7 tests Found 7 tests
6 Pass 7 Pass
1 Fail
Pass e.style['box-sizing'] = "margin-box" should not set the property value Pass e.style['box-sizing'] = "margin-box" should not set the property value
Pass e.style['box-sizing'] = "padding-box" should not set the property value Pass e.style['box-sizing'] = "padding-box" should not set the property value
Pass e.style['box-sizing'] = "fill-box" should not set the property value Pass e.style['box-sizing'] = "fill-box" should not set the property value
Pass e.style['box-sizing'] = "stroke-box" should not set the property value Pass e.style['box-sizing'] = "stroke-box" should not set the property value
Pass e.style['box-sizing'] = "view-box" should not set the property value Pass e.style['box-sizing'] = "view-box" should not set the property value
Pass e.style['box-sizing'] = "content-box border-box" should not set the property value Pass e.style['box-sizing'] = "content-box border-box" should not set the property value
Fail e.style['box-sizing'] = "content-box, border-box" should not set the property value Pass e.style['box-sizing'] = "content-box, border-box" should not set the property value

View file

@ -2,8 +2,7 @@ Harness status: OK
Found 11 tests Found 11 tests
10 Pass 11 Pass
1 Fail
Pass e.style['min-height'] = "none" should not set the property value Pass e.style['min-height'] = "none" should not set the property value
Pass e.style['min-height'] = "complex" should not set the property value Pass e.style['min-height'] = "complex" should not set the property value
Pass e.style['min-height'] = "-10%" should not set the property value Pass e.style['min-height'] = "-10%" should not set the property value
@ -13,5 +12,5 @@ Pass e.style['min-height'] = "10px 20%" should not set the property value
Pass e.style['min-height'] = "max-content 10px" should not set the property value Pass e.style['min-height'] = "max-content 10px" should not set the property value
Pass e.style['min-height'] = "min-content max-content" should not set the property value Pass e.style['min-height'] = "min-content max-content" should not set the property value
Pass e.style['min-height'] = "available" should not set the property value Pass e.style['min-height'] = "available" should not set the property value
Fail e.style['min-height'] = "10px border-box" should not set the property value Pass e.style['min-height'] = "10px border-box" should not set the property value
Pass e.style['min-height'] = "content-box 20%" should not set the property value Pass e.style['min-height'] = "content-box 20%" should not set the property value

View file

@ -2,8 +2,7 @@ Harness status: OK
Found 11 tests Found 11 tests
10 Pass 11 Pass
1 Fail
Pass e.style['min-width'] = "none" should not set the property value Pass e.style['min-width'] = "none" should not set the property value
Pass e.style['min-width'] = "complex" should not set the property value Pass e.style['min-width'] = "complex" should not set the property value
Pass e.style['min-width'] = "-10%" should not set the property value Pass e.style['min-width'] = "-10%" should not set the property value
@ -13,5 +12,5 @@ Pass e.style['min-width'] = "10px 20%" should not set the property value
Pass e.style['min-width'] = "max-content 10px" should not set the property value Pass e.style['min-width'] = "max-content 10px" should not set the property value
Pass e.style['min-width'] = "min-content max-content" should not set the property value Pass e.style['min-width'] = "min-content max-content" should not set the property value
Pass e.style['min-width'] = "available" should not set the property value Pass e.style['min-width'] = "available" should not set the property value
Fail e.style['min-width'] = "10px border-box" should not set the property value Pass e.style['min-width'] = "10px border-box" should not set the property value
Pass e.style['min-width'] = "content-box 20%" should not set the property value Pass e.style['min-width'] = "content-box 20%" should not set the property value