From d9a8349d8c96a6f991e0a8bd94eba9a9b20f7fec Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 23 May 2025 14:54:58 +0100 Subject: [PATCH] LibWeb/CSS: Parse font-variant and font-weight parts of font properly These are not the same as parsing their properties, but are limited to a small set of keywords each. The easiest way to handle these is parsing them directly here. Update some comments while I'm here. --- .../LibWeb/CSS/Parser/PropertyParsing.cpp | 64 +++++++++++++------ 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp index 062c17fd66a..c0d94107193 100644 --- a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp +++ b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp @@ -2310,35 +2310,73 @@ RefPtr Parser::parse_flex_flow_value(TokenStream Parser::parse_font_value(TokenStream& tokens) { - RefPtr font_width; + // [ [ <'font-style'> || || <'font-weight'> || ]? <'font-size'> [ / <'line-height'> ]? <'font-family'># ] | RefPtr font_style; + RefPtr font_variant; RefPtr font_weight; + RefPtr font_width; RefPtr font_size; RefPtr line_height; RefPtr font_families; - RefPtr font_variant; - // FIXME: Handle system fonts. (caption, icon, menu, message-box, small-caption, status-bar) + // FIXME: Handle . (caption, icon, menu, message-box, small-caption, status-bar) // Several sub-properties can be "normal", and appear in any order: style, variant, weight, stretch // So, we have to handle that separately. int normal_count = 0; - // FIXME: `font-variant` allows a lot of different values which aren't allowed in the `font` shorthand. - // FIXME: `font-width` allows values, which aren't allowed in the `font` shorthand. - auto remaining_longhands = Vector { PropertyID::FontSize, PropertyID::FontStyle, PropertyID::FontVariant, PropertyID::FontWeight, PropertyID::FontWidth }; + // font-variant and font-width aren't included because we have special parsing rules for them in font. + auto remaining_longhands = Vector { PropertyID::FontSize, PropertyID::FontStyle, PropertyID::FontWeight }; auto transaction = tokens.begin_transaction(); while (tokens.has_next_token()) { - auto& peek_token = tokens.next_token(); - if (peek_token.is_ident("normal"sv)) { + if (tokens.next_token().is_ident("normal"sv)) { normal_count++; tokens.discard_a_token(); continue; } + // = normal | small-caps + // So, we handle that manually instead of trying to parse the font-variant property. + if (!font_variant && tokens.peek_token().is_ident("small-caps"sv)) { + tokens.discard_a_token(); // small-caps + + font_variant = ShorthandStyleValue::create(PropertyID::FontVariant, + { PropertyID::FontVariantAlternates, + PropertyID::FontVariantCaps, + PropertyID::FontVariantEastAsian, + PropertyID::FontVariantEmoji, + PropertyID::FontVariantLigatures, + PropertyID::FontVariantNumeric, + PropertyID::FontVariantPosition }, + { + property_initial_value(PropertyID::FontVariantAlternates), + CSSKeywordValue::create(Keyword::SmallCaps), + property_initial_value(PropertyID::FontVariantEastAsian), + property_initial_value(PropertyID::FontVariantEmoji), + property_initial_value(PropertyID::FontVariantLigatures), + property_initial_value(PropertyID::FontVariantNumeric), + property_initial_value(PropertyID::FontVariantPosition), + }); + continue; + } + + // = normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded + // So again, we do this manually. + if (!font_width && tokens.peek_token().is(Token::Type::Ident)) { + auto font_width_transaction = tokens.begin_transaction(); + if (auto keyword = parse_keyword_value(tokens)) { + if (keyword_to_font_width(keyword->to_keyword()).has_value()) { + font_width_transaction.commit(); + font_width = keyword.release_nonnull(); + continue; + } + } + } + auto property_and_value = parse_css_value_for_properties(remaining_longhands, tokens); if (!property_and_value.has_value()) return nullptr; @@ -2367,21 +2405,11 @@ RefPtr Parser::parse_font_value(TokenStream font_families = maybe_font_families.release_nonnull(); continue; } - case PropertyID::FontWidth: { - VERIFY(!font_width); - font_width = value.release_nonnull(); - continue; - } case PropertyID::FontStyle: { VERIFY(!font_style); font_style = FontStyleStyleValue::create(*keyword_to_font_style(value.release_nonnull()->to_keyword())); continue; } - case PropertyID::FontVariant: { - VERIFY(!font_variant); - font_variant = value.release_nonnull(); - continue; - } case PropertyID::FontWeight: { VERIFY(!font_weight); font_weight = value.release_nonnull();