mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
font: fallback search should search full discovery chain
Fixes #668 We were previously only checking the first font result in the search. This also fixes our CoreText scoring algorithm to prioritize faces that have the codepoint we're searching for.
This commit is contained in:
@ -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(
|
||||
|
@ -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});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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: {
|
||||
|
Reference in New Issue
Block a user