diff --git a/src/font/SharedGrid.zig b/src/font/SharedGrid.zig index bfb8f411f..f69a474fb 100644 --- a/src/font/SharedGrid.zig +++ b/src/font/SharedGrid.zig @@ -9,6 +9,13 @@ //! reads well. Going even further, the font subsystem should be very rarely //! read at all since it should only be necessary when the grid actively //! changes. +//! +//! SharedGrid does NOT support resizing, font-family changes, font removals +//! in collections, etc. Because the Grid is shared this would cause a +//! major disruption in the rendering of multiple surfaces (i.e. increasing +//! the font size in one would increase it in all). In many cases this isn't +//! desirable so to implement configuration changes the grid should be +//! reinitialized and all surfaces should switch over to using that one. const SharedGrid = @This(); // TODO(fontmem): @@ -21,7 +28,9 @@ const font = @import("main.zig"); const Atlas = font.Atlas; const CodepointResolver = font.CodepointResolver; const Collection = font.Collection; +const Face = font.Face; const Glyph = font.Glyph; +const Library = font.Library; const Metrics = font.face.Metrics; const Presentation = font.Presentation; const Style = font.Style; @@ -48,6 +57,18 @@ resolver: CodepointResolver, /// This is calculated based on the resolver and current fonts. metrics: Metrics, +/// The RwLock used to protect the shared grid. +lock: std.Thread.RwLock, + +/// Initialize the grid. +/// +/// The resolver must have a collection that supports deferred loading +/// (collection.load_options != null). This is because we need the load +/// options data to determine grid metrics and setup our sprite font. +/// +/// SharedGrid always configures the sprite font. This struct is expected to be +/// used with a terminal grid and therefore the sprite font is always +/// necessary for correct rendering. pub fn init( alloc: Allocator, resolver: CodepointResolver, @@ -65,6 +86,8 @@ pub fn init( .resolver = resolver, .atlas_greyscale = atlas_greyscale, .atlas_color = atlas_color, + .lock = .{}, + .metrics = undefined, // Loaded below }; // We set an initial capacity that can fit a good number of characters. @@ -78,6 +101,7 @@ pub fn init( return result; } +/// Deinit. Assumes no concurrent access so no lock is taken. pub fn deinit(self: *SharedGrid, alloc: Allocator) void { self.codepoints.deinit(alloc); self.glyphs.deinit(alloc); @@ -118,3 +142,57 @@ const GlyphKey = struct { glyph: u32, opts: RenderOptions, }; + +const TestMode = enum { normal }; + +fn testGrid(mode: TestMode, alloc: Allocator, lib: Library) !SharedGrid { + const testFont = @import("test.zig").fontRegular; + + var c = try Collection.init(alloc); + c.load_options = .{ .library = lib }; + + switch (mode) { + .normal => { + _ = try c.add(alloc, .regular, .{ .loaded = try Face.init( + lib, + testFont, + .{ .size = .{ .points = 12, .xdpi = 96, .ydpi = 96 } }, + ) }); + }, + } + + var r: CodepointResolver = .{ .collection = c }; + errdefer r.deinit(alloc); + + return try init(alloc, r, false); +} + +test "SharedGrid inits metrics" { + const testing = std.testing; + const alloc = testing.allocator; + // const testEmoji = @import("test.zig").fontEmoji; + + var lib = try Library.init(); + defer lib.deinit(); + + var grid = try testGrid(.normal, alloc, lib); + defer grid.deinit(alloc); + + // Visible ASCII. Do it twice to verify cache is used. + // var i: u32 = 32; + // while (i < 127) : (i += 1) { + // const idx = (try cache.indexForCodepoint(alloc, i, .regular, null)).?; + // try testing.expectEqual(Style.regular, idx.style); + // try testing.expectEqual(@as(Group.FontIndex.IndexInt, 0), idx.idx); + // + // // Render + // const face = try cache.group.faceFromIndex(idx); + // const glyph_index = face.glyphIndex(i).?; + // _ = try cache.renderGlyph( + // alloc, + // idx, + // glyph_index, + // .{}, + // ); + // } +}