diff --git a/Userland/Libraries/LibWeb/CSS/FontFace.cpp b/Userland/Libraries/LibWeb/CSS/FontFace.cpp index 5c8520c680c..50d759447d0 100644 --- a/Userland/Libraries/LibWeb/CSS/FontFace.cpp +++ b/Userland/Libraries/LibWeb/CSS/FontFace.cpp @@ -402,6 +402,8 @@ void FontFace::load_font_source() FontDisplay::Auto, // FIXME: font_display {}, // font-named-instance doesn't exist in FontFace {}, // font-language-override doesn't exist in FontFace + {}, // FIXME: feature_settings + {}, // FIXME: variation_settings }; 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(); diff --git a/Userland/Libraries/LibWeb/CSS/ParsedFontFace.cpp b/Userland/Libraries/LibWeb/CSS/ParsedFontFace.cpp index 893695bf6ce..f2db1dfc33a 100644 --- a/Userland/Libraries/LibWeb/CSS/ParsedFontFace.cpp +++ b/Userland/Libraries/LibWeb/CSS/ParsedFontFace.cpp @@ -9,7 +9,7 @@ namespace Web::CSS { -ParsedFontFace::ParsedFontFace(FlyString font_family, Optional weight, Optional slope, Optional width, Vector sources, Vector unicode_ranges, Optional ascent_override, Optional descent_override, Optional line_gap_override, FontDisplay font_display, Optional font_named_instance, Optional font_language_override) +ParsedFontFace::ParsedFontFace(FlyString font_family, Optional weight, Optional slope, Optional width, Vector sources, Vector unicode_ranges, Optional ascent_override, Optional descent_override, Optional line_gap_override, FontDisplay font_display, Optional font_named_instance, Optional font_language_override, Optional> font_feature_settings, Optional> font_variation_settings) : m_font_family(move(font_family)) , m_font_named_instance(move(font_named_instance)) , m_weight(weight) @@ -22,6 +22,8 @@ ParsedFontFace::ParsedFontFace(FlyString font_family, Optional weight, Opti , m_line_gap_override(move(line_gap_override)) , m_font_display(font_display) , m_font_language_override(font_language_override) + , m_font_feature_settings(move(font_feature_settings)) + , m_font_variation_settings(move(font_variation_settings)) { } diff --git a/Userland/Libraries/LibWeb/CSS/ParsedFontFace.h b/Userland/Libraries/LibWeb/CSS/ParsedFontFace.h index 796f2985e77..21f2e8b599b 100644 --- a/Userland/Libraries/LibWeb/CSS/ParsedFontFace.h +++ b/Userland/Libraries/LibWeb/CSS/ParsedFontFace.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include #include @@ -23,15 +24,17 @@ public: Optional format; }; - ParsedFontFace(FlyString font_family, Optional weight, Optional slope, Optional width, Vector sources, Vector unicode_ranges, Optional ascent_override, Optional descent_override, Optional line_gap_override, FontDisplay font_display, Optional font_named_instance, Optional font_language_override); + ParsedFontFace(FlyString font_family, Optional weight, Optional slope, Optional width, Vector sources, Vector unicode_ranges, Optional ascent_override, Optional descent_override, Optional line_gap_override, FontDisplay font_display, Optional font_named_instance, Optional font_language_override, Optional> font_feature_settings, Optional> font_variation_settings); ~ParsedFontFace() = default; Optional ascent_override() const { return m_ascent_override; } Optional descent_override() const { return m_descent_override; } FontDisplay font_display() const { return m_font_display; } FlyString font_family() const { return m_font_family; } + Optional> font_feature_settings() const { return m_font_feature_settings; } Optional font_language_override() const { return m_font_language_override; } Optional font_named_instance() const { return m_font_named_instance; } + Optional> font_variation_settings() const { return m_font_variation_settings; } Optional slope() const { return m_slope; } Optional weight() const { return m_weight; } Optional width() const { return m_width; } @@ -52,6 +55,8 @@ private: Optional m_line_gap_override; FontDisplay m_font_display; Optional m_font_language_override; + Optional> m_font_feature_settings; + Optional> m_font_variation_settings; }; } diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index 72cc0f1ab06..2b593f6b9ef 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -5615,6 +5615,8 @@ JS::GCPtr Parser::parse_font_face_rule(TokenStream line_gap_override; FontDisplay font_display = FontDisplay::Auto; Optional language_override; + Optional> font_feature_settings; + Optional> font_variation_settings; // "normal" is returned as nullptr auto parse_as_percentage_or_normal = [&](Vector const& values) -> ErrorOr> { @@ -5734,6 +5736,40 @@ JS::GCPtr Parser::parse_font_face_rule(TokenStreamto_keyword() == Keyword::Normal) { + font_feature_settings.clear(); + } else if (value.value()->is_value_list()) { + auto const& feature_tags = value.value()->as_value_list().values(); + OrderedHashMap settings; + settings.ensure_capacity(feature_tags.size()); + for (auto const& feature_tag : feature_tags) { + if (!feature_tag->is_open_type_tagged()) { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Value in font-feature-settings descriptor is not an OpenTypeTaggedStyleValue; skipping"); + continue; + } + auto const& setting_value = feature_tag->as_open_type_tagged().value(); + if (setting_value->is_integer()) { + settings.set(feature_tag->as_open_type_tagged().tag(), setting_value->as_integer().integer()); + } else if (setting_value->is_math() && setting_value->as_math().resolves_to_number()) { + if (auto integer = setting_value->as_math().resolve_integer(); integer.has_value()) { + settings.set(feature_tag->as_open_type_tagged().tag(), *integer); + } else { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Calculated value in font-feature-settings descriptor cannot be resolved at parse time; skipping"); + } + } else { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Value in font-feature-settings descriptor is not an OpenTypeTaggedStyleValue holding a ; skipping"); + } + } + font_feature_settings = move(settings); + } else { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Failed to parse font-feature-settings descriptor, not compatible with value returned from parsing font-feature-settings property: {}", value.value()->to_string()); + } + } + continue; + } if (declaration.name().equals_ignoring_ascii_case("font-language-override"sv)) { TokenStream token_stream { declaration.values() }; if (auto maybe_value = parse_css_value(CSS::PropertyID::FontLanguageOverride, token_stream); !maybe_value.is_error()) { @@ -5774,6 +5810,40 @@ JS::GCPtr Parser::parse_font_face_rule(TokenStreamto_keyword() == Keyword::Normal) { + font_variation_settings.clear(); + } else if (value.value()->is_value_list()) { + auto const& variation_tags = value.value()->as_value_list().values(); + OrderedHashMap settings; + settings.ensure_capacity(variation_tags.size()); + for (auto const& variation_tag : variation_tags) { + if (!variation_tag->is_open_type_tagged()) { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Value in font-variation-settings descriptor is not an OpenTypeTaggedStyleValue; skipping"); + continue; + } + auto const& setting_value = variation_tag->as_open_type_tagged().value(); + if (setting_value->is_number()) { + settings.set(variation_tag->as_open_type_tagged().tag(), setting_value->as_number().number()); + } else if (setting_value->is_math() && setting_value->as_math().resolves_to_number()) { + if (auto number = setting_value->as_math().resolve_number(); number.has_value()) { + settings.set(variation_tag->as_open_type_tagged().tag(), *number); + } else { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Calculated value in font-variation-settings descriptor cannot be resolved at parse time; skipping"); + } + } else { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Value in font-variation-settings descriptor is not an OpenTypeTaggedStyleValue holding a ; skipping"); + } + } + font_variation_settings = move(settings); + } else { + dbgln_if(CSS_PARSER_DEBUG, "CSSParser: Failed to parse font-variation-settings descriptor, not compatible with value returned from parsing font-variation-settings property: {}", value.value()->to_string()); + } + } + 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()) { @@ -5827,7 +5897,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 3fdcce7d62b..a1b453394ca 100644 --- a/Userland/Libraries/LibWeb/Dump.cpp +++ b/Userland/Libraries/LibWeb/Dump.cpp @@ -709,6 +709,26 @@ void dump_font_face_rule(StringBuilder& builder, CSS::CSSFontFaceRule const& rul indent(builder, indent_levels + 1); builder.appendff("language-override: {}\n", font_face.font_language_override().value()); } + + if (font_face.font_feature_settings().has_value()) { + indent(builder, indent_levels + 1); + builder.append("feature-settings:"sv); + auto const& entries = font_face.font_feature_settings().value(); + for (auto const& [name, value] : entries) { + builder.appendff(" {}={}", name, value); + } + builder.append("\n"sv); + } + + if (font_face.font_variation_settings().has_value()) { + indent(builder, indent_levels + 1); + builder.append("variation-settings:"sv); + auto const& entries = font_face.font_variation_settings().value(); + for (auto const& [name, value] : entries) { + builder.appendff(" {}={}", name, value); + } + builder.append("\n"sv); + } } void dump_import_rule(StringBuilder& builder, CSS::CSSImportRule const& rule, int indent_levels)