mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
LibGfx+LibWeb: Only trigger @font-face loads from text shaping
This commit is contained in:
committed by
Andreas Kling
parent
acabf765c1
commit
8c49029bb7
Notes:
github-actions[bot]
2026-04-25 15:07:53 +00:00
Author: https://github.com/jdahlin Commit: https://github.com/LadybirdBrowser/ladybird/commit/8c49029bb76 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/9032 Reviewed-by: https://github.com/Psychpsyo
@@ -58,20 +58,27 @@ void FontCascadeList::extend(FontCascadeList const& other)
|
||||
m_pending_faces.extend(other.m_pending_faces);
|
||||
}
|
||||
|
||||
Gfx::Font const& FontCascadeList::font_for_code_point(u32 code_point) const
|
||||
Gfx::Font const& FontCascadeList::font_for_code_point(u32 code_point, TriggerPendingLoads trigger_pending_loads) const
|
||||
{
|
||||
// Walk pending entries first: if this codepoint falls in an unloaded face's
|
||||
// unicode-range we kick off the fetch and drop the entry — a fallback font that
|
||||
// happens to cover the codepoint shouldn't prevent the real face from loading.
|
||||
// FontComputer::clear_computed_font_cache() rebuilds the cascade once the fetch
|
||||
// completes, so later shapes pick up the loaded face. Run before the ASCII cache
|
||||
// lookup so a previously-cached codepoint still triggers a newly-added face.
|
||||
m_pending_faces.remove_all_matching([code_point](auto const& pending) {
|
||||
if (!pending->covers(code_point))
|
||||
return false;
|
||||
pending->start_load();
|
||||
return true;
|
||||
});
|
||||
// Only the text-shaping paths pass TriggerPendingLoads::Yes. Probes that don't
|
||||
// lead to a glyph being drawn (the U+0020 check used to compute first-available-
|
||||
// font metrics, for instance) skip this block so they can't initiate a download
|
||||
// for a subset face that happens to cover the probe codepoint.
|
||||
if (trigger_pending_loads == TriggerPendingLoads::Yes) {
|
||||
// Walk pending entries first: if this codepoint falls in an unloaded face's
|
||||
// unicode-range we kick off the fetch and drop the entry — a fallback font
|
||||
// that happens to cover the codepoint shouldn't prevent the real face from
|
||||
// loading. FontComputer::clear_computed_font_cache() rebuilds the cascade
|
||||
// once the fetch completes, so later shapes pick up the loaded face. Run
|
||||
// before the ASCII cache lookup so a previously-cached codepoint still
|
||||
// triggers a newly-added face.
|
||||
m_pending_faces.remove_all_matching([code_point](auto const& pending) {
|
||||
if (!pending->covers(code_point))
|
||||
return false;
|
||||
pending->start_load();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (code_point < m_ascii_cache.size()) {
|
||||
if (auto const* cached = m_ascii_cache[code_point])
|
||||
|
||||
@@ -43,7 +43,15 @@ public:
|
||||
|
||||
void extend(FontCascadeList const& other);
|
||||
|
||||
Gfx::Font const& font_for_code_point(u32 code_point) const;
|
||||
// A pending-face fetch should only be initiated for codepoints that are actually
|
||||
// being shaped into glyph runs. Callers that merely probe the cascade (e.g. the
|
||||
// U+0020 check in "first available font" metrics) pass No so that probing does
|
||||
// not kick off downloads for subset faces that happen to cover the probe point.
|
||||
enum class TriggerPendingLoads : u8 {
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
Gfx::Font const& font_for_code_point(u32 code_point, TriggerPendingLoads = TriggerPendingLoads::No) const;
|
||||
|
||||
bool equals(FontCascadeList const& other) const;
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ Vector<NonnullRefPtr<GlyphRun>> shape_text(FloatPoint baseline_start, Utf16View
|
||||
|
||||
auto it = string.begin();
|
||||
auto substring_begin_offset = string.iterator_offset(it);
|
||||
Font const* last_font = &font_cascade_list.font_for_code_point(*it);
|
||||
Font const* last_font = &font_cascade_list.font_for_code_point(*it, FontCascadeList::TriggerPendingLoads::Yes);
|
||||
FloatPoint last_position = baseline_start;
|
||||
|
||||
auto add_run = [&runs, &last_position, letter_spacing](Utf16View const& string, Font const& font) {
|
||||
@@ -132,7 +132,7 @@ Vector<NonnullRefPtr<GlyphRun>> shape_text(FloatPoint baseline_start, Utf16View
|
||||
|
||||
while (it != string.end()) {
|
||||
auto code_point = *it;
|
||||
auto const* font = &font_cascade_list.font_for_code_point(code_point);
|
||||
auto const* font = &font_cascade_list.font_for_code_point(code_point, FontCascadeList::TriggerPendingLoads::Yes);
|
||||
if (font != last_font) {
|
||||
auto substring = string.substring_view(substring_begin_offset, string.iterator_offset(it) - substring_begin_offset);
|
||||
add_run(substring, *last_font);
|
||||
|
||||
@@ -643,7 +643,7 @@ Gfx::Font const& TextNode::ChunkIterator::font_for_space(size_t at_index, u32 sp
|
||||
for (size_t i = at_index; i < m_view.length_in_code_units();) {
|
||||
auto cp = m_view.code_point_at(i);
|
||||
if (!is_interword_space(cp) && cp != '\t' && cp != '\n') {
|
||||
auto const& font = m_font_cascade_list.font_for_code_point(cp);
|
||||
auto const& font = m_font_cascade_list.font_for_code_point(cp, Gfx::FontCascadeList::TriggerPendingLoads::Yes);
|
||||
if (!font.is_emoji_font() && has_glyph(font))
|
||||
return font;
|
||||
// Text is coming from an emoji face; we'll fall back to (3).
|
||||
@@ -653,7 +653,7 @@ Gfx::Font const& TextNode::ChunkIterator::font_for_space(size_t at_index, u32 sp
|
||||
}
|
||||
|
||||
// 3. No text around (leading/trailing/all spaces) — pick a font with the glyph from the cascade.
|
||||
return m_font_cascade_list.font_for_code_point(space_code_point);
|
||||
return m_font_cascade_list.font_for_code_point(space_code_point, Gfx::FontCascadeList::TriggerPendingLoads::Yes);
|
||||
}
|
||||
|
||||
Optional<TextNode::Chunk> TextNode::ChunkIterator::next_without_peek()
|
||||
@@ -680,7 +680,7 @@ Optional<TextNode::Chunk> TextNode::ChunkIterator::next_without_peek()
|
||||
auto const& expected_font_for = [&](u32 cp) -> Gfx::Font const& {
|
||||
return is_interword_space(cp)
|
||||
? font_for_space(m_current_index, cp)
|
||||
: m_font_cascade_list.font_for_code_point(cp);
|
||||
: m_font_cascade_list.font_for_code_point(cp, Gfx::FontCascadeList::TriggerPendingLoads::Yes);
|
||||
};
|
||||
|
||||
auto const& font = expected_font_for(current_code_point());
|
||||
|
||||
@@ -1 +1 @@
|
||||
ProbeFont status: error
|
||||
ProbeFont status: unloaded
|
||||
|
||||
Reference in New Issue
Block a user