mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-04-18 18:00:31 +00:00
LibWeb: Don't compute font-feature-settings until compute-time
Previously we applied the computation logic (i.e. deduplication and sorting of tags) at parse time
This commit is contained in:
parent
3a515fd3ee
commit
1c1476f728
Notes:
github-actions[bot]
2026-01-13 10:22:33 +00:00
Author: https://github.com/Calme1709
Commit: 1c1476f728
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/7439
Reviewed-by: https://github.com/AtkinsSJ ✅
5 changed files with 17 additions and 32 deletions
|
|
@ -2801,12 +2801,8 @@ RefPtr<StyleValue const> Parser::parse_font_feature_settings_value(TokenStream<C
|
|||
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 const>> feature_tags_map;
|
||||
StyleValueVector feature_tags;
|
||||
feature_tags.ensure_capacity(tag_values.size());
|
||||
for (auto const& values : tag_values) {
|
||||
// <feature-tag-value> = <opentype-tag> [ <integer [0,∞]> | on | off ]?
|
||||
TokenStream tag_tokens { values };
|
||||
|
|
@ -2844,19 +2840,9 @@ RefPtr<StyleValue const> Parser::parse_font_feature_settings_value(TokenStream<C
|
|||
if (!opentype_tag || !value || tag_tokens.has_next_token())
|
||||
return nullptr;
|
||||
|
||||
feature_tags_map.set(opentype_tag->string_value(), OpenTypeTaggedStyleValue::create(OpenTypeTaggedStyleValue::Mode::FontFeatureSettings, opentype_tag->string_value(), value.release_nonnull()));
|
||||
feature_tags.append(OpenTypeTaggedStyleValue::create(OpenTypeTaggedStyleValue::Mode::FontFeatureSettings, 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1475,7 +1475,7 @@ void StyleComputer::compute_font(ComputedProperties& style, Optional<DOM::Abstra
|
|||
|
||||
style.set_property_without_modifying_flags(
|
||||
PropertyID::FontVariationSettings,
|
||||
compute_font_variation_settings(font_variation_settings_value, font_computation_context));
|
||||
compute_font_feature_tag_value_list(font_variation_settings_value, font_computation_context));
|
||||
|
||||
RefPtr<Gfx::Font const> const found_font = style.first_available_computed_font(m_document->font_computer());
|
||||
|
||||
|
|
@ -2278,8 +2278,9 @@ NonnullRefPtr<StyleValue const> StyleComputer::compute_value_of_property(
|
|||
case PropertyID::CornerTopLeftShape:
|
||||
case PropertyID::CornerTopRightShape:
|
||||
return compute_corner_shape(absolutized_value);
|
||||
case PropertyID::FontFeatureSettings:
|
||||
case PropertyID::FontVariationSettings:
|
||||
return compute_font_variation_settings(absolutized_value, computation_context);
|
||||
return compute_font_feature_tag_value_list(absolutized_value, computation_context);
|
||||
case PropertyID::LetterSpacing:
|
||||
case PropertyID::WordSpacing:
|
||||
if (absolutized_value->to_keyword() == Keyword::Normal)
|
||||
|
|
@ -2326,17 +2327,17 @@ NonnullRefPtr<StyleValue const> StyleComputer::compute_animation_name(NonnullRef
|
|||
});
|
||||
}
|
||||
|
||||
NonnullRefPtr<StyleValue const> StyleComputer::compute_font_variation_settings(NonnullRefPtr<StyleValue const> const& specified_value, ComputationContext const& computation_context)
|
||||
// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def
|
||||
// https://drafts.csswg.org/css-fonts/#font-feature-settings-prop
|
||||
NonnullRefPtr<StyleValue const> StyleComputer::compute_font_feature_tag_value_list(NonnullRefPtr<StyleValue const> const& specified_value, ComputationContext const& computation_context)
|
||||
{
|
||||
// NB: The computation logic is the same for both font-feature-settings and font-variation-settings, first we
|
||||
// deduplicate feature tags (with latter taking precedence), then we sort them in ascending order by code unit
|
||||
auto const& absolutized_value = specified_value->absolutized(computation_context);
|
||||
|
||||
if (absolutized_value->is_keyword())
|
||||
return absolutized_value;
|
||||
|
||||
// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def
|
||||
// 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.
|
||||
auto const& value_list = absolutized_value->as_value_list();
|
||||
OrderedHashMap<FlyString, NonnullRefPtr<OpenTypeTaggedStyleValue const>> axis_tags_map;
|
||||
for (size_t i = 0; i < value_list.values().size(); i++) {
|
||||
|
|
@ -2346,7 +2347,6 @@ NonnullRefPtr<StyleValue const> StyleComputer::compute_font_variation_settings(N
|
|||
|
||||
StyleValueVector axis_tags;
|
||||
|
||||
// The computed value contains the de-duplicated axis names, sorted in ascending order by code unit.
|
||||
for (auto const& [key, axis_tag] : axis_tags_map)
|
||||
axis_tags.append(axis_tag);
|
||||
|
||||
|
|
|
|||
|
|
@ -133,11 +133,11 @@ public:
|
|||
static NonnullRefPtr<StyleValue const> compute_animation_name(NonnullRefPtr<StyleValue const> const& absolutized_value);
|
||||
static NonnullRefPtr<StyleValue const> compute_border_or_outline_width(NonnullRefPtr<StyleValue const> const& absolutized_value, double device_pixels_per_css_pixel);
|
||||
static NonnullRefPtr<StyleValue const> compute_corner_shape(NonnullRefPtr<StyleValue const> const& absolutized_value);
|
||||
static NonnullRefPtr<StyleValue const> compute_font_feature_tag_value_list(NonnullRefPtr<StyleValue const> const& specified_value, ComputationContext const&);
|
||||
static NonnullRefPtr<StyleValue const> compute_font_size(NonnullRefPtr<StyleValue const> const& specified_value, int computed_math_depth, CSSPixels inherited_font_size, int inherited_math_depth, ComputationContext const&);
|
||||
static NonnullRefPtr<StyleValue const> compute_font_style(NonnullRefPtr<StyleValue const> const& specified_value, ComputationContext const&);
|
||||
static NonnullRefPtr<StyleValue const> compute_font_weight(NonnullRefPtr<StyleValue const> const& specified_value, double inherited_font_weight, ComputationContext const&);
|
||||
static NonnullRefPtr<StyleValue const> compute_font_width(NonnullRefPtr<StyleValue const> const& specified_value, ComputationContext const&);
|
||||
static NonnullRefPtr<StyleValue const> compute_font_variation_settings(NonnullRefPtr<StyleValue const> const& specified_value, ComputationContext const&);
|
||||
static NonnullRefPtr<StyleValue const> compute_line_height(NonnullRefPtr<StyleValue const> const& specified_value, ComputationContext const&);
|
||||
static NonnullRefPtr<StyleValue const> compute_opacity(NonnullRefPtr<StyleValue const> const& absolutized_value);
|
||||
static NonnullRefPtr<StyleValue const> compute_position_area(NonnullRefPtr<StyleValue const> const& absolutized_value);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
@font-face { font-family: "a1"; src: local("xyz"); }
|
||||
@font-face { font-family: "b1"; font-feature-settings: "aaaa", "bbbb" 0, "yyyy" 3, "zzzz"; }
|
||||
@font-face { font-family: "b2"; font-feature-settings: "aaaa" 3; }
|
||||
@font-face { font-family: "b1"; font-feature-settings: "bbbb" 0, "aaaa", "zzzz", "yyyy" 3; }
|
||||
@font-face { font-family: "b2"; font-feature-settings: "aaaa", "aaaa" 0, "aaaa" 3; }
|
||||
@font-face { font-family: "c1"; font-stretch: extra-condensed; }
|
||||
@font-face { font-family: "c2"; font-stretch: 50%; }
|
||||
@font-face { font-family: "c3"; font-stretch: extra-condensed; }
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@ Harness status: OK
|
|||
|
||||
Found 8 tests
|
||||
|
||||
6 Pass
|
||||
2 Fail
|
||||
8 Pass
|
||||
Pass e.style['font-feature-settings'] = "normal" should set the property value
|
||||
Pass e.style['font-feature-settings'] = "\"dlig\" 1" should set the property value
|
||||
Pass e.style['font-feature-settings'] = "\"smcp\" on" should set the property value
|
||||
Pass e.style['font-feature-settings'] = "'c2sc'" should set the property value
|
||||
Pass e.style['font-feature-settings'] = "\"liga\" off" should set the property value
|
||||
Fail e.style['font-feature-settings'] = "\"tnum\", 'hist'" should set the property value
|
||||
Pass e.style['font-feature-settings'] = "\"tnum\", 'hist'" should set the property value
|
||||
Pass e.style['font-feature-settings'] = "\"PKRN\"" should set the property value
|
||||
Fail e.style['font-feature-settings'] = "\"dlig\" 1, \"smcp\" on, \"dlig\" 0" should set the property value
|
||||
Pass e.style['font-feature-settings'] = "\"dlig\" 1, \"smcp\" on, \"dlig\" 0" should set the property value
|
||||
Loading…
Add table
Add a link
Reference in a new issue