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.
This commit is contained in:
Tim Ledbetter 2025-11-04 23:25:15 +00:00 committed by Andreas Kling
parent 4ed6eac5be
commit 8d81421526
Notes: github-actions[bot] 2025-11-05 11:03:01 +00:00
2 changed files with 34 additions and 1 deletions

View file

@ -131,6 +131,18 @@ struct Traits<Web::CSS::OwnFontFaceKey> : public DefaultTraits<Web::CSS::OwnFont
static unsigned hash(Web::CSS::OwnFontFaceKey const& key) { return pair_int_hash(key.family_name.hash(), pair_int_hash(key.weight, key.slope)); }
};
template<>
struct Traits<Web::CSS::FontMatchingAlgorithmCacheKey> : public DefaultTraits<Web::CSS::FontMatchingAlgorithmCacheKey> {
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<float>::hash(key.font_size_in_pt));
return hash;
}
};
}
namespace Web::CSS {
@ -1694,9 +1706,17 @@ RefPtr<Gfx::FontCascadeList const> StyleComputer::find_matching_font_weight_desc
return {};
}
RefPtr<Gfx::FontCascadeList const> 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<Gfx::FontCascadeList const> StyleComputer::font_matching_algorithm(FlyString const& family_name, int weight, int slope, float font_size_in_pt) const
RefPtr<Gfx::FontCascadeList const> 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);
}

View file

@ -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<FlyString, Vector<MatchingRule>> rules_by_id;
HashMap<FlyString, Vector<MatchingRule>> rules_by_class;
@ -241,6 +250,7 @@ private:
static RefPtr<Gfx::FontCascadeList const> find_matching_font_weight_ascending(Vector<MatchingFontCandidate> const& candidates, int target_weight, float font_size_in_pt, Gfx::FontVariationSettings const& variations, bool inclusive);
static RefPtr<Gfx::FontCascadeList const> find_matching_font_weight_descending(Vector<MatchingFontCandidate> const& candidates, int target_weight, float font_size_in_pt, Gfx::FontVariationSettings const& variations, bool inclusive);
RefPtr<Gfx::FontCascadeList const> font_matching_algorithm(FlyString const& family_name, int weight, int slope, float font_size_in_pt) const;
RefPtr<Gfx::FontCascadeList const> 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<DOM::AbstractElement>) 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<CountingBloomFilter<u8, 14>> m_ancestor_filter;
mutable HashMap<FontMatchingAlgorithmCacheKey, RefPtr<Gfx::FontCascadeList const>> m_font_matching_algorithm_cache;
};
class FontLoader final : public GC::Cell {