mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
search for fonts on startup
This commit is contained in:
30
src/Grid.zig
30
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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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()).?);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user