diff --git a/src/font/shaper/run.zig b/src/font/shaper/run.zig index 90917f657..0b6ebeb4c 100644 --- a/src/font/shaper/run.zig +++ b/src/font/shaper/run.zig @@ -17,6 +17,10 @@ pub const TextRun = struct { /// lower the chance of hash collisions if they become a problem. If /// there are hash collisions, it would result in rendering issues but /// the core data would be correct. + /// + /// The hash is position-independent within the row by using relative + /// cluster positions. This allows identical runs in different positions + /// to share the same cache entry, improving cache efficiency. hash: u64, /// The offset in the row where this run started @@ -77,7 +81,11 @@ pub const RunIterator = struct { // Go through cell by cell and accumulate while we build our run. var j: usize = self.i; while (j < max) : (j += 1) { - const cluster = j; + // Use relative cluster positions (offset from run start) to make + // the shaping cache position-independent. This ensures that runs + // with identical content but different starting positions in the + // row produce the same hash, enabling cache reuse. + const cluster = j - self.i; const cell = &cells[j]; // If we have a selection and we're at a boundary point, then diff --git a/src/renderer/generic.zig b/src/renderer/generic.zig index 8726f2951..dd0ed43bc 100644 --- a/src/renderer/generic.zig +++ b/src/renderer/generic.zig @@ -2530,7 +2530,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type { // Advance our index until we reach or pass // our current x position in the shaper cells. - while (shaper_cells.?[shaper_cells_i].x < x) { + while (shaper_cells.?[shaper_cells_i].x + run.offset < x) { shaper_cells_i += 1; } } @@ -2769,13 +2769,13 @@ pub fn Renderer(comptime GraphicsAPI: type) type { // If we encounter a shaper cell to the left of the current // cell then we have some problems. This logic relies on x // position monotonically increasing. - assert(cells[shaper_cells_i].x >= x); + assert(cells[shaper_cells_i].x + run.offset >= x); // NOTE: An assumption is made here that a single cell will never // be present in more than one shaper run. If that assumption is // violated, this logic breaks. - while (shaper_cells_i < cells.len and cells[shaper_cells_i].x == x) : ({ + while (shaper_cells_i < cells.len and cells[shaper_cells_i].x + run.offset == x) : ({ shaper_cells_i += 1; }) { self.addGlyph(