mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-08 17:19:13 +00:00
LibWeb/CSS: Parse and propagate font-feature-settings property
This commit is contained in:
parent
55812aaed2
commit
95c17dfab5
Notes:
github-actions[bot]
2024-10-02 15:37:38 +00:00
Author: https://github.com/AtkinsSJ
Commit: 95c17dfab5
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1599
9 changed files with 129 additions and 1 deletions
|
@ -11,6 +11,7 @@ fill: rgb(0, 0, 0)
|
||||||
fill-opacity: 1
|
fill-opacity: 1
|
||||||
fill-rule: nonzero
|
fill-rule: nonzero
|
||||||
font-family: serif
|
font-family: serif
|
||||||
|
font-feature-settings: normal
|
||||||
font-language-override: normal
|
font-language-override: normal
|
||||||
font-size: 16px
|
font-size: 16px
|
||||||
font-style: normal
|
font-style: normal
|
||||||
|
@ -119,7 +120,7 @@ grid-row-start: auto
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
grid-template-columns:
|
grid-template-columns:
|
||||||
grid-template-rows:
|
grid-template-rows:
|
||||||
height: 2057px
|
height: 2074px
|
||||||
inline-size: auto
|
inline-size: auto
|
||||||
inset-block-end: auto
|
inset-block-end: auto
|
||||||
inset-block-start: auto
|
inset-block-start: auto
|
||||||
|
|
|
@ -489,6 +489,7 @@ public:
|
||||||
int font_weight() const { return m_inherited.font_weight; }
|
int font_weight() const { return m_inherited.font_weight; }
|
||||||
CSS::FontVariant font_variant() const { return m_inherited.font_variant; }
|
CSS::FontVariant font_variant() const { return m_inherited.font_variant; }
|
||||||
Optional<FlyString> font_language_override() const { return m_inherited.font_language_override; }
|
Optional<FlyString> font_language_override() const { return m_inherited.font_language_override; }
|
||||||
|
Optional<HashMap<FlyString, IntegerOrCalculated>> font_feature_settings() const { return m_inherited.font_feature_settings; }
|
||||||
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings() const { return m_inherited.font_variation_settings; }
|
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings() const { return m_inherited.font_variation_settings; }
|
||||||
CSSPixels line_height() const { return m_inherited.line_height; }
|
CSSPixels line_height() const { return m_inherited.line_height; }
|
||||||
CSS::Time transition_delay() const { return m_noninherited.transition_delay; }
|
CSS::Time transition_delay() const { return m_noninherited.transition_delay; }
|
||||||
|
@ -522,6 +523,7 @@ protected:
|
||||||
int font_weight { InitialValues::font_weight() };
|
int font_weight { InitialValues::font_weight() };
|
||||||
CSS::FontVariant font_variant { InitialValues::font_variant() };
|
CSS::FontVariant font_variant { InitialValues::font_variant() };
|
||||||
Optional<FlyString> font_language_override;
|
Optional<FlyString> font_language_override;
|
||||||
|
Optional<HashMap<FlyString, IntegerOrCalculated>> font_feature_settings;
|
||||||
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings;
|
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings;
|
||||||
CSSPixels line_height { InitialValues::line_height() };
|
CSSPixels line_height { InitialValues::line_height() };
|
||||||
CSS::BorderCollapse border_collapse { InitialValues::border_collapse() };
|
CSS::BorderCollapse border_collapse { InitialValues::border_collapse() };
|
||||||
|
@ -681,6 +683,7 @@ public:
|
||||||
void set_font_weight(int font_weight) { m_inherited.font_weight = font_weight; }
|
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_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_language_override(Optional<FlyString> font_language_override) { m_inherited.font_language_override = font_language_override; }
|
||||||
|
void set_font_feature_settings(Optional<HashMap<FlyString, IntegerOrCalculated>> value) { m_inherited.font_feature_settings = move(value); }
|
||||||
void set_font_variation_settings(Optional<HashMap<FlyString, NumberOrCalculated>> value) { m_inherited.font_variation_settings = move(value); }
|
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_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_horizontal(CSS::Length border_spacing_horizontal) { m_inherited.border_spacing_horizontal = border_spacing_horizontal; }
|
||||||
|
|
|
@ -265,6 +265,8 @@
|
||||||
"nw-resize",
|
"nw-resize",
|
||||||
"nwse-resize",
|
"nwse-resize",
|
||||||
"oblique",
|
"oblique",
|
||||||
|
"off",
|
||||||
|
"on",
|
||||||
"opaque",
|
"opaque",
|
||||||
"open-quote",
|
"open-quote",
|
||||||
"optimizequality",
|
"optimizequality",
|
||||||
|
|
|
@ -5480,6 +5480,79 @@ RefPtr<CSSStyleValue> Parser::parse_font_language_override_value(TokenStream<Com
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefPtr<CSSStyleValue> Parser::parse_font_feature_settings_value(TokenStream<ComponentValue>& tokens)
|
||||||
|
{
|
||||||
|
// https://drafts.csswg.org/css-fonts/#propdef-font-feature-settings
|
||||||
|
// normal | <feature-tag-value>#
|
||||||
|
|
||||||
|
// normal
|
||||||
|
if (auto normal = parse_all_as_single_keyword_value(tokens, Keyword::Normal))
|
||||||
|
return normal;
|
||||||
|
|
||||||
|
// <feature-tag-value>#
|
||||||
|
auto transaction = tokens.begin_transaction();
|
||||||
|
auto tag_values = parse_a_comma_separated_list_of_component_values(tokens);
|
||||||
|
|
||||||
|
// "The computed value of font-feature-settings is a map, so any duplicates in the specified value must not be preserved.
|
||||||
|
// If the same feature tag appears more than once, the value associated with the last appearance supersedes any previous
|
||||||
|
// value for that axis."
|
||||||
|
// So, we deduplicate them here using a HashSet.
|
||||||
|
|
||||||
|
OrderedHashMap<FlyString, NonnullRefPtr<OpenTypeTaggedStyleValue>> feature_tags_map;
|
||||||
|
for (auto const& values : tag_values) {
|
||||||
|
// <feature-tag-value> = <opentype-tag> [ <integer [0,∞]> | on | off ]?
|
||||||
|
TokenStream tag_tokens { values };
|
||||||
|
tag_tokens.skip_whitespace();
|
||||||
|
auto opentype_tag = parse_opentype_tag_value(tag_tokens);
|
||||||
|
tag_tokens.skip_whitespace();
|
||||||
|
RefPtr<CSSStyleValue> value;
|
||||||
|
if (tag_tokens.has_next_token()) {
|
||||||
|
if (auto integer = parse_integer_value(tag_tokens)) {
|
||||||
|
if (integer->is_integer() && integer->as_integer().value() < 0)
|
||||||
|
return nullptr;
|
||||||
|
value = integer;
|
||||||
|
} else {
|
||||||
|
// A value of on is synonymous with 1 and off is synonymous with 0.
|
||||||
|
auto keyword = parse_keyword_value(tag_tokens);
|
||||||
|
if (!keyword)
|
||||||
|
return nullptr;
|
||||||
|
switch (keyword->to_keyword()) {
|
||||||
|
case Keyword::On:
|
||||||
|
value = IntegerStyleValue::create(1);
|
||||||
|
break;
|
||||||
|
case Keyword::Off:
|
||||||
|
value = IntegerStyleValue::create(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tag_tokens.skip_whitespace();
|
||||||
|
} else {
|
||||||
|
// "If the value is omitted, a value of 1 is assumed."
|
||||||
|
value = IntegerStyleValue::create(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opentype_tag || !value || tag_tokens.has_next_token())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
feature_tags_map.set(opentype_tag->string_value(), OpenTypeTaggedStyleValue::create(opentype_tag->string_value(), value.release_nonnull()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// "The computed value contains the de-duplicated feature tags, sorted in ascending order by code unit."
|
||||||
|
StyleValueVector feature_tags;
|
||||||
|
feature_tags.ensure_capacity(feature_tags_map.size());
|
||||||
|
for (auto const& [key, feature_tag] : feature_tags_map)
|
||||||
|
feature_tags.append(feature_tag);
|
||||||
|
|
||||||
|
quick_sort(feature_tags, [](auto& a, auto& b) {
|
||||||
|
return a->as_open_type_tagged().tag() < b->as_open_type_tagged().tag();
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction.commit();
|
||||||
|
return StyleValueList::create(move(feature_tags), StyleValueList::Separator::Comma);
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<CSSStyleValue> Parser::parse_font_variation_settings_value(TokenStream<ComponentValue>& tokens)
|
RefPtr<CSSStyleValue> Parser::parse_font_variation_settings_value(TokenStream<ComponentValue>& tokens)
|
||||||
{
|
{
|
||||||
// https://drafts.csswg.org/css-fonts/#propdef-font-variation-settings
|
// https://drafts.csswg.org/css-fonts/#propdef-font-variation-settings
|
||||||
|
@ -7620,6 +7693,10 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue>> Parser::parse_css_value(Prope
|
||||||
if (auto parsed_value = parse_font_family_value(tokens); parsed_value && !tokens.has_next_token())
|
if (auto parsed_value = parse_font_family_value(tokens); parsed_value && !tokens.has_next_token())
|
||||||
return parsed_value.release_nonnull();
|
return parsed_value.release_nonnull();
|
||||||
return ParseError::SyntaxError;
|
return ParseError::SyntaxError;
|
||||||
|
case PropertyID::FontFeatureSettings:
|
||||||
|
if (auto parsed_value = parse_font_feature_settings_value(tokens); parsed_value && !tokens.has_next_token())
|
||||||
|
return parsed_value.release_nonnull();
|
||||||
|
return ParseError::SyntaxError;
|
||||||
case PropertyID::FontLanguageOverride:
|
case PropertyID::FontLanguageOverride:
|
||||||
if (auto parsed_value = parse_font_language_override_value(tokens); parsed_value && !tokens.has_next_token())
|
if (auto parsed_value = parse_font_language_override_value(tokens); parsed_value && !tokens.has_next_token())
|
||||||
return parsed_value.release_nonnull();
|
return parsed_value.release_nonnull();
|
||||||
|
|
|
@ -307,6 +307,7 @@ private:
|
||||||
RefPtr<CSSStyleValue> parse_font_value(TokenStream<ComponentValue>&);
|
RefPtr<CSSStyleValue> parse_font_value(TokenStream<ComponentValue>&);
|
||||||
RefPtr<CSSStyleValue> parse_font_family_value(TokenStream<ComponentValue>&);
|
RefPtr<CSSStyleValue> parse_font_family_value(TokenStream<ComponentValue>&);
|
||||||
RefPtr<CSSStyleValue> parse_font_language_override_value(TokenStream<ComponentValue>&);
|
RefPtr<CSSStyleValue> parse_font_language_override_value(TokenStream<ComponentValue>&);
|
||||||
|
RefPtr<CSSStyleValue> parse_font_feature_settings_value(TokenStream<ComponentValue>&);
|
||||||
RefPtr<CSSStyleValue> parse_font_variation_settings_value(TokenStream<ComponentValue>&);
|
RefPtr<CSSStyleValue> parse_font_variation_settings_value(TokenStream<ComponentValue>&);
|
||||||
RefPtr<CSSStyleValue> parse_list_style_value(TokenStream<ComponentValue>&);
|
RefPtr<CSSStyleValue> parse_list_style_value(TokenStream<ComponentValue>&);
|
||||||
RefPtr<CSSStyleValue> parse_math_depth_value(TokenStream<ComponentValue>&);
|
RefPtr<CSSStyleValue> parse_math_depth_value(TokenStream<ComponentValue>&);
|
||||||
|
|
|
@ -1165,6 +1165,20 @@
|
||||||
"string"
|
"string"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"font-feature-settings": {
|
||||||
|
"animation-type": "discrete",
|
||||||
|
"inherited": true,
|
||||||
|
"initial": "normal",
|
||||||
|
"valid-types": [
|
||||||
|
"integer [0,∞]",
|
||||||
|
"opentype-tag"
|
||||||
|
],
|
||||||
|
"valid-identifiers": [
|
||||||
|
"normal",
|
||||||
|
"on",
|
||||||
|
"off"
|
||||||
|
]
|
||||||
|
},
|
||||||
"font-language-override": {
|
"font-language-override": {
|
||||||
"animation-type": "discrete",
|
"animation-type": "discrete",
|
||||||
"inherited": true,
|
"inherited": true,
|
||||||
|
|
|
@ -1028,6 +1028,33 @@ Optional<FlyString> StyleProperties::font_language_override() const
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Optional<HashMap<FlyString, IntegerOrCalculated>> StyleProperties::font_feature_settings() const
|
||||||
|
{
|
||||||
|
auto value = property(PropertyID::FontFeatureSettings);
|
||||||
|
|
||||||
|
if (value->is_keyword())
|
||||||
|
return {}; // normal
|
||||||
|
|
||||||
|
if (value->is_value_list()) {
|
||||||
|
auto const& feature_tags = value->as_value_list().values();
|
||||||
|
HashMap<FlyString, IntegerOrCalculated> result;
|
||||||
|
result.ensure_capacity(feature_tags.size());
|
||||||
|
for (auto const& tag_value : feature_tags) {
|
||||||
|
auto const& feature_tag = tag_value->as_open_type_tagged();
|
||||||
|
|
||||||
|
if (feature_tag.value()->is_integer()) {
|
||||||
|
result.set(feature_tag.tag(), feature_tag.value()->as_integer().value());
|
||||||
|
} else {
|
||||||
|
VERIFY(feature_tag.value()->is_math());
|
||||||
|
result.set(feature_tag.tag(), IntegerOrCalculated { feature_tag.value()->as_math() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
Optional<HashMap<FlyString, NumberOrCalculated>> StyleProperties::font_variation_settings() const
|
Optional<HashMap<FlyString, NumberOrCalculated>> StyleProperties::font_variation_settings() const
|
||||||
{
|
{
|
||||||
auto value = property(CSS::PropertyID::FontVariationSettings);
|
auto value = property(CSS::PropertyID::FontVariationSettings);
|
||||||
|
|
|
@ -149,6 +149,7 @@ public:
|
||||||
Variant<CSS::VerticalAlign, CSS::LengthPercentage> vertical_align() const;
|
Variant<CSS::VerticalAlign, CSS::LengthPercentage> vertical_align() const;
|
||||||
Optional<CSS::FontVariant> font_variant() const;
|
Optional<CSS::FontVariant> font_variant() const;
|
||||||
Optional<FlyString> font_language_override() const;
|
Optional<FlyString> font_language_override() const;
|
||||||
|
Optional<HashMap<FlyString, IntegerOrCalculated>> font_feature_settings() const;
|
||||||
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings() const;
|
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings() const;
|
||||||
CSS::GridTrackSizeList grid_auto_columns() const;
|
CSS::GridTrackSizeList grid_auto_columns() const;
|
||||||
CSS::GridTrackSizeList grid_auto_rows() const;
|
CSS::GridTrackSizeList grid_auto_rows() const;
|
||||||
|
|
|
@ -471,6 +471,8 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
|
||||||
computed_values.set_font_variant(maybe_font_variant.release_value());
|
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())
|
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());
|
computed_values.set_font_language_override(maybe_font_language_override.release_value());
|
||||||
|
if (auto maybe_font_feature_settings = computed_style.font_feature_settings(); maybe_font_feature_settings.has_value())
|
||||||
|
computed_values.set_font_feature_settings(maybe_font_feature_settings.release_value());
|
||||||
if (auto maybe_font_variation_settings = computed_style.font_variation_settings(); maybe_font_variation_settings.has_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());
|
computed_values.set_font_variation_settings(maybe_font_variation_settings.release_value());
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue