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
parent 412b758107
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_variant(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_emoji(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())
return parsed_value.release_nonnull();
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:
if (auto parsed_value = parse_font_variant_east_asian_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
@ -735,12 +731,14 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue>> Parser::parse_css_value(Prope
break;
}
// Some types (such as <ratio>) can be made from multiple ComponentValues, so if we only made 1 CSSStyleValue, return it directly.
if (parsed_values.size() == 1)
return *parsed_values.take_first();
if (!stream.has_next_token()) {
// Some types (such as <ratio>) can be made from multiple ComponentValues, so if we only made 1 CSSStyleValue, return it directly.
if (parsed_values.size() == 1)
return *parsed_values.take_first();
if (!parsed_values.is_empty() && parsed_values.size() <= property_maximum_value_count(property_id))
return StyleValueList::create(move(parsed_values), StyleValueList::Separator::Space);
if (!parsed_values.is_empty() && parsed_values.size() <= property_maximum_value_count(property_id))
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.
@ -2869,30 +2867,6 @@ RefPtr<CSSStyleValue> Parser::parse_font_variant_alternates_value(TokenStream<Co
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)
{
// 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
23 Pass
3 Fail
24 Pass
2 Fail
Pass Default gap is 'normal'
Pass gap accepts pixels
Pass gap accepts pixels 2
@ -28,5 +28,5 @@ Pass Angle gap is invalid
Pass Resolution gap is invalid
Pass Time gap 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

View file

@ -2,8 +2,8 @@ Harness status: OK
Found 26 tests
23 Pass
3 Fail
24 Pass
2 Fail
Pass Default grid-gap is 'normal'
Pass grid-gap accepts pixels
Pass grid-gap accepts pixels 2
@ -28,5 +28,5 @@ Pass Angle grid-gap is invalid
Pass Resolution grid-gap is invalid
Pass Time grid-gap 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

View file

@ -2,9 +2,8 @@ Harness status: OK
Found 4 tests
3 Pass
1 Fail
4 Pass
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'] = "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
3 Pass
1 Fail
4 Pass
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'] = "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
3 Pass
1 Fail
4 Pass
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'] = "-50%" should not set the property value

View file

@ -2,12 +2,11 @@ Harness status: OK
Found 7 tests
5 Pass
2 Fail
7 Pass
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'] = "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'] = "text emoji" should not set the property value
Fail 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'] = "normal, unicode" 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
6 Pass
1 Fail
7 Pass
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'] = "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'] = "view-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
10 Pass
1 Fail
11 Pass
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'] = "-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'] = "min-content max-content" 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

View file

@ -2,8 +2,7 @@ Harness status: OK
Found 11 tests
10 Pass
1 Fail
11 Pass
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'] = "-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'] = "min-content max-content" 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