font: look up Apple Color Emoji by exact name on macOS

The Apple Color Emoji fallback font was discovered with the generic
discovery path, which builds a CTFontCollection and runs system-wide
font matching. Since we know the exact font we want, we can look it
up directly with CTFontCreateWithName instead.
This commit is contained in:
Mitchell Hashimoto
2026-08-09 15:40:44 -07:00
parent 3225e9ebb1
commit afc79b8ccf
3 changed files with 77 additions and 0 deletions

View File

@@ -18,6 +18,17 @@ pub const Font = opaque {
) orelse Allocator.Error.OutOfMemory;
}
pub fn createWithName(name: *foundation.String, size: f32) Allocator.Error!*Font {
return @as(
?*Font,
@ptrFromInt(@intFromPtr(c.CTFontCreateWithName(
@ptrCast(name),
size,
null,
))),
) orelse Allocator.Error.OutOfMemory;
}
pub fn createForString(
self: *Font,
str: *foundation.String,

View File

@@ -340,6 +340,24 @@ fn collection(
// specifying a font-family for emoji.
if (comptime builtin.target.os.tag.isDarwin() and Discover != void) apple_emoji: {
const disco = try self.discover() orelse break :apple_emoji;
// Fast path: we know the exact name of the font we want so we
// can look it up directly, which is sometimes significantly faster than
// full discovery (e.g. CoreText).
if (@hasDecl(Discover, "discoverExactFamily")) {
if (try disco.discoverExactFamily(
"Apple Color Emoji",
)) |face| {
_ = try c.addDeferred(self.alloc, face, .{
.style = .regular,
.fallback = true,
// No size adjustment for emojis.
.size_adjustment = .none,
});
break :apple_emoji;
}
}
var disco_it = try disco.discover(self.alloc, .{
.family = "Apple Color Emoji",
});

View File

@@ -383,6 +383,54 @@ pub const CoreText = struct {
};
}
/// Discover a font by its exact name (family, full, or PostScript
/// name). This is significantly faster than `discover` because it
/// avoids the system-wide font matching that CTFontCollection does
/// (which takes multiple milliseconds). This should be preferred
/// when the desired font is known exactly, e.g. system fonts such
/// as Apple Color Emoji.
///
/// Returns null if no font with this exact family name exists;
/// CoreText fallback fonts are never returned.
pub fn discoverExactFamily(
self: *const CoreText,
family: []const u8,
) !?DeferredFace {
_ = self;
const family_str = try macos.foundation.String.createWithBytes(
family,
.utf8,
false,
);
defer family_str.release();
// Create our font. We need a size to initialize it so we use size
// 12 but we will alter the size later (same as DiscoverIterator).
const ct_font = try macos.text.Font.createWithName(family_str, 12);
// CTFontCreateWithName never returns null: if the requested font
// isn't installed it returns a substitute font. Verify we got
// the family we asked for, otherwise report not found.
const found: bool = found: {
const actual = ct_font.copyFamilyName();
defer actual.release();
var buf: [256]u8 = undefined;
const actual_slice = actual.cstring(&buf, .utf8) orelse
break :found false;
break :found std.mem.eql(u8, actual_slice, family);
};
if (!found) {
ct_font.release();
return null;
}
return .{ .ct = .{
.font = ct_font,
.variations = &.{},
} };
}
pub fn discoverFallback(
self: *const CoreText,
alloc: Allocator,