diff options
Diffstat (limited to 'src/gui/gui.zig')
| -rw-r--r-- | src/gui/gui.zig | 46 |
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); |
