From 489ed57e2f924e6993158427ad9317f21eede9eb Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 11 Dec 2023 21:41:13 -0800 Subject: [PATCH] font/harfbuzz: track x/y offsets --- pkg/harfbuzz/font.zig | 8 ++++++++ src/font/face/coretext.zig | 1 + src/font/shaper/harfbuzz.zig | 34 ++++++++++++++++++++++++++++++---- src/renderer/Metal.zig | 14 ++++---------- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/pkg/harfbuzz/font.zig b/pkg/harfbuzz/font.zig index 259274446..0947ea0b2 100644 --- a/pkg/harfbuzz/font.zig +++ b/pkg/harfbuzz/font.zig @@ -17,4 +17,12 @@ pub const Font = struct { pub fn destroy(self: *Font) void { c.hb_font_destroy(self.handle); } + + pub fn setScale(self: *Font, x: u32, y: u32) void { + c.hb_font_set_scale( + self.handle, + @intCast(x), + @intCast(y), + ); + } }; diff --git a/src/font/face/coretext.zig b/src/font/face/coretext.zig index 188a3bce8..a57216df4 100644 --- a/src/font/face/coretext.zig +++ b/src/font/face/coretext.zig @@ -77,6 +77,7 @@ pub const Face = struct { pub fn initFont(ct_font: *macos.text.Font, opts: font.face.Options) !Face { var hb_font = try harfbuzz.coretext.createFont(ct_font); errdefer hb_font.destroy(); + hb_font.setScale(opts.size.pixels(), opts.size.pixels()); const traits = ct_font.getSymbolicTraits(); const metrics = metrics: { diff --git a/src/font/shaper/harfbuzz.zig b/src/font/shaper/harfbuzz.zig index 781d5a708..4a3613276 100644 --- a/src/font/shaper/harfbuzz.zig +++ b/src/font/shaper/harfbuzz.zig @@ -133,17 +133,43 @@ pub const Shaper = struct { // If it isn't true, I'd like to catch it and learn more. assert(info.len == pos.len); + // This keeps track of the current offsets within a single cell. + var cell_offset: struct { + cluster: u32 = 0, + x: i32 = 0, + y: i32 = 0, + } = .{}; + // Convert all our info/pos to cells and set it. self.cell_buf.clearRetainingCapacity(); try self.cell_buf.ensureTotalCapacity(self.alloc, info.len); - for (info) |v| { + for (info, pos) |info_v, pos_v| { + if (info_v.cluster != cell_offset.cluster) cell_offset = .{ + .cluster = info_v.cluster, + }; + self.cell_buf.appendAssumeCapacity(.{ - .x = @intCast(v.cluster), - .glyph_index = v.codepoint, + .x = @intCast(info_v.cluster), + .x_offset = @intCast(cell_offset.x), + .y_offset = @intCast(cell_offset.y), + .glyph_index = info_v.codepoint, }); - // log.warn("i={} info={} pos={} cell={}", .{ i, v, pos[i], self.cell_buf[i] }); + if (font.options.backend.hasFreetype()) { + // Freetype returns 26.6 fixed point values, so we need to + // divide by 64 to get the actual value. I can't find any + // HB API to stop this. + cell_offset.x += pos_v.x_advance >> 6; + cell_offset.y += pos_v.y_advance >> 6; + } else { + cell_offset.x += pos_v.x_advance; + cell_offset.y += pos_v.y_advance; + } + + // const i = self.cell_buf.items.len - 1; + // log.warn("i={} info={} pos={} cell={}", .{ i, info_v, pos_v, self.cell_buf.items[i] }); } + //log.warn("----------------", .{}); return self.cell_buf.items; } diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index 9f7356d4b..ea151819a 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -1787,15 +1787,6 @@ pub fn updateCell( .emoji => .fg_color, }; - // If this glyph doesn't have an advance, then we assume it is - // connected to the previous glyph (perhaps an unsafe assumption...) - // and offset by the cell width. - // Related: https://github.com/mitchellh/ghostty/issues/1046 - const extra_offset: i32 = if (glyph.advance_x == 0) - @intCast(self.grid_metrics.cell_width) - else - 0; - self.cells.appendAssumeCapacity(.{ .mode = mode, .grid_pos = .{ @as(f32, @floatFromInt(x)), @as(f32, @floatFromInt(y)) }, @@ -1804,7 +1795,10 @@ pub fn updateCell( .bg_color = bg, .glyph_pos = .{ glyph.atlas_x, glyph.atlas_y }, .glyph_size = .{ glyph.width, glyph.height }, - .glyph_offset = .{ glyph.offset_x + extra_offset, glyph.offset_y }, + .glyph_offset = .{ + glyph.offset_x + shaper_cell.x_offset, + glyph.offset_y + shaper_cell.y_offset, + }, }); }