From 8d81421526488c3f6bc72c8ea4a5f9470bab972b Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Tue, 4 Nov 2025 23:25:15 +0000 Subject: [PATCH] LibWeb: Cache font matching algorithm results The majority of time in `compute_font()` was spent in `font_matching_algorithm()` repeatedly computing the same values. We now cache these values to avoid unnecessary work. --- Libraries/LibWeb/CSS/StyleComputer.cpp | 23 ++++++++++++++++++++++- Libraries/LibWeb/CSS/StyleComputer.h | 12 ++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/Libraries/LibWeb/CSS/StyleComputer.cpp b/Libraries/LibWeb/CSS/StyleComputer.cpp index 643592cac7c..e7138af3072 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -131,6 +131,18 @@ struct Traits : public DefaultTraits +struct Traits : public DefaultTraits { + static unsigned hash(Web::CSS::FontMatchingAlgorithmCacheKey const& key) + { + auto hash = key.family_name.hash(); + hash = pair_int_hash(hash, key.weight); + hash = pair_int_hash(hash, key.slope); + hash = pair_int_hash(hash, Traits::hash(key.font_size_in_pt)); + return hash; + } +}; + } namespace Web::CSS { @@ -1694,9 +1706,17 @@ RefPtr StyleComputer::find_matching_font_weight_desc return {}; } +RefPtr StyleComputer::font_matching_algorithm(FlyString const& family_name, int weight, int slope, float font_size_in_pt) const +{ + FontMatchingAlgorithmCacheKey key { family_name, weight, slope, font_size_in_pt }; + return m_font_matching_algorithm_cache.ensure(key, [&] { + return font_matching_algorithm_impl(family_name, weight, slope, font_size_in_pt); + }); +} + // Partial implementation of the font-matching algorithm: https://www.w3.org/TR/css-fonts-4/#font-matching-algorithm // FIXME: This should be replaced by the full CSS font selection algorithm. -RefPtr StyleComputer::font_matching_algorithm(FlyString const& family_name, int weight, int slope, float font_size_in_pt) const +RefPtr StyleComputer::font_matching_algorithm_impl(FlyString const& family_name, int weight, int slope, float font_size_in_pt) const { // If a font family match occurs, the user agent assembles the set of font faces in that family and then // narrows the set to a single face using other font properties in the order given below. @@ -2948,6 +2968,7 @@ void StyleComputer::invalidate_rule_cache() void StyleComputer::did_load_font(FlyString const&) { + m_font_matching_algorithm_cache = {}; document().invalidate_style(DOM::StyleInvalidationReason::CSSFontLoaded); } diff --git a/Libraries/LibWeb/CSS/StyleComputer.h b/Libraries/LibWeb/CSS/StyleComputer.h index 7b33345c904..e52aa01c9f4 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.h +++ b/Libraries/LibWeb/CSS/StyleComputer.h @@ -111,6 +111,15 @@ struct OwnFontFaceKey { int slope { 0 }; }; +struct FontMatchingAlgorithmCacheKey { + FlyString family_name; + int weight; + int slope; + float font_size_in_pt; + + [[nodiscard]] bool operator==(FontMatchingAlgorithmCacheKey const& other) const = default; +}; + struct RuleCache { HashMap> rules_by_id; HashMap> rules_by_class; @@ -241,6 +250,7 @@ private: static RefPtr find_matching_font_weight_ascending(Vector const& candidates, int target_weight, float font_size_in_pt, Gfx::FontVariationSettings const& variations, bool inclusive); static RefPtr find_matching_font_weight_descending(Vector const& candidates, int target_weight, float font_size_in_pt, Gfx::FontVariationSettings const& variations, bool inclusive); RefPtr font_matching_algorithm(FlyString const& family_name, int weight, int slope, float font_size_in_pt) const; + RefPtr font_matching_algorithm_impl(FlyString const& family_name, int weight, int slope, float font_size_in_pt) const; void compute_custom_properties(ComputedProperties&, DOM::AbstractElement) const; void compute_math_depth(ComputedProperties&, Optional) const; void start_needed_transitions(ComputedProperties const& old_style, ComputedProperties& new_style, DOM::AbstractElement) const; @@ -309,6 +319,8 @@ private: CSSPixelRect m_viewport_rect; OwnPtr> m_ancestor_filter; + + mutable HashMap> m_font_matching_algorithm_cache; }; class FontLoader final : public GC::Cell {