mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-07-31 04:39:01 +00:00
terminal/apc/glyph: clone glossary entries
Glossary entries own decoded glyph payloads, so callers could not copy an entry without sharing outline storage. Add clone methods for glossary entries and glyf outlines that allocate fresh contour and point slices while copying the scalar registration metadata directly. This keeps the ownership contract symmetric with deinit and lets cloned entries be released independently from their source.
This commit is contained in:
@@ -50,6 +50,23 @@ pub const Glyf = struct {
|
||||
return self.points[start..end];
|
||||
}
|
||||
|
||||
/// Deep copy this outline using `alloc`.
|
||||
///
|
||||
/// The returned outline owns its contour and point storage and must be
|
||||
/// released with `deinit`.
|
||||
pub fn clone(self: *const Outline, alloc: Allocator) Allocator.Error!Outline {
|
||||
const contours = try alloc.dupe(sfnt.uint16, self.contours);
|
||||
errdefer alloc.free(contours);
|
||||
|
||||
const points = try alloc.dupe(Point, self.points);
|
||||
errdefer alloc.free(points);
|
||||
|
||||
return .{
|
||||
.contours = contours,
|
||||
.points = points,
|
||||
};
|
||||
}
|
||||
|
||||
/// Free all memory owned by this outline. Pass in the same
|
||||
/// allocator used for decoding.
|
||||
pub fn deinit(self: *Outline, alloc: Allocator) void {
|
||||
|
||||
@@ -193,6 +193,23 @@ pub const Entry = struct {
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
/// Deep copy this glossary entry using `alloc`.
|
||||
///
|
||||
/// The returned entry owns decoded glyph memory and must be released with
|
||||
/// `deinit`.
|
||||
pub fn clone(self: *const Entry, alloc: Allocator) Allocator.Error!Entry {
|
||||
const glyph: Glyph = switch (self.glyph) {
|
||||
.glyf => |*outline| .{ .glyf = try outline.clone(alloc) },
|
||||
};
|
||||
|
||||
return .{
|
||||
.glyph = glyph,
|
||||
.design = self.design,
|
||||
.width = self.width,
|
||||
.constraint = self.constraint,
|
||||
};
|
||||
}
|
||||
|
||||
/// Return the renderer constraint for a register request.
|
||||
///
|
||||
/// Glyph Protocol §8.5 defines sizing, alignment, and padding in terms of
|
||||
@@ -320,6 +337,26 @@ test "Entry init decodes glyf payload and applies register fields" {
|
||||
try testing.expectEqual(@as(usize, 1), entry.glyph.glyf.contours.len);
|
||||
}
|
||||
|
||||
test "Entry clone deep copies decoded glyf payload" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var entry = try testRegisterEntry(alloc, 0xE000);
|
||||
defer entry.deinit(alloc);
|
||||
|
||||
var cloned = try entry.clone(alloc);
|
||||
defer cloned.deinit(alloc);
|
||||
|
||||
try testing.expectEqual(entry.design, cloned.design);
|
||||
try testing.expectEqual(entry.width, cloned.width);
|
||||
try testing.expectEqual(entry.constraint, cloned.constraint);
|
||||
|
||||
try testing.expectEqualSlices(u16, entry.glyph.glyf.contours, cloned.glyph.glyf.contours);
|
||||
try testing.expectEqualSlices(Glyf.Outline.Point, entry.glyph.glyf.points, cloned.glyph.glyf.points);
|
||||
try testing.expect(entry.glyph.glyf.contours.ptr != cloned.glyph.glyf.contours.ptr);
|
||||
try testing.expect(entry.glyph.glyf.points.ptr != cloned.glyph.glyf.points.ptr);
|
||||
}
|
||||
|
||||
test "Entry init rejects invalid register payload" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
Reference in New Issue
Block a user