From 0f19251aa6bc494a173af3077aaaa85714fe1a1e Mon Sep 17 00:00:00 2001 From: em-dash <33614480+em-dash@users.noreply.github.com> Date: Sat, 24 Feb 2024 20:49:51 +1100 Subject: [PATCH 1/3] fix crash in underline drawing math --- src/font/sprite/underline.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/font/sprite/underline.zig b/src/font/sprite/underline.zig index 55a29d80c..163a8fb78 100644 --- a/src/font/sprite/underline.zig +++ b/src/font/sprite/underline.zig @@ -80,7 +80,7 @@ const Draw = struct { // Ensure we never overflow out of bounds on the canvas const y_max = self.height -| 1; const bottom = @min(self.pos + self.thickness, y_max); - const y = @as(i32, @intCast(bottom - self.thickness)); + const y = @as(i32, @intCast(bottom)) - @as(i32, @intCast(self.thickness)); canvas.rect(.{ .x = 0, From 759c8cddb4f705902762cf8efdbda8522eefc78d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 24 Feb 2024 09:30:04 -0800 Subject: [PATCH 2/3] font/sprite: test for thick underline, assertion on x/y for rect --- src/font/sprite/canvas.zig | 3 +++ src/font/sprite/underline.zig | 22 +++++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/font/sprite/canvas.zig b/src/font/sprite/canvas.zig index 83d924008..5f869ae98 100644 --- a/src/font/sprite/canvas.zig +++ b/src/font/sprite/canvas.zig @@ -424,6 +424,9 @@ const PixmanImpl = struct { /// Draw and fill a rectangle. This is the main primitive for drawing /// lines as well (which are just generally skinny rectangles...) pub fn rect(self: *Canvas, v: Rect, color: Color) void { + assert(v.x >= 0); + assert(v.y >= 0); + const boxes = &[_]pixman.Box32{ .{ .x1 = @intCast(v.x), diff --git a/src/font/sprite/underline.zig b/src/font/sprite/underline.zig index 163a8fb78..64859b0a6 100644 --- a/src/font/sprite/underline.zig +++ b/src/font/sprite/underline.zig @@ -80,7 +80,7 @@ const Draw = struct { // Ensure we never overflow out of bounds on the canvas const y_max = self.height -| 1; const bottom = @min(self.pos + self.thickness, y_max); - const y = @as(i32, @intCast(bottom)) - @as(i32, @intCast(self.thickness)); + const y = @as(i32, @intCast(bottom -| self.thickness)); canvas.rect(.{ .x = 0, @@ -224,6 +224,26 @@ test "single" { ); } +test "single large thickness" { + const testing = std.testing; + const alloc = testing.allocator; + + var atlas_greyscale = try font.Atlas.init(alloc, 512, .greyscale); + defer atlas_greyscale.deinit(alloc); + + // unrealistic thickness but used to cause a crash + // https://github.com/mitchellh/ghostty/pull/1548 + _ = try renderGlyph( + alloc, + &atlas_greyscale, + .underline, + 36, + 18, + 9, + 200, + ); +} + test "curly" { const testing = std.testing; const alloc = testing.allocator; From 796d1312ff2732c53b0872cdefec0ab0eb634000 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 24 Feb 2024 13:19:49 -0800 Subject: [PATCH 3/3] font/sprite: rect must be smaller than canvas dims --- src/font/sprite/canvas.zig | 7 ++++--- src/font/sprite/underline.zig | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/font/sprite/canvas.zig b/src/font/sprite/canvas.zig index 5f869ae98..e7072f56a 100644 --- a/src/font/sprite/canvas.zig +++ b/src/font/sprite/canvas.zig @@ -424,9 +424,6 @@ const PixmanImpl = struct { /// Draw and fill a rectangle. This is the main primitive for drawing /// lines as well (which are just generally skinny rectangles...) pub fn rect(self: *Canvas, v: Rect, color: Color) void { - assert(v.x >= 0); - assert(v.y >= 0); - const boxes = &[_]pixman.Box32{ .{ .x1 = @intCast(v.x), @@ -436,6 +433,10 @@ const PixmanImpl = struct { }, }; + assert(boxes[0].x1 >= 0); + assert(boxes[0].y1 >= 0); + assert(boxes[0].x2 <= @as(i32, @intCast(self.image.getWidth()))); + assert(boxes[0].y2 <= @as(i32, @intCast(self.image.getHeight()))); self.image.fillBoxes(.src, color.pixmanColor(), boxes) catch {}; } diff --git a/src/font/sprite/underline.zig b/src/font/sprite/underline.zig index 64859b0a6..064efc74f 100644 --- a/src/font/sprite/underline.zig +++ b/src/font/sprite/underline.zig @@ -80,13 +80,14 @@ const Draw = struct { // Ensure we never overflow out of bounds on the canvas const y_max = self.height -| 1; const bottom = @min(self.pos + self.thickness, y_max); - const y = @as(i32, @intCast(bottom -| self.thickness)); + const y = bottom -| self.thickness; + const max_height = self.height - y; canvas.rect(.{ .x = 0, - .y = y, + .y = @intCast(y), .width = self.width, - .height = self.thickness, + .height = @min(self.thickness, max_height), }, .on); }