diff --git a/src/Grid.zig b/src/Grid.zig index 6ff0eaa08..735063946 100644 --- a/src/Grid.zig +++ b/src/Grid.zig @@ -160,10 +160,36 @@ pub fn init( var font_lib = try font.Library.init(); errdefer font_lib.deinit(); var font_group = try font.GroupCache.init(alloc, group: { - var group = try font.Group.init(alloc, font_lib); + var group = try font.Group.init(alloc, font_lib, font_size); errdefer group.deinit(alloc); - // Our regular font + // Search for fonts + { + var disco = font.Discover.init(); + defer disco.deinit(); + + { + var disco_it = try disco.discover(.{ + .family = "Fira Code", + .size = font_size.points, + }); + defer disco_it.deinit(); + if (try disco_it.next()) |face| + try group.addFace(alloc, .regular, face); + } + { + var disco_it = try disco.discover(.{ + .family = "Fira Code", + .size = font_size.points, + .bold = true, + }); + defer disco_it.deinit(); + if (try disco_it.next()) |face| + try group.addFace(alloc, .bold, face); + } + } + + // Our built-in font will be used as a backup try group.addFace( alloc, .regular, diff --git a/src/font/DeferredFace.zig b/src/font/DeferredFace.zig index 4693ed5bc..b6bef7384 100644 --- a/src/font/DeferredFace.zig +++ b/src/font/DeferredFace.zig @@ -32,11 +32,6 @@ pub const Fontconfig = struct { charset: *const fontconfig.CharSet, langset: *const fontconfig.LangSet, - /// The requested size in points for this font. This is used for loading. - /// This can't be derived from pattern because the requested size may - /// differ from the size the font advertises supported. - req_size: u16, - pub fn deinit(self: *Fontconfig) void { self.pattern.destroy(); self.* = undefined; @@ -60,13 +55,28 @@ pub inline fn loaded(self: DeferredFace) bool { return self.face != null; } +/// Returns the name of this face. The memory is always owned by the +/// face so it doesn't have to be freed. +pub fn name(self: DeferredFace) ![:0]const u8 { + if (options.fontconfig) { + if (self.fc) |fc| + return (try fc.pattern.get(.fullname, 0)).string; + } + + return "TODO: built-in font names"; +} + /// Load the deferred font face. This does nothing if the face is loaded. -pub fn load(self: *DeferredFace, lib: Library) !void { +pub fn load( + self: *DeferredFace, + lib: Library, + size: Face.DesiredSize, +) !void { // No-op if we already loaded if (self.face != null) return; if (options.fontconfig) { - try self.loadFontconfig(lib); + try self.loadFontconfig(lib, size); return; } @@ -75,7 +85,11 @@ pub fn load(self: *DeferredFace, lib: Library) !void { unreachable; } -fn loadFontconfig(self: *DeferredFace, lib: Library) !void { +fn loadFontconfig( + self: *DeferredFace, + lib: Library, + size: Face.DesiredSize, +) !void { assert(self.face == null); const fc = self.fc.?; @@ -83,9 +97,7 @@ fn loadFontconfig(self: *DeferredFace, lib: Library) !void { const filename = (try fc.pattern.get(.file, 0)).string; const face_index = (try fc.pattern.get(.index, 0)).integer; - self.face = try Face.initFile(lib, filename, face_index, .{ - .points = fc.req_size, - }); + self.face = try Face.initFile(lib, filename, face_index, size); } /// Returns true if this face can satisfy the given codepoint and @@ -165,8 +177,12 @@ test "fontconfig" { defer def.deinit(); try testing.expect(!def.loaded()); + // Verify we can get the name + const n = try def.name(); + try testing.expect(n.len > 0); + // Load it and verify it works - try def.load(lib); + try def.load(lib, .{ .points = 12 }); try testing.expect(def.hasCodepoint(' ', null)); try testing.expect(def.face.?.glyphIndex(' ') != null); } diff --git a/src/font/Group.zig b/src/font/Group.zig index 3c9454e28..623af7802 100644 --- a/src/font/Group.zig +++ b/src/font/Group.zig @@ -31,12 +31,19 @@ const StyleArray = std.EnumArray(Style, std.ArrayListUnmanaged(DeferredFace)); /// The library being used for all the faces. lib: Library, +/// The desired font size. All fonts in a group must share the same size. +size: Face.DesiredSize, + /// The available faces we have. This shouldn't be modified manually. /// Instead, use the functions available on Group. faces: StyleArray, -pub fn init(alloc: Allocator, lib: Library) !Group { - var result = Group{ .lib = lib, .faces = undefined }; +pub fn init( + alloc: Allocator, + lib: Library, + size: Face.DesiredSize, +) !Group { + var result = Group{ .lib = lib, .size = size, .faces = undefined }; // Initialize all our styles to initially sized lists. var i: usize = 0; @@ -131,7 +138,7 @@ fn indexForCodepointExact(self: Group, cp: u32, style: Style, p: ?Presentation) /// Return the Face represented by a given FontIndex. pub fn faceFromIndex(self: Group, index: FontIndex) !Face { const deferred = &self.faces.get(index.style).items[@intCast(usize, index.idx)]; - try deferred.load(self.lib); + try deferred.load(self.lib, self.size); return deferred.face.?; } @@ -154,7 +161,7 @@ pub fn renderGlyph( glyph_index: u32, ) !Glyph { const face = &self.faces.get(index.style).items[@intCast(usize, index.idx)]; - try face.load(self.lib); + try face.load(self.lib, self.size); return try face.face.?.renderGlyph(alloc, atlas, glyph_index); } @@ -171,7 +178,7 @@ test { var lib = try Library.init(); defer lib.deinit(); - var group = try init(alloc, lib); + var group = try init(alloc, lib, .{ .points = 12 }); defer group.deinit(alloc); try group.addFace(alloc, .regular, DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12 }))); @@ -231,7 +238,7 @@ test { // Initialize the group with the deferred face var lib = try Library.init(); defer lib.deinit(); - var group = try init(alloc, lib); + var group = try init(alloc, lib, .{ .points = 12 }); defer group.deinit(alloc); try group.addFace(alloc, .regular, (try it.next()).?); diff --git a/src/font/GroupCache.zig b/src/font/GroupCache.zig index 479d11b4b..86bbbd520 100644 --- a/src/font/GroupCache.zig +++ b/src/font/GroupCache.zig @@ -218,7 +218,11 @@ test { var lib = try Library.init(); defer lib.deinit(); - var cache = try init(alloc, try Group.init(alloc, lib)); + var cache = try init(alloc, try Group.init( + alloc, + lib, + .{ .points = 12 }, + )); defer cache.deinit(alloc); // Setup group diff --git a/src/font/Shaper.zig b/src/font/Shaper.zig index e1968e92a..dde0a5235 100644 --- a/src/font/Shaper.zig +++ b/src/font/Shaper.zig @@ -596,7 +596,11 @@ fn testShaper(alloc: Allocator) !TestShaper { var cache_ptr = try alloc.create(GroupCache); errdefer alloc.destroy(cache_ptr); - cache_ptr.* = try GroupCache.init(alloc, try Group.init(alloc, lib)); + cache_ptr.* = try GroupCache.init(alloc, try Group.init( + alloc, + lib, + .{ .points = 12 }, + )); errdefer cache_ptr.*.deinit(alloc); // Setup group diff --git a/src/font/discovery.zig b/src/font/discovery.zig index b5f725a42..d3b325782 100644 --- a/src/font/discovery.zig +++ b/src/font/discovery.zig @@ -39,7 +39,11 @@ pub const Descriptor = struct { pub fn toFcPattern(self: Descriptor) *fontconfig.Pattern { const pat = fontconfig.Pattern.create(); assert(pat.add(.family, .{ .string = self.family }, false)); - if (self.size > 0) assert(pat.add(.size, .{ .integer = self.size }, false)); + if (self.size > 0) assert(pat.add( + .size, + .{ .integer = self.size }, + false, + )); if (self.bold) assert(pat.add( .weight, .{ .integer = @enumToInt(fontconfig.Weight.bold) }, @@ -64,6 +68,10 @@ pub const Fontconfig = struct { return .{ .fc_config = fontconfig.initLoadConfigAndFonts() }; } + pub fn deinit(self: *Fontconfig) void { + _ = self; + } + /// Discover fonts from a descriptor. This returns an iterator that can /// be used to build up the deferred fonts. pub fn discover(self: *Fontconfig, desc: Descriptor) !DiscoverIterator { @@ -84,7 +92,6 @@ pub const Fontconfig = struct { .set = res.fs, .fonts = res.fs.fonts(), .i = 0, - .req_size = @floatToInt(u16, (try pat.get(.size, 0)).double), }; } @@ -94,7 +101,6 @@ pub const Fontconfig = struct { set: *fontconfig.FontSet, fonts: []*fontconfig.Pattern, i: usize, - req_size: u16, pub fn deinit(self: *DiscoverIterator) void { self.set.destroy(); @@ -122,7 +128,6 @@ pub const Fontconfig = struct { .pattern = font_pattern, .charset = (try font_pattern.get(.charset, 0)).char_set, .langset = (try font_pattern.get(.lang, 0)).lang_set, - .req_size = self.req_size, }, }; }