diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-04-04 19:22:04 +0300 |
|---|---|---|
| committer | Can Celik <ogulcancelik@gmail.com> | 2026-04-05 01:23:06 +0300 |
| commit | 41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch) | |
| tree | 3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/pkg/macos | |
| parent | 55c138263e190a1e79d4b997bfb9397306c0ec1f (diff) | |
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/pkg/macos')
59 files changed, 3580 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/pkg/macos/animation.zig b/vendor/libghostty-vt/pkg/macos/animation.zig new file mode 100644 index 00000000..247f9760 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/animation.zig @@ -0,0 +1,10 @@ +pub const c = @import("animation/c.zig").c; + +/// https://developer.apple.com/documentation/quartzcore/calayer/contents_gravity_values?language=objc +pub extern "c" const kCAGravityTopLeft: *anyopaque; +pub extern "c" const kCAGravityBottomLeft: *anyopaque; +pub extern "c" const kCAGravityCenter: *anyopaque; + +test { + @import("std").testing.refAllDecls(@This()); +} diff --git a/vendor/libghostty-vt/pkg/macos/animation/c.zig b/vendor/libghostty-vt/pkg/macos/animation/c.zig new file mode 100644 index 00000000..1a7d1627 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/animation/c.zig @@ -0,0 +1 @@ +pub const c = @import("../main.zig").c; diff --git a/vendor/libghostty-vt/pkg/macos/build.zig b/vendor/libghostty-vt/pkg/macos/build.zig new file mode 100644 index 00000000..0525e481 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/build.zig @@ -0,0 +1,82 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const apple_sdk = @import("apple_sdk"); + +pub fn build(b: *std.Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const module = b.addModule("macos", .{ + .root_source_file = b.path("main.zig"), + .target = target, + .optimize = optimize, + }); + + const lib = b.addLibrary(.{ + .name = "macos", + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + }), + .linkage = .static, + }); + + lib.addCSourceFile(.{ + .file = b.path("os/zig_macos.c"), + .flags = &.{"-std=c99"}, + }); + lib.addCSourceFile(.{ + .file = b.path("text/ext.c"), + }); + lib.linkFramework("CoreFoundation"); + lib.linkFramework("CoreGraphics"); + lib.linkFramework("CoreText"); + lib.linkFramework("CoreVideo"); + lib.linkFramework("QuartzCore"); + lib.linkFramework("IOSurface"); + if (target.result.os.tag == .macos) { + lib.linkFramework("Carbon"); + module.linkFramework("Carbon", .{}); + } + + if (target.result.os.tag.isDarwin()) { + module.linkFramework("CoreFoundation", .{}); + module.linkFramework("CoreGraphics", .{}); + module.linkFramework("CoreText", .{}); + module.linkFramework("CoreVideo", .{}); + module.linkFramework("QuartzCore", .{}); + module.linkFramework("IOSurface", .{}); + + try apple_sdk.addPaths(b, lib); + } + b.installArtifact(lib); + + { + const test_exe = b.addTest(.{ + .name = "test", + .root_module = b.createModule(.{ + .root_source_file = b.path("main.zig"), + .target = target, + .optimize = optimize, + }), + }); + if (target.result.os.tag.isDarwin()) { + try apple_sdk.addPaths(b, test_exe); + } + test_exe.linkLibrary(lib); + + var it = module.import_table.iterator(); + while (it.next()) |entry| { + test_exe.root_module.addImport( + entry.key_ptr.*, + entry.value_ptr.*, + ); + } + + b.installArtifact(test_exe); + + const tests_run = b.addRunArtifact(test_exe); + const test_step = b.step("test", "Run tests"); + test_step.dependOn(&tests_run.step); + } +} diff --git a/vendor/libghostty-vt/pkg/macos/build.zig.zon b/vendor/libghostty-vt/pkg/macos/build.zig.zon new file mode 100644 index 00000000..4c22ad7c --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/build.zig.zon @@ -0,0 +1,9 @@ +.{ + .name = .macos, + .version = "0.1.0", + .fingerprint = 0x45e2f6107d5b2b2c, + .paths = .{""}, + .dependencies = .{ + .apple_sdk = .{ .path = "../apple-sdk" }, + }, +} diff --git a/vendor/libghostty-vt/pkg/macos/carbon.zig b/vendor/libghostty-vt/pkg/macos/carbon.zig new file mode 100644 index 00000000..8eafaffe --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/carbon.zig @@ -0,0 +1,5 @@ +pub const c = @import("carbon/c.zig").c; + +test { + @import("std").testing.refAllDecls(@This()); +} diff --git a/vendor/libghostty-vt/pkg/macos/carbon/c.zig b/vendor/libghostty-vt/pkg/macos/carbon/c.zig new file mode 100644 index 00000000..1a7d1627 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/carbon/c.zig @@ -0,0 +1 @@ +pub const c = @import("../main.zig").c; diff --git a/vendor/libghostty-vt/pkg/macos/dispatch.zig b/vendor/libghostty-vt/pkg/macos/dispatch.zig new file mode 100644 index 00000000..3add9c0e --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/dispatch.zig @@ -0,0 +1,18 @@ +pub const c = @import("dispatch/c.zig").c; +pub const data = @import("dispatch/data.zig"); +pub const queue = @import("dispatch/queue.zig"); +pub const Data = data.Data; + +pub extern "c" fn dispatch_sync( + queue: *anyopaque, + block: *anyopaque, +) void; + +pub extern "c" fn dispatch_async( + queue: *anyopaque, + block: *anyopaque, +) void; + +test { + @import("std").testing.refAllDecls(@This()); +} diff --git a/vendor/libghostty-vt/pkg/macos/dispatch/c.zig b/vendor/libghostty-vt/pkg/macos/dispatch/c.zig new file mode 100644 index 00000000..1a7d1627 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/dispatch/c.zig @@ -0,0 +1 @@ +pub const c = @import("../main.zig").c; diff --git a/vendor/libghostty-vt/pkg/macos/dispatch/data.zig b/vendor/libghostty-vt/pkg/macos/dispatch/data.zig new file mode 100644 index 00000000..28df24b7 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/dispatch/data.zig @@ -0,0 +1,31 @@ +const std = @import("std"); +const foundation = @import("../foundation.zig"); +const c = @import("c.zig").c; + +pub const Data = opaque { + pub const DESTRUCTOR_DEFAULT = c.DISPATCH_DATA_DESTRUCTOR_DEFAULT; + + pub fn create( + data: []const u8, + queue: ?*anyopaque, + destructor: ?*anyopaque, + ) !*Data { + return dispatch_data_create( + data.ptr, + data.len, + queue, + destructor, + ) orelse return error.OutOfMemory; + } + + pub fn release(data: *Data) void { + foundation.c.CFRelease(data); + } +}; + +extern "c" fn dispatch_data_create( + data: [*]const u8, + len: usize, + queue: ?*anyopaque, + destructor: ?*anyopaque, +) ?*Data; diff --git a/vendor/libghostty-vt/pkg/macos/dispatch/queue.zig b/vendor/libghostty-vt/pkg/macos/dispatch/queue.zig new file mode 100644 index 00000000..cb2ca01c --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/dispatch/queue.zig @@ -0,0 +1,8 @@ +const std = @import("std"); +const c = @import("c.zig").c; + +pub const Queue = *anyopaque; // dispatch_queue_t + +pub fn getMain() Queue { + return c.dispatch_get_main_queue().?; +} diff --git a/vendor/libghostty-vt/pkg/macos/foundation.zig b/vendor/libghostty-vt/pkg/macos/foundation.zig new file mode 100644 index 00000000..d4f63409 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/foundation.zig @@ -0,0 +1,37 @@ +const array = @import("foundation/array.zig"); +const attributed_string = @import("foundation/attributed_string.zig"); +const base = @import("foundation/base.zig"); +const character_set = @import("foundation/character_set.zig"); +const data = @import("foundation/data.zig"); +const dictionary = @import("foundation/dictionary.zig"); +const number = @import("foundation/number.zig"); +const string = @import("foundation/string.zig"); +const typepkg = @import("foundation/type.zig"); +const url = @import("foundation/url.zig"); + +pub const c = @import("foundation/c.zig").c; +pub const Array = array.Array; +pub const MutableArray = array.MutableArray; +pub const AttributedString = attributed_string.AttributedString; +pub const MutableAttributedString = attributed_string.MutableAttributedString; +pub const ComparisonResult = base.ComparisonResult; +pub const Range = base.Range; +pub const FourCharCode = base.FourCharCode; +pub const CharacterSet = character_set.CharacterSet; +pub const Data = data.Data; +pub const Dictionary = dictionary.Dictionary; +pub const MutableDictionary = dictionary.MutableDictionary; +pub const Number = number.Number; +pub const String = string.String; +pub const MutableString = string.MutableString; +pub const StringComparison = string.StringComparison; +pub const StringEncoding = string.StringEncoding; +pub const stringGetSurrogatePairForLongCharacter = string.stringGetSurrogatePairForLongCharacter; +pub const URL = url.URL; +pub const URLPathStyle = url.URLPathStyle; +pub const CFRelease = typepkg.CFRelease; +pub const CFRetain = typepkg.CFRetain; + +test { + @import("std").testing.refAllDecls(@This()); +} diff --git a/vendor/libghostty-vt/pkg/macos/foundation/array.zig b/vendor/libghostty-vt/pkg/macos/foundation/array.zig new file mode 100644 index 00000000..7b580eb0 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/foundation/array.zig @@ -0,0 +1,176 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const base = @import("base.zig"); +const c = @import("c.zig").c; +const cftype = @import("type.zig"); +const ComparisonResult = base.ComparisonResult; +const Range = base.Range; + +pub const Array = opaque { + pub fn create(comptime T: type, values: []*const T) Allocator.Error!*Array { + return CFArrayCreate( + null, + @ptrCast(values.ptr), + @intCast(values.len), + null, + ) orelse error.OutOfMemory; + } + + pub fn release(self: *Array) void { + cftype.CFRelease(self); + } + + pub fn getCount(self: *Array) usize { + return CFArrayGetCount(self); + } + + /// Note the return type is actually a `*const T` but we strip the + /// constness so that further API calls work correctly. The Foundation + /// API doesn't properly mark things const/non-const. + pub fn getValueAtIndex(self: *Array, comptime T: type, idx: usize) *T { + return @ptrCast(@alignCast(CFArrayGetValueAtIndex(self, idx))); + } + + pub extern "c" fn CFArrayCreate( + allocator: ?*anyopaque, + values: [*]*const anyopaque, + num_values: usize, + callbacks: ?*const anyopaque, + ) ?*Array; + pub extern "c" fn CFArrayGetCount(*Array) usize; + pub extern "c" fn CFArrayGetValueAtIndex(*Array, usize) *anyopaque; + extern "c" var kCFTypeArrayCallBacks: anyopaque; +}; + +pub const MutableArray = opaque { + pub fn create() Allocator.Error!*MutableArray { + return CFArrayCreateMutable( + null, + 0, + &c.kCFTypeArrayCallBacks, + ) orelse error.OutOfMemory; + } + + pub fn createCopy(array: *Array) Allocator.Error!*MutableArray { + return CFArrayCreateMutableCopy( + null, + 0, + array, + ) orelse error.OutOfMemory; + } + + pub fn release(self: *MutableArray) void { + cftype.CFRelease(self); + } + + pub fn appendValue( + self: *MutableArray, + comptime Elem: type, + value: *const Elem, + ) void { + CFArrayAppendValue(self, @ptrCast(@constCast(value))); + } + + pub fn removeValue(self: *MutableArray, idx: usize) void { + CFArrayRemoveValueAtIndex(self, idx); + } + + pub fn sortValues( + self: *MutableArray, + comptime Elem: type, + comptime Context: type, + context: ?*Context, + comptime comparator: ?*const fn ( + a: *const Elem, + b: *const Elem, + context: ?*Context, + ) callconv(.c) ComparisonResult, + ) void { + CFArraySortValues( + self, + Range.init(0, Array.CFArrayGetCount(@ptrCast(self))), + comparator, + context, + ); + } + + extern "c" fn CFArrayCreateMutable( + allocator: ?*anyopaque, + capacity: usize, + callbacks: ?*const anyopaque, + ) ?*MutableArray; + extern "c" fn CFArrayCreateMutableCopy( + allocator: ?*anyopaque, + capacity: usize, + array: *Array, + ) ?*MutableArray; + extern "c" fn CFArrayAppendValue( + *MutableArray, + *anyopaque, + ) void; + extern "c" fn CFArrayRemoveValueAtIndex( + *MutableArray, + usize, + ) void; + extern "c" fn CFArraySortValues( + array: *MutableArray, + range: Range, + comparator: ?*const anyopaque, + context: ?*anyopaque, + ) void; +}; + +test "array" { + const testing = std.testing; + + const str = "hello"; + var values = [_]*const u8{ &str[0], &str[1] }; + const arr = try Array.create(u8, &values); + defer arr.release(); + + try testing.expectEqual(@as(usize, 2), arr.getCount()); + + { + const ch = arr.getValueAtIndex(u8, 0); + try testing.expectEqual(@as(u8, 'h'), ch.*); + } + + // Can make it mutable + var mut = try MutableArray.createCopy(arr); + defer mut.release(); +} + +test "array sorting" { + const testing = std.testing; + + const str = "hello"; + var values = [_]*const u8{ &str[0], &str[1] }; + const arr = try Array.create(u8, &values); + defer arr.release(); + const mut = try MutableArray.createCopy(arr); + defer mut.release(); + + mut.sortValues( + u8, + void, + null, + struct { + fn compare(a: *const u8, b: *const u8, _: ?*void) callconv(.c) ComparisonResult { + if (a.* > b.*) return .greater; + if (a.* == b.*) return .equal; + return .less; + } + }.compare, + ); + + { + const mutarr: *Array = @ptrCast(mut); + const ch = mutarr.getValueAtIndex(u8, 0); + try testing.expectEqual(@as(u8, 'e'), ch.*); + } + { + const mutarr: *Array = @ptrCast(mut); + const ch = mutarr.getValueAtIndex(u8, 1); + try testing.expectEqual(@as(u8, 'h'), ch.*); + } +} diff --git a/vendor/libghostty-vt/pkg/macos/foundation/attributed_string.zig b/vendor/libghostty-vt/pkg/macos/foundation/attributed_string.zig new file mode 100644 index 00000000..c7f27d7d --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/foundation/attributed_string.zig @@ -0,0 +1,103 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const text = @import("../text.zig"); +const c = @import("c.zig").c; + +pub const AttributedString = opaque { + pub fn create( + str: *foundation.String, + attributes: *foundation.Dictionary, + ) Allocator.Error!*AttributedString { + return @ptrCast(@constCast(c.CFAttributedStringCreate( + null, + @ptrCast(str), + @ptrCast(attributes), + ) orelse return Allocator.Error.OutOfMemory)); + } + + pub fn release(self: *AttributedString) void { + foundation.CFRelease(self); + } + + pub fn getLength(self: *AttributedString) usize { + return @intCast(c.CFAttributedStringGetLength(@ptrCast(self))); + } + + pub fn getString(self: *AttributedString) *foundation.String { + return @ptrFromInt(@intFromPtr( + c.CFAttributedStringGetString(@ptrCast(self)), + )); + } +}; + +pub const MutableAttributedString = opaque { + pub fn create(cap: usize) Allocator.Error!*MutableAttributedString { + return @as( + ?*MutableAttributedString, + @ptrFromInt(@intFromPtr(c.CFAttributedStringCreateMutable( + null, + @intCast(cap), + ))), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn release(self: *MutableAttributedString) void { + foundation.CFRelease(self); + } + + pub fn replaceString( + self: *MutableAttributedString, + range: foundation.Range, + replacement: *foundation.String, + ) void { + c.CFAttributedStringReplaceString( + @ptrCast(self), + @bitCast(range), + @ptrCast(replacement), + ); + } + + pub fn setAttribute( + self: *MutableAttributedString, + range: foundation.Range, + key: anytype, + value: ?*anyopaque, + ) void { + const T = @TypeOf(key); + const info = @typeInfo(T); + const Key = if (info != .pointer) T else info.pointer.child; + const key_arg = if (@hasDecl(Key, "key")) + key.key() + else + key; + + c.CFAttributedStringSetAttribute( + @ptrCast(self), + @bitCast(range), + @ptrCast(key_arg), + value, + ); + } + + pub fn getLength(self: *MutableAttributedString) usize { + return @intCast(c.CFAttributedStringGetLength(@ptrCast(self))); + } +}; + +test "mutable attributed string" { + //const testing = std.testing; + + const str = try MutableAttributedString.create(0); + defer str.release(); + + { + const rep = try foundation.String.createWithBytes("hello", .utf8, false); + defer rep.release(); + str.replaceString(foundation.Range.init(0, 0), rep); + } + + str.setAttribute(foundation.Range.init(0, 0), text.FontAttribute.url, null); + str.setAttribute(foundation.Range.init(0, 0), text.FontAttribute.name.key(), null); +} diff --git a/vendor/libghostty-vt/pkg/macos/foundation/base.zig b/vendor/libghostty-vt/pkg/macos/foundation/base.zig new file mode 100644 index 00000000..b926523f --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/foundation/base.zig @@ -0,0 +1,35 @@ +const std = @import("std"); +const assert = std.debug.assert; +const c = @import("c.zig").c; + +pub const ComparisonResult = enum(c_int) { + less = -1, + equal = 0, + greater = 1, +}; + +pub const Range = extern struct { + location: c.CFIndex, + length: c.CFIndex, + + pub fn init(loc: usize, len: usize) Range { + return @bitCast(c.CFRangeMake(@intCast(loc), @intCast(len))); + } +}; + +pub const FourCharCode = packed struct(u32) { + d: u8, + c: u8, + b: u8, + a: u8, + + pub fn init(v: *const [4]u8) FourCharCode { + return .{ .a = v[0], .b = v[1], .c = v[2], .d = v[3] }; + } + + /// Converts the ID to a string. The return value is only valid + /// for the lifetime of the self pointer. + pub fn str(self: FourCharCode) [4]u8 { + return .{ self.a, self.b, self.c, self.d }; + } +}; diff --git a/vendor/libghostty-vt/pkg/macos/foundation/c.zig b/vendor/libghostty-vt/pkg/macos/foundation/c.zig new file mode 100644 index 00000000..1a7d1627 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/foundation/c.zig @@ -0,0 +1 @@ +pub const c = @import("../main.zig").c; diff --git a/vendor/libghostty-vt/pkg/macos/foundation/character_set.zig b/vendor/libghostty-vt/pkg/macos/foundation/character_set.zig new file mode 100644 index 00000000..d80ca45d --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/foundation/character_set.zig @@ -0,0 +1,49 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const c = @import("c.zig").c; + +pub const CharacterSet = opaque { + pub fn createWithCharactersInString( + str: *foundation.String, + ) Allocator.Error!*CharacterSet { + return @as(?*CharacterSet, @ptrFromInt(@intFromPtr(c.CFCharacterSetCreateWithCharactersInString( + null, + @ptrCast(str), + )))) orelse Allocator.Error.OutOfMemory; + } + + pub fn createWithCharactersInRange( + range: foundation.Range, + ) Allocator.Error!*CharacterSet { + return @as(?*CharacterSet, @ptrFromInt(@intFromPtr(c.CFCharacterSetCreateWithCharactersInRange( + null, + @bitCast(range), + )))) orelse Allocator.Error.OutOfMemory; + } + + pub fn release(self: *CharacterSet) void { + c.CFRelease(self); + } +}; + +test "character set" { + //const testing = std.testing; + + const str = try foundation.String.createWithBytes("hello world", .ascii, false); + defer str.release(); + + const cs = try CharacterSet.createWithCharactersInString(str); + defer cs.release(); +} + +test "character set range" { + //const testing = std.testing; + + const cs = try CharacterSet.createWithCharactersInRange(.{ + .location = 'A', + .length = 1, + }); + defer cs.release(); +} diff --git a/vendor/libghostty-vt/pkg/macos/foundation/data.zig b/vendor/libghostty-vt/pkg/macos/foundation/data.zig new file mode 100644 index 00000000..c06da65b --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/foundation/data.zig @@ -0,0 +1,38 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const c = @import("c.zig").c; + +pub const Data = opaque { + pub fn createWithBytesNoCopy(data: []const u8) Allocator.Error!*Data { + return @as( + ?*Data, + @ptrFromInt(@intFromPtr(c.CFDataCreateWithBytesNoCopy( + null, + data.ptr, + @intCast(data.len), + c.kCFAllocatorNull, + ))), + ) orelse error.OutOfMemory; + } + + pub fn release(self: *Data) void { + foundation.CFRelease(self); + } + + pub fn getPointer(self: *Data) [*]const u8 { + return @ptrCast(c.CFDataGetBytePtr(@ptrCast(self))); + } + + pub fn getLength(self: *Data) usize { + return @intCast(c.CFDataGetLength(@ptrCast(self))); + } +}; + +test { + //const testing = std.testing; + + const raw = "hello world"; + const data = try Data.createWithBytesNoCopy(raw); + defer data.release(); +} diff --git a/vendor/libghostty-vt/pkg/macos/foundation/dictionary.zig b/vendor/libghostty-vt/pkg/macos/foundation/dictionary.zig new file mode 100644 index 00000000..a529442a --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/foundation/dictionary.zig @@ -0,0 +1,125 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const c = @import("c.zig").c; + +pub const Dictionary = opaque { + pub fn create( + keys: ?[]const ?*const anyopaque, + values: ?[]const ?*const anyopaque, + ) Allocator.Error!*Dictionary { + if (keys != null or values != null) { + assert(keys != null); + assert(values != null); + assert(keys.?.len == values.?.len); + } + + return @as(?*Dictionary, @ptrFromInt(@intFromPtr(c.CFDictionaryCreate( + null, + @ptrCast(@constCast(if (keys) |slice| slice.ptr else null)), + @ptrCast(@constCast(if (values) |slice| slice.ptr else null)), + @intCast(if (keys) |slice| slice.len else 0), + &c.kCFTypeDictionaryKeyCallBacks, + &c.kCFTypeDictionaryValueCallBacks, + )))) orelse Allocator.Error.OutOfMemory; + } + + pub fn release(self: *Dictionary) void { + foundation.CFRelease(self); + } + + pub fn getCount(self: *Dictionary) usize { + return @intCast(c.CFDictionaryGetCount(@ptrCast(self))); + } + + pub fn getValue(self: *Dictionary, comptime V: type, key: ?*const anyopaque) ?*V { + return @ptrFromInt(@intFromPtr(c.CFDictionaryGetValue( + @ptrCast(self), + key, + ))); + } + + pub fn getKeysAndValues(self: *Dictionary, alloc: Allocator) !struct { + keys: []?*const anyopaque, + values: []?*const anyopaque, + } { + const count = self.getCount(); + const keys = try alloc.alloc(?*const anyopaque, count); + errdefer alloc.free(keys); + const values = try alloc.alloc(?*const anyopaque, count); + errdefer alloc.free(values); + c.CFDictionaryGetKeysAndValues( + @ptrCast(self), + @ptrCast(keys.ptr), + @ptrCast(values.ptr), + ); + return .{ .keys = keys, .values = values }; + } +}; + +pub const MutableDictionary = opaque { + pub fn create(cap: usize) Allocator.Error!*MutableDictionary { + return @as(?*MutableDictionary, @ptrFromInt(@intFromPtr(c.CFDictionaryCreateMutable( + null, + @intCast(cap), + &c.kCFTypeDictionaryKeyCallBacks, + &c.kCFTypeDictionaryValueCallBacks, + )))) orelse Allocator.Error.OutOfMemory; + } + + pub fn createMutableCopy(cap: usize, src: *Dictionary) Allocator.Error!*MutableDictionary { + return @as(?*MutableDictionary, @ptrFromInt(@intFromPtr(c.CFDictionaryCreateMutableCopy( + null, + @intCast(cap), + @ptrCast(src), + )))) orelse Allocator.Error.OutOfMemory; + } + + pub fn release(self: *MutableDictionary) void { + foundation.CFRelease(self); + } + + pub fn setValue(self: *MutableDictionary, key: ?*const anyopaque, value: ?*const anyopaque) void { + c.CFDictionarySetValue( + @ptrCast(self), + key, + value, + ); + } +}; + +test "dictionary" { + const testing = std.testing; + + const str = try foundation.String.createWithBytes("hello", .unicode, false); + defer str.release(); + + var keys = [_]?*const anyopaque{c.kCFURLIsPurgeableKey}; + var values = [_]?*const anyopaque{str}; + const dict = try Dictionary.create(&keys, &values); + defer dict.release(); + + try testing.expectEqual(@as(usize, 1), dict.getCount()); + try testing.expect(dict.getValue(foundation.String, c.kCFURLIsPurgeableKey) != null); + try testing.expect(dict.getValue(foundation.String, c.kCFURLIsVolumeKey) == null); +} + +test "mutable dictionary" { + const testing = std.testing; + + const dict = try MutableDictionary.create(0); + defer dict.release(); + + const str = try foundation.String.createWithBytes("hello", .unicode, false); + defer str.release(); + + dict.setValue(c.kCFURLIsPurgeableKey, str); + + { + const imm = @as(*Dictionary, @ptrCast(dict)); + try testing.expectEqual(@as(usize, 1), imm.getCount()); + try testing.expect(imm.getValue(foundation.String, c.kCFURLIsPurgeableKey) != null); + try testing.expect(imm.getValue(foundation.String, c.kCFURLIsVolumeKey) == null); + } +} diff --git a/vendor/libghostty-vt/pkg/macos/foundation/number.zig b/vendor/libghostty-vt/pkg/macos/foundation/number.zig new file mode 100644 index 00000000..88bf9edf --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/foundation/number.zig @@ -0,0 +1,79 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const c = @import("c.zig").c; + +pub const Number = opaque { + pub fn create( + comptime type_: NumberType, + value: *const type_.ValueType(), + ) Allocator.Error!*Number { + return @as(?*Number, @ptrFromInt(@intFromPtr(c.CFNumberCreate( + null, + @intFromEnum(type_), + value, + )))) orelse Allocator.Error.OutOfMemory; + } + + pub fn getValue(self: *const Number, comptime t: NumberType, ptr: *t.ValueType()) bool { + return c.CFNumberGetValue( + @ptrCast(self), + @intFromEnum(t), + ptr, + ) == 1; + } + + pub fn release(self: *Number) void { + c.CFRelease(self); + } +}; + +pub const NumberType = enum(c.CFNumberType) { + sint8 = c.kCFNumberSInt8Type, + sint16 = c.kCFNumberSInt16Type, + sint32 = c.kCFNumberSInt32Type, + sint64 = c.kCFNumberSInt64Type, + float32 = c.kCFNumberFloat32Type, + float64 = c.kCFNumberFloat64Type, + char = c.kCFNumberCharType, + short = c.kCFNumberShortType, + int = c.kCFNumberIntType, + long = c.kCFNumberLongType, + long_long = c.kCFNumberLongLongType, + float = c.kCFNumberFloatType, + double = c.kCFNumberDoubleType, + cf_index = c.kCFNumberCFIndexType, + ns_integer = c.kCFNumberNSIntegerType, + cg_float = c.kCFNumberCGFloatType, + + pub fn ValueType(comptime self: NumberType) type { + return switch (self) { + .sint8 => i8, + .sint16 => i16, + .sint32 => i32, + .sint64 => i64, + .float32 => f32, + .float64 => f64, + .char => u8, + .short => c_short, + .int => c_int, + .long => c_long, + .long_long => c_longlong, + .float => f32, + .double => f64, + else => unreachable, // TODO + }; + } +}; + +test { + const testing = std.testing; + + const inner: i8 = 42; + const v = try Number.create(.sint8, &inner); + defer v.release(); + + var result: i8 = undefined; + try testing.expect(v.getValue(.sint8, &result)); + try testing.expectEqual(result, inner); +} diff --git a/vendor/libghostty-vt/pkg/macos/foundation/string.zig b/vendor/libghostty-vt/pkg/macos/foundation/string.zig new file mode 100644 index 00000000..2f679fef --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/foundation/string.zig @@ -0,0 +1,174 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const c = @import("c.zig").c; + +pub const String = opaque { + pub fn createWithBytes( + bs: []const u8, + encoding: StringEncoding, + external: bool, + ) Allocator.Error!*String { + return @as(?*String, @ptrFromInt(@intFromPtr(c.CFStringCreateWithBytes( + null, + bs.ptr, + @intCast(bs.len), + @intFromEnum(encoding), + @intFromBool(external), + )))) orelse Allocator.Error.OutOfMemory; + } + + pub fn createWithCharactersNoCopy( + unichars: []const u16, + ) *String { + return @as(*String, @ptrFromInt(@intFromPtr(c.CFStringCreateWithCharactersNoCopy( + null, + @ptrCast(unichars.ptr), + @intCast(unichars.len), + foundation.c.kCFAllocatorNull, + )))); + } + + pub fn release(self: *String) void { + c.CFRelease(self); + } + + pub fn getLength(self: *String) usize { + return @intCast(c.CFStringGetLength(@ptrCast(self))); + } + + pub fn hasPrefix(self: *String, prefix: *String) bool { + return c.CFStringHasPrefix( + @ptrCast(self), + @ptrCast(prefix), + ) == 1; + } + + pub fn compare( + self: *String, + other: *String, + options: StringComparison, + ) foundation.ComparisonResult { + return @enumFromInt(c.CFStringCompare( + @ptrCast(self), + @ptrCast(other), + @intCast(@as(c_int, @bitCast(options))), + )); + } + + pub fn cstring(self: *String, buf: []u8, encoding: StringEncoding) ?[]const u8 { + if (c.CFStringGetCString( + @ptrCast(self), + buf.ptr, + @intCast(buf.len), + @intFromEnum(encoding), + ) == 0) return null; + return std.mem.sliceTo(buf, 0); + } + + pub fn cstringPtr(self: *String, encoding: StringEncoding) ?[:0]const u8 { + const ptr = c.CFStringGetCStringPtr( + @ptrCast(self), + @intFromEnum(encoding), + ); + if (ptr == null) return null; + return std.mem.sliceTo(ptr, 0); + } +}; + +pub const MutableString = opaque { + pub fn create(cap: usize) !*MutableString { + return @ptrCast(c.CFStringCreateMutable( + null, + @intCast(cap), + ) orelse return Allocator.Error.OutOfMemory); + } + + pub fn release(self: *MutableString) void { + foundation.CFRelease(self); + } + + pub fn string(self: *MutableString) *String { + return @ptrCast(self); + } + + pub fn appendCharacters(self: *MutableString, chars: []const u16) void { + c.CFStringAppendCharacters( + @ptrCast(self), + chars.ptr, + @intCast(chars.len), + ); + } +}; + +pub const StringComparison = packed struct { + case_insensitive: bool = false, + _unused_2: bool = false, + backwards: bool = false, + anchored: bool = false, + nonliteral: bool = false, + localized: bool = false, + numerically: bool = false, + diacritic_insensitive: bool = false, + width_insensitive: bool = false, + forced_ordering: bool = false, + _padding: u22 = 0, + + test { + try std.testing.expectEqual(@bitSizeOf(c_int), @bitSizeOf(StringComparison)); + } +}; + +/// https://developer.apple.com/documentation/corefoundation/cfstringencoding?language=objc +pub const StringEncoding = enum(u32) { + invalid = 0xffffffff, + mac_roman = 0, + windows_latin1 = 0x0500, + iso_latin1 = 0x0201, + nextstep_latin = 0x0B01, + ascii = 0x0600, + unicode = 0x0100, + utf8 = 0x08000100, + non_lossy_ascii = 0x0BFF, + utf16_be = 0x10000100, + utf16_le = 0x14000100, + utf32 = 0x0c000100, + utf32_be = 0x18000100, + utf32_le = 0x1c000100, +}; + +pub fn stringGetSurrogatePairForLongCharacter( + ch: u32, + surrogates: []u16, +) bool { + assert(surrogates.len >= 2); + return c.CFStringGetSurrogatePairForLongCharacter(ch, surrogates.ptr) == 1; +} + +test "string" { + const testing = std.testing; + + const str = try String.createWithBytes("hello world", .ascii, false); + defer str.release(); + + const prefix = try String.createWithBytes("hello", .ascii, false); + defer prefix.release(); + + try testing.expect(str.hasPrefix(prefix)); + try testing.expectEqual(foundation.ComparisonResult.equal, str.compare(str, .{})); + try testing.expectEqualStrings("hello world", str.cstringPtr(.ascii).?); + + { + var buf: [128]u8 = undefined; + const cstr = str.cstring(&buf, .ascii).?; + try testing.expectEqualStrings("hello world", cstr); + } +} + +test "unichar" { + const testing = std.testing; + + var unichars: [2]u16 = undefined; + try testing.expect(!stringGetSurrogatePairForLongCharacter('A', &unichars)); +} diff --git a/vendor/libghostty-vt/pkg/macos/foundation/type.zig b/vendor/libghostty-vt/pkg/macos/foundation/type.zig new file mode 100644 index 00000000..45bd0905 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/foundation/type.zig @@ -0,0 +1,2 @@ +pub extern "c" fn CFRelease(*anyopaque) void; +pub extern "c" fn CFRetain(*anyopaque) void; diff --git a/vendor/libghostty-vt/pkg/macos/foundation/url.zig b/vendor/libghostty-vt/pkg/macos/foundation/url.zig new file mode 100644 index 00000000..b48a7181 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/foundation/url.zig @@ -0,0 +1,104 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const c = @import("c.zig").c; + +pub const URL = opaque { + pub fn createWithString(str: *foundation.String, base: ?*URL) Allocator.Error!*URL { + return CFURLCreateWithString( + null, + str, + base, + ) orelse error.OutOfMemory; + } + + pub fn createWithFileSystemPath( + path: *foundation.String, + style: URLPathStyle, + dir: bool, + ) Allocator.Error!*URL { + return @as( + ?*URL, + @ptrFromInt(@intFromPtr(c.CFURLCreateWithFileSystemPath( + null, + @ptrCast(path), + @intFromEnum(style), + if (dir) 1 else 0, + ))), + ) orelse error.OutOfMemory; + } + + pub fn createStringByReplacingPercentEscapes( + str: *foundation.String, + escape: *foundation.String, + ) Allocator.Error!*foundation.String { + return CFURLCreateStringByReplacingPercentEscapes( + null, + str, + escape, + ) orelse return error.OutOfMemory; + } + + pub fn release(self: *URL) void { + foundation.CFRelease(self); + } + + pub fn copyPath(self: *URL) ?*foundation.String { + return CFURLCopyPath(self); + } + + pub extern "c" fn CFURLCreateWithString( + allocator: ?*anyopaque, + url_string: *const anyopaque, + base_url: ?*const anyopaque, + ) ?*URL; + pub extern "c" fn CFURLCopyPath(*URL) ?*foundation.String; + pub extern "c" fn CFURLCreateStringByReplacingPercentEscapes( + allocator: ?*anyopaque, + original: *const anyopaque, + escape: *const anyopaque, + ) ?*foundation.String; +}; + +pub const URLPathStyle = enum(c_int) { + posix = c.kCFURLPOSIXPathStyle, + windows = c.kCFURLWindowsPathStyle, +}; + +test { + const testing = std.testing; + + const str = try foundation.String.createWithBytes("http://www.example.com/foo", .utf8, false); + defer str.release(); + + const url = try URL.createWithString(str, null); + defer url.release(); + + { + const path = url.copyPath().?; + defer path.release(); + + var buf: [128]u8 = undefined; + const cstr = path.cstring(&buf, .utf8).?; + try testing.expectEqualStrings("/foo", cstr); + } +} + +test "path" { + const testing = std.testing; + + const str = try foundation.String.createWithBytes("foo/bar.ttf", .utf8, false); + defer str.release(); + + const url = try URL.createWithFileSystemPath(str, .posix, false); + defer url.release(); + + { + const path = url.copyPath().?; + defer path.release(); + + var buf: [128]u8 = undefined; + const cstr = path.cstring(&buf, .utf8).?; + try testing.expectEqualStrings("foo/bar.ttf", cstr); + } +} diff --git a/vendor/libghostty-vt/pkg/macos/graphics.zig b/vendor/libghostty-vt/pkg/macos/graphics.zig new file mode 100644 index 00000000..5195da4a --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/graphics.zig @@ -0,0 +1,24 @@ +const affine_transform = @import("graphics/affine_transform.zig"); +const bitmap_context = @import("graphics/bitmap_context.zig"); +const color_space = @import("graphics/color_space.zig"); +const font = @import("graphics/font.zig"); +const geometry = @import("graphics/geometry.zig"); +const image = @import("graphics/image.zig"); +const path = @import("graphics/path.zig"); + +pub const c = @import("graphics/c.zig").c; +pub const AffineTransform = affine_transform.AffineTransform; +pub const BitmapContext = bitmap_context.BitmapContext; +pub const ColorSpace = color_space.ColorSpace; +pub const Glyph = font.Glyph; +pub const Point = geometry.Point; +pub const Rect = geometry.Rect; +pub const Size = geometry.Size; +pub const ImageAlphaInfo = image.ImageAlphaInfo; +pub const BitmapInfo = image.BitmapInfo; +pub const Path = path.Path; +pub const MutablePath = path.MutablePath; + +test { + @import("std").testing.refAllDecls(@This()); +} diff --git a/vendor/libghostty-vt/pkg/macos/graphics/affine_transform.zig b/vendor/libghostty-vt/pkg/macos/graphics/affine_transform.zig new file mode 100644 index 00000000..e649e7a1 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/graphics/affine_transform.zig @@ -0,0 +1,16 @@ +const std = @import("std"); +const assert = std.debug.assert; +const c = @import("c.zig").c; + +pub const AffineTransform = extern struct { + a: c.CGFloat, + b: c.CGFloat, + c: c.CGFloat, + d: c.CGFloat, + tx: c.CGFloat, + ty: c.CGFloat, + + pub fn identity() AffineTransform { + return @bitCast(c.CGAffineTransformIdentity); + } +}; diff --git a/vendor/libghostty-vt/pkg/macos/graphics/bitmap_context.zig b/vendor/libghostty-vt/pkg/macos/graphics/bitmap_context.zig new file mode 100644 index 00000000..7db5577f --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/graphics/bitmap_context.zig @@ -0,0 +1,50 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const graphics = @import("../graphics.zig"); +const Context = @import("context.zig").Context; +const c = @import("c.zig").c; + +pub const BitmapContext = opaque { + pub const context = Context(BitmapContext); + + pub fn create( + data: ?[]u8, + width: usize, + height: usize, + bits_per_component: usize, + bytes_per_row: usize, + space: *graphics.ColorSpace, + opts: c_uint, + ) Allocator.Error!*BitmapContext { + return @as( + ?*BitmapContext, + @ptrFromInt(@intFromPtr(c.CGBitmapContextCreate( + @ptrCast(if (data) |d| d.ptr else null), + width, + height, + bits_per_component, + bytes_per_row, + @ptrCast(space), + opts, + ))), + ) orelse Allocator.Error.OutOfMemory; + } +}; + +test { + //const testing = std.testing; + + const cs = try graphics.ColorSpace.createDeviceGray(); + defer cs.release(); + const ctx = try BitmapContext.create(null, 80, 80, 8, 80, cs, 0); + const context = BitmapContext.context; + defer context.release(ctx); + context.setShouldAntialias(ctx, true); + context.setShouldSmoothFonts(ctx, false); + context.setGrayFillColor(ctx, 1, 1); + context.setGrayStrokeColor(ctx, 1, 1); + context.setTextDrawingMode(ctx, .fill); + context.setTextMatrix(ctx, graphics.AffineTransform.identity()); + context.setTextPosition(ctx, 0, 0); +} diff --git a/vendor/libghostty-vt/pkg/macos/graphics/c.zig b/vendor/libghostty-vt/pkg/macos/graphics/c.zig new file mode 100644 index 00000000..1a7d1627 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/graphics/c.zig @@ -0,0 +1 @@ +pub const c = @import("../main.zig").c; diff --git a/vendor/libghostty-vt/pkg/macos/graphics/color_space.zig b/vendor/libghostty-vt/pkg/macos/graphics/color_space.zig new file mode 100644 index 00000000..16960591 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/graphics/color_space.zig @@ -0,0 +1,99 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const c = @import("c.zig").c; + +pub const ColorSpace = opaque { + pub fn createDeviceGray() Allocator.Error!*ColorSpace { + return @as( + ?*ColorSpace, + @ptrFromInt(@intFromPtr(c.CGColorSpaceCreateDeviceGray())), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn createDeviceRGB() Allocator.Error!*ColorSpace { + return @as( + ?*ColorSpace, + @ptrFromInt(@intFromPtr(c.CGColorSpaceCreateDeviceRGB())), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn createNamed(name: Name) Allocator.Error!*ColorSpace { + return @as( + ?*ColorSpace, + @ptrFromInt(@intFromPtr(c.CGColorSpaceCreateWithName(name.cfstring()))), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn release(self: *ColorSpace) void { + c.CGColorSpaceRelease(@ptrCast(self)); + } + + pub const Name = enum { + /// This color space uses the DCI P3 primaries, a D65 white point, and + /// the sRGB transfer function. + displayP3, + /// The Display P3 color space with a linear transfer function and + /// extended-range values. + extendedLinearDisplayP3, + /// The sRGB colorimetry and non-linear transfer function are specified + /// in IEC 61966-2-1. + sRGB, + /// This color space has the same colorimetry as `sRGB`, but uses a + /// linear transfer function. + linearSRGB, + /// This color space has the same colorimetry as `sRGB`, but you can + /// encode component values below `0.0` and above `1.0`. Negative values + /// are encoded as the signed reflection of the original encoding + /// function, as shown in the formula below: + /// ``` + /// extendedTransferFunction(x) = sign(x) * sRGBTransferFunction(abs(x)) + /// ``` + extendedSRGB, + /// This color space has the same colorimetry as `sRGB`; in addition, + /// you may encode component values below `0.0` and above `1.0`. + extendedLinearSRGB, + /// ... + genericGrayGamma2_2, + /// ... + linearGray, + /// This color space has the same colorimetry as `genericGrayGamma2_2`, + /// but you can encode component values below `0.0` and above `1.0`. + /// Negative values are encoded as the signed reflection of the + /// original encoding function, as shown in the formula below: + /// ``` + /// extendedGrayTransferFunction(x) = sign(x) * gamma22Function(abs(x)) + /// ``` + extendedGray, + /// This color space has the same colorimetry as `linearGray`; in + /// addition, you may encode component values below `0.0` and above `1.0`. + extendedLinearGray, + + fn cfstring(self: Name) c.CFStringRef { + return switch (self) { + .displayP3 => c.kCGColorSpaceDisplayP3, + .extendedLinearDisplayP3 => c.kCGColorSpaceExtendedLinearDisplayP3, + .sRGB => c.kCGColorSpaceSRGB, + .extendedSRGB => c.kCGColorSpaceExtendedSRGB, + .linearSRGB => c.kCGColorSpaceLinearSRGB, + .extendedLinearSRGB => c.kCGColorSpaceExtendedLinearSRGB, + .genericGrayGamma2_2 => c.kCGColorSpaceGenericGrayGamma2_2, + .extendedGray => c.kCGColorSpaceExtendedGray, + .linearGray => c.kCGColorSpaceLinearGray, + .extendedLinearGray => c.kCGColorSpaceExtendedLinearGray, + }; + } + }; +}; + +test { + //const testing = std.testing; + + const space = try ColorSpace.createDeviceGray(); + defer space.release(); +} + +test { + const space = try ColorSpace.createDeviceRGB(); + defer space.release(); +} diff --git a/vendor/libghostty-vt/pkg/macos/graphics/context.zig b/vendor/libghostty-vt/pkg/macos/graphics/context.zig new file mode 100644 index 00000000..77e4344e --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/graphics/context.zig @@ -0,0 +1,172 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const graphics = @import("../graphics.zig"); +const c = @import("c.zig").c; + +/// Returns a struct that has all the shared context functions for the +/// given type. +pub fn Context(comptime T: type) type { + return struct { + value: *T, + + pub fn release(self: *T) void { + c.CGContextRelease(@ptrCast(self)); + } + + pub fn setLineWidth(self: *T, width: f64) void { + c.CGContextSetLineWidth( + @ptrCast(self), + width, + ); + } + + pub fn setAllowsAntialiasing(self: *T, v: bool) void { + c.CGContextSetAllowsAntialiasing( + @ptrCast(self), + v, + ); + } + + pub fn setAllowsFontSmoothing(self: *T, v: bool) void { + c.CGContextSetAllowsFontSmoothing( + @ptrCast(self), + v, + ); + } + + pub fn setAllowsFontSubpixelPositioning(self: *T, v: bool) void { + c.CGContextSetAllowsFontSubpixelPositioning( + @ptrCast(self), + v, + ); + } + + pub fn setAllowsFontSubpixelQuantization(self: *T, v: bool) void { + c.CGContextSetAllowsFontSubpixelQuantization( + @ptrCast(self), + v, + ); + } + + pub fn setShouldAntialias(self: *T, v: bool) void { + c.CGContextSetShouldAntialias( + @ptrCast(self), + v, + ); + } + + pub fn setShouldSmoothFonts(self: *T, v: bool) void { + c.CGContextSetShouldSmoothFonts( + @ptrCast(self), + v, + ); + } + + pub fn setShouldSubpixelPositionFonts(self: *T, v: bool) void { + c.CGContextSetShouldSubpixelPositionFonts( + @ptrCast(self), + v, + ); + } + + pub fn setShouldSubpixelQuantizeFonts(self: *T, v: bool) void { + c.CGContextSetShouldSubpixelQuantizeFonts( + @ptrCast(self), + v, + ); + } + + pub fn setGrayFillColor(self: *T, gray: f64, alpha: f64) void { + c.CGContextSetGrayFillColor( + @ptrCast(self), + gray, + alpha, + ); + } + + pub fn setGrayStrokeColor(self: *T, gray: f64, alpha: f64) void { + c.CGContextSetGrayStrokeColor( + @ptrCast(self), + gray, + alpha, + ); + } + + pub fn setRGBFillColor(self: *T, r: f64, g: f64, b: f64, alpha: f64) void { + c.CGContextSetRGBFillColor( + @ptrCast(self), + r, + g, + b, + alpha, + ); + } + + pub fn setRGBStrokeColor(self: *T, r: f64, g: f64, b: f64, alpha: f64) void { + c.CGContextSetRGBStrokeColor( + @ptrCast(self), + r, + g, + b, + alpha, + ); + } + + pub fn setTextDrawingMode(self: *T, mode: TextDrawingMode) void { + c.CGContextSetTextDrawingMode( + @ptrCast(self), + @intFromEnum(mode), + ); + } + + pub fn setTextMatrix(self: *T, matrix: graphics.AffineTransform) void { + c.CGContextSetTextMatrix( + @ptrCast(self), + @bitCast(matrix), + ); + } + + pub fn setTextPosition(self: *T, x: f64, y: f64) void { + c.CGContextSetTextPosition( + @ptrCast(self), + x, + y, + ); + } + + pub fn fillRect(self: *T, rect: graphics.Rect) void { + c.CGContextFillRect( + @ptrCast(self), + @bitCast(rect), + ); + } + + pub fn scaleCTM(self: *T, sx: c.CGFloat, sy: c.CGFloat) void { + c.CGContextScaleCTM( + @ptrCast(self), + sx, + sy, + ); + } + + pub fn translateCTM(self: *T, tx: c.CGFloat, ty: c.CGFloat) void { + c.CGContextTranslateCTM( + @ptrCast(self), + tx, + ty, + ); + } + }; +} + +pub const TextDrawingMode = enum(c_int) { + fill = c.kCGTextFill, + stroke = c.kCGTextStroke, + fill_stroke = c.kCGTextFillStroke, + invisible = c.kCGTextInvisible, + fill_clip = c.kCGTextFillClip, + stroke_clip = c.kCGTextStrokeClip, + fill_stroke_clip = c.kCGTextFillStrokeClip, + clip = c.kCGTextClip, +}; diff --git a/vendor/libghostty-vt/pkg/macos/graphics/font.zig b/vendor/libghostty-vt/pkg/macos/graphics/font.zig new file mode 100644 index 00000000..c310c62a --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/graphics/font.zig @@ -0,0 +1,3 @@ +const c = @import("c.zig").c; + +pub const Glyph = c.CGGlyph; diff --git a/vendor/libghostty-vt/pkg/macos/graphics/geometry.zig b/vendor/libghostty-vt/pkg/macos/graphics/geometry.zig new file mode 100644 index 00000000..66937403 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/graphics/geometry.zig @@ -0,0 +1,34 @@ +const std = @import("std"); +const assert = std.debug.assert; +const c = @import("c.zig").c; + +pub const Point = extern struct { + x: c.CGFloat, + y: c.CGFloat, +}; + +pub const Rect = extern struct { + origin: Point, + size: Size, + + pub fn init(x: f64, y: f64, width: f64, height: f64) Rect { + return @bitCast(c.CGRectMake(x, y, width, height)); + } + + pub fn isNull(self: Rect) bool { + return c.CGRectIsNull(@bitCast(self)); + } + + pub fn getHeight(self: Rect) c.CGFloat { + return c.CGRectGetHeight(@bitCast(self)); + } + + pub fn getWidth(self: Rect) c.CGFloat { + return c.CGRectGetWidth(@bitCast(self)); + } +}; + +pub const Size = extern struct { + width: c.CGFloat, + height: c.CGFloat, +}; diff --git a/vendor/libghostty-vt/pkg/macos/graphics/image.zig b/vendor/libghostty-vt/pkg/macos/graphics/image.zig new file mode 100644 index 00000000..879384b1 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/graphics/image.zig @@ -0,0 +1,31 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const graphics = @import("../graphics.zig"); +const context = @import("context.zig"); +const c = @import("c.zig").c; + +pub const ImageAlphaInfo = enum(c_uint) { + none = c.kCGImageAlphaNone, + premultiplied_last = c.kCGImageAlphaPremultipliedLast, + premultiplied_first = c.kCGImageAlphaPremultipliedFirst, + last = c.kCGImageAlphaLast, + first = c.kCGImageAlphaFirst, + none_skip_last = c.kCGImageAlphaNoneSkipLast, + none_skip_first = c.kCGImageAlphaNoneSkipFirst, + only = c.kCGImageAlphaOnly, +}; + +pub const BitmapInfo = enum(c_uint) { + alpha_mask = c.kCGBitmapAlphaInfoMask, + float_mask = c.kCGBitmapFloatInfoMask, + float_components = c.kCGBitmapFloatComponents, + byte_order_mask = c.kCGBitmapByteOrderMask, + byte_order_default = c.kCGBitmapByteOrderDefault, + byte_order_16_little = c.kCGBitmapByteOrder16Little, + byte_order_32_little = c.kCGBitmapByteOrder32Little, + byte_order_16_big = c.kCGBitmapByteOrder16Big, + byte_order_32_big = c.kCGBitmapByteOrder32Big, + + _, +}; diff --git a/vendor/libghostty-vt/pkg/macos/graphics/path.zig b/vendor/libghostty-vt/pkg/macos/graphics/path.zig new file mode 100644 index 00000000..7f549709 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/graphics/path.zig @@ -0,0 +1,68 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const graphics = @import("../graphics.zig"); +const c = @import("c.zig").c; + +pub const Path = opaque { + pub fn createWithRect( + rect: graphics.Rect, + transform: ?*const graphics.AffineTransform, + ) Allocator.Error!*Path { + return @as( + ?*Path, + @ptrFromInt(@intFromPtr(c.CGPathCreateWithRect( + @bitCast(rect), + @ptrCast(transform), + ))), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn release(self: *Path) void { + foundation.CFRelease(self); + } +}; + +pub const MutablePath = opaque { + pub fn create() Allocator.Error!*MutablePath { + return @as( + ?*MutablePath, + @ptrFromInt(@intFromPtr(c.CGPathCreateMutable())), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn release(self: *MutablePath) void { + foundation.CFRelease(self); + } + + pub fn addRect( + self: *MutablePath, + transform: ?*const graphics.AffineTransform, + rect: graphics.Rect, + ) void { + c.CGPathAddRect( + @ptrCast(self), + @ptrCast(transform), + @bitCast(rect), + ); + } + + pub fn getBoundingBox(self: *MutablePath) graphics.Rect { + return @bitCast(c.CGPathGetBoundingBox(@ptrCast(self))); + } +}; + +test "mutable path" { + //const testing = std.testing; + + const path = try MutablePath.create(); + defer path.release(); + + path.addRect(null, graphics.Rect.init(0, 0, 100, 200)); +} + +test "path from rect" { + const path = try Path.createWithRect(graphics.Rect.init(0, 0, 100, 200), null); + defer path.release(); +} diff --git a/vendor/libghostty-vt/pkg/macos/iosurface.zig b/vendor/libghostty-vt/pkg/macos/iosurface.zig new file mode 100644 index 00000000..9d2e750c --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/iosurface.zig @@ -0,0 +1,8 @@ +const iosurface = @import("iosurface/iosurface.zig"); + +pub const c = @import("iosurface/c.zig").c; +pub const IOSurface = iosurface.IOSurface; + +test { + @import("std").testing.refAllDecls(@This()); +} diff --git a/vendor/libghostty-vt/pkg/macos/iosurface/c.zig b/vendor/libghostty-vt/pkg/macos/iosurface/c.zig new file mode 100644 index 00000000..1a7d1627 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/iosurface/c.zig @@ -0,0 +1 @@ +pub const c = @import("../main.zig").c; diff --git a/vendor/libghostty-vt/pkg/macos/iosurface/iosurface.zig b/vendor/libghostty-vt/pkg/macos/iosurface/iosurface.zig new file mode 100644 index 00000000..37f8712b --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/iosurface/iosurface.zig @@ -0,0 +1,136 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const c = @import("c.zig").c; +const foundation = @import("../foundation.zig"); +const graphics = @import("../graphics.zig"); +const video = @import("../video.zig"); + +pub const IOSurface = opaque { + pub const Error = error{ + InvalidOperation, + }; + + pub const Properties = struct { + width: c_int, + height: c_int, + pixel_format: video.PixelFormat, + bytes_per_element: c_int, + colorspace: ?*graphics.ColorSpace, + }; + + pub fn init(properties: Properties) Allocator.Error!*IOSurface { + var w = try foundation.Number.create(.int, &properties.width); + defer w.release(); + var h = try foundation.Number.create(.int, &properties.height); + defer h.release(); + var pf = try foundation.Number.create(.int, &@as(c_int, @intFromEnum(properties.pixel_format))); + defer pf.release(); + var bpe = try foundation.Number.create(.int, &properties.bytes_per_element); + defer bpe.release(); + + var properties_dict = try foundation.Dictionary.create( + &[_]?*const anyopaque{ + c.kIOSurfaceWidth, + c.kIOSurfaceHeight, + c.kIOSurfacePixelFormat, + c.kIOSurfaceBytesPerElement, + }, + &[_]?*const anyopaque{ w, h, pf, bpe }, + ); + defer properties_dict.release(); + + var surface = @as(?*IOSurface, @ptrFromInt(@intFromPtr( + c.IOSurfaceCreate(@ptrCast(properties_dict)), + ))) orelse return error.OutOfMemory; + + if (properties.colorspace) |space| { + surface.setColorSpace(space); + } + + return surface; + } + + pub fn deinit(self: *IOSurface) void { + // We mark it purgeable so that it is immediately unloaded, so that we + // don't have to wait for CoreFoundation garbage collection to trigger. + _ = c.IOSurfaceSetPurgeable( + @ptrCast(self), + c.kIOSurfacePurgeableEmpty, + null, + ); + foundation.CFRelease(self); + } + + pub fn retain(self: *IOSurface) void { + foundation.CFRetain(self); + } + + pub fn release(self: *IOSurface) void { + foundation.CFRelease(self); + } + + pub fn setColorSpace(self: *IOSurface, colorspace: *graphics.ColorSpace) void { + const serialized_colorspace = graphics.c.CGColorSpaceCopyPropertyList( + @ptrCast(colorspace), + ).?; + defer foundation.CFRelease(@constCast(serialized_colorspace)); + + c.IOSurfaceSetValue( + @ptrCast(self), + c.kIOSurfaceColorSpace, + @ptrCast(serialized_colorspace), + ); + } + + pub inline fn lock(self: *IOSurface) void { + c.IOSurfaceLock( + @ptrCast(self), + 0, + null, + ); + } + pub inline fn unlock(self: *IOSurface) void { + c.IOSurfaceUnlock( + @ptrCast(self), + 0, + null, + ); + } + + pub inline fn getAllocSize(self: *IOSurface) usize { + return c.IOSurfaceGetAllocSize(@ptrCast(self)); + } + + pub inline fn getWidth(self: *IOSurface) usize { + return c.IOSurfaceGetWidth(@ptrCast(self)); + } + + pub inline fn getHeight(self: *IOSurface) usize { + return c.IOSurfaceGetHeight(@ptrCast(self)); + } + + pub inline fn getBytesPerElement(self: *IOSurface) usize { + return c.IOSurfaceGetBytesPerElement(@ptrCast(self)); + } + + pub inline fn getBytesPerRow(self: *IOSurface) usize { + return c.IOSurfaceGetBytesPerRow(@ptrCast(self)); + } + + pub inline fn getBaseAddress(self: *IOSurface) ?[*]u8 { + return @ptrCast(c.IOSurfaceGetBaseAddress(@ptrCast(self))); + } + + pub inline fn getElementWidth(self: *IOSurface) usize { + return c.IOSurfaceGetElementWidth(@ptrCast(self)); + } + + pub inline fn getElementHeight(self: *IOSurface) usize { + return c.IOSurfaceGetElementHeight(@ptrCast(self)); + } + + pub inline fn getPixelFormat(self: *IOSurface) video.PixelFormat { + return @enumFromInt(c.IOSurfaceGetPixelFormat(@ptrCast(self))); + } +}; diff --git a/vendor/libghostty-vt/pkg/macos/main.zig b/vendor/libghostty-vt/pkg/macos/main.zig new file mode 100644 index 00000000..e4f4b950 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/main.zig @@ -0,0 +1,35 @@ +const builtin = @import("builtin"); + +pub const carbon = @import("carbon.zig"); +pub const foundation = @import("foundation.zig"); +pub const animation = @import("animation.zig"); +pub const dispatch = @import("dispatch.zig"); +pub const graphics = @import("graphics.zig"); +pub const os = @import("os.zig"); +pub const text = @import("text.zig"); +pub const video = @import("video.zig"); +pub const iosurface = @import("iosurface.zig"); + +// All of our C imports consolidated into one place. We used to +// import them one by one in each package but Zig 0.14 has some +// kind of issue with that I wasn't able to minimize. +pub const c = @cImport({ + @cInclude("CoreFoundation/CoreFoundation.h"); + @cInclude("CoreGraphics/CoreGraphics.h"); + @cInclude("CoreText/CoreText.h"); + @cInclude("CoreVideo/CoreVideo.h"); + @cInclude("CoreVideo/CVPixelBuffer.h"); + @cInclude("QuartzCore/CALayer.h"); + @cInclude("IOSurface/IOSurfaceRef.h"); + @cInclude("dispatch/dispatch.h"); + @cInclude("os/log.h"); + @cInclude("os/signpost.h"); + + if (builtin.os.tag == .macos) { + @cInclude("Carbon/Carbon.h"); + } +}); + +test { + @import("std").testing.refAllDecls(@This()); +} diff --git a/vendor/libghostty-vt/pkg/macos/os.zig b/vendor/libghostty-vt/pkg/macos/os.zig new file mode 100644 index 00000000..9716a9ab --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/os.zig @@ -0,0 +1,10 @@ +const log = @import("os/log.zig"); + +pub const c = @import("os/c.zig"); +pub const signpost = @import("os/signpost.zig"); +pub const Log = log.Log; +pub const LogType = log.LogType; + +test { + @import("std").testing.refAllDecls(@This()); +} diff --git a/vendor/libghostty-vt/pkg/macos/os/c.zig b/vendor/libghostty-vt/pkg/macos/os/c.zig new file mode 100644 index 00000000..1a7d1627 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/os/c.zig @@ -0,0 +1 @@ +pub const c = @import("../main.zig").c; diff --git a/vendor/libghostty-vt/pkg/macos/os/log.zig b/vendor/libghostty-vt/pkg/macos/os/log.zig new file mode 100644 index 00000000..219c914d --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/os/log.zig @@ -0,0 +1,65 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const c = @import("c.zig").c; + +pub const Log = opaque { + pub fn create( + subsystem: [:0]const u8, + category: [:0]const u8, + ) *Log { + return @ptrCast(c.os_log_create( + subsystem.ptr, + category.ptr, + ).?); + } + + pub fn release(self: *Log) void { + c.os_release(self); + } + + pub fn typeEnabled(self: *Log, typ: LogType) bool { + return c.os_log_type_enabled( + @ptrCast(self), + @intFromEnum(typ), + ); + } + + pub fn log( + self: *Log, + alloc: Allocator, + typ: LogType, + comptime format: []const u8, + args: anytype, + ) void { + const str = nosuspend std.fmt.allocPrintSentinel( + alloc, + format, + args, + 0, + ) catch return; + defer alloc.free(str); + zig_os_log_with_type(self, typ, str.ptr); + } + + extern "c" fn zig_os_log_with_type(*Log, LogType, [*c]const u8) void; +}; + +/// https://developer.apple.com/documentation/os/os_log_type_t?language=objc +pub const LogType = enum(c.os_log_type_t) { + default = c.OS_LOG_TYPE_DEFAULT, + debug = c.OS_LOG_TYPE_DEBUG, + info = c.OS_LOG_TYPE_INFO, + err = c.OS_LOG_TYPE_ERROR, + fault = c.OS_LOG_TYPE_FAULT, +}; + +test { + const testing = std.testing; + + const log = Log.create("com.mitchellh.ghostty", "test"); + defer log.release(); + + try testing.expect(log.typeEnabled(.fault)); + log.log(testing.allocator, .default, "hello {d}", .{12}); +} diff --git a/vendor/libghostty-vt/pkg/macos/os/signpost.zig b/vendor/libghostty-vt/pkg/macos/os/signpost.zig new file mode 100644 index 00000000..2bd12566 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/os/signpost.zig @@ -0,0 +1,214 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const c = @import("c.zig").c; +const logpkg = @import("log.zig"); +const Log = logpkg.Log; + +/// This should be called once at the start of the program to intialize +/// some required state for signpost logging. +/// +/// This is all to workaround a Zig bug: +/// https://github.com/ziglang/zig/issues/24370 +pub fn init() void { + if (__dso_handle != null) return; + + const sym = comptime sym: { + const root = @import("root"); + + // If we have a main function, use that as the symbol. + if (@hasDecl(root, "main")) break :sym root.main; + + // Otherwise, we're in a library, so we just use the first + // function in our root module. I actually don't know if this is + // all required or if we can just use the real `__dso_handle` symbol, + // but this seems to work for now. + for (@typeInfo(root).@"struct".decls) |decl_info| { + const decl = @field(root, decl_info.name); + if (@typeInfo(@TypeOf(decl)) == .@"fn") break :sym decl; + } + + @compileError("no functions found in root module"); + }; + + // Since __dso_handle is not automatically populated by the linker, + // we populate it by looking up the main function's module address + // which should be a mach-o header. + var info: DlInfo = undefined; + const result = dladdr(sym, &info); + assert(result != 0); + __dso_handle = @ptrCast(@alignCast(info.dli_fbase)); +} + +/// This should REALLY be an extern var that is populated by the linker, +/// but there is a Zig bug: https://github.com/ziglang/zig/issues/24370 +var __dso_handle: ?*c.mach_header = null; + +// Import the necessary C functions and types +extern "c" fn dladdr(addr: ?*const anyopaque, info: *DlInfo) c_int; + +// Define the Dl_info structure +const DlInfo = extern struct { + dli_fname: [*:0]const u8, // Pathname of shared object + dli_fbase: ?*anyopaque, // Base address of shared object + dli_sname: [*:0]const u8, // Name of nearest symbol + dli_saddr: ?*anyopaque, // Address of nearest symbol +}; + +/// Checks whether signpost logging is enabled for the given log handle. +/// Returns true if signposts will be recorded for this log, false otherwise. +/// This can be used to avoid expensive operations when signpost logging is disabled. +/// +/// https://developer.apple.com/documentation/os/os_signpost_enabled?language=objc +pub fn enabled(log: *Log) bool { + return c.os_signpost_enabled(@ptrCast(log)); +} + +/// Emits a signpost event - a single point in time marker. +/// Events are useful for marking when specific actions occur, such as +/// user interactions, state changes, or other discrete occurrences. +/// The event will appear as a vertical line in Instruments. +/// +/// https://developer.apple.com/documentation/os/os_signpost_event_emit?language=objc +pub fn emitEvent( + log: *Log, + id: Id, + comptime name: [:0]const u8, +) void { + emitWithName(log, id, .event, name); +} + +/// Marks the beginning of a time interval. +/// Use this with intervalEnd to measure the duration of operations. +/// The same ID must be used for both the begin and end calls. +/// Intervals appear as horizontal bars in Instruments timeline. +/// +/// https://developer.apple.com/documentation/os/os_signpost_interval_begin?language=objc +pub fn intervalBegin(log: *Log, id: Id, comptime name: [:0]const u8) void { + emitWithName(log, id, .interval_begin, name); +} + +/// Marks the end of a time interval. +/// Must be paired with a prior intervalBegin call using the same ID. +/// The name should match the name used in intervalBegin. +/// Instruments will calculate and display the duration between begin and end. +/// +/// https://developer.apple.com/documentation/os/os_signpost_interval_end?language=objc +pub fn intervalEnd(log: *Log, id: Id, comptime name: [:0]const u8) void { + emitWithName(log, id, .interval_end, name); +} + +/// The internal function to emit a signpost with a specific name. +fn emitWithName( + log: *Log, + id: Id, + typ: Type, + comptime name: [:0]const u8, +) void { + // Init must be called by this point. + assert(__dso_handle != null); + + var buf: [2]u8 = @splat(0); + c._os_signpost_emit_with_name_impl( + __dso_handle, + @ptrCast(log), + @intFromEnum(typ), + @intFromEnum(id), + name.ptr, + "".ptr, + &buf, + buf.len, + ); +} + +/// https://developer.apple.com/documentation/os/os_signpost_id_t?language=objc +pub const Id = enum(u64) { + null = 0, // OS_SIGNPOST_ID_NULL + invalid = 0xFFFFFFFFFFFFFFFF, // OS_SIGNPOST_ID_INVALID + exclusive = 0xEEEEB0B5B2B2EEEE, // OS_SIGNPOST_ID_EXCLUSIVE + _, + + /// Generates a new signpost ID for use with signpost operations. + /// The ID is unique for the given log handle and can be used to track + /// asynchronous operations or mark specific points of interest in the code. + /// Returns a unique signpost ID that can be used with os_signpost functions. + /// + /// https://developer.apple.com/documentation/os/os_signpost_id_generate?language=objc + pub fn generate(log: *Log) Id { + return @enumFromInt(c.os_signpost_id_generate(@ptrCast(log))); + } + + /// Creates a signpost ID based on a pointer value. + /// This is useful for tracking operations associated with a specific object + /// or memory location. The same pointer will always generate the same ID + /// for a given log handle, allowing correlation of signpost events. + /// Pass null to get the null signpost ID. + /// + /// https://developer.apple.com/documentation/os/os_signpost_id_for_pointer?language=objc + pub fn forPointer(log: *Log, ptr: ?*anyopaque) Id { + return @enumFromInt(c.os_signpost_id_make_with_pointer( + @ptrCast(log), + @ptrCast(ptr), + )); + } + + test "generate ID" { + // We can't really test the return value because it may return null + // if signposts are disabled. + const id: Id = .generate(Log.create("com.mitchellh.ghostty", "test")); + try std.testing.expect(id != .invalid); + } + + test "generate ID for pointer" { + var foo: usize = 0x1234; + const id: Id = .forPointer(Log.create("com.mitchellh.ghostty", "test"), &foo); + try std.testing.expect(id != .null); + } +}; + +/// https://developer.apple.com/documentation/os/ossignposttype?language=objc +pub const Type = enum(u8) { + event = 0, // OS_SIGNPOST_EVENT + interval_begin = 1, // OS_SIGNPOST_INTERVAL_BEGIN + interval_end = 2, // OS_SIGNPOST_INTERVAL_END + + pub const mask: u8 = 0x03; // OS_SIGNPOST_TYPE_MASK +}; + +/// Special os_log category values that surface in Instruments and other +/// tooling. +pub const Category = struct { + /// Points of Interest appear as a dedicated track in Instruments. + /// Use this for high-level application events that help understand + /// the flow of your application. + pub const points_of_interest: [:0]const u8 = "PointsOfInterest"; + + /// Dynamic Tracing category enables runtime-configurable logging. + /// Signposts in this category can be enabled/disabled dynamically + /// without recompiling. + pub const dynamic_tracing: [:0]const u8 = "DynamicTracing"; + + /// Dynamic Stack Tracing category captures call stacks at signpost + /// events. This provides deeper debugging information but has higher + /// performance overhead. + pub const dynamic_stack_tracing: [:0]const u8 = "DynamicStackTracing"; +}; + +test { + _ = Id; +} + +test enabled { + _ = enabled(Log.create("com.mitchellh.ghostty", "test")); +} + +test "intervals" { + init(); + + const log = Log.create("com.mitchellh.ghostty", "test"); + defer log.release(); + + // Test that we can begin and end an interval + const id = Id.generate(log); + intervalBegin(log, id, "Test Interval"); +} diff --git a/vendor/libghostty-vt/pkg/macos/os/zig_macos.c b/vendor/libghostty-vt/pkg/macos/os/zig_macos.c new file mode 100644 index 00000000..1c4f0698 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/os/zig_macos.c @@ -0,0 +1,11 @@ +#include <os/log.h> +#include <os/signpost.h> + +// A wrapper so we can use the os_log_with_type macro. +void zig_os_log_with_type( + os_log_t log, + os_log_type_t type, + const char *message +) { + os_log_with_type(log, type, "%{public}s", message); +} diff --git a/vendor/libghostty-vt/pkg/macos/text.zig b/vendor/libghostty-vt/pkg/macos/text.zig new file mode 100644 index 00000000..bfaa388b --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/text.zig @@ -0,0 +1,38 @@ +const font = @import("text/font.zig"); +const font_collection = @import("text/font_collection.zig"); +const font_descriptor = @import("text/font_descriptor.zig"); +const font_manager = @import("text/font_manager.zig"); +const frame = @import("text/frame.zig"); +const framesetter = @import("text/framesetter.zig"); +const typesetter = @import("text/typesetter.zig"); +const line = @import("text/line.zig"); +const paragraph_style = @import("text/paragraph_style.zig"); +const run = @import("text/run.zig"); +const stylized_strings = @import("text/stylized_strings.zig"); + +pub const c = @import("text/c.zig").c; +pub const Font = font.Font; +pub const FontTableTag = font.FontTableTag; +pub const FontCollection = font_collection.FontCollection; +pub const FontDescriptor = font_descriptor.FontDescriptor; +pub const FontAttribute = font_descriptor.FontAttribute; +pub const FontTraitKey = font_descriptor.FontTraitKey; +pub const FontVariationAxisKey = font_descriptor.FontVariationAxisKey; +pub const FontSymbolicTraits = font_descriptor.FontSymbolicTraits; +pub const createFontDescriptorsFromURL = font_manager.createFontDescriptorsFromURL; +pub const createFontDescriptorsFromData = font_manager.createFontDescriptorsFromData; +pub const createFontDescriptorFromData = font_manager.createFontDescriptorFromData; +pub const Frame = frame.Frame; +pub const Framesetter = framesetter.Framesetter; +pub const Typesetter = typesetter.Typesetter; +pub const Line = line.Line; +pub const ParagraphStyle = paragraph_style.ParagraphStyle; +pub const ParagraphStyleSetting = paragraph_style.ParagraphStyleSetting; +pub const ParagraphStyleSpecifier = paragraph_style.ParagraphStyleSpecifier; +pub const WritingDirection = paragraph_style.WritingDirection; +pub const Run = run.Run; +pub const StringAttribute = stylized_strings.StringAttribute; + +test { + @import("std").testing.refAllDecls(@This()); +} diff --git a/vendor/libghostty-vt/pkg/macos/text/c.zig b/vendor/libghostty-vt/pkg/macos/text/c.zig new file mode 100644 index 00000000..1a7d1627 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/text/c.zig @@ -0,0 +1 @@ +pub const c = @import("../main.zig").c; diff --git a/vendor/libghostty-vt/pkg/macos/text/ext.c b/vendor/libghostty-vt/pkg/macos/text/ext.c new file mode 100644 index 00000000..55bff8a6 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/text/ext.c @@ -0,0 +1,10 @@ +#include <CoreText/CoreText.h> + +// A wrapper to fix a Zig C ABI issue. +void zig_cabi_CTLineGetBoundsWithOptions( + CTLineRef line, + CTLineBoundsOptions options, + CGRect *result +) { + *result = CTLineGetBoundsWithOptions(line, options); +} diff --git a/vendor/libghostty-vt/pkg/macos/text/font.zig b/vendor/libghostty-vt/pkg/macos/text/font.zig new file mode 100644 index 00000000..ea37891f --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/text/font.zig @@ -0,0 +1,306 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const graphics = @import("../graphics.zig"); +const text = @import("../text.zig"); +const c = @import("c.zig").c; + +pub const Font = opaque { + pub fn createWithFontDescriptor(desc: *const text.FontDescriptor, size: f32) Allocator.Error!*Font { + return @as( + ?*Font, + @ptrFromInt(@intFromPtr(c.CTFontCreateWithFontDescriptor( + @ptrCast(desc), + size, + null, + ))), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn createForString( + self: *Font, + str: *foundation.String, + range: foundation.Range, + ) ?*Font { + return @ptrCast(@constCast(c.CTFontCreateForString( + @ptrCast(self), + @ptrCast(str), + @bitCast(range), + ))); + } + + pub fn copyWithAttributes( + self: *Font, + size: f32, + matrix: ?*const graphics.AffineTransform, + attrs: ?*text.FontDescriptor, + ) Allocator.Error!*Font { + return @as( + ?*Font, + @ptrFromInt(@intFromPtr(c.CTFontCreateCopyWithAttributes( + @ptrCast(self), + size, + @ptrCast(matrix), + @ptrCast(attrs), + ))), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn release(self: *Font) void { + c.CFRelease(self); + } + + pub fn retain(self: *Font) void { + _ = c.CFRetain(self); + } + + pub fn copyDescriptor(self: *Font) *text.FontDescriptor { + return @ptrCast(@constCast(c.CTFontCopyFontDescriptor(@ptrCast(self)))); + } + + pub fn copyFeatures(self: *Font) *foundation.Array { + return @ptrCast(@constCast(c.CTFontCopyFeatures(@ptrCast(self)))); + } + + pub fn copyDefaultCascadeListForLanguages(self: *Font) *foundation.Array { + return @ptrCast(@constCast(c.CTFontCopyDefaultCascadeListForLanguages(@ptrCast(self), null))); + } + + pub fn copyTable(self: *Font, tag: FontTableTag) ?*foundation.Data { + return @ptrCast(@constCast(c.CTFontCopyTable( + @ptrCast(self), + @intFromEnum(tag), + c.kCTFontTableOptionNoOptions, + ))); + } + + pub fn getGlyphCount(self: *Font) usize { + return @intCast(c.CTFontGetGlyphCount(@ptrCast(self))); + } + + pub fn getGlyphsForCharacters(self: *Font, chars: []const u16, glyphs: []graphics.Glyph) bool { + assert(chars.len == glyphs.len); + return c.CTFontGetGlyphsForCharacters( + @ptrCast(self), + chars.ptr, + glyphs.ptr, + @intCast(chars.len), + ); + } + + pub fn createPathForGlyph(self: *Font, glyph: graphics.Glyph) ?*graphics.Path { + return @ptrCast(@constCast(c.CTFontCreatePathForGlyph( + @ptrCast(self), + glyph, + null, + ))); + } + + pub fn drawGlyphs( + self: *Font, + glyphs: []const graphics.Glyph, + positions: []const graphics.Point, + context: anytype, // Must be some context type from graphics + ) void { + assert(positions.len == glyphs.len); + c.CTFontDrawGlyphs( + @ptrCast(self), + glyphs.ptr, + @ptrCast(positions.ptr), + glyphs.len, + @ptrCast(context), + ); + } + + pub fn getBoundingRectsForGlyphs( + self: *Font, + orientation: FontOrientation, + glyphs: []const graphics.Glyph, + rects: ?[]graphics.Rect, + ) graphics.Rect { + if (rects) |s| assert(glyphs.len == s.len); + return @bitCast(c.CTFontGetBoundingRectsForGlyphs( + @ptrCast(self), + @intFromEnum(orientation), + glyphs.ptr, + @ptrCast(if (rects) |s| s.ptr else null), + @intCast(glyphs.len), + )); + } + + pub fn getAdvancesForGlyphs( + self: *Font, + orientation: FontOrientation, + glyphs: []const graphics.Glyph, + advances: ?[]graphics.Size, + ) f64 { + if (advances) |s| assert(glyphs.len == s.len); + return c.CTFontGetAdvancesForGlyphs( + @ptrCast(self), + @intFromEnum(orientation), + glyphs.ptr, + @ptrCast(if (advances) |s| s.ptr else null), + @intCast(glyphs.len), + ); + } + + pub fn copyAttribute(self: *Font, comptime attr: text.FontAttribute) ?attr.Value() { + return @ptrFromInt(@intFromPtr(c.CTFontCopyAttribute( + @ptrCast(self), + @ptrCast(attr.key()), + ))); + } + + pub fn copyFamilyName(self: *Font) *foundation.String { + return @ptrFromInt(@intFromPtr(c.CTFontCopyFamilyName(@ptrCast(self)))); + } + + pub fn copyDisplayName(self: *Font) *foundation.String { + return @ptrFromInt(@intFromPtr(c.CTFontCopyDisplayName(@ptrCast(self)))); + } + + pub fn copyPostScriptName(self: *Font) *foundation.String { + return @ptrFromInt(@intFromPtr(c.CTFontCopyPostScriptName(@ptrCast(self)))); + } + + pub fn getSymbolicTraits(self: *Font) text.FontSymbolicTraits { + return @bitCast(c.CTFontGetSymbolicTraits(@ptrCast(self))); + } + + pub fn getAscent(self: *Font) f64 { + return c.CTFontGetAscent(@ptrCast(self)); + } + + pub fn getDescent(self: *Font) f64 { + return c.CTFontGetDescent(@ptrCast(self)); + } + + pub fn getLeading(self: *Font) f64 { + return c.CTFontGetLeading(@ptrCast(self)); + } + + pub fn getBoundingBox(self: *Font) graphics.Rect { + return @bitCast(c.CTFontGetBoundingBox(@ptrCast(self))); + } + + pub fn getUnderlinePosition(self: *Font) f64 { + return c.CTFontGetUnderlinePosition(@ptrCast(self)); + } + + pub fn getUnderlineThickness(self: *Font) f64 { + return c.CTFontGetUnderlineThickness(@ptrCast(self)); + } + + pub fn getCapHeight(self: *Font) f64 { + return c.CTFontGetCapHeight(@ptrCast(self)); + } + + pub fn getXHeight(self: *Font) f64 { + return c.CTFontGetXHeight(@ptrCast(self)); + } + + pub fn getUnitsPerEm(self: *Font) u32 { + return c.CTFontGetUnitsPerEm(@ptrCast(self)); + } + + pub fn getSize(self: *Font) f64 { + return c.CTFontGetSize(@ptrCast(self)); + } +}; + +pub const FontOrientation = enum(c_uint) { + default = c.kCTFontOrientationDefault, + horizontal = c.kCTFontOrientationHorizontal, + vertical = c.kCTFontOrientationVertical, +}; + +pub const FontTableTag = enum(u32) { + svg = c.kCTFontTableSVG, + os2 = c.kCTFontTableOS2, + head = c.kCTFontTableHead, + hhea = c.kCTFontTableHhea, + post = c.kCTFontTablePost, + _, + + pub fn init(v: *const [4]u8) FontTableTag { + const raw: u32 = @bitCast(foundation.FourCharCode.init(v)); + return @enumFromInt(raw); + } +}; + +test { + const testing = std.testing; + + const name = try foundation.String.createWithBytes("Monaco", .utf8, false); + defer name.release(); + const desc = try text.FontDescriptor.createWithNameAndSize(name, 12); + defer desc.release(); + + const font = try Font.createWithFontDescriptor(desc, 12); + defer font.release(); + + // Traits + { + const traits = font.getSymbolicTraits(); + try testing.expect(!traits.color_glyphs); + } + + var glyphs = [1]graphics.Glyph{0}; + try testing.expect(font.getGlyphsForCharacters( + &[_]u16{'A'}, + &glyphs, + )); + try testing.expect(glyphs[0] > 0); + + // Bounding rect + { + var rect = font.getBoundingRectsForGlyphs(.horizontal, &glyphs, null); + try testing.expect(rect.size.width > 0); + + var singles: [1]graphics.Rect = undefined; + rect = font.getBoundingRectsForGlyphs(.horizontal, &glyphs, &singles); + try testing.expect(rect.size.width > 0); + try testing.expect(singles[0].size.width > 0); + } + + // Advances + { + var advance = font.getAdvancesForGlyphs(.horizontal, &glyphs, null); + try testing.expect(advance > 0); + + var singles: [1]graphics.Size = undefined; + advance = font.getAdvancesForGlyphs(.horizontal, &glyphs, &singles); + try testing.expect(advance > 0); + try testing.expect(singles[0].width > 0); + } + + // Draw + { + const cs = try graphics.ColorSpace.createDeviceGray(); + defer cs.release(); + const ctx = try graphics.BitmapContext.create(null, 80, 80, 8, 80, cs, 0); + const context = graphics.BitmapContext.context; + defer context.release(ctx); + + var pos = [_]graphics.Point{.{ .x = 0, .y = 0 }}; + font.drawGlyphs( + &glyphs, + &pos, + ctx, + ); + } +} + +test "copy" { + const name = try foundation.String.createWithBytes("Monaco", .utf8, false); + defer name.release(); + const desc = try text.FontDescriptor.createWithNameAndSize(name, 12); + defer desc.release(); + + const font = try Font.createWithFontDescriptor(desc, 12); + defer font.release(); + + const f2 = try font.copyWithAttributes(14, null, null); + defer f2.release(); +} diff --git a/vendor/libghostty-vt/pkg/macos/text/font_collection.zig b/vendor/libghostty-vt/pkg/macos/text/font_collection.zig new file mode 100644 index 00000000..8b4a86a6 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/text/font_collection.zig @@ -0,0 +1,139 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const text = @import("../text.zig"); +const c = @import("c.zig").c; + +pub const FontCollection = opaque { + pub fn createFromAvailableFonts() Allocator.Error!*FontCollection { + return @as( + ?*FontCollection, + @ptrFromInt(@intFromPtr(c.CTFontCollectionCreateFromAvailableFonts(null))), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn createWithFontDescriptors(descs: *foundation.Array) Allocator.Error!*FontCollection { + return @as( + ?*FontCollection, + @ptrFromInt(@intFromPtr(c.CTFontCollectionCreateWithFontDescriptors( + @ptrCast(descs), + null, + ))), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn release(self: *FontCollection) void { + c.CFRelease(self); + } + + pub fn createMatchingFontDescriptors(self: *FontCollection) *foundation.Array { + const result = c.CTFontCollectionCreateMatchingFontDescriptors(@ptrCast(self)); + if (result) |ptr| return @ptrFromInt(@intFromPtr(ptr)); + + // If we have no results, we create an empty array. This is not + // exactly matching the Mac API. We can fix this later if we want + // but I chose this to make it slightly more Zig-like at the cost + // of some memory in the rare case. + return foundation.Array.create(anyopaque, &[_]*const anyopaque{}) catch unreachable; + } +}; + +fn debugDumpList(list: *foundation.Array) !void { + var i: usize = 0; + while (i < list.getCount()) : (i += 1) { + const desc = list.getValueAtIndex(text.FontDescriptor, i); + { + var buf: [128]u8 = undefined; + const name = desc.copyAttribute(.name); + defer name.release(); + const cstr = name.cstring(&buf, .utf8).?; + + var family_buf: [128]u8 = undefined; + const family = desc.copyAttribute(.family_name); + defer family.release(); + const family_cstr = family.cstring(&family_buf, .utf8).?; + + var buf2: [128]u8 = undefined; + const url = desc.copyAttribute(.url); + defer url.release(); + const path = path: { + const blank = try foundation.String.createWithBytes("", .utf8, false); + defer blank.release(); + + const path = url.copyPath() orelse break :path "<no path>"; + defer path.release(); + + const decoded = try foundation.URL.createStringByReplacingPercentEscapes( + path, + blank, + ); + defer decoded.release(); + + break :path decoded.cstring(&buf2, .utf8) orelse + "<path cannot be converted to string>"; + }; + + std.log.warn("i={d} name={s} family={s} path={s}", .{ i, cstr, family_cstr, path }); + } + } +} + +test "collection" { + const testing = std.testing; + + const v = try FontCollection.createFromAvailableFonts(); + defer v.release(); + + const list = v.createMatchingFontDescriptors(); + defer list.release(); + + try testing.expect(list.getCount() > 0); +} + +test "from descriptors" { + const testing = std.testing; + + const name = try foundation.String.createWithBytes("AppleColorEmoji", .utf8, false); + defer name.release(); + + const desc = try text.FontDescriptor.createWithNameAndSize(name, 12); + defer desc.release(); + + var desc_arr = [_]*const text.FontDescriptor{desc}; + const arr = try foundation.Array.create(text.FontDescriptor, &desc_arr); + defer arr.release(); + + const v = try FontCollection.createWithFontDescriptors(arr); + defer v.release(); + + const list = v.createMatchingFontDescriptors(); + defer list.release(); + + try testing.expect(list.getCount() > 0); + + // try debugDumpList(list); +} + +test "from descriptors no match" { + const testing = std.testing; + + const name = try foundation.String.createWithBytes("ThisShouldNeverExist", .utf8, false); + defer name.release(); + + const desc = try text.FontDescriptor.createWithNameAndSize(name, 12); + defer desc.release(); + + var desc_arr = [_]*const text.FontDescriptor{desc}; + const arr = try foundation.Array.create(text.FontDescriptor, &desc_arr); + defer arr.release(); + + const v = try FontCollection.createWithFontDescriptors(arr); + defer v.release(); + + const list = v.createMatchingFontDescriptors(); + defer list.release(); + + try testing.expect(list.getCount() == 0); + + //try debugDumpList(list); +} diff --git a/vendor/libghostty-vt/pkg/macos/text/font_descriptor.zig b/vendor/libghostty-vt/pkg/macos/text/font_descriptor.zig new file mode 100644 index 00000000..563165bc --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/text/font_descriptor.zig @@ -0,0 +1,287 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const c = @import("c.zig").c; + +pub const FontDescriptor = opaque { + pub fn createWithNameAndSize(name: *foundation.String, size: f64) Allocator.Error!*FontDescriptor { + return @as( + ?*FontDescriptor, + @ptrFromInt(@intFromPtr(c.CTFontDescriptorCreateWithNameAndSize(@ptrCast(name), size))), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn createWithAttributes(dict: *foundation.Dictionary) Allocator.Error!*FontDescriptor { + return @as( + ?*FontDescriptor, + @ptrFromInt(@intFromPtr(c.CTFontDescriptorCreateWithAttributes(@ptrCast(dict)))), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn createCopyWithAttributes( + original: *FontDescriptor, + dict: *foundation.Dictionary, + ) Allocator.Error!*FontDescriptor { + return @as( + ?*FontDescriptor, + @ptrFromInt(@intFromPtr(c.CTFontDescriptorCreateCopyWithAttributes( + @ptrCast(original), + @ptrCast(dict), + ))), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn createCopyWithVariation( + original: *FontDescriptor, + id: *foundation.Number, + value: f64, + ) Allocator.Error!*FontDescriptor { + return @as( + ?*FontDescriptor, + @ptrCast(@constCast(c.CTFontDescriptorCreateCopyWithVariation( + @ptrCast(original), + @ptrCast(id), + value, + ))), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn retain(self: *FontDescriptor) void { + _ = c.CFRetain(self); + } + + pub fn release(self: *FontDescriptor) void { + c.CFRelease(self); + } + + pub fn copyAttribute(self: *const FontDescriptor, comptime attr: FontAttribute) ?attr.Value() { + return @ptrFromInt(@intFromPtr(c.CTFontDescriptorCopyAttribute( + @ptrCast(self), + @ptrCast(attr.key()), + ))); + } + + pub fn copyAttributes(self: *const FontDescriptor) *foundation.Dictionary { + return @ptrFromInt(@intFromPtr(c.CTFontDescriptorCopyAttributes( + @ptrCast(self), + ))); + } +}; + +pub const FontAttribute = enum { + url, + name, + display_name, + family_name, + style_name, + traits, + variation, + size, + matrix, + cascade_list, + character_set, + languages, + baseline_adjust, + macintosh_encodings, + features, + feature_settings, + fixed_advance, + orientation, + format, + registration_scope, + priority, + enabled, + downloadable, + downloaded, + + // https://developer.apple.com/documentation/coretext/core_text_constants?language=objc + variation_axes, + + pub fn key(self: FontAttribute) *foundation.String { + return @as(*foundation.String, @ptrFromInt(@intFromPtr(switch (self) { + .url => c.kCTFontURLAttribute, + .name => c.kCTFontNameAttribute, + .display_name => c.kCTFontDisplayNameAttribute, + .family_name => c.kCTFontFamilyNameAttribute, + .style_name => c.kCTFontStyleNameAttribute, + .traits => c.kCTFontTraitsAttribute, + .variation => c.kCTFontVariationAttribute, + .size => c.kCTFontSizeAttribute, + .matrix => c.kCTFontMatrixAttribute, + .cascade_list => c.kCTFontCascadeListAttribute, + .character_set => c.kCTFontCharacterSetAttribute, + .languages => c.kCTFontLanguagesAttribute, + .baseline_adjust => c.kCTFontBaselineAdjustAttribute, + .macintosh_encodings => c.kCTFontMacintoshEncodingsAttribute, + .features => c.kCTFontFeaturesAttribute, + .feature_settings => c.kCTFontFeatureSettingsAttribute, + .fixed_advance => c.kCTFontFixedAdvanceAttribute, + .orientation => c.kCTFontOrientationAttribute, + .format => c.kCTFontFormatAttribute, + .registration_scope => c.kCTFontRegistrationScopeAttribute, + .priority => c.kCTFontPriorityAttribute, + .enabled => c.kCTFontEnabledAttribute, + .downloadable => c.kCTFontDownloadableAttribute, + .downloaded => c.kCTFontDownloadedAttribute, + .variation_axes => c.kCTFontVariationAxesAttribute, + }))); + } + + pub fn Value(comptime self: FontAttribute) type { + return switch (self) { + .url => *foundation.URL, + .name => *foundation.String, + .display_name => *foundation.String, + .family_name => *foundation.String, + .style_name => *foundation.String, + .traits => *foundation.Dictionary, + .variation => *foundation.Dictionary, + .size => *foundation.Number, + .matrix => *anyopaque, // CFDataRef + .cascade_list => *foundation.Array, + .character_set => *anyopaque, // CFCharacterSetRef + .languages => *foundation.Array, + .baseline_adjust => *foundation.Number, + .macintosh_encodings => *foundation.Number, + .features => *foundation.Array, + .feature_settings => *foundation.Array, + .fixed_advance => *foundation.Number, + .orientation => *foundation.Number, + .format => *foundation.Number, + .registration_scope => *foundation.Number, + .priority => *foundation.Number, + .enabled => *foundation.Number, + .downloadable => *anyopaque, // CFBoolean + .downloaded => *anyopaque, // CFBoolean + .variation_axes => *foundation.Array, + }; + } +}; + +pub const FontTraitKey = enum { + symbolic, + weight, + width, + slant, + + pub fn key(self: FontTraitKey) *foundation.String { + return @as(*foundation.String, @ptrFromInt(@intFromPtr(switch (self) { + .symbolic => c.kCTFontSymbolicTrait, + .weight => c.kCTFontWeightTrait, + .width => c.kCTFontWidthTrait, + .slant => c.kCTFontSlantTrait, + }))); + } + + pub fn Value(self: FontTraitKey) type { + return switch (self) { + .symbolic => *foundation.Number, + .weight => *foundation.Number, + .width => *foundation.Number, + .slant => *foundation.Number, + }; + } +}; + +// https://developer.apple.com/documentation/coretext/ctfont/font_variation_axis_dictionary_keys?language=objc +pub const FontVariationAxisKey = enum { + identifier, + minimum_value, + maximum_value, + default_value, + name, + hidden, + + pub fn key(self: FontVariationAxisKey) *foundation.String { + return @as(*foundation.String, @ptrFromInt(@intFromPtr(switch (self) { + .identifier => c.kCTFontVariationAxisIdentifierKey, + .minimum_value => c.kCTFontVariationAxisMinimumValueKey, + .maximum_value => c.kCTFontVariationAxisMaximumValueKey, + .default_value => c.kCTFontVariationAxisDefaultValueKey, + .name => c.kCTFontVariationAxisNameKey, + .hidden => c.kCTFontVariationAxisHiddenKey, + }))); + } + + pub fn Value(comptime self: FontVariationAxisKey) type { + return switch (self) { + .identifier => foundation.Number, + .minimum_value => foundation.Number, + .maximum_value => foundation.Number, + .default_value => foundation.Number, + .name => foundation.String, + .hidden => foundation.Number, + }; + } +}; + +pub const FontSymbolicTraits = packed struct(u32) { + italic: bool = false, + bold: bool = false, + _unused1: u3 = 0, + expanded: bool = false, + condensed: bool = false, + _unused2: u3 = 0, + monospace: bool = false, + vertical: bool = false, + ui_optimized: bool = false, + color_glyphs: bool = false, + composite: bool = false, + _padding: u17 = 0, + + pub fn init(num: *foundation.Number) FontSymbolicTraits { + var raw: i32 = undefined; + _ = num.getValue(.sint32, &raw); + return @as(FontSymbolicTraits, @bitCast(raw)); + } + + test { + try std.testing.expectEqual( + @bitSizeOf(c.CTFontSymbolicTraits), + @bitSizeOf(FontSymbolicTraits), + ); + } + + test "bitcast" { + const actual: c.CTFontSymbolicTraits = c.kCTFontTraitMonoSpace | c.kCTFontTraitExpanded; + const expected: FontSymbolicTraits = .{ + .monospace = true, + .expanded = true, + }; + + try std.testing.expectEqual(actual, @as(c.CTFontSymbolicTraits, @bitCast(expected))); + } + + test "number" { + const raw: i32 = c.kCTFontTraitMonoSpace | c.kCTFontTraitExpanded; + const num = try foundation.Number.create(.sint32, &raw); + defer num.release(); + + const expected: FontSymbolicTraits = .{ .monospace = true, .expanded = true }; + const actual = FontSymbolicTraits.init(num); + try std.testing.expect(std.meta.eql(expected, actual)); + } +}; + +test { + @import("std").testing.refAllDecls(@This()); +} + +test "descriptor" { + const testing = std.testing; + + const name = try foundation.String.createWithBytes("foo", .utf8, false); + defer name.release(); + + const v = try FontDescriptor.createWithNameAndSize(name, 12); + defer v.release(); + + const copy_name = v.copyAttribute(.name).?; + defer copy_name.release(); + + { + var buf: [128]u8 = undefined; + const cstr = copy_name.cstring(&buf, .utf8).?; + try testing.expectEqualStrings("foo", cstr); + } +} diff --git a/vendor/libghostty-vt/pkg/macos/text/font_manager.zig b/vendor/libghostty-vt/pkg/macos/text/font_manager.zig new file mode 100644 index 00000000..988da122 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/text/font_manager.zig @@ -0,0 +1,23 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const FontDescriptor = @import("./font_descriptor.zig").FontDescriptor; +const c = @import("c.zig").c; + +pub fn createFontDescriptorsFromURL(url: *foundation.URL) ?*foundation.Array { + return @ptrFromInt(@intFromPtr(c.CTFontManagerCreateFontDescriptorsFromURL( + @ptrCast(url), + ))); +} + +pub fn createFontDescriptorsFromData(data: *foundation.Data) ?*foundation.Array { + return @ptrFromInt(@intFromPtr(c.CTFontManagerCreateFontDescriptorsFromData( + @ptrCast(data), + ))); +} + +pub fn createFontDescriptorFromData(data: *foundation.Data) ?*FontDescriptor { + return @ptrFromInt(@intFromPtr(c.CTFontManagerCreateFontDescriptorFromData( + @ptrCast(data), + ))); +} diff --git a/vendor/libghostty-vt/pkg/macos/text/frame.zig b/vendor/libghostty-vt/pkg/macos/text/frame.zig new file mode 100644 index 00000000..979134a1 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/text/frame.zig @@ -0,0 +1,33 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const graphics = @import("../graphics.zig"); +const text = @import("../text.zig"); +const c = @import("c.zig").c; + +pub const Frame = opaque { + pub fn release(self: *Frame) void { + foundation.CFRelease(self); + } + + pub fn getLineOrigins( + self: *Frame, + range: foundation.Range, + points: []graphics.Point, + ) void { + c.CTFrameGetLineOrigins( + @ptrCast(self), + @bitCast(range), + @ptrCast(points.ptr), + ); + } + + pub fn getLines(self: *Frame) *foundation.Array { + return @ptrFromInt(@intFromPtr(c.CTFrameGetLines(@ptrCast(self)))); + } +}; + +test { + // See framesetter tests... +} diff --git a/vendor/libghostty-vt/pkg/macos/text/framesetter.zig b/vendor/libghostty-vt/pkg/macos/text/framesetter.zig new file mode 100644 index 00000000..dbd82762 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/text/framesetter.zig @@ -0,0 +1,66 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const graphics = @import("../graphics.zig"); +const text = @import("../text.zig"); +const c = @import("c.zig").c; + +pub const Framesetter = opaque { + pub fn createWithAttributedString(str: *foundation.AttributedString) Allocator.Error!*Framesetter { + return @as( + ?*Framesetter, + @ptrFromInt(@intFromPtr(c.CTFramesetterCreateWithAttributedString( + @ptrCast(str), + ))), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn release(self: *Framesetter) void { + foundation.CFRelease(self); + } + + pub fn createFrame( + self: *Framesetter, + range: foundation.Range, + path: *graphics.Path, + attrs: ?*foundation.Dictionary, + ) !*text.Frame { + return @as( + ?*text.Frame, + @ptrFromInt(@intFromPtr(c.CTFramesetterCreateFrame( + @ptrCast(self), + @bitCast(range), + @ptrCast(path), + @ptrCast(attrs), + ))), + ) orelse error.FrameCreateFailed; + } +}; + +test { + const str = try foundation.MutableAttributedString.create(0); + defer str.release(); + { + const rep = try foundation.String.createWithBytes("hello", .utf8, false); + defer rep.release(); + str.replaceString(foundation.Range.init(0, 0), rep); + } + + const fs = try Framesetter.createWithAttributedString(@ptrCast(str)); + defer fs.release(); + + const path = try graphics.Path.createWithRect(graphics.Rect.init(0, 0, 100, 200), null); + defer path.release(); + const frame = try fs.createFrame( + foundation.Range.init(0, 0), + path, + null, + ); + defer frame.release(); + + { + var points: [1]graphics.Point = undefined; + frame.getLineOrigins(foundation.Range.init(0, 1), &points); + } +} diff --git a/vendor/libghostty-vt/pkg/macos/text/line.zig b/vendor/libghostty-vt/pkg/macos/text/line.zig new file mode 100644 index 00000000..248f8e64 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/text/line.zig @@ -0,0 +1,123 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const graphics = @import("../graphics.zig"); +const text = @import("../text.zig"); +const c = @import("c.zig").c; + +pub const Line = opaque { + pub fn createWithAttributedString(str: *foundation.AttributedString) Allocator.Error!*Line { + return @as( + ?*Line, + @ptrFromInt(@intFromPtr(c.CTLineCreateWithAttributedString( + @ptrCast(str), + ))), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn release(self: *Line) void { + foundation.CFRelease(self); + } + + pub fn getGlyphCount(self: *Line) usize { + return @intCast(c.CTLineGetGlyphCount( + @ptrCast(self), + )); + } + + pub fn getBoundsWithOptions( + self: *Line, + opts: LineBoundsOptions, + ) graphics.Rect { + return @bitCast(c.CTLineGetBoundsWithOptions( + @ptrCast(self), + @bitCast(opts), + )); + } + + pub fn getTypographicBounds( + self: *Line, + ascent: ?*f64, + descent: ?*f64, + leading: ?*f64, + ) f64 { + return c.CTLineGetTypographicBounds( + @ptrCast(self), + ascent, + descent, + leading, + ); + } + + pub fn getGlyphRuns(self: *Line) *foundation.Array { + return @ptrCast(@constCast(c.CTLineGetGlyphRuns(@ptrCast(self)))); + } +}; + +pub const LineBoundsOptions = packed struct { + exclude_leading: bool = false, + exclude_shifts: bool = false, + hanging_punctuation: bool = false, + glyph_path_bounds: bool = false, + use_optical_bounds: bool = false, + language_extents: bool = false, + _padding: u58 = 0, + + test { + try std.testing.expectEqual( + @bitSizeOf(c.CTLineBoundsOptions), + @bitSizeOf(LineBoundsOptions), + ); + } + + test "bitcast" { + const actual: c.CTLineBoundsOptions = c.kCTLineBoundsExcludeTypographicShifts | + c.kCTLineBoundsUseOpticalBounds; + const expected: LineBoundsOptions = .{ + .exclude_shifts = true, + .use_optical_bounds = true, + }; + + try std.testing.expectEqual(actual, @as(c.CTLineBoundsOptions, @bitCast(expected))); + } +}; + +test { + @import("std").testing.refAllDecls(@This()); +} + +test "line" { + const testing = std.testing; + + const font = font: { + const name = try foundation.String.createWithBytes("Monaco", .utf8, false); + defer name.release(); + const desc = try text.FontDescriptor.createWithNameAndSize(name, 12); + defer desc.release(); + + break :font try text.Font.createWithFontDescriptor(desc, 12); + }; + defer font.release(); + + const rep = try foundation.String.createWithBytes("hello", .utf8, false); + defer rep.release(); + const str = try foundation.MutableAttributedString.create(rep.getLength()); + defer str.release(); + str.replaceString(foundation.Range.init(0, 0), rep); + str.setAttribute( + foundation.Range.init(0, rep.getLength()), + text.StringAttribute.font, + font, + ); + + const line = try Line.createWithAttributedString(@as(*foundation.AttributedString, @ptrCast(str))); + defer line.release(); + + try testing.expectEqual(@as(usize, 5), line.getGlyphCount()); + + // TODO: this is a garbage value but should work... + const bounds = line.getBoundsWithOptions(.{}); + _ = bounds; + //std.log.warn("bounds={}", .{bounds}); +} diff --git a/vendor/libghostty-vt/pkg/macos/text/paragraph_style.zig b/vendor/libghostty-vt/pkg/macos/text/paragraph_style.zig new file mode 100644 index 00000000..f1d7fe95 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/text/paragraph_style.zig @@ -0,0 +1,49 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const graphics = @import("../graphics.zig"); +const text = @import("../text.zig"); +const c = @import("c.zig").c; + +// https://developer.apple.com/documentation/coretext/ctparagraphstyle?language=objc +pub const ParagraphStyle = opaque { + pub fn create( + settings: []const ParagraphStyleSetting, + ) Allocator.Error!*ParagraphStyle { + return @ptrCast(@constCast(c.CTParagraphStyleCreate( + @ptrCast(settings.ptr), + settings.len, + ))); + } + + pub fn release(self: *ParagraphStyle) void { + foundation.CFRelease(self); + } +}; + +/// https://developer.apple.com/documentation/coretext/ctparagraphstylesetting?language=objc +pub const ParagraphStyleSetting = extern struct { + spec: ParagraphStyleSpecifier, + value_size: usize, + value: *const anyopaque, +}; + +/// https://developer.apple.com/documentation/coretext/ctparagraphstylespecifier?language=objc +pub const ParagraphStyleSpecifier = enum(c_uint) { + base_writing_direction = 13, +}; + +/// https://developer.apple.com/documentation/uikit/nswritingdirectionattributename?language=objc +pub const WritingDirection = enum(c_int) { + natural = -1, + ltr = 0, + rtl = 1, + lro = 2, + rlo = 3, +}; + +test ParagraphStyle { + const p = try ParagraphStyle.create(&.{}); + defer p.release(); +} diff --git a/vendor/libghostty-vt/pkg/macos/text/run.zig b/vendor/libghostty-vt/pkg/macos/text/run.zig new file mode 100644 index 00000000..2895bfe3 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/text/run.zig @@ -0,0 +1,117 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const graphics = @import("../graphics.zig"); +const text = @import("../text.zig"); +const c = @import("c.zig").c; + +pub const Run = opaque { + pub fn release(self: *Run) void { + foundation.CFRelease(self); + } + + pub fn getGlyphCount(self: *Run) usize { + return @intCast(c.CTRunGetGlyphCount(@ptrCast(self))); + } + + pub fn getGlyphsPtr(self: *Run) ?[]const graphics.Glyph { + const len = self.getGlyphCount(); + if (len == 0) return &.{}; + const ptr: [*c]const graphics.Glyph = @ptrCast( + c.CTRunGetGlyphsPtr(@ptrCast(self)), + ); + if (ptr == null) return null; + return ptr[0..len]; + } + + pub fn getGlyphs(self: *Run, alloc: Allocator) ![]const graphics.Glyph { + const len = self.getGlyphCount(); + const ptr = try alloc.alloc(graphics.Glyph, len); + errdefer alloc.free(ptr); + c.CTRunGetGlyphs( + @ptrCast(self), + .{ .location = 0, .length = 0 }, + @ptrCast(ptr.ptr), + ); + return ptr; + } + + pub fn getPositionsPtr(self: *Run) ?[]const graphics.Point { + const len = self.getGlyphCount(); + if (len == 0) return &.{}; + const ptr: [*c]const graphics.Point = @ptrCast( + c.CTRunGetPositionsPtr(@ptrCast(self)), + ); + if (ptr == null) return null; + return ptr[0..len]; + } + + pub fn getPositions(self: *Run, alloc: Allocator) ![]const graphics.Point { + const len = self.getGlyphCount(); + const ptr = try alloc.alloc(graphics.Point, len); + errdefer alloc.free(ptr); + c.CTRunGetPositions( + @ptrCast(self), + .{ .location = 0, .length = 0 }, + @ptrCast(ptr.ptr), + ); + return ptr; + } + + pub fn getAdvancesPtr(self: *Run) ?[]const graphics.Size { + const len = self.getGlyphCount(); + if (len == 0) return &.{}; + const ptr: [*c]const graphics.Size = @ptrCast( + c.CTRunGetAdvancesPtr(@ptrCast(self)), + ); + if (ptr == null) return null; + return ptr[0..len]; + } + + pub fn getAdvances(self: *Run, alloc: Allocator) ![]const graphics.Size { + const len = self.getGlyphCount(); + const ptr = try alloc.alloc(graphics.Size, len); + errdefer alloc.free(ptr); + c.CTRunGetAdvances( + @ptrCast(self), + .{ .location = 0, .length = 0 }, + @ptrCast(ptr.ptr), + ); + return ptr; + } + + pub fn getStringIndicesPtr(self: *Run) ?[]const usize { + const len = self.getGlyphCount(); + if (len == 0) return &.{}; + const ptr: [*c]const usize = @ptrCast( + c.CTRunGetStringIndicesPtr(@ptrCast(self)), + ); + if (ptr == null) return null; + return ptr[0..len]; + } + + pub fn getStringIndices(self: *Run, alloc: Allocator) ![]const usize { + const len = self.getGlyphCount(); + const ptr = try alloc.alloc(usize, len); + errdefer alloc.free(ptr); + c.CTRunGetStringIndices( + @ptrCast(self), + .{ .location = 0, .length = 0 }, + @ptrCast(ptr.ptr), + ); + return ptr; + } + + pub fn getStatus(self: *Run) Status { + return @bitCast(c.CTRunGetStatus(@ptrCast(self))); + } +}; + +/// https://developer.apple.com/documentation/coretext/ctrunstatus?language=objc +pub const Status = packed struct(u32) { + right_to_left: bool, + non_monotonic: bool, + has_non_identity_matrix: bool, + _pad: u29 = 0, +}; diff --git a/vendor/libghostty-vt/pkg/macos/text/stylized_strings.zig b/vendor/libghostty-vt/pkg/macos/text/stylized_strings.zig new file mode 100644 index 00000000..8e262f9a --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/text/stylized_strings.zig @@ -0,0 +1,16 @@ +const foundation = @import("../foundation.zig"); +const c = @import("c.zig").c; + +pub const StringAttribute = enum { + font, + paragraph_style, + writing_direction, + + pub fn key(self: StringAttribute) *foundation.String { + return @ptrFromInt(@intFromPtr(switch (self) { + .font => c.kCTFontAttributeName, + .paragraph_style => c.kCTParagraphStyleAttributeName, + .writing_direction => c.kCTWritingDirectionAttributeName, + })); + } +}; diff --git a/vendor/libghostty-vt/pkg/macos/text/typesetter.zig b/vendor/libghostty-vt/pkg/macos/text/typesetter.zig new file mode 100644 index 00000000..dc07df98 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/text/typesetter.zig @@ -0,0 +1,36 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const graphics = @import("../graphics.zig"); +const text = @import("../text.zig"); +const c = @import("c.zig").c; + +pub const Typesetter = opaque { + pub fn createWithAttributedStringAndOptions( + str: *foundation.AttributedString, + opts: *foundation.Dictionary, + ) Allocator.Error!*Typesetter { + return @as( + ?*Typesetter, + @ptrFromInt(@intFromPtr(c.CTTypesetterCreateWithAttributedStringAndOptions( + @ptrCast(str), + @ptrCast(opts), + ))), + ) orelse Allocator.Error.OutOfMemory; + } + + pub fn release(self: *Typesetter) void { + foundation.CFRelease(self); + } + + pub fn createLine( + self: *Typesetter, + range: foundation.c.CFRange, + ) *text.Line { + return @ptrFromInt(@intFromPtr(c.CTTypesetterCreateLine( + @ptrCast(self), + range, + ))); + } +}; diff --git a/vendor/libghostty-vt/pkg/macos/video.zig b/vendor/libghostty-vt/pkg/macos/video.zig new file mode 100644 index 00000000..d0b1125a --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/video.zig @@ -0,0 +1,10 @@ +const display_link = @import("video/display_link.zig"); +const pixel_format = @import("video/pixel_format.zig"); + +pub const c = @import("video/c.zig").c; +pub const DisplayLink = display_link.DisplayLink; +pub const PixelFormat = pixel_format.PixelFormat; + +test { + @import("std").testing.refAllDecls(@This()); +} diff --git a/vendor/libghostty-vt/pkg/macos/video/c.zig b/vendor/libghostty-vt/pkg/macos/video/c.zig new file mode 100644 index 00000000..1a7d1627 --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/video/c.zig @@ -0,0 +1 @@ +pub const c = @import("../main.zig").c; diff --git a/vendor/libghostty-vt/pkg/macos/video/display_link.zig b/vendor/libghostty-vt/pkg/macos/video/display_link.zig new file mode 100644 index 00000000..7d6b437f --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/video/display_link.zig @@ -0,0 +1,86 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const c = @import("c.zig").c; + +pub const DisplayLink = opaque { + pub const Error = error{ + InvalidOperation, + }; + + pub fn createWithActiveCGDisplays() Allocator.Error!*DisplayLink { + var result: ?*DisplayLink = null; + if (c.CVDisplayLinkCreateWithActiveCGDisplays( + @ptrCast(&result), + ) != c.kCVReturnSuccess) + return error.OutOfMemory; + + return result orelse error.OutOfMemory; + } + + pub fn release(self: *DisplayLink) void { + c.CVDisplayLinkRelease(@ptrCast(self)); + } + + pub fn start(self: *DisplayLink) Error!void { + if (c.CVDisplayLinkStart(@ptrCast(self)) != c.kCVReturnSuccess) + return error.InvalidOperation; + } + + pub fn stop(self: *DisplayLink) Error!void { + if (c.CVDisplayLinkStop(@ptrCast(self)) != c.kCVReturnSuccess) + return error.InvalidOperation; + } + + pub fn isRunning(self: *DisplayLink) bool { + return c.CVDisplayLinkIsRunning(@ptrCast(self)) != 0; + } + + pub fn setCurrentCGDisplay( + self: *DisplayLink, + display_id: c.CGDirectDisplayID, + ) Error!void { + if (c.CVDisplayLinkSetCurrentCGDisplay( + @ptrCast(self), + display_id, + ) != c.kCVReturnSuccess) + return error.InvalidOperation; + } + + // Note: this purposely throws away a ton of arguments I didn't need. + // It would be trivial to refactor this into Zig types and properly + // pass this through. + pub fn setOutputCallback( + self: *DisplayLink, + comptime Userdata: type, + comptime callbackFn: *const fn (*DisplayLink, ?*Userdata) void, + userinfo: ?*Userdata, + ) Error!void { + if (c.CVDisplayLinkSetOutputCallback( + @ptrCast(self), + @ptrCast(&(struct { + fn callback( + displayLink: *DisplayLink, + inNow: *const c.CVTimeStamp, + inOutputTime: *const c.CVTimeStamp, + flagsIn: c.CVOptionFlags, + flagsOut: *c.CVOptionFlags, + inner_userinfo: ?*anyopaque, + ) callconv(.c) c.CVReturn { + _ = inNow; + _ = inOutputTime; + _ = flagsIn; + _ = flagsOut; + + callbackFn( + displayLink, + @ptrCast(@alignCast(inner_userinfo)), + ); + return c.kCVReturnSuccess; + } + }).callback), + userinfo, + ) != c.kCVReturnSuccess) + return error.InvalidOperation; + } +}; diff --git a/vendor/libghostty-vt/pkg/macos/video/pixel_format.zig b/vendor/libghostty-vt/pkg/macos/video/pixel_format.zig new file mode 100644 index 00000000..78091daa --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/video/pixel_format.zig @@ -0,0 +1,171 @@ +const c = @import("c.zig").c; + +pub const PixelFormat = enum(c_int) { + /// 1 bit indexed + @"1Monochrome" = c.kCVPixelFormatType_1Monochrome, + /// 2 bit indexed + @"2Indexed" = c.kCVPixelFormatType_2Indexed, + /// 4 bit indexed + @"4Indexed" = c.kCVPixelFormatType_4Indexed, + /// 8 bit indexed + @"8Indexed" = c.kCVPixelFormatType_8Indexed, + /// 1 bit indexed gray, white is zero + @"1IndexedGray_WhiteIsZero" = c.kCVPixelFormatType_1IndexedGray_WhiteIsZero, + /// 2 bit indexed gray, white is zero + @"2IndexedGray_WhiteIsZero" = c.kCVPixelFormatType_2IndexedGray_WhiteIsZero, + /// 4 bit indexed gray, white is zero + @"4IndexedGray_WhiteIsZero" = c.kCVPixelFormatType_4IndexedGray_WhiteIsZero, + /// 8 bit indexed gray, white is zero + @"8IndexedGray_WhiteIsZero" = c.kCVPixelFormatType_8IndexedGray_WhiteIsZero, + /// 16 bit BE RGB 555 + @"16BE555" = c.kCVPixelFormatType_16BE555, + /// 16 bit LE RGB 555 + @"16LE555" = c.kCVPixelFormatType_16LE555, + /// 16 bit LE RGB 5551 + @"16LE5551" = c.kCVPixelFormatType_16LE5551, + /// 16 bit BE RGB 565 + @"16BE565" = c.kCVPixelFormatType_16BE565, + /// 16 bit LE RGB 565 + @"16LE565" = c.kCVPixelFormatType_16LE565, + /// 24 bit RGB + @"24RGB" = c.kCVPixelFormatType_24RGB, + /// 24 bit BGR + @"24BGR" = c.kCVPixelFormatType_24BGR, + /// 32 bit ARGB + @"32ARGB" = c.kCVPixelFormatType_32ARGB, + /// 32 bit BGRA + @"32BGRA" = c.kCVPixelFormatType_32BGRA, + /// 32 bit ABGR + @"32ABGR" = c.kCVPixelFormatType_32ABGR, + /// 32 bit RGBA + @"32RGBA" = c.kCVPixelFormatType_32RGBA, + /// 64 bit ARGB, 16-bit big-endian samples + @"64ARGB" = c.kCVPixelFormatType_64ARGB, + /// 64 bit RGBA, 16-bit little-endian full-range (0-65535) samples + @"64RGBALE" = c.kCVPixelFormatType_64RGBALE, + /// 48 bit RGB, 16-bit big-endian samples + @"48RGB" = c.kCVPixelFormatType_48RGB, + /// 32 bit AlphaGray, 16-bit big-endian samples, black is zero + @"32AlphaGray" = c.kCVPixelFormatType_32AlphaGray, + /// 16 bit Grayscale, 16-bit big-endian samples, black is zero + @"16Gray" = c.kCVPixelFormatType_16Gray, + /// 30 bit RGB, 10-bit big-endian samples, 2 unused padding bits (at least significant end). + @"30RGB" = c.kCVPixelFormatType_30RGB, + /// 30 bit RGB, 10-bit big-endian samples, 2 unused padding bits (at most significant end), video-range (64-940). + @"30RGB_r210" = c.kCVPixelFormatType_30RGB_r210, + /// Component Y'CbCr 8-bit 4:2:2, ordered Cb Y'0 Cr Y'1 + @"422YpCbCr8" = c.kCVPixelFormatType_422YpCbCr8, + /// Component Y'CbCrA 8-bit 4:4:4:4, ordered Cb Y' Cr A + @"4444YpCbCrA8" = c.kCVPixelFormatType_4444YpCbCrA8, + /// Component Y'CbCrA 8-bit 4:4:4:4, rendering format. full range alpha, zero biased YUV, ordered A Y' Cb Cr + @"4444YpCbCrA8R" = c.kCVPixelFormatType_4444YpCbCrA8R, + /// Component Y'CbCrA 8-bit 4:4:4:4, ordered A Y' Cb Cr, full range alpha, video range Y'CbCr. + @"4444AYpCbCr8" = c.kCVPixelFormatType_4444AYpCbCr8, + /// Component Y'CbCrA 16-bit 4:4:4:4, ordered A Y' Cb Cr, full range alpha, video range Y'CbCr, 16-bit little-endian samples. + @"4444AYpCbCr16" = c.kCVPixelFormatType_4444AYpCbCr16, + /// Component AY'CbCr single precision floating-point 4:4:4:4 + @"4444AYpCbCrFloat" = c.kCVPixelFormatType_4444AYpCbCrFloat, + /// Component Y'CbCr 8-bit 4:4:4, ordered Cr Y' Cb, video range Y'CbCr + @"444YpCbCr8" = c.kCVPixelFormatType_444YpCbCr8, + /// Component Y'CbCr 10,12,14,16-bit 4:2:2 + @"422YpCbCr16" = c.kCVPixelFormatType_422YpCbCr16, + /// Component Y'CbCr 10-bit 4:2:2 + @"422YpCbCr10" = c.kCVPixelFormatType_422YpCbCr10, + /// Component Y'CbCr 10-bit 4:4:4 + @"444YpCbCr10" = c.kCVPixelFormatType_444YpCbCr10, + /// Planar Component Y'CbCr 8-bit 4:2:0. baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrPlanar struct + @"420YpCbCr8Planar" = c.kCVPixelFormatType_420YpCbCr8Planar, + /// Planar Component Y'CbCr 8-bit 4:2:0, full range. baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrPlanar struct + @"420YpCbCr8PlanarFullRange" = c.kCVPixelFormatType_420YpCbCr8PlanarFullRange, + /// First plane: Video-range Component Y'CbCr 8-bit 4:2:2, ordered Cb Y'0 Cr Y'1; second plane: alpha 8-bit 0-255 + @"422YpCbCr_4A_8BiPlanar" = c.kCVPixelFormatType_422YpCbCr_4A_8BiPlanar, + /// Bi-Planar Component Y'CbCr 8-bit 4:2:0, video-range (luma=[16,235] chroma=[16,240]). baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct + @"420YpCbCr8BiPlanarVideoRange" = c.kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, + /// Bi-Planar Component Y'CbCr 8-bit 4:2:0, full-range (luma=[0,255] chroma=[1,255]). baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct + @"420YpCbCr8BiPlanarFullRange" = c.kCVPixelFormatType_420YpCbCr8BiPlanarFullRange, + /// Bi-Planar Component Y'CbCr 8-bit 4:2:2, video-range (luma=[16,235] chroma=[16,240]). baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct + @"422YpCbCr8BiPlanarVideoRange" = c.kCVPixelFormatType_422YpCbCr8BiPlanarVideoRange, + /// Bi-Planar Component Y'CbCr 8-bit 4:2:2, full-range (luma=[0,255] chroma=[1,255]). baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct + @"422YpCbCr8BiPlanarFullRange" = c.kCVPixelFormatType_422YpCbCr8BiPlanarFullRange, + /// Bi-Planar Component Y'CbCr 8-bit 4:4:4, video-range (luma=[16,235] chroma=[16,240]). baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct + @"444YpCbCr8BiPlanarVideoRange" = c.kCVPixelFormatType_444YpCbCr8BiPlanarVideoRange, + /// Bi-Planar Component Y'CbCr 8-bit 4:4:4, full-range (luma=[0,255] chroma=[1,255]). baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct + @"444YpCbCr8BiPlanarFullRange" = c.kCVPixelFormatType_444YpCbCr8BiPlanarFullRange, + /// Component Y'CbCr 8-bit 4:2:2, ordered Y'0 Cb Y'1 Cr + @"422YpCbCr8_yuvs" = c.kCVPixelFormatType_422YpCbCr8_yuvs, + /// Component Y'CbCr 8-bit 4:2:2, full range, ordered Y'0 Cb Y'1 Cr + @"422YpCbCr8FullRange" = c.kCVPixelFormatType_422YpCbCr8FullRange, + /// 8 bit one component, black is zero + OneComponent8 = c.kCVPixelFormatType_OneComponent8, + /// 8 bit two component, black is zero + TwoComponent8 = c.kCVPixelFormatType_TwoComponent8, + /// little-endian RGB101010, 2 MSB are ignored, wide-gamut (384-895) + @"30RGBLEPackedWideGamut" = c.kCVPixelFormatType_30RGBLEPackedWideGamut, + /// little-endian ARGB2101010 full-range ARGB + ARGB2101010LEPacked = c.kCVPixelFormatType_ARGB2101010LEPacked, + /// little-endian ARGB10101010, each 10 bits in the MSBs of 16bits, wide-gamut (384-895, including alpha) + @"40ARGBLEWideGamut" = c.kCVPixelFormatType_40ARGBLEWideGamut, + /// little-endian ARGB10101010, each 10 bits in the MSBs of 16bits, wide-gamut (384-895, including alpha). Alpha premultiplied + @"40ARGBLEWideGamutPremultiplied" = c.kCVPixelFormatType_40ARGBLEWideGamutPremultiplied, + /// 10 bit little-endian one component, stored as 10 MSBs of 16 bits, black is zero + OneComponent10 = c.kCVPixelFormatType_OneComponent10, + /// 12 bit little-endian one component, stored as 12 MSBs of 16 bits, black is zero + OneComponent12 = c.kCVPixelFormatType_OneComponent12, + /// 16 bit little-endian one component, black is zero + OneComponent16 = c.kCVPixelFormatType_OneComponent16, + /// 16 bit little-endian two component, black is zero + TwoComponent16 = c.kCVPixelFormatType_TwoComponent16, + /// 16 bit one component IEEE half-precision float, 16-bit little-endian samples + OneComponent16Half = c.kCVPixelFormatType_OneComponent16Half, + /// 32 bit one component IEEE float, 32-bit little-endian samples + OneComponent32Float = c.kCVPixelFormatType_OneComponent32Float, + /// 16 bit two component IEEE half-precision float, 16-bit little-endian samples + TwoComponent16Half = c.kCVPixelFormatType_TwoComponent16Half, + /// 32 bit two component IEEE float, 32-bit little-endian samples + TwoComponent32Float = c.kCVPixelFormatType_TwoComponent32Float, + /// 64 bit RGBA IEEE half-precision float, 16-bit little-endian samples + @"64RGBAHalf" = c.kCVPixelFormatType_64RGBAHalf, + /// 128 bit RGBA IEEE float, 32-bit little-endian samples + @"128RGBAFloat" = c.kCVPixelFormatType_128RGBAFloat, + /// Bayer 14-bit Little-Endian, packed in 16-bits, ordered G R G R... alternating with B G B G... + @"14Bayer_GRBG" = c.kCVPixelFormatType_14Bayer_GRBG, + /// Bayer 14-bit Little-Endian, packed in 16-bits, ordered R G R G... alternating with G B G B... + @"14Bayer_RGGB" = c.kCVPixelFormatType_14Bayer_RGGB, + /// Bayer 14-bit Little-Endian, packed in 16-bits, ordered B G B G... alternating with G R G R... + @"14Bayer_BGGR" = c.kCVPixelFormatType_14Bayer_BGGR, + /// Bayer 14-bit Little-Endian, packed in 16-bits, ordered G B G B... alternating with R G R G... + @"14Bayer_GBRG" = c.kCVPixelFormatType_14Bayer_GBRG, + /// IEEE754-2008 binary16 (half float), describing the normalized shift when comparing two images. Units are 1/meters: ( pixelShift / (pixelFocalLength * baselineInMeters) ) + DisparityFloat16 = c.kCVPixelFormatType_DisparityFloat16, + /// IEEE754-2008 binary32 float, describing the normalized shift when comparing two images. Units are 1/meters: ( pixelShift / (pixelFocalLength * baselineInMeters) ) + DisparityFloat32 = c.kCVPixelFormatType_DisparityFloat32, + /// IEEE754-2008 binary16 (half float), describing the depth (distance to an object) in meters + DepthFloat16 = c.kCVPixelFormatType_DepthFloat16, + /// IEEE754-2008 binary32 float, describing the depth (distance to an object) in meters + DepthFloat32 = c.kCVPixelFormatType_DepthFloat32, + /// 2 plane YCbCr10 4:2:0, each 10 bits in the MSBs of 16bits, video-range (luma=[64,940] chroma=[64,960]) + @"420YpCbCr10BiPlanarVideoRange" = c.kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange, + /// 2 plane YCbCr10 4:2:2, each 10 bits in the MSBs of 16bits, video-range (luma=[64,940] chroma=[64,960]) + @"422YpCbCr10BiPlanarVideoRange" = c.kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange, + /// 2 plane YCbCr10 4:4:4, each 10 bits in the MSBs of 16bits, video-range (luma=[64,940] chroma=[64,960]) + @"444YpCbCr10BiPlanarVideoRange" = c.kCVPixelFormatType_444YpCbCr10BiPlanarVideoRange, + /// 2 plane YCbCr10 4:2:0, each 10 bits in the MSBs of 16bits, full-range (Y range 0-1023) + @"420YpCbCr10BiPlanarFullRange" = c.kCVPixelFormatType_420YpCbCr10BiPlanarFullRange, + /// 2 plane YCbCr10 4:2:2, each 10 bits in the MSBs of 16bits, full-range (Y range 0-1023) + @"422YpCbCr10BiPlanarFullRange" = c.kCVPixelFormatType_422YpCbCr10BiPlanarFullRange, + /// 2 plane YCbCr10 4:4:4, each 10 bits in the MSBs of 16bits, full-range (Y range 0-1023) + @"444YpCbCr10BiPlanarFullRange" = c.kCVPixelFormatType_444YpCbCr10BiPlanarFullRange, + /// first and second planes as per 420YpCbCr8BiPlanarVideoRange (420v), alpha 8 bits in third plane full-range. No CVPlanarPixelBufferInfo struct. + @"420YpCbCr8VideoRange_8A_TriPlanar" = c.kCVPixelFormatType_420YpCbCr8VideoRange_8A_TriPlanar, + /// Single plane Bayer 16-bit little-endian sensor element ("sensel".*) samples from full-size decoding of ProRes RAW images; Bayer pattern (sensel ordering) and other raw conversion information is described via buffer attachments + @"16VersatileBayer" = c.kCVPixelFormatType_16VersatileBayer, + /// Single plane 64-bit RGBA (16-bit little-endian samples) from downscaled decoding of ProRes RAW images; components--which may not be co-sited with one another--are sensel values and require raw conversion, information for which is described via buffer attachments + @"64RGBA_DownscaledProResRAW" = c.kCVPixelFormatType_64RGBA_DownscaledProResRAW, + /// 2 plane YCbCr16 4:2:2, video-range (luma=[4096,60160] chroma=[4096,61440]) + @"422YpCbCr16BiPlanarVideoRange" = c.kCVPixelFormatType_422YpCbCr16BiPlanarVideoRange, + /// 2 plane YCbCr16 4:4:4, video-range (luma=[4096,60160] chroma=[4096,61440]) + @"444YpCbCr16BiPlanarVideoRange" = c.kCVPixelFormatType_444YpCbCr16BiPlanarVideoRange, + /// 3 plane video-range YCbCr16 4:4:4 with 16-bit full-range alpha (luma=[4096,60160] chroma=[4096,61440] alpha=[0,65535]). No CVPlanarPixelBufferInfo struct. + @"444YpCbCr16VideoRange_16A_TriPlanar" = c.kCVPixelFormatType_444YpCbCr16VideoRange_16A_TriPlanar, + _, +}; |
