Merge pull request #670 from mitchellh/font-fallbakc

font: fallback search should search full discovery chain
This commit is contained in:
Mitchell Hashimoto
2023-10-13 12:29:59 -07:00
committed by GitHub
3 changed files with 40 additions and 10 deletions

View File

@ -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(

View File

@ -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 "<error>",
});
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 "<error>",
});
return self.addFace(style, .{ .deferred = face }) catch break :discover;
}
log.debug("no fallback face found for cp={x}", .{cp});
}
}

View File

@ -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: {