LibGfx+LibWeb: Add some extra fields to glyph run data

We currently have a mixup in LibWeb between code unit offset and glyph
offset during hit testing. These extra fields will allow us to correct
this discrepency.
This commit is contained in:
Timothy Flynn 2025-08-19 13:33:45 -04:00 committed by Andreas Kling
commit 047f521c4c
Notes: github-actions[bot] 2025-08-22 12:08:06 +00:00
3 changed files with 33 additions and 8 deletions

View file

@ -110,11 +110,36 @@ NonnullRefPtr<GlyphRun> shape_text(FloatPoint baseline_start, float letter_spaci
Vector<DrawGlyph> glyph_run;
glyph_run.ensure_capacity(glyph_count);
FloatPoint point = baseline_start;
// We track the code unit length rather than just the code unit offset because LibWeb may later collapse glyph runs.
// Updating the offset of each glyph gets tricky when handling text direction (LTR/RTL). So rather than doing that,
// we just provide the glyph's code unit length and base LibWeb algorithms on that.
//
// A single grapheme may be represented by multiple glyphs, where any of those glyphs are zero-width. We want to
// assign code unit lengths such that each glyph knows the length of the text it respresents.
auto glyph_length_in_code_units = [&](auto index) -> size_t {
auto starting_offset = glyph_info[index].cluster;
for (size_t i = index + 1; i < glyph_count; ++i) {
if (auto offset = glyph_info[i].cluster; offset != starting_offset)
return offset - starting_offset;
}
return string.length_in_code_units() - starting_offset;
};
for (size_t i = 0; i < glyph_count; ++i) {
auto position = point
- FloatPoint { 0, font.pixel_metrics().ascent }
+ FloatPoint { positions[i].x_offset, positions[i].y_offset } / text_shaping_resolution;
glyph_run.unchecked_append({ position, glyph_info[i].codepoint });
glyph_run.unchecked_append({
.position = position,
.length_in_code_units = glyph_length_in_code_units(i),
.glyph_width = positions[i].x_advance / text_shaping_resolution,
.glyph_id = glyph_info[i].codepoint,
});
point += FloatPoint { positions[i].x_advance, positions[i].y_advance } / text_shaping_resolution;
// NOTE: The spec says that we "really should not" apply letter-spacing to the trailing edge of a line but

View file

@ -20,12 +20,9 @@ namespace Gfx {
struct DrawGlyph {
FloatPoint position;
u32 glyph_id;
void translate_by(FloatPoint const& delta)
{
position.translate_by(delta);
}
size_t length_in_code_units { 0 };
float glyph_width { 0.0 };
u32 glyph_id { 0 };
};
typedef struct ShapeFeature {

View file

@ -395,7 +395,10 @@ void InlineFormattingContext::generate_line_boxes()
glyphs.remove(last_glyph_index - 1, remove_item_count);
glyphs.append(Gfx::DrawGlyph {
.position = last_glyph_position,
.glyph_id = glyph_run->font().glyph_id_for_code_point(ellipsis_codepoint) });
.length_in_code_units = AK::UnicodeUtils::code_unit_length_for_code_point(ellipsis_codepoint),
.glyph_width = glyph_run->font().glyph_width(ellipsis_codepoint),
.glyph_id = glyph_run->font().glyph_id_for_code_point(ellipsis_codepoint),
});
}
}
}