LibWeb: Parse ascent-, descent-, and line-gap-override descriptors

This commit is contained in:
Sam Atkins 2024-09-26 12:51:41 +01:00 committed by Andreas Kling
commit 2f7d18865d
Notes: github-actions[bot] 2024-09-28 12:44:05 +00:00
5 changed files with 100 additions and 16 deletions

View file

@ -388,7 +388,7 @@ void FontFace::load_font_source()
auto& style_computer = const_cast<StyleComputer&>(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<int>(), 0 /* FIXME: slope */, font->m_urls, font->m_unicode_ranges };
ParsedFontFace parsed_font_face { font->m_family, font->m_weight.to_number<int>(), 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 {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022-2023, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2022-2024, Sam Atkins <sam@ladybird.org>
* Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
@ -9,12 +9,15 @@
namespace Web::CSS {
ParsedFontFace::ParsedFontFace(FlyString font_family, Optional<int> weight, Optional<int> slope, Vector<Source> sources, Vector<Gfx::UnicodeRange> unicode_ranges)
ParsedFontFace::ParsedFontFace(FlyString font_family, Optional<int> weight, Optional<int> slope, Vector<Source> sources, Vector<Gfx::UnicodeRange> unicode_ranges, Optional<Percentage> ascent_override, Optional<Percentage> descent_override, Optional<Percentage> 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))
{
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022-2023, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2022-2024, Sam Atkins <sam@ladybird.org>
* Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
@ -10,6 +10,7 @@
#include <AK/FlyString.h>
#include <LibGfx/Font/UnicodeRange.h>
#include <LibURL/URL.h>
#include <LibWeb/CSS/Percentage.h>
namespace Web::CSS {
@ -21,15 +22,17 @@ public:
Optional<FlyString> format;
};
ParsedFontFace(FlyString font_family, Optional<int> weight, Optional<int> slope, Vector<Source> sources, Vector<Gfx::UnicodeRange> unicode_ranges);
ParsedFontFace(FlyString font_family, Optional<int> weight, Optional<int> slope, Vector<Source> sources, Vector<Gfx::UnicodeRange> unicode_ranges, Optional<Percentage> ascent_override, Optional<Percentage> descent_override, Optional<Percentage> line_gap_override);
~ParsedFontFace() = default;
Optional<Percentage> ascent_override() const { return m_ascent_override; }
Optional<Percentage> descent_override() const { return m_descent_override; }
FlyString font_family() const { return m_font_family; }
Optional<int> weight() const { return m_weight; }
Optional<int> slope() const { return m_slope; }
Optional<int> weight() const { return m_weight; }
Optional<Percentage> line_gap_override() const { return m_line_gap_override; }
Vector<Source> const& sources() const { return m_sources; }
Vector<Gfx::UnicodeRange> 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<int> m_slope { 0 };
Vector<Source> m_sources;
Vector<Gfx::UnicodeRange> m_unicode_ranges;
Optional<Percentage> m_ascent_override;
Optional<Percentage> m_descent_override;
Optional<Percentage> m_line_gap_override;
};
}

View file

@ -5455,6 +5455,41 @@ JS::GCPtr<CSSFontFaceRule> Parser::parse_font_face_rule(TokenStream<ComponentVal
Vector<Gfx::UnicodeRange> unicode_range;
Optional<int> weight;
Optional<int> slope;
Optional<Percentage> ascent_override;
Optional<Percentage> descent_override;
Optional<Percentage> line_gap_override;
// "normal" is returned as nullptr
auto parse_as_percentage_or_normal = [&](Vector<ComponentValue> const& values) -> ErrorOr<Optional<Percentage>> {
// normal | <percentage [0,∞]>
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 | <percentage [0,∞]>`");
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<CSSFontFaceRule> Parser::parse_font_face_rule(TokenStream<ComponentVal
}
auto const& declaration = declaration_or_at_rule.declaration();
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();
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<CSSFontFaceRule> Parser::parse_font_face_rule(TokenStream<ComponentVal
font_family = String::join(' ', font_family_parts).release_value_but_fixme_should_propagate_errors();
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();
}
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<ParsedFontFace::Source> supported_sources = parse_font_face_src(token_stream);
@ -5550,7 +5612,7 @@ JS::GCPtr<CSSFontFaceRule> Parser::parse_font_face_rule(TokenStream<ComponentVal
unicode_range.empend(0x0u, 0x10FFFFu);
}
return CSSFontFaceRule::create(m_context.realm(), ParsedFontFace { font_family.release_value(), weight, slope, move(src), move(unicode_range) });
return CSSFontFaceRule::create(m_context.realm(), ParsedFontFace { font_family.release_value(), weight, slope, move(src), move(unicode_range), move(ascent_override), move(descent_override), move(line_gap_override) });
}
Vector<ParsedFontFace::Source> Parser::parse_as_font_face_src()

View file

@ -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)