diff --git a/src/font/SharedGrid.zig b/src/font/SharedGrid.zig index 03f364570..a1b0f798b 100644 --- a/src/font/SharedGrid.zig +++ b/src/font/SharedGrid.zig @@ -129,6 +129,7 @@ fn reloadMetrics(self: *SharedGrid, thicken: bool) !void { .thickness = self.metrics.underline_thickness * @as(u32, if (thicken) 2 else 1), .underline_position = self.metrics.underline_position, + .strikethrough_position = self.metrics.strikethrough_position, }; } diff --git a/src/font/sprite.zig b/src/font/sprite.zig index fd37bc852..5f679631d 100644 --- a/src/font/sprite.zig +++ b/src/font/sprite.zig @@ -20,6 +20,8 @@ pub const Sprite = enum(u32) { underline_dashed, underline_curly, + strikethrough, + cursor_rect, cursor_hollow_rect, cursor_bar, diff --git a/src/font/sprite/Face.zig b/src/font/sprite/Face.zig index 86dd70c71..676598d97 100644 --- a/src/font/sprite/Face.zig +++ b/src/font/sprite/Face.zig @@ -30,11 +30,17 @@ height: u32, /// Base thickness value for lines of sprites. This is in pixels. If you /// want to do any DPI scaling, it is expected to be done earlier. -thickness: u32, +thickness: u32 = 1, /// The position of the underline. underline_position: u32 = 0, +/// The position of the strikethrough. +// NOTE(mitchellh): We don't use a dedicated strikethrough thickness +// setting yet but fonts can in theory set this. If this becomes an +// issue in practice we can add it here. +strikethrough_position: u32 = 0, + /// Returns true if the codepoint exists in our sprite font. pub fn hasCodepoint(self: Face, cp: u32, p: ?font.Presentation) bool { // We ignore presentation. No matter what presentation is requested @@ -113,6 +119,16 @@ pub fn renderGlyph( self.thickness, ), + .strikethrough => try underline.renderGlyph( + alloc, + atlas, + @enumFromInt(cp), + width, + self.height, + self.strikethrough_position, + self.thickness, + ), + .powerline => powerline: { const f: Powerline = .{ .width = width, @@ -129,6 +145,7 @@ pub fn renderGlyph( const Kind = enum { box, underline, + strikethrough, powerline, pub fn init(cp: u32) ?Kind { @@ -141,6 +158,9 @@ const Kind = enum { .underline_curly, => .underline, + .strikethrough, + => .strikethrough, + .cursor_rect, .cursor_hollow_rect, .cursor_bar, @@ -189,3 +209,7 @@ const Kind = enum { }; } }; + +test { + @import("std").testing.refAllDecls(@This()); +} diff --git a/src/font/sprite/underline.zig b/src/font/sprite/underline.zig index 064efc74f..19e228def 100644 --- a/src/font/sprite/underline.zig +++ b/src/font/sprite/underline.zig @@ -7,6 +7,9 @@ //! to maintain and debug another set of shaders for each renderer instead of //! just relying on the glyph system we already need to support for text //! anyways. +//! +//! This also renders strikethrough, so its really more generally a +//! "horizontal line" renderer. const std = @import("std"); const builtin = @import("builtin"); const assert = std.debug.assert; @@ -71,6 +74,7 @@ const Draw = struct { .underline_dotted => self.drawDotted(canvas), .underline_dashed => self.drawDashed(canvas), .underline_curly => self.drawCurly(canvas), + .strikethrough => self.drawSingle(canvas), else => unreachable, } } @@ -225,6 +229,24 @@ test "single" { ); } +test "strikethrough" { + const testing = std.testing; + const alloc = testing.allocator; + + var atlas_greyscale = try font.Atlas.init(alloc, 512, .greyscale); + defer atlas_greyscale.deinit(alloc); + + _ = try renderGlyph( + alloc, + &atlas_greyscale, + .strikethrough, + 36, + 18, + 9, + 2, + ); +} + test "single large thickness" { const testing = std.testing; const alloc = testing.allocator; diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index f525f986a..1476b90c1 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -1914,13 +1914,36 @@ fn updateCell( } if (style.flags.strikethrough) { + const render = try self.font_grid.renderGlyph( + self.alloc, + font.sprite_index, + @intFromEnum(font.Sprite.strikethrough), + .{ + .cell_width = if (cell.wide == .wide) 2 else 1, + .grid_metrics = self.grid_metrics, + }, + ); + + const color = style.underlineColor(palette) orelse colors.fg; + self.cells.appendAssumeCapacity(.{ - .mode = .strikethrough, + .mode = .fg, .grid_pos = .{ @as(f32, @floatFromInt(x)), @as(f32, @floatFromInt(y)) }, .cell_width = cell.gridWidth(), - .color = .{ colors.fg.r, colors.fg.g, colors.fg.b, alpha }, + .color = .{ color.r, color.g, color.b, alpha }, .bg_color = bg, + .glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y }, + .glyph_size = .{ render.glyph.width, render.glyph.height }, + .glyph_offset = .{ render.glyph.offset_x, render.glyph.offset_y }, }); + + // self.cells.appendAssumeCapacity(.{ + // .mode = .strikethrough, + // .grid_pos = .{ @as(f32, @floatFromInt(x)), @as(f32, @floatFromInt(y)) }, + // .cell_width = cell.gridWidth(), + // .color = .{ colors.fg.r, colors.fg.g, colors.fg.b, alpha }, + // .bg_color = bg, + // }); } return true;