summaryrefslogtreecommitdiff
path: root/src/gui/gui.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/gui.zig')
-rw-r--r--src/gui/gui.zig46
1 files changed, 21 insertions, 25 deletions
diff --git a/src/gui/gui.zig b/src/gui/gui.zig
index 48087d0b..7ad9fe9a 100644
--- a/src/gui/gui.zig
+++ b/src/gui/gui.zig
@@ -253,7 +253,7 @@ test "FreeType atlas raster is grayscale, bounded, and clears blank cells" {
var bitmap: [128 * 128]u8 = @splat(0xaa);
try std.testing.expectEqual(
@as(c_int, 1),
- c.ui_font_raster(font, size, 'H', &bitmap, stride, cell_w, cell_h, ascent),
+ c.ui_font_raster(font, size, 'H', 0, &bitmap, stride, cell_w, cell_h, ascent),
);
var ink: usize = 0;
@@ -269,7 +269,11 @@ test "FreeType atlas raster is grayscale, bounded, and clears blank cells" {
}
try std.testing.expect(ink > 0);
try std.testing.expect(soft > 0);
- decorateGlyph(&bitmap, @intCast(stride), @intCast(cell_w), @intCast(cell_h), ascent, .{ .bold = true });
+ // Synthetic bold thickens the outline inside the same cell.
+ try std.testing.expectEqual(
+ @as(c_int, 1),
+ c.ui_font_raster(font, size, 'H', 1, &bitmap, stride, cell_w, cell_h, ascent),
+ );
var bold_coverage: usize = 0;
for (0..@intCast(cell_h)) |y| {
for (0..@intCast(cell_w)) |x| bold_coverage += bitmap[y * @as(usize, @intCast(stride)) + x];
@@ -280,7 +284,7 @@ test "FreeType atlas raster is grayscale, bounded, and clears blank cells" {
try std.testing.expectEqual(
@as(c_int, 0),
- c.ui_font_raster(font, size, ' ', &bitmap, stride, cell_w, cell_h, ascent),
+ c.ui_font_raster(font, size, ' ', 0, &bitmap, stride, cell_w, cell_h, ascent),
);
for (0..@intCast(cell_h)) |y|
for (0..@intCast(cell_w)) |x|
@@ -326,6 +330,7 @@ test "tagline glyph shrinks into its own cell and stays vertically centered" {
font,
body_scale,
'H',
+ 0,
&body,
stride,
cell_w,
@@ -336,6 +341,7 @@ test "tagline glyph shrinks into its own cell and stays vertically centered" {
font,
tag.scale,
'H',
+ 0,
&tagline,
stride,
@intCast(tag.width),
@@ -2311,7 +2317,7 @@ fn runNative(init: std.process.Init, opts_in: pardes.Options, attach: ?[]const u
defer if (g.font_bytes.len != 0) gpa.free(g.font_bytes); // set by Font, if it ran
defer c.ui_font_free(g.font);
defer gpa.free(g.scroll_edge); // grown on demand by stepScroll
- _ = c.ui_font_raster(font, scale, ' ', atlas_stage.ptr, @intCast(atlas_w), @intCast(cell_w), @intCast(cell_h), asc);
+ _ = c.ui_font_raster(font, scale, ' ', 0, atlas_stage.ptr, @intCast(atlas_w), @intCast(cell_w), @intCast(cell_h), asc);
g.pen_x = cell_w;
if (attach) |requested| return attachRequested(gpa, &g, requested);
@@ -5896,7 +5902,7 @@ fn refitFont(g: *Gui, core: ?*pardes.Pardes) void {
fn resetGlyphAtlas(g: *Gui) void {
g.glyphs.clearRetainingCapacity();
@memset(g.atlas_stage, 0);
- _ = c.ui_font_raster(g.font, g.scale, ' ', g.atlas_stage.ptr, @intCast(atlas_w), @intCast(g.cell_w), @intCast(g.cell_h), g.ascent);
+ _ = c.ui_font_raster(g.font, g.scale, ' ', 0, g.atlas_stage.ptr, @intCast(atlas_w), @intCast(g.cell_w), @intCast(g.cell_h), g.ascent);
g.space_slot = .{ .u = 0, .v = 0 };
g.pen_x = g.cell_w;
g.pen_y = 0;
@@ -5938,11 +5944,11 @@ fn cachedGlyph(g: *Gui, cp: u32, role: pardes.FontRole, decoration: GlyphDecorat
const raster_w = if (centered) slot_w else if (role == .tagline) g.tagline_width else g.cell_w;
const raster_h = if (role == .tagline) g.tagline_height else g.cell_h;
if (centered) {
- _ = c.ui_font_raster_centered(face, scale, @intCast(cp), out, @intCast(atlas_w), @intCast(raster_w), @intCast(raster_h));
+ _ = c.ui_font_raster_centered(face, scale, @intCast(cp), @intFromBool(decoration.bold), out, @intCast(atlas_w), @intCast(raster_w), @intCast(raster_h));
} else {
- _ = c.ui_font_raster(face, scale, @intCast(cp), out, @intCast(atlas_w), @intCast(raster_w), @intCast(raster_h), baseline);
+ _ = c.ui_font_raster(face, scale, @intCast(cp), @intFromBool(decoration.bold), out, @intCast(atlas_w), @intCast(raster_w), @intCast(raster_h), baseline);
}
- decorateGlyph(out, atlas_w, raster_w, raster_h, baseline, decoration);
+ decorateLine(out, atlas_w, raster_w, raster_h, baseline, decoration);
if (centered) centerGlyphInk(out, raster_w, raster_h);
g.glyphs.put(key, s) catch return null;
g.pen_x += slot_w;
@@ -6056,23 +6062,13 @@ test "pane indicator halves share dissolve changes and safe exhausted atlas" {
}
}
-// Decorations stay inside the existing atlas slot, so text advance, caret and
-// selection geometry are identical to the regular glyph. The cached mask keeps
-// this work out of steady-state rendering and also decorates terminal spaces.
-fn decorateGlyph(out: [*]u8, stride: usize, width: usize, height: usize, baseline: i32, decoration: GlyphDecoration) void {
+// Underline and strikethrough stay inside the existing atlas slot, so text
+// advance, caret and selection geometry are identical to the regular glyph.
+// The cached mask keeps this work out of steady-state rendering and also
+// decorates terminal spaces. Bold is not drawn here: the rasterizer emboldens
+// the outline.
+fn decorateLine(out: [*]u8, stride: usize, width: usize, height: usize, baseline: i32, decoration: GlyphDecoration) void {
if (width == 0 or height == 0) return;
- if (decoration.bold) {
- // A fractional one-pixel embolden preserves counters at small UI sizes.
- // Right-to-left traversal reads the original left neighbour each time.
- for (0..height) |y| {
- var x = width - 1;
- while (x > 0) : (x -= 1) {
- const previous = out[y * stride + x - 1];
- const target = &out[y * stride + x];
- target.* = @max(target.*, @as(u8, @intCast(@as(u16, previous) * 3 / 4)));
- }
- }
- }
if (decoration.underline != .off) {
const base: usize = @intCast(@max(0, baseline));
const row = @min(base + 1, height - 1);
@@ -6115,7 +6111,7 @@ test "glyph decorations render spaces and stay inside their atlas slot" {
}) |decoration| {
var mask: [stride * (height + 1)]u8 = @splat(0xa5);
for (0..height) |y| @memset(mask[y * stride ..][0..width], 0);
- decorateGlyph(&mask, stride, width, height, 5, decoration);
+ decorateLine(&mask, stride, width, height, 5, decoration);
try std.testing.expect(inkBounds(&mask, stride, width, height) != null);
for (0..height) |y| for (mask[y * stride + width ..][0 .. stride - width]) |guard|
try std.testing.expectEqual(@as(u8, 0xa5), guard);