aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/pkg/macos/text/font.zig
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-04-04 19:22:04 +0300
committerCan Celik <ogulcancelik@gmail.com>2026-04-05 01:23:06 +0300
commit41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch)
tree3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/pkg/macos/text/font.zig
parent55c138263e190a1e79d4b997bfb9397306c0ec1f (diff)
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/pkg/macos/text/font.zig')
-rw-r--r--vendor/libghostty-vt/pkg/macos/text/font.zig306
1 files changed, 306 insertions, 0 deletions
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();
+}