mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
font/shaper: add hash to text runs
This commit is contained in:
@ -4,11 +4,21 @@ const Allocator = std.mem.Allocator;
|
|||||||
const font = @import("../main.zig");
|
const font = @import("../main.zig");
|
||||||
const shape = @import("../shape.zig");
|
const shape = @import("../shape.zig");
|
||||||
const terminal = @import("../../terminal/main.zig");
|
const terminal = @import("../../terminal/main.zig");
|
||||||
|
const autoHash = std.hash.autoHash;
|
||||||
|
const Hasher = std.hash.Wyhash;
|
||||||
|
|
||||||
/// A single text run. A text run is only valid for one Shaper instance and
|
/// A single text run. A text run is only valid for one Shaper instance and
|
||||||
/// until the next run is created. A text run never goes across multiple
|
/// until the next run is created. A text run never goes across multiple
|
||||||
/// rows in a terminal, so it is guaranteed to always be one line.
|
/// rows in a terminal, so it is guaranteed to always be one line.
|
||||||
pub const TextRun = struct {
|
pub const TextRun = struct {
|
||||||
|
/// A unique hash for this run. This can be used to cache the shaping
|
||||||
|
/// results. We don't provide a means to compare actual values if the
|
||||||
|
/// hash is the same, so we should continue to improve this hash to
|
||||||
|
/// 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.
|
||||||
|
hash: u64,
|
||||||
|
|
||||||
/// The offset in the row where this run started
|
/// The offset in the row where this run started
|
||||||
offset: u16,
|
offset: u16,
|
||||||
|
|
||||||
@ -54,6 +64,9 @@ pub const RunIterator = struct {
|
|||||||
// Allow the hook to prepare
|
// Allow the hook to prepare
|
||||||
try self.hooks.prepare();
|
try self.hooks.prepare();
|
||||||
|
|
||||||
|
// Initialize our hash for this run.
|
||||||
|
var hasher = Hasher.init(0);
|
||||||
|
|
||||||
// Let's get our style that we'll expect for the run.
|
// Let's get our style that we'll expect for the run.
|
||||||
const style = self.row.style(&cells[self.i]);
|
const style = self.row.style(&cells[self.i]);
|
||||||
|
|
||||||
@ -211,12 +224,13 @@ pub const RunIterator = struct {
|
|||||||
// If we're a fallback character, add that and continue; we
|
// If we're a fallback character, add that and continue; we
|
||||||
// don't want to add the entire grapheme.
|
// don't want to add the entire grapheme.
|
||||||
if (font_info.fallback) |cp| {
|
if (font_info.fallback) |cp| {
|
||||||
try self.hooks.addCodepoint(cp, @intCast(cluster));
|
try self.addCodepoint(&hasher, cp, @intCast(cluster));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all the codepoints for our grapheme
|
// Add all the codepoints for our grapheme
|
||||||
try self.hooks.addCodepoint(
|
try self.addCodepoint(
|
||||||
|
&hasher,
|
||||||
if (cell.codepoint() == 0) ' ' else cell.codepoint(),
|
if (cell.codepoint() == 0) ' ' else cell.codepoint(),
|
||||||
@intCast(cluster),
|
@intCast(cluster),
|
||||||
);
|
);
|
||||||
@ -225,7 +239,7 @@ pub const RunIterator = struct {
|
|||||||
for (cps) |cp| {
|
for (cps) |cp| {
|
||||||
// Do not send presentation modifiers
|
// Do not send presentation modifiers
|
||||||
if (cp == 0xFE0E or cp == 0xFE0F) continue;
|
if (cp == 0xFE0E or cp == 0xFE0F) continue;
|
||||||
try self.hooks.addCodepoint(cp, @intCast(cluster));
|
try self.addCodepoint(&hasher, cp, @intCast(cluster));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -233,10 +247,14 @@ pub const RunIterator = struct {
|
|||||||
// Finalize our buffer
|
// Finalize our buffer
|
||||||
try self.hooks.finalize();
|
try self.hooks.finalize();
|
||||||
|
|
||||||
|
// Add our length to the hash as an additional mechanism to avoid collisions
|
||||||
|
autoHash(&hasher, j - self.i);
|
||||||
|
|
||||||
// Move our cursor. Must defer since we use self.i below.
|
// Move our cursor. Must defer since we use self.i below.
|
||||||
defer self.i = j;
|
defer self.i = j;
|
||||||
|
|
||||||
return TextRun{
|
return TextRun{
|
||||||
|
.hash = hasher.final(),
|
||||||
.offset = @intCast(self.i),
|
.offset = @intCast(self.i),
|
||||||
.cells = @intCast(j - self.i),
|
.cells = @intCast(j - self.i),
|
||||||
.grid = self.grid,
|
.grid = self.grid,
|
||||||
@ -244,6 +262,12 @@ pub const RunIterator = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn addCodepoint(self: *RunIterator, hasher: anytype, cp: u32, cluster: u32) !void {
|
||||||
|
autoHash(hasher, cp);
|
||||||
|
autoHash(hasher, cluster);
|
||||||
|
try self.hooks.addCodepoint(cp, cluster);
|
||||||
|
}
|
||||||
|
|
||||||
/// Find a font index that supports the grapheme for the given cell,
|
/// Find a font index that supports the grapheme for the given cell,
|
||||||
/// or null if no such font exists.
|
/// or null if no such font exists.
|
||||||
///
|
///
|
||||||
|
Reference in New Issue
Block a user