diff --git a/src/Surface.zig b/src/Surface.zig index f952a88df..7c994ef0f 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -4338,8 +4338,3 @@ fn presentSurface(self: *Surface) !void { {}, ); } - -pub const face_ttf = @embedFile("font/res/JetBrainsMono-Regular.ttf"); -pub const face_bold_ttf = @embedFile("font/res/JetBrainsMono-Bold.ttf"); -pub const face_emoji_ttf = @embedFile("font/res/NotoColorEmoji.ttf"); -pub const face_emoji_text_ttf = @embedFile("font/res/NotoEmoji-Regular.ttf"); diff --git a/src/font/CodepointResolver.zig b/src/font/CodepointResolver.zig index c090356ff..f3be843c5 100644 --- a/src/font/CodepointResolver.zig +++ b/src/font/CodepointResolver.zig @@ -376,9 +376,9 @@ const DescriptorCache = std.HashMapUnmanaged( test getIndex { const testing = std.testing; const alloc = testing.allocator; - const testFont = @import("test.zig").fontRegular; - const testEmoji = @import("test.zig").fontEmoji; - const testEmojiText = @import("test.zig").fontEmojiText; + const testFont = font.embedded.regular; + const testEmoji = font.embedded.emoji; + const testEmojiText = font.embedded.emoji_text; var lib = try Library.init(); defer lib.deinit(); @@ -456,7 +456,7 @@ test getIndex { test "getIndex disabled font style" { const testing = std.testing; const alloc = testing.allocator; - const testFont = @import("test.zig").fontRegular; + const testFont = font.embedded.regular; var atlas_grayscale = try font.Atlas.init(alloc, 512, .grayscale); defer atlas_grayscale.deinit(alloc); diff --git a/src/font/Collection.zig b/src/font/Collection.zig index 4601a012e..8f338be16 100644 --- a/src/font/Collection.zig +++ b/src/font/Collection.zig @@ -203,11 +203,11 @@ pub const CompleteError = Allocator.Error || error{ }; /// Ensure we have an option for all styles in the collection, such -/// as italic and bold. +/// as italic and bold by synthesizing them if necessary from the +/// first regular face that has text glyphs. /// -/// This requires that a regular font face is already loaded. -/// This is asserted. If a font style is missing, we will synthesize -/// it if possible. Otherwise, we will use the regular font style. +/// If there is no regular face that has text glyphs, then this +/// does nothing. pub fn completeStyles( self: *Collection, alloc: Allocator, @@ -229,7 +229,7 @@ pub fn completeStyles( // if a user configures something like an Emoji font first. const regular_entry: *Entry = entry: { const list = self.faces.getPtr(.regular); - assert(list.count() > 0); + if (list.count() == 0) return; // Find our first regular face that has text glyphs. var it = list.iterator(0); @@ -663,7 +663,7 @@ test init { test "add full" { const testing = std.testing; const alloc = testing.allocator; - const testFont = @import("test.zig").fontRegular; + const testFont = font.embedded.regular; var lib = try Library.init(); defer lib.deinit(); @@ -709,7 +709,7 @@ test "add deferred without loading options" { test getFace { const testing = std.testing; const alloc = testing.allocator; - const testFont = @import("test.zig").fontRegular; + const testFont = font.embedded.regular; var lib = try Library.init(); defer lib.deinit(); @@ -733,7 +733,7 @@ test getFace { test getIndex { const testing = std.testing; const alloc = testing.allocator; - const testFont = @import("test.zig").fontRegular; + const testFont = font.embedded.regular; var lib = try Library.init(); defer lib.deinit(); @@ -764,7 +764,7 @@ test getIndex { test completeStyles { const testing = std.testing; const alloc = testing.allocator; - const testFont = @import("test.zig").fontRegular; + const testFont = font.embedded.regular; var lib = try Library.init(); defer lib.deinit(); @@ -791,7 +791,7 @@ test completeStyles { test setSize { const testing = std.testing; const alloc = testing.allocator; - const testFont = @import("test.zig").fontRegular; + const testFont = font.embedded.regular; var lib = try Library.init(); defer lib.deinit(); @@ -814,7 +814,7 @@ test setSize { test hasCodepoint { const testing = std.testing; const alloc = testing.allocator; - const testFont = @import("test.zig").fontRegular; + const testFont = font.embedded.regular; var lib = try Library.init(); defer lib.deinit(); @@ -838,7 +838,7 @@ test "hasCodepoint emoji default graphical" { const testing = std.testing; const alloc = testing.allocator; - const testEmoji = @import("test.zig").fontEmoji; + const testEmoji = font.embedded.emoji; var lib = try Library.init(); defer lib.deinit(); diff --git a/src/font/SharedGrid.zig b/src/font/SharedGrid.zig index 6c5fa43f2..8af385b84 100644 --- a/src/font/SharedGrid.zig +++ b/src/font/SharedGrid.zig @@ -323,7 +323,7 @@ const GlyphKey = struct { const TestMode = enum { normal }; fn testGrid(mode: TestMode, alloc: Allocator, lib: Library) !SharedGrid { - const testFont = @import("test.zig").fontRegular; + const testFont = font.embedded.regular; var c = Collection.init(); c.load_options = .{ .library = lib }; diff --git a/src/font/SharedGridSet.zig b/src/font/SharedGridSet.zig index 25d1f0410..f0dd095d5 100644 --- a/src/font/SharedGridSet.zig +++ b/src/font/SharedGridSet.zig @@ -245,13 +245,46 @@ fn collection( } } + // Complete our styles to ensure we have something to satisfy every + // possible style request. We do this before adding our built-in font + // because we want to ensure our built-in styles are fallbacks to + // the configured styles. + try c.completeStyles(self.alloc, config.@"font-synthetic-style"); + // Our built-in font will be used as a backup _ = try c.add( self.alloc, .regular, .{ .fallback_loaded = try Face.init( self.font_lib, - face_ttf, + font.embedded.regular, + load_options.faceOptions(), + ) }, + ); + _ = try c.add( + self.alloc, + .bold, + .{ .fallback_loaded = try Face.init( + self.font_lib, + font.embedded.bold, + load_options.faceOptions(), + ) }, + ); + _ = try c.add( + self.alloc, + .italic, + .{ .fallback_loaded = try Face.init( + self.font_lib, + font.embedded.italic, + load_options.faceOptions(), + ) }, + ); + _ = try c.add( + self.alloc, + .bold_italic, + .{ .fallback_loaded = try Face.init( + self.font_lib, + font.embedded.bold_italic, load_options.faceOptions(), ) }, ); @@ -284,7 +317,7 @@ fn collection( .regular, .{ .fallback_loaded = try Face.init( self.font_lib, - face_emoji_ttf, + font.embedded.emoji, load_options.faceOptions(), ) }, ); @@ -293,16 +326,12 @@ fn collection( .regular, .{ .fallback_loaded = try Face.init( self.font_lib, - face_emoji_text_ttf, + font.embedded.emoji_text, load_options.faceOptions(), ) }, ); } - // Complete our styles to ensure we have something to satisfy every - // possible style request. - try c.completeStyles(self.alloc, config.@"font-synthetic-style"); - return c; } @@ -633,11 +662,6 @@ pub const Key = struct { } }; -const face_ttf = @embedFile("res/JetBrainsMono-Regular.ttf"); -const face_bold_ttf = @embedFile("res/JetBrainsMono-Bold.ttf"); -const face_emoji_ttf = @embedFile("res/NotoColorEmoji.ttf"); -const face_emoji_text_ttf = @embedFile("res/NotoEmoji-Regular.ttf"); - test "Key" { const testing = std.testing; const alloc = testing.allocator; diff --git a/src/font/embedded.zig b/src/font/embedded.zig new file mode 100644 index 000000000..2f496f86a --- /dev/null +++ b/src/font/embedded.zig @@ -0,0 +1,35 @@ +//! Fonts that can be embedded with Ghostty. Note they are only actually +//! embedded in the binary if they are referenced by the code, so fonts +//! used for tests will not result in the final binary being larger. +//! +//! Be careful to ensure that any fonts you embed are licensed for +//! redistribution and include their license as necessary. + +/// Default fonts that we prefer for Ghostty. +pub const regular = @embedFile("res/JetBrainsMonoNerdFont-Regular.ttf"); +pub const bold = @embedFile("res/JetBrainsMonoNerdFont-Bold.ttf"); +pub const italic = @embedFile("res/JetBrainsMonoNerdFont-Italic.ttf"); +pub const bold_italic = @embedFile("res/JetBrainsMonoNerdFont-BoldItalic.ttf"); +pub const emoji = @embedFile("res/NotoColorEmoji.ttf"); +pub const emoji_text = @embedFile("res/NotoEmoji-Regular.ttf"); + +/// Fonts with general properties +pub const variable = @embedFile("res/Lilex-VF.ttf"); + +/// Font with nerd fonts embedded. +pub const nerd_font = @embedFile("res/JetBrainsMonoNerdFont-Regular.ttf"); + +/// Specific font families below: +pub const code_new_roman = @embedFile("res/CodeNewRoman-Regular.otf"); +pub const inconsolata = @embedFile("res/Inconsolata-Regular.ttf"); +pub const geist_mono = @embedFile("res/GeistMono-Regular.ttf"); +pub const jetbrains_mono = @embedFile("res/JetBrainsMonoNoNF-Regular.ttf"); +pub const julia_mono = @embedFile("res/JuliaMono-Regular.ttf"); + +/// Cozette is a unique font because it embeds some emoji characters +/// but has a text presentation. +pub const cozette = @embedFile("res/CozetteVector.ttf"); + +/// Monaspace has weird ligature behaviors we want to test in our shapers +/// so we embed it here. +pub const monaspace_neon = @embedFile("res/MonaspaceNeon-Regular.otf"); diff --git a/src/font/face/coretext.zig b/src/font/face/coretext.zig index dacb79476..2403b3902 100644 --- a/src/font/face/coretext.zig +++ b/src/font/face/coretext.zig @@ -798,7 +798,7 @@ test "emoji" { test "in-memory" { const testing = std.testing; const alloc = testing.allocator; - const testFont = @import("../test.zig").fontRegular; + const testFont = font.embedded.regular; var atlas = try font.Atlas.init(alloc, 512, .grayscale); defer atlas.deinit(alloc); @@ -820,7 +820,7 @@ test "in-memory" { test "variable" { const testing = std.testing; const alloc = testing.allocator; - const testFont = @import("../test.zig").fontVariable; + const testFont = font.embedded.variable; var atlas = try font.Atlas.init(alloc, 512, .grayscale); defer atlas.deinit(alloc); @@ -842,7 +842,7 @@ test "variable" { test "variable set variation" { const testing = std.testing; const alloc = testing.allocator; - const testFont = @import("../test.zig").fontVariable; + const testFont = font.embedded.variable; var atlas = try font.Atlas.init(alloc, 512, .grayscale); defer atlas.deinit(alloc); @@ -868,7 +868,7 @@ test "variable set variation" { test "svg font table" { const testing = std.testing; const alloc = testing.allocator; - const testFont = @import("../test.zig").fontJuliaMono; + const testFont = font.embedded.julia_mono; var lib = try font.Library.init(); defer lib.deinit(); @@ -884,7 +884,7 @@ test "svg font table" { test "glyphIndex colored vs text" { const testing = std.testing; - const testFont = @import("../test.zig").fontJuliaMono; + const testFont = font.embedded.julia_mono; var lib = try font.Library.init(); defer lib.deinit(); diff --git a/src/font/face/freetype.zig b/src/font/face/freetype.zig index 3ff9e9ffa..7bb9ecbab 100644 --- a/src/font/face/freetype.zig +++ b/src/font/face/freetype.zig @@ -742,7 +742,7 @@ pub const Face = struct { }; test { - const testFont = @import("../test.zig").fontRegular; + const testFont = font.embedded.inconsolata; const alloc = testing.allocator; var lib = try Library.init(); @@ -771,13 +771,13 @@ test { try ft_font.setSize(.{ .size = .{ .points = 24, .xdpi = 96, .ydpi = 96 } }); const g2 = try ft_font.renderGlyph(alloc, &atlas, ft_font.glyphIndex('A').?, .{}); - try testing.expectEqual(@as(u32, 21), g2.height); + try testing.expectEqual(@as(u32, 20), g2.height); } } test "color emoji" { const alloc = testing.allocator; - const testFont = @import("../test.zig").fontEmoji; + const testFont = font.embedded.emoji; var lib = try Library.init(); defer lib.deinit(); @@ -819,7 +819,7 @@ test "color emoji" { } test "metrics" { - const testFont = @import("../test.zig").fontRegular; + const testFont = font.embedded.inconsolata; const alloc = testing.allocator; var lib = try Library.init(); @@ -860,7 +860,7 @@ test "metrics" { test "mono to rgba" { const alloc = testing.allocator; - const testFont = @import("../test.zig").fontEmoji; + const testFont = font.embedded.emoji; var lib = try Library.init(); defer lib.deinit(); @@ -877,7 +877,7 @@ test "mono to rgba" { test "svg font table" { const alloc = testing.allocator; - const testFont = @import("../test.zig").fontJuliaMono; + const testFont = font.embedded.julia_mono; var lib = try font.Library.init(); defer lib.deinit(); diff --git a/src/font/main.zig b/src/font/main.zig index 4c0d206b3..60e7593cb 100644 --- a/src/font/main.zig +++ b/src/font/main.zig @@ -6,6 +6,7 @@ const library = @import("library.zig"); pub const Atlas = @import("Atlas.zig"); pub const discovery = @import("discovery.zig"); +pub const embedded = @import("embedded.zig"); pub const face = @import("face.zig"); pub const CodepointMap = @import("CodepointMap.zig"); pub const CodepointResolver = @import("CodepointResolver.zig"); diff --git a/src/font/opentype/svg.zig b/src/font/opentype/svg.zig index 985e58bec..ff431dee2 100644 --- a/src/font/opentype/svg.zig +++ b/src/font/opentype/svg.zig @@ -95,7 +95,7 @@ pub const SVG = struct { test "SVG" { const testing = std.testing; const alloc = testing.allocator; - const testFont = @import("../test.zig").fontJuliaMono; + const testFont = font.embedded.julia_mono; var lib = try font.Library.init(); defer lib.deinit(); diff --git a/src/font/res/Inconsolata-Bold.ttf b/src/font/res/Inconsolata-Bold.ttf deleted file mode 100644 index 6330f5b28..000000000 Binary files a/src/font/res/Inconsolata-Bold.ttf and /dev/null differ diff --git a/src/font/res/Inconsolata-Regular.ttf b/src/font/res/Inconsolata-Regular.ttf index 3b74e08a1..20251d93e 100755 Binary files a/src/font/res/Inconsolata-Regular.ttf and b/src/font/res/Inconsolata-Regular.ttf differ diff --git a/src/font/res/Inconsolata.ttf b/src/font/res/Inconsolata.ttf deleted file mode 100755 index 20251d93e..000000000 Binary files a/src/font/res/Inconsolata.ttf and /dev/null differ diff --git a/src/font/res/JetBrainsMono-Bold.ttf b/src/font/res/JetBrainsMonoNerdFont-Bold.ttf similarity index 79% rename from src/font/res/JetBrainsMono-Bold.ttf rename to src/font/res/JetBrainsMonoNerdFont-Bold.ttf index 610c8c02b..b82ccbcb8 100644 Binary files a/src/font/res/JetBrainsMono-Bold.ttf and b/src/font/res/JetBrainsMonoNerdFont-Bold.ttf differ diff --git a/src/font/res/JetBrainsMonoNerdFont-BoldItalic.ttf b/src/font/res/JetBrainsMonoNerdFont-BoldItalic.ttf new file mode 100644 index 000000000..35f0080ef Binary files /dev/null and b/src/font/res/JetBrainsMonoNerdFont-BoldItalic.ttf differ diff --git a/src/font/res/JetBrainsMono-Regular.ttf b/src/font/res/JetBrainsMonoNerdFont-Italic.ttf similarity index 73% rename from src/font/res/JetBrainsMono-Regular.ttf rename to src/font/res/JetBrainsMonoNerdFont-Italic.ttf index 2e02cab2d..a341a3758 100644 Binary files a/src/font/res/JetBrainsMono-Regular.ttf and b/src/font/res/JetBrainsMonoNerdFont-Italic.ttf differ diff --git a/src/font/res/JetBrainsMonoNerdFont-Regular.ttf b/src/font/res/JetBrainsMonoNerdFont-Regular.ttf index 8d19bd88c..a6031886f 100644 Binary files a/src/font/res/JetBrainsMonoNerdFont-Regular.ttf and b/src/font/res/JetBrainsMonoNerdFont-Regular.ttf differ diff --git a/src/font/shaper/coretext.zig b/src/font/shaper/coretext.zig index afb41f596..185ff1aca 100644 --- a/src/font/shaper/coretext.zig +++ b/src/font/shaper/coretext.zig @@ -1732,15 +1732,15 @@ fn testShaper(alloc: Allocator) !TestShaper { } fn testShaperWithFont(alloc: Allocator, font_req: TestFont) !TestShaper { - const testEmoji = @import("../test.zig").fontEmoji; - const testEmojiText = @import("../test.zig").fontEmojiText; + const testEmoji = font.embedded.emoji; + const testEmojiText = font.embedded.emoji_text; const testFont = switch (font_req) { - .code_new_roman => @import("../test.zig").fontCodeNewRoman, - .inconsolata => @import("../test.zig").fontRegular, - .geist_mono => @import("../test.zig").fontGeistMono, - .jetbrains_mono => @import("../test.zig").fontJetBrainsMono, - .monaspace_neon => @import("../test.zig").fontMonaspaceNeon, - .nerd_font => @import("../test.zig").fontNerdFont, + .code_new_roman => font.embedded.code_new_roman, + .inconsolata => font.embedded.inconsolata, + .geist_mono => font.embedded.geist_mono, + .jetbrains_mono => font.embedded.jetbrains_mono, + .monaspace_neon => font.embedded.monaspace_neon, + .nerd_font => font.embedded.nerd_font, }; var lib = try Library.init(); diff --git a/src/font/shaper/harfbuzz.zig b/src/font/shaper/harfbuzz.zig index 8c04b759d..6dd520ad4 100644 --- a/src/font/shaper/harfbuzz.zig +++ b/src/font/shaper/harfbuzz.zig @@ -1197,11 +1197,11 @@ fn testShaper(alloc: Allocator) !TestShaper { } fn testShaperWithFont(alloc: Allocator, font_req: TestFont) !TestShaper { - const testEmoji = @import("../test.zig").fontEmoji; - const testEmojiText = @import("../test.zig").fontEmojiText; + const testEmoji = font.embedded.emoji; + const testEmojiText = font.embedded.emoji_text; const testFont = switch (font_req) { - .inconsolata => @import("../test.zig").fontRegular, - .monaspace_neon => @import("../test.zig").fontMonaspaceNeon, + .inconsolata => font.embedded.inconsolata, + .monaspace_neon => font.embedded.monaspace_neon, }; var lib = try Library.init(); diff --git a/src/font/test.zig b/src/font/test.zig deleted file mode 100644 index c7b68e5c6..000000000 --- a/src/font/test.zig +++ /dev/null @@ -1,30 +0,0 @@ -//! Fonts that can be embedded with Ghostty. Note they are only actually -//! embedded in the binary if they are referenced by the code, so fonts -//! used for tests will not result in the final binary being larger. -//! -//! Be careful to ensure that any fonts you embed are licensed for -//! redistribution and include their license as necessary. - -/// Fonts with general properties -pub const fontRegular = @embedFile("res/Inconsolata-Regular.ttf"); -pub const fontBold = @embedFile("res/Inconsolata-Bold.ttf"); -pub const fontEmoji = @embedFile("res/NotoColorEmoji.ttf"); -pub const fontEmojiText = @embedFile("res/NotoEmoji-Regular.ttf"); -pub const fontVariable = @embedFile("res/Lilex-VF.ttf"); - -/// Font with nerd fonts embedded. -pub const fontNerdFont = @embedFile("res/JetBrainsMonoNerdFont-Regular.ttf"); - -/// Specific font families below: -pub const fontCodeNewRoman = @embedFile("res/CodeNewRoman-Regular.otf"); -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. -pub const fontCozette = @embedFile("res/CozetteVector.ttf"); - -/// Monaspace has weird ligature behaviors we want to test in our shapers -/// so we embed it here. -pub const fontMonaspaceNeon = @embedFile("res/MonaspaceNeon-Regular.otf"); diff --git a/src/inspector/Inspector.zig b/src/inspector/Inspector.zig index 1de666b09..14ebadf04 100644 --- a/src/inspector/Inspector.zig +++ b/src/inspector/Inspector.zig @@ -9,6 +9,7 @@ const Allocator = std.mem.Allocator; const builtin = @import("builtin"); const cimgui = @import("cimgui"); const Surface = @import("../Surface.zig"); +const font = @import("../font/main.zig"); const input = @import("../input.zig"); const terminal = @import("../terminal/main.zig"); const inspector = @import("main.zig"); @@ -130,8 +131,8 @@ pub fn setup() void { font_config.FontDataOwnedByAtlas = false; _ = cimgui.c.ImFontAtlas_AddFontFromMemoryTTF( io.Fonts, - @constCast(@ptrCast(Surface.face_ttf)), - Surface.face_ttf.len, + @constCast(@ptrCast(font.embedded.regular)), + font.embedded.regular.len, font_size, font_config, null,