LibWeb/CSS: Parse and propagate font-variation-settings property

This commit is contained in:
Sam Atkins 2024-10-01 09:20:06 +01:00 committed by Sam Atkins
parent 1a127c9d37
commit 55812aaed2
Notes: github-actions[bot] 2024-10-02 15:37:43 +00:00
8 changed files with 102 additions and 2 deletions

View file

@ -15,6 +15,7 @@ font-language-override: normal
font-size: 16px
font-style: normal
font-variant: normal
font-variation-settings: normal
font-weight: 400
font-width: normal
image-rendering: auto
@ -118,7 +119,7 @@ grid-row-start: auto
grid-template-areas:
grid-template-columns:
grid-template-rows:
height: 2040px
height: 2057px
inline-size: auto
inset-block-end: auto
inset-block-start: auto

View file

@ -7,6 +7,7 @@
#pragma once
#include <AK/FlyString.h>
#include <AK/HashMap.h>
#include <AK/Optional.h>
#include <LibGfx/FontCascadeList.h>
#include <LibGfx/ScalingMode.h>
@ -488,6 +489,7 @@ public:
int font_weight() const { return m_inherited.font_weight; }
CSS::FontVariant font_variant() const { return m_inherited.font_variant; }
Optional<FlyString> font_language_override() const { return m_inherited.font_language_override; }
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings() const { return m_inherited.font_variation_settings; }
CSSPixels line_height() const { return m_inherited.line_height; }
CSS::Time transition_delay() const { return m_noninherited.transition_delay; }
@ -520,6 +522,7 @@ protected:
int font_weight { InitialValues::font_weight() };
CSS::FontVariant font_variant { InitialValues::font_variant() };
Optional<FlyString> font_language_override;
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings;
CSSPixels line_height { InitialValues::line_height() };
CSS::BorderCollapse border_collapse { InitialValues::border_collapse() };
CSS::Length border_spacing_horizontal { InitialValues::border_spacing() };
@ -678,6 +681,7 @@ public:
void set_font_weight(int font_weight) { m_inherited.font_weight = font_weight; }
void set_font_variant(CSS::FontVariant font_variant) { m_inherited.font_variant = font_variant; }
void set_font_language_override(Optional<FlyString> font_language_override) { m_inherited.font_language_override = font_language_override; }
void set_font_variation_settings(Optional<HashMap<FlyString, NumberOrCalculated>> value) { m_inherited.font_variation_settings = move(value); }
void set_line_height(CSSPixels line_height) { m_inherited.line_height = line_height; }
void set_border_spacing_horizontal(CSS::Length border_spacing_horizontal) { m_inherited.border_spacing_horizontal = border_spacing_horizontal; }
void set_border_spacing_vertical(CSS::Length border_spacing_vertical) { m_inherited.border_spacing_vertical = border_spacing_vertical; }

View file

@ -71,6 +71,7 @@
#include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
#include <LibWeb/CSS/StyleValues/MathDepthStyleValue.h>
#include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
#include <LibWeb/CSS/StyleValues/OpenTypeTaggedStyleValue.h>
#include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
#include <LibWeb/CSS/StyleValues/PositionStyleValue.h>
#include <LibWeb/CSS/StyleValues/RatioStyleValue.h>
@ -5479,6 +5480,52 @@ RefPtr<CSSStyleValue> Parser::parse_font_language_override_value(TokenStream<Com
return nullptr;
}
RefPtr<CSSStyleValue> Parser::parse_font_variation_settings_value(TokenStream<ComponentValue>& tokens)
{
// https://drafts.csswg.org/css-fonts/#propdef-font-variation-settings
// normal | [ <opentype-tag> <number>]#
// normal
if (auto normal = parse_all_as_single_keyword_value(tokens, Keyword::Normal))
return normal;
// [ <opentype-tag> <number>]#
auto transaction = tokens.begin_transaction();
auto tag_values = parse_a_comma_separated_list_of_component_values(tokens);
// "If the same axis name appears more than once, the value associated with the last appearance supersedes any
// previous value for that axis. This deduplication is observable by accessing the computed value of this property."
// So, we deduplicate them here using a HashSet.
OrderedHashMap<FlyString, NonnullRefPtr<OpenTypeTaggedStyleValue>> axis_tags_map;
for (auto const& values : tag_values) {
TokenStream tag_tokens { values };
tag_tokens.skip_whitespace();
auto opentype_tag = parse_opentype_tag_value(tag_tokens);
tag_tokens.skip_whitespace();
auto number = parse_number_value(tag_tokens);
tag_tokens.skip_whitespace();
if (!opentype_tag || !number || tag_tokens.has_next_token())
return nullptr;
axis_tags_map.set(opentype_tag->string_value(), OpenTypeTaggedStyleValue::create(opentype_tag->string_value(), number.release_nonnull()));
}
// "The computed value contains the de-duplicated axis names, sorted in ascending order by code unit."
StyleValueVector axis_tags;
axis_tags.ensure_capacity(axis_tags_map.size());
for (auto const& [key, axis_tag] : axis_tags_map)
axis_tags.append(axis_tag);
quick_sort(axis_tags, [](auto& a, auto& b) {
return a->as_open_type_tagged().tag() < b->as_open_type_tagged().tag();
});
transaction.commit();
return StyleValueList::create(move(axis_tags), StyleValueList::Separator::Comma);
}
JS::GCPtr<CSSFontFaceRule> Parser::parse_font_face_rule(TokenStream<ComponentValue>& tokens)
{
auto declarations_and_at_rules = parse_a_list_of_declarations(tokens);
@ -7577,6 +7624,10 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue>> Parser::parse_css_value(Prope
if (auto parsed_value = parse_font_language_override_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::FontVariationSettings:
if (auto parsed_value = parse_font_variation_settings_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::GridArea:
if (auto parsed_value = parse_grid_area_shorthand_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();

View file

@ -307,6 +307,7 @@ private:
RefPtr<CSSStyleValue> parse_font_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_family_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_language_override_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_variation_settings_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_list_style_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_math_depth_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_overflow_value(TokenStream<ComponentValue>&);

View file

@ -1223,6 +1223,18 @@
"font-variant"
]
},
"font-variation-settings": {
"animation-type": "custom",
"inherited": true,
"initial": "normal",
"valid-types": [
"number",
"opentype-tag"
],
"valid-identifiers": [
"normal"
]
},
"font-weight": {
"animation-type": "by-computed-value",
"inherited": true,

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018-2024, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2021-2024, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2021-2024, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -23,6 +23,7 @@
#include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
#include <LibWeb/CSS/StyleValues/MathDepthStyleValue.h>
#include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
#include <LibWeb/CSS/StyleValues/OpenTypeTaggedStyleValue.h>
#include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
#include <LibWeb/CSS/StyleValues/PositionStyleValue.h>
#include <LibWeb/CSS/StyleValues/RectStyleValue.h>
@ -1027,6 +1028,33 @@ Optional<FlyString> StyleProperties::font_language_override() const
return {};
}
Optional<HashMap<FlyString, NumberOrCalculated>> StyleProperties::font_variation_settings() const
{
auto value = property(CSS::PropertyID::FontVariationSettings);
if (value->is_keyword())
return {}; // normal
if (value->is_value_list()) {
auto const& axis_tags = value->as_value_list().values();
HashMap<FlyString, NumberOrCalculated> result;
result.ensure_capacity(axis_tags.size());
for (auto const& tag_value : axis_tags) {
auto const& axis_tag = tag_value->as_open_type_tagged();
if (axis_tag.value()->is_number()) {
result.set(axis_tag.tag(), axis_tag.value()->as_number().value());
} else {
VERIFY(axis_tag.value()->is_math());
result.set(axis_tag.tag(), NumberOrCalculated { axis_tag.value()->as_math() });
}
}
return result;
}
return {};
}
CSS::GridTrackSizeList StyleProperties::grid_auto_columns() const
{
auto value = property(CSS::PropertyID::GridAutoColumns);

View file

@ -149,6 +149,7 @@ public:
Variant<CSS::VerticalAlign, CSS::LengthPercentage> vertical_align() const;
Optional<CSS::FontVariant> font_variant() const;
Optional<FlyString> font_language_override() const;
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings() const;
CSS::GridTrackSizeList grid_auto_columns() const;
CSS::GridTrackSizeList grid_auto_rows() const;
CSS::GridTrackSizeList grid_template_columns() const;

View file

@ -471,6 +471,8 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
computed_values.set_font_variant(maybe_font_variant.release_value());
if (auto maybe_font_language_override = computed_style.font_language_override(); maybe_font_language_override.has_value())
computed_values.set_font_language_override(maybe_font_language_override.release_value());
if (auto maybe_font_variation_settings = computed_style.font_variation_settings(); maybe_font_variation_settings.has_value())
computed_values.set_font_variation_settings(maybe_font_variation_settings.release_value());
auto border_bottom_left_radius = computed_style.property(CSS::PropertyID::BorderBottomLeftRadius);
if (border_bottom_left_radius->is_border_radius()) {