Merge pull request #1799 from mitchellh/mixed-font

font: treated fonts with mixed color/non-color glyphs as text
This commit is contained in:
Mitchell Hashimoto
2024-05-26 15:24:54 -07:00
committed by GitHub
6 changed files with 45 additions and 0 deletions

View File

@ -81,6 +81,14 @@ pub const Font = opaque {
);
}
pub fn createPathForGlyph(self: *Font, glyph: graphics.Glyph) ?*graphics.Path {
return @constCast(@ptrCast(c.CTFontCreatePathForGlyph(
@ptrCast(self),
glyph,
null,
)));
}
pub fn drawGlyphs(
self: *Font,
glyphs: []const graphics.Glyph,

View File

@ -102,6 +102,20 @@ pub const Face = struct {
};
result.quirks_disable_default_font_features = quirks.disableDefaultFontFeatures(&result);
// If our presentation is emoji, we also check for the presence of
// emoji codepoints. This forces fonts with colorized glyphs that aren't
// emoji font to be treated as text. Long term, this isn't what we want
// but this fixes some bugs in the short term. See:
// https://github.com/mitchellh/ghostty/issues/1768
//
// Longer term, we'd like to detect mixed color/non-color fonts and
// handle them correctly by rendering the color glyphs as color and the
// non-color glyphs as text.
if (result.presentation == .emoji and result.glyphIndex('🥸') == null) {
log.warn("font has colorized glyphs but isn't emoji, treating as text", .{});
result.presentation = .text;
}
// In debug mode, we output information about available variation axes,
// if they exist.
if (comptime builtin.mode == .Debug) {
@ -700,3 +714,16 @@ test "variable set variation" {
_ = try face.renderGlyph(alloc, &atlas, face.glyphIndex(i).?, .{});
}
}
test "mixed color/non-color font treated as text" {
const testing = std.testing;
const testFont = @import("../test.zig").fontJuliaMono;
var lib = try font.Library.init();
defer lib.deinit();
var face = try Face.init(lib, testFont, .{ .size = .{ .points = 12 } });
defer face.deinit();
try testing.expect(face.presentation == .text);
}

View File

@ -72,6 +72,12 @@ pub const Face = struct {
};
result.quirks_disable_default_font_features = quirks.disableDefaultFontFeatures(&result);
// See coretext.zig which has a similar check for this.
if (result.presentation == .emoji and result.glyphIndex('🥸') == null) {
log.warn("font has colorized glyphs but isn't emoji, treating as text", .{});
result.presentation = .text;
}
// In debug mode, we output information about available variation axes,
// if they exist.
if (comptime builtin.mode == .Debug) mm: {

Binary file not shown.

View File

@ -18,6 +18,7 @@ pub const fontNerdFont = @embedFile("res/JetBrainsMonoNerdFont-Regular.ttf");
/// Specific font families below:
pub const fontGeistMono = @embedFile("res/GeistMono-Regular.ttf");
pub const fontJetBrainsMono = @embedFile("res/JetBrainsMonoNoNF-Regular.ttf");
pub const fontJuliaMono = @embedFile("res/JuliaMono-Regular.ttf");
/// Cozette is a unique font because it embeds some emoji characters
/// but has a text presentation.

View File

@ -22,8 +22,11 @@ pub fn disableDefaultFontFeatures(face: *const font.Face) bool {
// CodeNewRoman, Menlo and Monaco both have a default ligature of "fi" that
// looks really bad in terminal grids, so we want to disable ligatures
// by default for these faces.
//
// JuliaMono has a default ligature of "st" that looks bad.
return std.mem.eql(u8, name, "CodeNewRoman") or
std.mem.eql(u8, name, "CodeNewRoman Nerd Font") or
std.mem.eql(u8, name, "JuliaMono") or
std.mem.eql(u8, name, "Menlo") or
std.mem.eql(u8, name, "Monaco");
}