c6a25e27
Add Atlas.reset and Face.reinit for scale changes
a73x 2026-04-09 10:19
Atlas.reset() zeroes pixel memory, restores the cursor-white pixel at (0,0), rewinds packing cursors, clears the glyph cache, and marks the atlas dirty. Face.reinit() replaces the underlying FT_Face at a new px_size without re-creating the FT_Library. These are the primitives Task 5/6 need to rebuild rasterization when the wl_surface buffer scale changes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
diff --git a/src/font.zig b/src/font.zig index fe1cde6..89f3001 100644 --- a/src/font.zig +++ b/src/font.zig @@ -85,6 +85,25 @@ pub const Face = struct { _ = c.FT_Done_FreeType(self.library); } pub fn reinit( self: *Face, path: [:0]const u8, index: c_int, px_size: u32, ) !void { _ = c.FT_Done_Face(self.face); self.face = null; var new_face: c.FT_Face = null; if (c.FT_New_Face(self.library, path.ptr, index, &new_face) != 0) return error.FtNewFaceFailed; errdefer _ = c.FT_Done_Face(new_face); if (c.FT_Set_Pixel_Sizes(new_face, 0, px_size) != 0) return error.FtSetPixelSizesFailed; self.face = new_face; self.px_size = px_size; } pub fn rasterize(self: *Face, codepoint: u21) !Glyph { const glyph_index = c.FT_Get_Char_Index(self.face, codepoint); if (c.FT_Load_Glyph(self.face, glyph_index, c.FT_LOAD_RENDER) != 0) { @@ -191,6 +210,16 @@ pub const Atlas = struct { self.cache.deinit(); } pub fn reset(self: *Atlas) void { @memset(self.pixels, 0); self.pixels[0] = 255; self.cursor_x = 1; self.cursor_y = 0; self.row_height = 1; self.cache.clearRetainingCapacity(); self.dirty = true; } pub fn cursorUV(self: *const Atlas) GlyphUV { return .{ .u0 = 0, @@ -301,3 +330,39 @@ test "Atlas reserves a white pixel for cursor rendering" { try std.testing.expectEqual(@as(f32, 0), uv.u0); try std.testing.expectEqual(@as(f32, 0), uv.v0); } test "Atlas.reset clears cache and starts fresh" { var lookup = try lookupConfiguredFont(std.testing.allocator); defer lookup.deinit(std.testing.allocator); var face = try Face.init(std.testing.allocator, lookup.path, lookup.index, 14); defer face.deinit(); var atlas = try Atlas.init(std.testing.allocator, 256, 256); defer atlas.deinit(); _ = try atlas.getOrInsert(&face, 'A'); try std.testing.expect(atlas.cache.count() > 0); atlas.reset(); try std.testing.expectEqual(@as(u32, 0), atlas.cache.count()); try std.testing.expectEqual(@as(u8, 255), atlas.pixels[0]); try std.testing.expect(atlas.dirty); // Re-inserting the same glyph should succeed after reset. _ = try atlas.getOrInsert(&face, 'A'); } test "Face.reinit switches px_size and produces different cell metrics" { var lookup = try lookupConfiguredFont(std.testing.allocator); defer lookup.deinit(std.testing.allocator); var face = try Face.init(std.testing.allocator, lookup.path, lookup.index, 14); defer face.deinit(); const small_cell = face.cellWidth(); try face.reinit(lookup.path, lookup.index, 28); const large_cell = face.cellWidth(); try std.testing.expect(large_cell > small_cell); }