From 1a7cde9e3e61826cc863848d697079b8927aada0 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 27 May 2024 20:23:10 -0700 Subject: [PATCH] font/coretext: can read font tables --- pkg/macos/foundation/base.zig | 17 +++++++++++++++++ pkg/macos/foundation/data.zig | 6 +++++- pkg/macos/text/font.zig | 18 ++++++++++++++++++ src/font/face/coretext.zig | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/pkg/macos/foundation/base.zig b/pkg/macos/foundation/base.zig index bfd436115..24673ea2f 100644 --- a/pkg/macos/foundation/base.zig +++ b/pkg/macos/foundation/base.zig @@ -16,3 +16,20 @@ pub const Range = extern struct { 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/pkg/macos/foundation/data.zig b/pkg/macos/foundation/data.zig index 7c9b7d6cb..cbac0db54 100644 --- a/pkg/macos/foundation/data.zig +++ b/pkg/macos/foundation/data.zig @@ -20,9 +20,13 @@ pub const Data = opaque { foundation.CFRelease(self); } - pub fn getPointer(self: *Data) *const anyopaque { + 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 { diff --git a/pkg/macos/text/font.zig b/pkg/macos/text/font.zig index f4db72d6c..10f8c23ca 100644 --- a/pkg/macos/text/font.zig +++ b/pkg/macos/text/font.zig @@ -67,6 +67,14 @@ pub const Font = opaque { return @ptrCast(@constCast(c.CTFontCopyDefaultCascadeListForLanguages(@ptrCast(self), null))); } + pub fn copyTable(self: *Font, tag: FontTableTag) ?*foundation.Data { + return @constCast(@ptrCast(c.CTFontCopyTable( + @ptrCast(self), + @intFromEnum(tag), + c.kCTFontTableOptionNoOptions, + ))); + } + pub fn getGlyphCount(self: *Font) usize { return @intCast(c.CTFontGetGlyphCount(@ptrCast(self))); } @@ -195,6 +203,16 @@ pub const FontOrientation = enum(c_uint) { vertical = c.kCTFontOrientationVertical, }; +pub const FontTableTag = enum(u32) { + svg = c.kCTFontTableSVG, + _, + + pub fn init(v: *const [4]u8) FontTableTag { + const raw: u32 = @bitCast(foundation.FourCharCode.init(v)); + return @enumFromInt(raw); + } +}; + test { const testing = std.testing; diff --git a/src/font/face/coretext.zig b/src/font/face/coretext.zig index 72c0a6d9e..fdc063b1c 100644 --- a/src/font/face/coretext.zig +++ b/src/font/face/coretext.zig @@ -570,6 +570,21 @@ pub const Face = struct { return result; } + + /// Copy the font table data for the given tag. + pub fn copyTable(self: Face, alloc: Allocator, tag: *const [4]u8) !?[]u8 { + const data = self.font.copyTable(macos.text.FontTableTag.init(tag)) orelse + return null; + defer data.release(); + + const buf = try alloc.alloc(u8, data.getLength()); + errdefer alloc.free(buf); + + const ptr = data.getPointer(); + @memcpy(buf, ptr[0..buf.len]); + + return buf; + } }; test { @@ -727,3 +742,20 @@ test "mixed color/non-color font treated as text" { try testing.expect(face.presentation == .text); } + +test "svg font table" { + const testing = std.testing; + const alloc = testing.allocator; + const testFont = @import("../test.zig").fontJuliaMono; + + var lib = try font.Library.init(); + defer lib.deinit(); + + var face = try Face.init(lib, testFont, .{ .size = .{ .points = 12 } }); + defer face.deinit(); + + const table = (try face.copyTable(alloc, "SVG ")).?; + defer alloc.free(table); + + try testing.expect(table.len > 0); +}