diff --git a/pkg/macos/foundation/string.zig b/pkg/macos/foundation/string.zig index 2f679fef4..3d1c5c05c 100644 --- a/pkg/macos/foundation/string.zig +++ b/pkg/macos/foundation/string.zig @@ -21,13 +21,13 @@ pub const String = opaque { pub fn createWithCharactersNoCopy( unichars: []const u16, - ) *String { - return @as(*String, @ptrFromInt(@intFromPtr(c.CFStringCreateWithCharactersNoCopy( + ) Allocator.Error!*String { + return @ptrCast(@constCast(c.CFStringCreateWithCharactersNoCopy( null, @ptrCast(unichars.ptr), @intCast(unichars.len), foundation.c.kCFAllocatorNull, - )))); + ) orelse return error.OutOfMemory)); } pub fn release(self: *String) void { diff --git a/pkg/macos/text/typesetter.zig b/pkg/macos/text/typesetter.zig index dc07df980..16cd78169 100644 --- a/pkg/macos/text/typesetter.zig +++ b/pkg/macos/text/typesetter.zig @@ -27,10 +27,10 @@ pub const Typesetter = opaque { pub fn createLine( self: *Typesetter, range: foundation.c.CFRange, - ) *text.Line { - return @ptrFromInt(@intFromPtr(c.CTTypesetterCreateLine( + ) Allocator.Error!*text.Line { + return @ptrCast(@constCast(c.CTTypesetterCreateLine( @ptrCast(self), range, - ))); + ) orelse return error.OutOfMemory)); } }; diff --git a/src/font/shaper/coretext.zig b/src/font/shaper/coretext.zig index 27da357a7..5172744d8 100644 --- a/src/font/shaper/coretext.zig +++ b/src/font/shaper/coretext.zig @@ -361,7 +361,7 @@ pub const Shaper = struct { // Make room for the attributed string, CTTypesetter, and CTLine. try self.cf_release_pool.ensureUnusedCapacity(self.alloc, 4); - const str = macos.foundation.String.createWithCharactersNoCopy(state.unichars.items); + const str = try macos.foundation.String.createWithCharactersNoCopy(state.unichars.items); self.cf_release_pool.appendAssumeCapacity(str); // Create an attributed string from our string @@ -381,7 +381,7 @@ pub const Shaper = struct { self.cf_release_pool.appendAssumeCapacity(typesetter); // Create a line from the typesetter - const line = typesetter.createLine(.{ .location = 0, .length = 0 }); + const line = try typesetter.createLine(.{ .location = 0, .length = 0 }); self.cf_release_pool.appendAssumeCapacity(line); // This keeps track of the current x offset (sum of advance.width) and diff --git a/src/renderer/generic.zig b/src/renderer/generic.zig index 2882c9c8e..1337c5154 100644 --- a/src/renderer/generic.zig +++ b/src/renderer/generic.zig @@ -1146,6 +1146,11 @@ pub fn Renderer(comptime GraphicsAPI: type) type { state: *renderer.State, cursor_blink_visible: bool, ) Allocator.Error!void { + // CoreText shaping accumulates objects for deferred release over + // the course of a frame. Always flush those objects, including + // when rebuilding the frame fails due to memory pressure. + defer self.font_shaper.endFrame(); + // We fully deinit and reset the terminal state every so often // so that a particularly large terminal state doesn't cause // the renderer to hold on to retained memory. @@ -1444,10 +1449,6 @@ pub fn Renderer(comptime GraphicsAPI: type) type { // Update custom shader uniforms that depend on terminal state. self.updateCustomShaderUniformsFromState(); } - - // Notify our shaper we're done for the frame. For some shapers, - // such as CoreText, this triggers off-thread cleanup logic. - self.font_shaper.endFrame(); } /// Draw the frame to the screen.