From 077dad11b4583085400fe3dd76dc5a783b6603e5 Mon Sep 17 00:00:00 2001 From: Qwerasd Date: Sat, 21 Dec 2024 20:15:32 -0500 Subject: [PATCH 1/4] font: add `cursor-height` metric, and `adjust-` config for it. --- src/config/Config.zig | 12 +++++++----- src/font/SharedGridSet.zig | 3 +++ src/font/face/Metrics.zig | 18 +++++++++++------- src/font/sprite/Face.zig | 21 ++++++--------------- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/config/Config.zig b/src/config/Config.zig index 720c1f3052..110ff2bc15 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -241,16 +241,15 @@ const c = @cImport({ /// `-100%`) can cause the terminal to be unusable. Use with caution and reason. /// /// Some values are clamped to minimum or maximum values. This can make it -/// appear that certain values are ignored. For example, the underline position -/// is clamped to the height of a cell. If you set the underline position so -/// high that it extends beyond the bottom of the cell size, it will be clamped -/// to the bottom of the cell. +/// appear that certain values are ignored. For example, many `*-thickness` +/// adjustments cannot go below 1px. /// /// `adjust-cell-height` has some additional behaviors to describe: /// /// * The font will be centered vertically in the cell. /// -/// * The cursor will remain the same size as the font. +/// * The cursor will remain the same size as the font, but may be +/// adjusted separately with `adjust-cursor-height`. /// /// * Powerline glyphs will be adjusted along with the cell height so /// that things like status lines continue to look aligned. @@ -276,6 +275,9 @@ const c = @cImport({ @"adjust-overline-thickness": ?MetricModifier = null, /// Thickness in pixels of the bar cursor and outlined rect cursor. @"adjust-cursor-thickness": ?MetricModifier = null, +/// Height in pixels of the cursor. Currently applies to all cursor types: +/// bar, rect, and outlined rect. +@"adjust-cursor-height": ?MetricModifier = null, /// Thickness in pixels of box drawing characters. @"adjust-box-thickness": ?MetricModifier = null, diff --git a/src/font/SharedGridSet.zig b/src/font/SharedGridSet.zig index 2f25ec5214..95ef02495e 100644 --- a/src/font/SharedGridSet.zig +++ b/src/font/SharedGridSet.zig @@ -430,6 +430,7 @@ pub const DerivedConfig = struct { @"adjust-overline-position": ?Metrics.Modifier, @"adjust-overline-thickness": ?Metrics.Modifier, @"adjust-cursor-thickness": ?Metrics.Modifier, + @"adjust-cursor-height": ?Metrics.Modifier, @"adjust-box-thickness": ?Metrics.Modifier, @"freetype-load-flags": font.face.FreetypeLoadFlags, @@ -468,6 +469,7 @@ pub const DerivedConfig = struct { .@"adjust-overline-position" = config.@"adjust-overline-position", .@"adjust-overline-thickness" = config.@"adjust-overline-thickness", .@"adjust-cursor-thickness" = config.@"adjust-cursor-thickness", + .@"adjust-cursor-height" = config.@"adjust-cursor-height", .@"adjust-box-thickness" = config.@"adjust-box-thickness", .@"freetype-load-flags" = if (font.face.FreetypeLoadFlags != void) config.@"freetype-load-flags" else {}, @@ -613,6 +615,7 @@ pub const Key = struct { if (config.@"adjust-overline-position") |m| try set.put(alloc, .overline_position, m); if (config.@"adjust-overline-thickness") |m| try set.put(alloc, .overline_thickness, m); if (config.@"adjust-cursor-thickness") |m| try set.put(alloc, .cursor_thickness, m); + if (config.@"adjust-cursor-height") |m| try set.put(alloc, .cursor_height, m); if (config.@"adjust-box-thickness") |m| try set.put(alloc, .box_thickness, m); break :set set; }; diff --git a/src/font/face/Metrics.zig b/src/font/face/Metrics.zig index d6b1bdd0c7..2ee563bf73 100644 --- a/src/font/face/Metrics.zig +++ b/src/font/face/Metrics.zig @@ -32,10 +32,12 @@ box_thickness: u32, /// because it is not determined by fonts but rather by user configuration. cursor_thickness: u32 = 1, -/// Original cell width and height. These are used to render the cursor -/// in the original cell size after modification. +/// The height in pixels of the cursor sprite. +cursor_height: u32, + +/// Original cell width in pixels. This is used to keep +/// glyphs centered if the cell width is adjusted wider. original_cell_width: ?u32 = null, -original_cell_height: ?u32 = null, /// Minimum acceptable values for some fields to prevent modifiers /// from being able to, for example, cause 0-thickness underlines. @@ -47,6 +49,7 @@ const Minimums = struct { const overline_thickness = 1; const box_thickness = 1; const cursor_thickness = 1; + const cursor_height = 1; }; const CalcOpts = struct { @@ -167,6 +170,7 @@ pub fn calc(opts: CalcOpts) Metrics { .overline_position = 0, .overline_thickness = @intFromFloat(underline_thickness), .box_thickness = @intFromFloat(underline_thickness), + .cursor_height = @intFromFloat(cell_height), }; // Ensure all metrics are within their allowable range. @@ -192,10 +196,9 @@ pub fn apply(self: *Metrics, mods: ModifierSet) void { const new = @max(entry.value_ptr.apply(original), 1); if (new == original) continue; - // Preserve the original cell width and height if not set. + // Preserve the original cell width if not set. if (self.original_cell_width == null) { self.original_cell_width = self.cell_width; - self.original_cell_height = self.cell_height; } // Set the new value @@ -410,6 +413,7 @@ fn init() Metrics { .overline_position = 0, .overline_thickness = 0, .box_thickness = 0, + .cursor_height = 0, }; } @@ -445,7 +449,7 @@ test "Metrics: adjust cell height smaller" { try testing.expectEqual(@as(u32, 25), m.cell_baseline); try testing.expectEqual(@as(u32, 30), m.underline_position); try testing.expectEqual(@as(u32, 5), m.strikethrough_position); - try testing.expectEqual(@as(u32, 100), m.original_cell_height.?); + try testing.expectEqual(@as(u32, 100), m.cursor_height); } test "Metrics: adjust cell height larger" { @@ -466,7 +470,7 @@ test "Metrics: adjust cell height larger" { try testing.expectEqual(@as(u32, 100), m.cell_baseline); try testing.expectEqual(@as(u32, 105), m.underline_position); try testing.expectEqual(@as(u32, 80), m.strikethrough_position); - try testing.expectEqual(@as(u32, 100), m.original_cell_height.?); + try testing.expectEqual(@as(u32, 100), m.cursor_height); } test "Modifier: parse absolute" { diff --git a/src/font/sprite/Face.zig b/src/font/sprite/Face.zig index ede67d00d9..2915ea5f1d 100644 --- a/src/font/sprite/Face.zig +++ b/src/font/sprite/Face.zig @@ -126,29 +126,20 @@ pub fn renderGlyph( }, .cursor => cursor: { - // Cursors should be drawn with the original cell height if - // it has been adjusted larger, so they don't get stretched. - const height, const dy = adjust: { - const h = metrics.cell_height; - if (metrics.original_cell_height) |original| { - if (h > original) { - break :adjust .{ original, (h - original) / 2 }; - } - } - break :adjust .{ h, 0 }; - }; - var g = try cursor.renderGlyph( alloc, atlas, @enumFromInt(cp), width, - height, + metrics.cursor_height, metrics.cursor_thickness, ); - // Keep the cursor centered in the cell if it's shorter. - g.offset_y += @intCast(dy); + // Cursors are drawn at their specified height + // and are centered vertically within the cell. + const cursor_height: i32 = @intCast(metrics.cursor_height); + const cell_height: i32 = @intCast(metrics.cell_height); + g.offset_y += @divTrunc(cell_height - cursor_height, 2); break :cursor g; }, From 08ebb6b64d048f3d3c50f2ebb513cdfcc5f53b66 Mon Sep 17 00:00:00 2001 From: Qwerasd Date: Sun, 22 Dec 2024 12:34:43 -0500 Subject: [PATCH 2/4] fix tests for freetype to include cursor_height metric --- src/font/face/freetype.zig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/font/face/freetype.zig b/src/font/face/freetype.zig index f5ec9e7ec1..bc503a3afb 100644 --- a/src/font/face/freetype.zig +++ b/src/font/face/freetype.zig @@ -906,6 +906,7 @@ test "color emoji" { .overline_position = 0, .overline_thickness = 0, .box_thickness = 0, + .cursor_height = 0, }, }); try testing.expectEqual(@as(u32, 24), glyph.height); @@ -952,6 +953,7 @@ test "metrics" { .overline_position = 0, .overline_thickness = 1, .box_thickness = 1, + .cursor_height = 17, }, ft_font.metrics); // Resize should change metrics @@ -967,6 +969,7 @@ test "metrics" { .overline_position = 0, .overline_thickness = 2, .box_thickness = 2, + .cursor_height = 34, }, ft_font.metrics); } From d624db30c6ff5fc7acbc98f0db8bb26fdc66adbc Mon Sep 17 00:00:00 2001 From: Qwerasd Date: Sun, 22 Dec 2024 12:38:17 -0500 Subject: [PATCH 3/4] test(metrics): fix to initialize cursor height + add comment --- src/font/face/Metrics.zig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/font/face/Metrics.zig b/src/font/face/Metrics.zig index 2ee563bf73..7bc4566294 100644 --- a/src/font/face/Metrics.zig +++ b/src/font/face/Metrics.zig @@ -444,11 +444,13 @@ test "Metrics: adjust cell height smaller" { m.underline_position = 55; m.strikethrough_position = 30; m.cell_height = 100; + m.cursor_height = 100; m.apply(set); try testing.expectEqual(@as(u32, 50), m.cell_height); try testing.expectEqual(@as(u32, 25), m.cell_baseline); try testing.expectEqual(@as(u32, 30), m.underline_position); try testing.expectEqual(@as(u32, 5), m.strikethrough_position); + // Cursor height is separate from cell height and does not follow it. try testing.expectEqual(@as(u32, 100), m.cursor_height); } @@ -465,11 +467,13 @@ test "Metrics: adjust cell height larger" { m.underline_position = 55; m.strikethrough_position = 30; m.cell_height = 100; + m.cursor_height = 100; m.apply(set); try testing.expectEqual(@as(u32, 200), m.cell_height); try testing.expectEqual(@as(u32, 100), m.cell_baseline); try testing.expectEqual(@as(u32, 105), m.underline_position); try testing.expectEqual(@as(u32, 80), m.strikethrough_position); + // Cursor height is separate from cell height and does not follow it. try testing.expectEqual(@as(u32, 100), m.cursor_height); } From 3b6d8f3175badf13cdeb52cfe7509f58b96e5fbc Mon Sep 17 00:00:00 2001 From: Qwerasd Date: Sun, 22 Dec 2024 12:52:04 -0500 Subject: [PATCH 4/4] fix tests for coretext to include cursor_height --- src/font/face/coretext.zig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/font/face/coretext.zig b/src/font/face/coretext.zig index 885ea277e9..92ab4d396a 100644 --- a/src/font/face/coretext.zig +++ b/src/font/face/coretext.zig @@ -1045,6 +1045,7 @@ test "coretext: metrics" { .overline_position = 0, .overline_thickness = 1, .box_thickness = 1, + .cursor_height = 17, }, ct_font.metrics); // Resize should change metrics @@ -1060,5 +1061,6 @@ test "coretext: metrics" { .overline_position = 0, .overline_thickness = 2, .box_thickness = 2, + .cursor_height = 34, }, ct_font.metrics); }