mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
font: coretext shaper owns the cf release pool
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const macos = @import("macos");
|
||||
@ -49,13 +50,18 @@ pub const Shaper = struct {
|
||||
/// and releasing many objects when shaping.
|
||||
writing_direction: *macos.foundation.Array,
|
||||
|
||||
/// List where we cache fonts, so we don't have to
|
||||
/// remake them for every single shaping operation.
|
||||
/// List where we cache fonts, so we don't have to remake them for
|
||||
/// every single shaping operation.
|
||||
///
|
||||
/// Fonts are cached as attribute dictionaries to
|
||||
/// be applied directly to attributed strings.
|
||||
/// Fonts are cached as attribute dictionaries to be applied directly to
|
||||
/// attributed strings.
|
||||
cached_fonts: std.ArrayList(?*macos.foundation.Dictionary),
|
||||
|
||||
/// The list of CoreFoundation objects to release on the dedicated
|
||||
/// release thread. This is built up over the course of shaping and
|
||||
/// sent to the release thread when endFrame is called.
|
||||
cf_release_pool: std.ArrayListUnmanaged(*anyopaque),
|
||||
|
||||
const CellBuf = std.ArrayListUnmanaged(font.shape.Cell);
|
||||
const CodepointList = std.ArrayListUnmanaged(Codepoint);
|
||||
const Codepoint = struct {
|
||||
@ -209,13 +215,14 @@ pub const Shaper = struct {
|
||||
const cached_fonts = std.ArrayList(?*macos.foundation.Dictionary).init(alloc);
|
||||
errdefer cached_fonts.deinit();
|
||||
|
||||
return Shaper{
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
.cell_buf = .{},
|
||||
.run_state = run_state,
|
||||
.features = feats,
|
||||
.writing_direction = writing_direction,
|
||||
.cached_fonts = cached_fonts,
|
||||
.cf_release_pool = .{},
|
||||
};
|
||||
}
|
||||
|
||||
@ -227,6 +234,19 @@ pub const Shaper = struct {
|
||||
|
||||
self.releaseCachedFonts();
|
||||
self.cached_fonts.deinit();
|
||||
|
||||
if (self.cf_release_pool.items.len > 0) {
|
||||
for (self.cf_release_pool.items) |ref| macos.foundation.CFRelease(ref);
|
||||
|
||||
// For tests this logic is normal because we don't want to
|
||||
// wait for a release thread. But in production this is a bug
|
||||
// and we should warn.
|
||||
if (comptime !builtin.is_test) log.warn(
|
||||
"BUG: CFRelease pool was not empty, releasing remaining objects",
|
||||
.{},
|
||||
);
|
||||
}
|
||||
self.cf_release_pool.deinit(self.alloc);
|
||||
}
|
||||
|
||||
/// Release all cached fonts.
|
||||
@ -256,13 +276,12 @@ pub const Shaper = struct {
|
||||
};
|
||||
}
|
||||
|
||||
/// Expects an ArrayList `cf_release_pool` in which `CFTypeRef`s
|
||||
/// can be placed, which guarantees that they will be `CFRelease`d
|
||||
/// eventually.
|
||||
/// Note that this will accumulate garbage in the release pool. The
|
||||
/// caller must ensure you're properly calling endFrame to release
|
||||
/// all the objects.
|
||||
pub fn shape(
|
||||
self: *Shaper,
|
||||
run: font.shape.TextRun,
|
||||
cf_release_pool: *std.ArrayList(*anyopaque),
|
||||
) ![]const font.shape.Cell {
|
||||
const state = &self.run_state;
|
||||
|
||||
@ -297,25 +316,24 @@ pub const Shaper = struct {
|
||||
const attr_dict: *macos.foundation.Dictionary = try self.getFont(
|
||||
run.grid,
|
||||
run.font_index,
|
||||
cf_release_pool,
|
||||
);
|
||||
|
||||
// Make room for the attributed string and the CTLine.
|
||||
try cf_release_pool.ensureUnusedCapacity(3);
|
||||
try self.cf_release_pool.ensureUnusedCapacity(self.alloc, 3);
|
||||
|
||||
const str = macos.foundation.String.createWithCharactersNoCopy(state.unichars.items);
|
||||
cf_release_pool.appendAssumeCapacity(str);
|
||||
self.cf_release_pool.appendAssumeCapacity(str);
|
||||
|
||||
// Create an attributed string from our string
|
||||
const attr_str = try macos.foundation.AttributedString.create(
|
||||
str,
|
||||
attr_dict,
|
||||
);
|
||||
cf_release_pool.appendAssumeCapacity(attr_str);
|
||||
self.cf_release_pool.appendAssumeCapacity(attr_str);
|
||||
|
||||
// We should always have one run because we do our own run splitting.
|
||||
const line = try macos.text.Line.createWithAttributedString(attr_str);
|
||||
cf_release_pool.appendAssumeCapacity(line);
|
||||
self.cf_release_pool.appendAssumeCapacity(line);
|
||||
|
||||
// This keeps track of the current offsets within a single cell.
|
||||
var cell_offset: struct {
|
||||
@ -411,7 +429,6 @@ pub const Shaper = struct {
|
||||
self: *Shaper,
|
||||
grid: *font.SharedGrid,
|
||||
index: font.Collection.Index,
|
||||
cf_release_pool: *std.ArrayList(*anyopaque),
|
||||
) !*macos.foundation.Dictionary {
|
||||
const index_int = index.int();
|
||||
|
||||
@ -426,7 +443,8 @@ pub const Shaper = struct {
|
||||
return cached;
|
||||
}
|
||||
|
||||
try cf_release_pool.ensureUnusedCapacity(3);
|
||||
// Features dictionary, font descriptor, font
|
||||
try self.cf_release_pool.ensureUnusedCapacity(self.alloc, 3);
|
||||
|
||||
const run_font = font: {
|
||||
// The CoreText shaper relies on CoreText and CoreText claims
|
||||
@ -450,17 +468,17 @@ pub const Shaper = struct {
|
||||
const original = face.font;
|
||||
|
||||
const attrs = try self.features.attrsDict(face.quirks_disable_default_font_features);
|
||||
cf_release_pool.appendAssumeCapacity(attrs);
|
||||
self.cf_release_pool.appendAssumeCapacity(attrs);
|
||||
|
||||
const desc = try macos.text.FontDescriptor.createWithAttributes(attrs);
|
||||
cf_release_pool.appendAssumeCapacity(desc);
|
||||
self.cf_release_pool.appendAssumeCapacity(desc);
|
||||
|
||||
const copied = try original.copyWithAttributes(0, null, desc);
|
||||
errdefer copied.release();
|
||||
|
||||
break :font copied;
|
||||
};
|
||||
cf_release_pool.appendAssumeCapacity(run_font);
|
||||
self.cf_release_pool.appendAssumeCapacity(run_font);
|
||||
|
||||
// Get our font and use that get the attributes to set for the
|
||||
// attributed string so the whole string uses the same font.
|
||||
@ -500,7 +518,7 @@ pub const Shaper = struct {
|
||||
|
||||
const pair = macos.foundation.stringGetSurrogatePairForLongCharacter(
|
||||
cp,
|
||||
state.unichars.items[state.unichars.items.len-2..][0..2],
|
||||
state.unichars.items[state.unichars.items.len - 2 ..][0..2],
|
||||
);
|
||||
if (!pair) {
|
||||
state.unichars.items.len -= 1;
|
||||
@ -599,14 +617,6 @@ test "run iterator: empty cells with background set" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaper(alloc);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -646,7 +656,7 @@ test "run iterator: empty cells with background set" {
|
||||
);
|
||||
{
|
||||
const run = (try it.next(alloc)).?;
|
||||
const cells = try shaper.shape(run, &cf_release_pool);
|
||||
const cells = try shaper.shape(run);
|
||||
try testing.expectEqual(@as(usize, 3), cells.len);
|
||||
}
|
||||
try testing.expect(try it.next(alloc) == null);
|
||||
@ -657,14 +667,6 @@ test "shape" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaper(alloc);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -691,7 +693,7 @@ test "shape" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 1), count);
|
||||
}
|
||||
@ -700,14 +702,6 @@ test "shape nerd fonts" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaperWithFont(alloc, .nerd_font);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -734,7 +728,7 @@ test "shape nerd fonts" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 1), count);
|
||||
}
|
||||
@ -743,14 +737,6 @@ test "shape inconsolata ligs" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaper(alloc);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -771,7 +757,7 @@ test "shape inconsolata ligs" {
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
|
||||
const cells = try shaper.shape(run, &cf_release_pool);
|
||||
const cells = try shaper.shape(run);
|
||||
try testing.expectEqual(@as(usize, 2), cells.len);
|
||||
try testing.expect(cells[0].glyph_index != null);
|
||||
try testing.expect(cells[1].glyph_index == null);
|
||||
@ -796,7 +782,7 @@ test "shape inconsolata ligs" {
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
|
||||
const cells = try shaper.shape(run, &cf_release_pool);
|
||||
const cells = try shaper.shape(run);
|
||||
try testing.expectEqual(@as(usize, 3), cells.len);
|
||||
try testing.expect(cells[0].glyph_index != null);
|
||||
try testing.expect(cells[1].glyph_index == null);
|
||||
@ -810,14 +796,6 @@ test "shape monaspace ligs" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaperWithFont(alloc, .monaspace_neon);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -838,7 +816,7 @@ test "shape monaspace ligs" {
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
|
||||
const cells = try shaper.shape(run, &cf_release_pool);
|
||||
const cells = try shaper.shape(run);
|
||||
try testing.expectEqual(@as(usize, 3), cells.len);
|
||||
try testing.expect(cells[0].glyph_index != null);
|
||||
try testing.expect(cells[1].glyph_index == null);
|
||||
@ -853,14 +831,6 @@ test "shape left-replaced lig in last run" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaperWithFont(alloc, .geist_mono);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -881,7 +851,7 @@ test "shape left-replaced lig in last run" {
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
|
||||
const cells = try shaper.shape(run, &cf_release_pool);
|
||||
const cells = try shaper.shape(run);
|
||||
try testing.expectEqual(@as(usize, 3), cells.len);
|
||||
try testing.expect(cells[0].glyph_index != null);
|
||||
try testing.expect(cells[1].glyph_index == null);
|
||||
@ -896,14 +866,6 @@ test "shape left-replaced lig in early run" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaperWithFont(alloc, .geist_mono);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -922,7 +884,7 @@ test "shape left-replaced lig in early run" {
|
||||
);
|
||||
|
||||
const run = (try it.next(alloc)).?;
|
||||
const cells = try shaper.shape(run, &cf_release_pool);
|
||||
const cells = try shaper.shape(run);
|
||||
try testing.expectEqual(@as(usize, 4), cells.len);
|
||||
try testing.expect(cells[0].glyph_index != null);
|
||||
try testing.expect(cells[1].glyph_index == null);
|
||||
@ -936,14 +898,6 @@ test "shape U+3C9 with JB Mono" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaperWithFont(alloc, .jetbrains_mono);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -965,7 +919,7 @@ test "shape U+3C9 with JB Mono" {
|
||||
var cell_count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
run_count += 1;
|
||||
const cells = try shaper.shape(run, &cf_release_pool);
|
||||
const cells = try shaper.shape(run);
|
||||
cell_count += cells.len;
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 1), run_count);
|
||||
@ -977,14 +931,6 @@ test "shape emoji width" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaper(alloc);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -1005,7 +951,7 @@ test "shape emoji width" {
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
|
||||
const cells = try shaper.shape(run, &cf_release_pool);
|
||||
const cells = try shaper.shape(run);
|
||||
try testing.expectEqual(@as(usize, 1), cells.len);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 1), count);
|
||||
@ -1016,14 +962,6 @@ test "shape emoji width long" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaper(alloc);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -1052,7 +990,7 @@ test "shape emoji width long" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
const cells = try shaper.shape(run, &cf_release_pool);
|
||||
const cells = try shaper.shape(run);
|
||||
|
||||
// screen.testWriteString isn't grapheme aware, otherwise this is one
|
||||
try testing.expectEqual(@as(usize, 5), cells.len);
|
||||
@ -1064,14 +1002,6 @@ test "shape variation selector VS15" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaper(alloc);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -1097,7 +1027,7 @@ test "shape variation selector VS15" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
const cells = try shaper.shape(run, &cf_release_pool);
|
||||
const cells = try shaper.shape(run);
|
||||
try testing.expectEqual(@as(usize, 1), cells.len);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 1), count);
|
||||
@ -1107,14 +1037,6 @@ test "shape variation selector VS16" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaper(alloc);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -1140,7 +1062,7 @@ test "shape variation selector VS16" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
const cells = try shaper.shape(run, &cf_release_pool);
|
||||
const cells = try shaper.shape(run);
|
||||
try testing.expectEqual(@as(usize, 1), cells.len);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 1), count);
|
||||
@ -1150,14 +1072,6 @@ test "shape with empty cells in between" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaper(alloc);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -1181,7 +1095,7 @@ test "shape with empty cells in between" {
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
|
||||
const cells = try shaper.shape(run, &cf_release_pool);
|
||||
const cells = try shaper.shape(run);
|
||||
try testing.expectEqual(@as(usize, 1), count);
|
||||
try testing.expectEqual(@as(usize, 7), cells.len);
|
||||
}
|
||||
@ -1191,14 +1105,6 @@ test "shape Chinese characters" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaper(alloc);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -1227,7 +1133,7 @@ test "shape Chinese characters" {
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
|
||||
const cells = try shaper.shape(run, &cf_release_pool);
|
||||
const cells = try shaper.shape(run);
|
||||
try testing.expectEqual(@as(usize, 4), cells.len);
|
||||
try testing.expectEqual(@as(u16, 0), cells[0].x);
|
||||
try testing.expectEqual(@as(u16, 0), cells[1].x);
|
||||
@ -1241,14 +1147,6 @@ test "shape box glyphs" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaper(alloc);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -1274,7 +1172,7 @@ test "shape box glyphs" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
const cells = try shaper.shape(run, &cf_release_pool);
|
||||
const cells = try shaper.shape(run);
|
||||
try testing.expectEqual(@as(usize, 2), cells.len);
|
||||
try testing.expectEqual(@as(u32, 0x2500), cells[0].glyph_index.?);
|
||||
try testing.expectEqual(@as(u16, 0), cells[0].x);
|
||||
@ -1288,14 +1186,6 @@ test "shape selection boundary" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaper(alloc);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -1322,7 +1212,7 @@ test "shape selection boundary" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 1), count);
|
||||
}
|
||||
@ -1345,7 +1235,7 @@ test "shape selection boundary" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 2), count);
|
||||
}
|
||||
@ -1368,7 +1258,7 @@ test "shape selection boundary" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 2), count);
|
||||
}
|
||||
@ -1391,7 +1281,7 @@ test "shape selection boundary" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 3), count);
|
||||
}
|
||||
@ -1414,7 +1304,7 @@ test "shape selection boundary" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 3), count);
|
||||
}
|
||||
@ -1424,14 +1314,6 @@ test "shape cursor boundary" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaper(alloc);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -1454,7 +1336,7 @@ test "shape cursor boundary" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 1), count);
|
||||
}
|
||||
@ -1473,7 +1355,7 @@ test "shape cursor boundary" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 2), count);
|
||||
}
|
||||
@ -1492,7 +1374,7 @@ test "shape cursor boundary" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 3), count);
|
||||
}
|
||||
@ -1511,7 +1393,7 @@ test "shape cursor boundary" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 2), count);
|
||||
}
|
||||
@ -1521,14 +1403,6 @@ test "shape cursor boundary and colored emoji" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaper(alloc);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -1551,7 +1425,7 @@ test "shape cursor boundary and colored emoji" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 1), count);
|
||||
}
|
||||
@ -1570,7 +1444,7 @@ test "shape cursor boundary and colored emoji" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 1), count);
|
||||
}
|
||||
@ -1587,7 +1461,7 @@ test "shape cursor boundary and colored emoji" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 1), count);
|
||||
}
|
||||
@ -1597,14 +1471,6 @@ test "shape cell attribute change" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
var testdata = try testShaper(alloc);
|
||||
defer testdata.deinit();
|
||||
|
||||
@ -1625,7 +1491,7 @@ test "shape cell attribute change" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 1), count);
|
||||
}
|
||||
@ -1649,7 +1515,7 @@ test "shape cell attribute change" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 2), count);
|
||||
}
|
||||
@ -1674,7 +1540,7 @@ test "shape cell attribute change" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 2), count);
|
||||
}
|
||||
@ -1699,7 +1565,7 @@ test "shape cell attribute change" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 1), count);
|
||||
}
|
||||
@ -1723,7 +1589,7 @@ test "shape cell attribute change" {
|
||||
var count: usize = 0;
|
||||
while (try it.next(alloc)) |run| {
|
||||
count += 1;
|
||||
_ = try shaper.shape(run, &cf_release_pool);
|
||||
_ = try shaper.shape(run);
|
||||
}
|
||||
try testing.expectEqual(@as(usize, 1), count);
|
||||
}
|
||||
|
@ -1018,9 +1018,6 @@ pub fn updateFrame(
|
||||
if (critical.preedit) |p| p.deinit(self.alloc);
|
||||
}
|
||||
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(self.alloc);
|
||||
try cf_release_pool.ensureTotalCapacity(state.terminal.rows * 8);
|
||||
|
||||
// Build our GPU cells
|
||||
try self.rebuildCells(
|
||||
critical.full_rebuild,
|
||||
@ -1029,27 +1026,23 @@ pub fn updateFrame(
|
||||
critical.preedit,
|
||||
critical.cursor_style,
|
||||
&critical.color_palette,
|
||||
&cf_release_pool,
|
||||
);
|
||||
|
||||
if (cf_release_pool.items.len > 0) {
|
||||
const items = try cf_release_pool.toOwnedSlice();
|
||||
if (self.font_shaper.cf_release_pool.items.len > 0) {
|
||||
const alloc = self.font_shaper.alloc;
|
||||
const items = try self.font_shaper.cf_release_pool.toOwnedSlice(alloc);
|
||||
if (self.cf_release_thread.mailbox.push(
|
||||
.{ .release = .{
|
||||
.refs = items,
|
||||
.alloc = self.alloc,
|
||||
.alloc = alloc,
|
||||
} },
|
||||
.{ .forever = {} },
|
||||
) != 0) {
|
||||
try self.cf_release_thread.wakeup.notify();
|
||||
} else {
|
||||
for (items) |ref| {
|
||||
macos.foundation.CFRelease(ref);
|
||||
}
|
||||
self.alloc.free(items);
|
||||
for (items) |ref| macos.foundation.CFRelease(ref);
|
||||
alloc.free(items);
|
||||
}
|
||||
} else {
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
|
||||
// Update our viewport pin
|
||||
@ -1931,7 +1924,6 @@ fn rebuildCells(
|
||||
preedit: ?renderer.State.Preedit,
|
||||
cursor_style_: ?renderer.CursorStyle,
|
||||
color_palette: *const terminal.color.Palette,
|
||||
cf_release_pool: *std.ArrayList(*anyopaque),
|
||||
) !void {
|
||||
// const start = try std.time.Instant.now();
|
||||
// const start_micro = std.time.microTimestamp();
|
||||
@ -2013,10 +2005,7 @@ fn rebuildCells(
|
||||
while (try iter.next(self.alloc)) |run| {
|
||||
// Try to read the cells from the shaping cache if we can.
|
||||
const shaper_cells = self.font_shaper_cache.get(run) orelse cache: {
|
||||
const cells = if (font.options.backend == .coretext)
|
||||
try self.font_shaper.shape(run, cf_release_pool)
|
||||
else
|
||||
try self.font_shaper.shape(run);
|
||||
const cells = try self.font_shaper.shape(run);
|
||||
|
||||
// Try to cache them. If caching fails for any reason we continue
|
||||
// because it is just a performance optimization, not a correctness
|
||||
|
@ -1025,16 +1025,7 @@ pub fn rebuildCells(
|
||||
while (try iter.next(self.alloc)) |run| {
|
||||
// Try to read the cells from the shaping cache if we can.
|
||||
const shaper_cells = self.font_shaper_cache.get(run) orelse cache: {
|
||||
const cells = if (font.options.backend == .coretext) ct: {
|
||||
var cf_release_pool = std.ArrayList(*anyopaque).init(self.alloc);
|
||||
defer {
|
||||
for (cf_release_pool.items) |ref| {
|
||||
@import("macos").foundation.CFRelease(ref);
|
||||
}
|
||||
cf_release_pool.deinit();
|
||||
}
|
||||
break :ct try self.font_shaper.shape(run, &cf_release_pool);
|
||||
} else try self.font_shaper.shape(run);
|
||||
const cells = try self.font_shaper.shape(run);
|
||||
|
||||
// Try to cache them. If caching fails for any reason we continue
|
||||
// because it is just a performance optimization, not a correctness
|
||||
|
Reference in New Issue
Block a user