diff --git a/pkg/macos/text/font.zig b/pkg/macos/text/font.zig index 0cef4d8a6..df32c17ac 100644 --- a/pkg/macos/text/font.zig +++ b/pkg/macos/text/font.zig @@ -7,7 +7,7 @@ const text = @import("../text.zig"); const c = @import("c.zig"); pub const Font = opaque { - pub fn createWithFontDescriptor(desc: *text.FontDescriptor, size: f32) Allocator.Error!*Font { + pub fn createWithFontDescriptor(desc: *const text.FontDescriptor, size: f32) Allocator.Error!*Font { return @as( ?*Font, @ptrFromInt(@intFromPtr(c.CTFontCreateWithFontDescriptor( diff --git a/src/font/Group.zig b/src/font/Group.zig index 67503abf3..ba08ad53f 100644 --- a/src/font/Group.zig +++ b/src/font/Group.zig @@ -327,6 +327,7 @@ pub fn indexForCodepoint( // If we are regular, try looking for a fallback using discovery. if (style == .regular and font.Discover != void) { + log.debug("searching for a fallback font for cp={x}", .{cp}); if (self.discover) |disco| discover: { var disco_it = disco.discover(self.alloc, .{ .codepoint = cp, @@ -337,19 +338,27 @@ pub fn indexForCodepoint( }) catch break :discover; defer disco_it.deinit(); - if (disco_it.next() catch break :discover) |face| { + while (true) { + const face_ = disco_it.next() catch |err| { + log.warn("fallback search failed with error err={}", .{err}); + break; + }; + const face = face_ orelse break; + // Discovery is supposed to only return faces that have our // codepoint but we can't search presentation in discovery so // we have to check it here. - if (face.hasCodepoint(cp, p)) { - var buf: [256]u8 = undefined; - log.info("found codepoint 0x{x} in fallback face={s}", .{ - cp, - face.name(&buf) catch "", - }); - return self.addFace(style, .{ .deferred = face }) catch break :discover; - } + if (!face.hasCodepoint(cp, p)) continue; + + var buf: [256]u8 = undefined; + log.info("found codepoint 0x{x} in fallback face={s}", .{ + cp, + face.name(&buf) catch "", + }); + return self.addFace(style, .{ .deferred = face }) catch break :discover; } + + log.debug("no fallback face found for cp={x}", .{cp}); } } diff --git a/src/font/discovery.zig b/src/font/discovery.zig index 12552c96b..7d15d2def 100644 --- a/src/font/discovery.zig +++ b/src/font/discovery.zig @@ -399,6 +399,7 @@ pub const CoreText = struct { style: Style = .unmatched, monospace: bool = false, + codepoint: bool = false, const Style = enum(u8) { unmatched = 0, match = 0xFF, _ }; @@ -410,6 +411,26 @@ pub const CoreText = struct { fn score(desc: *const Descriptor, ct_desc: *const macos.text.FontDescriptor) Score { var score_acc: Score = .{}; + // If we're searching for a codepoint, prioritize fonts that + // have that codepoint. + if (desc.codepoint > 0) codepoint: { + const font = macos.text.Font.createWithFontDescriptor(ct_desc, 12) catch + break :codepoint; + defer font.release(); + + // Turn UTF-32 into UTF-16 for CT API + var unichars: [2]u16 = undefined; + const pair = macos.foundation.stringGetSurrogatePairForLongCharacter( + desc.codepoint, + &unichars, + ); + const len: usize = if (pair) 2 else 1; + + // Get our glyphs + var glyphs = [2]macos.graphics.Glyph{ 0, 0 }; + score_acc.codepoint = font.getGlyphsForCharacters(unichars[0..len], glyphs[0..len]); + } + // Get our symbolic traits for the descriptor so we can compare // boolean attributes like bold, monospace, etc. const symbolic_traits: macos.text.FontSymbolicTraits = traits: {