diff --git a/Userland/Libraries/LibWeb/CSS/FontFace.cpp b/Userland/Libraries/LibWeb/CSS/FontFace.cpp index a253f310ba9..5e82efb24ef 100644 --- a/Userland/Libraries/LibWeb/CSS/FontFace.cpp +++ b/Userland/Libraries/LibWeb/CSS/FontFace.cpp @@ -388,7 +388,7 @@ void FontFace::load_font_source() auto& style_computer = const_cast(window.document()->style_computer()); // FIXME: The ParsedFontFace is kind of expensive to create. We should be using a shared sub-object for the data - ParsedFontFace parsed_font_face { font->m_family, font->m_weight.to_number(), 0 /* FIXME: slope */, font->m_urls, font->m_unicode_ranges }; + ParsedFontFace parsed_font_face { font->m_family, font->m_weight.to_number(), 0 /* FIXME: slope */, font->m_urls, font->m_unicode_ranges, /* FIXME: ascent_override */ {}, /* FIXME: descent_override */ {}, /* FIXME: line_gap_override */ {} }; if (auto loader = style_computer.load_font_face(parsed_font_face, move(on_load), move(on_error)); loader.has_value()) loader->start_loading_next_url(); } else { diff --git a/Userland/Libraries/LibWeb/CSS/ParsedFontFace.cpp b/Userland/Libraries/LibWeb/CSS/ParsedFontFace.cpp index 1a6f42bd1a3..a6146f10b97 100644 --- a/Userland/Libraries/LibWeb/CSS/ParsedFontFace.cpp +++ b/Userland/Libraries/LibWeb/CSS/ParsedFontFace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2023, Sam Atkins + * Copyright (c) 2022-2024, Sam Atkins * Copyright (c) 2023, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause @@ -9,12 +9,15 @@ namespace Web::CSS { -ParsedFontFace::ParsedFontFace(FlyString font_family, Optional weight, Optional slope, Vector sources, Vector unicode_ranges) +ParsedFontFace::ParsedFontFace(FlyString font_family, Optional weight, Optional slope, Vector sources, Vector unicode_ranges, Optional ascent_override, Optional descent_override, Optional line_gap_override) : m_font_family(move(font_family)) , m_weight(weight) , m_slope(slope) , m_sources(move(sources)) , m_unicode_ranges(move(unicode_ranges)) + , m_ascent_override(move(ascent_override)) + , m_descent_override(move(descent_override)) + , m_line_gap_override(move(line_gap_override)) { } diff --git a/Userland/Libraries/LibWeb/CSS/ParsedFontFace.h b/Userland/Libraries/LibWeb/CSS/ParsedFontFace.h index f2321ee0876..89538dddffe 100644 --- a/Userland/Libraries/LibWeb/CSS/ParsedFontFace.h +++ b/Userland/Libraries/LibWeb/CSS/ParsedFontFace.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2023, Sam Atkins + * Copyright (c) 2022-2024, Sam Atkins * Copyright (c) 2023, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause @@ -10,6 +10,7 @@ #include #include #include +#include namespace Web::CSS { @@ -21,15 +22,17 @@ public: Optional format; }; - ParsedFontFace(FlyString font_family, Optional weight, Optional slope, Vector sources, Vector unicode_ranges); + ParsedFontFace(FlyString font_family, Optional weight, Optional slope, Vector sources, Vector unicode_ranges, Optional ascent_override, Optional descent_override, Optional line_gap_override); ~ParsedFontFace() = default; + Optional ascent_override() const { return m_ascent_override; } + Optional descent_override() const { return m_descent_override; } FlyString font_family() const { return m_font_family; } - Optional weight() const { return m_weight; } Optional slope() const { return m_slope; } + Optional weight() const { return m_weight; } + Optional line_gap_override() const { return m_line_gap_override; } Vector const& sources() const { return m_sources; } Vector const& unicode_ranges() const { return m_unicode_ranges; } - // FIXME: font-stretch, font-feature-settings private: FlyString m_font_family; @@ -37,6 +40,9 @@ private: Optional m_slope { 0 }; Vector m_sources; Vector m_unicode_ranges; + Optional m_ascent_override; + Optional m_descent_override; + Optional m_line_gap_override; }; } diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index deeeae53973..f07183740fb 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -5455,6 +5455,41 @@ JS::GCPtr Parser::parse_font_face_rule(TokenStream unicode_range; Optional weight; Optional slope; + Optional ascent_override; + Optional descent_override; + Optional line_gap_override; + + // "normal" is returned as nullptr + auto parse_as_percentage_or_normal = [&](Vector const& values) -> ErrorOr> { + // normal | + TokenStream tokens { values }; + if (auto percentage_value = parse_percentage_value(tokens)) { + tokens.skip_whitespace(); + if (tokens.has_next_token()) + return Error::from_string_literal("Unexpected trailing tokens"); + + if (percentage_value->is_percentage() && percentage_value->as_percentage().percentage().value() >= 0) + return percentage_value->as_percentage().percentage(); + + // TODO: Once we implement calc-simplification in the parser, we should no longer see math values here, + // unless they're impossible to resolve and thus invalid. + if (percentage_value->is_math()) { + if (auto result = percentage_value->as_math().resolve_percentage(); result.has_value()) + return result.value(); + } + + return Error::from_string_literal("Invalid percentage"); + } + + tokens.skip_whitespace(); + if (!tokens.next_token().is_ident("normal"sv)) + return Error::from_string_literal("Expected `normal | `"); + tokens.skip_whitespace(); + if (tokens.has_next_token()) + return Error::from_string_literal("Unexpected trailing tokens"); + + return OptionalNone {}; + }; for (auto& declaration_or_at_rule : declarations_and_at_rules) { if (declaration_or_at_rule.is_at_rule()) { @@ -5463,17 +5498,21 @@ JS::GCPtr Parser::parse_font_face_rule(TokenStreamto_font_weight(); + if (declaration.name().equals_ignoring_ascii_case("ascent-override"sv)) { + auto value = parse_as_percentage_or_normal(declaration.values()); + if (value.is_error()) { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Failed to parse @font-face ascent-override: {}", value.error()); + } else { + ascent_override = value.release_value(); } continue; } - if (declaration.name().equals_ignoring_ascii_case("font-style"sv)) { - TokenStream token_stream { declaration.values() }; - if (auto value = parse_css_value(CSS::PropertyID::FontStyle, token_stream); !value.is_error()) { - slope = value.value()->to_font_slope(); + if (declaration.name().equals_ignoring_ascii_case("descent-override"sv)) { + auto value = parse_as_percentage_or_normal(declaration.values()); + if (value.is_error()) { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Failed to parse @font-face descent-override: {}", value.error()); + } else { + descent_override = value.release_value(); } continue; } @@ -5521,6 +5560,29 @@ JS::GCPtr Parser::parse_font_face_rule(TokenStreamto_font_slope(); + } + continue; + } + if (declaration.name().equals_ignoring_ascii_case("font-weight"sv)) { + TokenStream token_stream { declaration.values() }; + if (auto value = parse_css_value(CSS::PropertyID::FontWeight, token_stream); !value.is_error()) { + weight = value.value()->to_font_weight(); + } + continue; + } + if (declaration.name().equals_ignoring_ascii_case("line-gap-override"sv)) { + auto value = parse_as_percentage_or_normal(declaration.values()); + if (value.is_error()) { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Failed to parse @font-face line-gap-override: {}", value.error()); + } else { + line_gap_override = value.release_value(); + } + continue; + } if (declaration.name().equals_ignoring_ascii_case("src"sv)) { TokenStream token_stream { declaration.values() }; Vector supported_sources = parse_font_face_src(token_stream); @@ -5550,7 +5612,7 @@ JS::GCPtr Parser::parse_font_face_rule(TokenStream Parser::parse_as_font_face_src() diff --git a/Userland/Libraries/LibWeb/Dump.cpp b/Userland/Libraries/LibWeb/Dump.cpp index f4fe4a3234b..39242e23736 100644 --- a/Userland/Libraries/LibWeb/Dump.cpp +++ b/Userland/Libraries/LibWeb/Dump.cpp @@ -678,6 +678,19 @@ void dump_font_face_rule(StringBuilder& builder, CSS::CSSFontFaceRule const& rul indent(builder, indent_levels + 2); builder.appendff("{}\n", unicode_range.to_string()); } + + if (font_face.ascent_override().has_value()) { + indent(builder, indent_levels + 1); + builder.appendff("ascent-override: {}\n", font_face.ascent_override().value()); + } + if (font_face.descent_override().has_value()) { + indent(builder, indent_levels + 1); + builder.appendff("descent-override: {}\n", font_face.descent_override().value()); + } + if (font_face.line_gap_override().has_value()) { + indent(builder, indent_levels + 1); + builder.appendff("line-gap-override: {}\n", font_face.line_gap_override().value()); + } } void dump_import_rule(StringBuilder& builder, CSS::CSSImportRule const& rule, int indent_levels)