Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

font: coretext_freetype backend supports font variations #2146

Merged
merged 3 commits into from
Aug 25, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/macos/foundation/number.zig
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ pub const Number = opaque {
)))) orelse Allocator.Error.OutOfMemory;
}

pub fn getValue(self: *Number, comptime t: NumberType, ptr: *t.ValueType()) bool {
pub fn getValue(self: *const Number, comptime t: NumberType, ptr: *t.ValueType()) bool {
return c.CFNumberGetValue(
@ptrCast(self),
@intFromEnum(t),
2 changes: 1 addition & 1 deletion pkg/macos/text/font.zig
Original file line number Diff line number Diff line change
@@ -145,7 +145,7 @@ pub const Font = opaque {
);
}

pub fn copyAttribute(self: *Font, comptime attr: text.FontAttribute) attr.Value() {
pub fn copyAttribute(self: *Font, comptime attr: text.FontAttribute) ?attr.Value() {
return @ptrFromInt(@intFromPtr(c.CTFontCopyAttribute(
@ptrCast(self),
@ptrCast(attr.key()),
4 changes: 2 additions & 2 deletions pkg/macos/text/font_descriptor.zig
Original file line number Diff line number Diff line change
@@ -54,7 +54,7 @@ pub const FontDescriptor = opaque {
c.CFRelease(self);
}

pub fn copyAttribute(self: *const FontDescriptor, comptime attr: FontAttribute) attr.Value() {
pub fn copyAttribute(self: *const FontDescriptor, comptime attr: FontAttribute) ?attr.Value() {
return @ptrFromInt(@intFromPtr(c.CTFontDescriptorCopyAttribute(
@ptrCast(self),
@ptrCast(attr.key()),
@@ -153,7 +153,7 @@ pub const FontAttribute = enum {
.enabled => *foundation.Number,
.downloadable => *anyopaque, // CFBoolean
.downloaded => *anyopaque, // CFBoolean
.variation_axes => ?*foundation.Array,
.variation_axes => *foundation.Array,
};
}
};
3 changes: 2 additions & 1 deletion src/apprt/embedded.zig
Original file line number Diff line number Diff line change
@@ -1981,7 +1981,8 @@ pub const CAPI = struct {
// at 1x but callers of this should be using scaled or apply
// scale themselves.
const size: f32 = size: {
const num = face.font.copyAttribute(.size);
const num = face.font.copyAttribute(.size) orelse
break :size 12;
defer num.release();
var v: f32 = 12;
_ = num.getValue(.float, &v);
52 changes: 47 additions & 5 deletions src/font/DeferredFace.zig
Original file line number Diff line number Diff line change
@@ -107,7 +107,8 @@ pub fn familyName(self: DeferredFace, buf: []u8) ![]const u8 {
.coretext_harfbuzz,
.coretext_noshape,
=> if (self.ct) |ct| {
const family_name = ct.font.copyAttribute(.family_name);
const family_name = ct.font.copyAttribute(.family_name) orelse
return "unknown";
return family_name.cstringPtr(.utf8) orelse unsupported: {
break :unsupported family_name.cstring(buf, .utf8) orelse
return error.OutOfMemory;
@@ -204,7 +205,8 @@ fn loadCoreTextFreetype(
const ct = self.ct.?;

// Get the URL for the font so we can get the filepath
const url = ct.font.copyAttribute(.url);
const url = ct.font.copyAttribute(.url) orelse
return error.FontHasNoFile;
defer url.release();

// Get the path from the URL
@@ -229,10 +231,50 @@ fn loadCoreTextFreetype(
// the end for a zero so we set that up here.
buf[path_slice.len] = 0;

// TODO: face index 0 is not correct long term and we should switch
// to using CoreText for rendering, too.
// Face index 0 is not always correct. We don't ship this configuration
// in a release build. Users should use the pure CoreText builds.
//std.log.warn("path={s}", .{path_slice});
return try Face.initFile(lib, buf[0..path_slice.len :0], 0, opts);
var face = try Face.initFile(lib, buf[0..path_slice.len :0], 0, opts);
errdefer face.deinit();

// If our ct font has variations, apply them to the face.
if (ct.font.copyAttribute(.variation)) |variations| vars: {
defer variations.release();
if (variations.getCount() == 0) break :vars;

// This configuration is just used for testing so we don't want to
// have to pass a full allocator through so use the stack. We
// shouldn't have a lot of variations and if we do we should use
// another mechanism.
//
// On macOS the default stack size for a thread is 512KB and the main
// thread gets megabytes so 16KB is a safe stack allocation.
var data: [1024 * 16]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&data);
const alloc = fba.allocator();

var face_vars = std.ArrayList(font.face.Variation).init(alloc);
const kav = try variations.getKeysAndValues(alloc);
for (kav.keys, kav.values) |key, value| {
const num: *const macos.foundation.Number = @ptrCast(key.?);
const val: *const macos.foundation.Number = @ptrCast(value.?);

var num_i32: i32 = undefined;
if (!num.getValue(.sint32, &num_i32)) continue;

var val_f64: f64 = undefined;
if (!val.getValue(.float64, &val_f64)) continue;

try face_vars.append(.{
.id = @bitCast(num_i32),
.value = val_f64,
});
}

try face.setVariations(face_vars.items, opts);
}

return face;
}

fn loadWebCanvas(
5 changes: 3 additions & 2 deletions src/font/discovery.zig
Original file line number Diff line number Diff line change
@@ -613,7 +613,7 @@ pub const CoreText = struct {
// Get our symbolic traits for the descriptor so we can compare
// boolean attributes like bold, monospace, etc.
const symbolic_traits: macos.text.FontSymbolicTraits = traits: {
const traits = ct_desc.copyAttribute(.traits);
const traits = ct_desc.copyAttribute(.traits) orelse break :traits .{};
defer traits.release();

const key = macos.text.FontTraitKey.symbolic.key();
@@ -626,7 +626,8 @@ pub const CoreText = struct {
score_acc.monospace = symbolic_traits.monospace;

score_acc.style = style: {
const style = ct_desc.copyAttribute(.style_name);
const style = ct_desc.copyAttribute(.style_name) orelse
break :style .unmatched;
defer style.release();

// If we have a specific desired style, attempt to search for that.
Loading