mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +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();
|
var font_lib = try font.Library.init();
|
||||||
errdefer font_lib.deinit();
|
errdefer font_lib.deinit();
|
||||||
var font_group = try font.GroupCache.init(alloc, group: {
|
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);
|
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(
|
try group.addFace(
|
||||||
alloc,
|
alloc,
|
||||||
.regular,
|
.regular,
|
||||||
|
@ -32,11 +32,6 @@ pub const Fontconfig = struct {
|
|||||||
charset: *const fontconfig.CharSet,
|
charset: *const fontconfig.CharSet,
|
||||||
langset: *const fontconfig.LangSet,
|
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 {
|
pub fn deinit(self: *Fontconfig) void {
|
||||||
self.pattern.destroy();
|
self.pattern.destroy();
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
@ -60,13 +55,28 @@ pub inline fn loaded(self: DeferredFace) bool {
|
|||||||
return self.face != null;
|
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.
|
/// 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
|
// No-op if we already loaded
|
||||||
if (self.face != null) return;
|
if (self.face != null) return;
|
||||||
|
|
||||||
if (options.fontconfig) {
|
if (options.fontconfig) {
|
||||||
try self.loadFontconfig(lib);
|
try self.loadFontconfig(lib, size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +85,11 @@ pub fn load(self: *DeferredFace, lib: Library) !void {
|
|||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadFontconfig(self: *DeferredFace, lib: Library) !void {
|
fn loadFontconfig(
|
||||||
|
self: *DeferredFace,
|
||||||
|
lib: Library,
|
||||||
|
size: Face.DesiredSize,
|
||||||
|
) !void {
|
||||||
assert(self.face == null);
|
assert(self.face == null);
|
||||||
const fc = self.fc.?;
|
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 filename = (try fc.pattern.get(.file, 0)).string;
|
||||||
const face_index = (try fc.pattern.get(.index, 0)).integer;
|
const face_index = (try fc.pattern.get(.index, 0)).integer;
|
||||||
|
|
||||||
self.face = try Face.initFile(lib, filename, face_index, .{
|
self.face = try Face.initFile(lib, filename, face_index, size);
|
||||||
.points = fc.req_size,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this face can satisfy the given codepoint and
|
/// Returns true if this face can satisfy the given codepoint and
|
||||||
@ -165,8 +177,12 @@ test "fontconfig" {
|
|||||||
defer def.deinit();
|
defer def.deinit();
|
||||||
try testing.expect(!def.loaded());
|
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
|
// 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.hasCodepoint(' ', null));
|
||||||
try testing.expect(def.face.?.glyphIndex(' ') != 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.
|
/// The library being used for all the faces.
|
||||||
lib: Library,
|
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.
|
/// The available faces we have. This shouldn't be modified manually.
|
||||||
/// Instead, use the functions available on Group.
|
/// Instead, use the functions available on Group.
|
||||||
faces: StyleArray,
|
faces: StyleArray,
|
||||||
|
|
||||||
pub fn init(alloc: Allocator, lib: Library) !Group {
|
pub fn init(
|
||||||
var result = Group{ .lib = lib, .faces = undefined };
|
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.
|
// Initialize all our styles to initially sized lists.
|
||||||
var i: usize = 0;
|
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.
|
/// Return the Face represented by a given FontIndex.
|
||||||
pub fn faceFromIndex(self: Group, index: FontIndex) !Face {
|
pub fn faceFromIndex(self: Group, index: FontIndex) !Face {
|
||||||
const deferred = &self.faces.get(index.style).items[@intCast(usize, index.idx)];
|
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.?;
|
return deferred.face.?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +161,7 @@ pub fn renderGlyph(
|
|||||||
glyph_index: u32,
|
glyph_index: u32,
|
||||||
) !Glyph {
|
) !Glyph {
|
||||||
const face = &self.faces.get(index.style).items[@intCast(usize, index.idx)];
|
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);
|
return try face.face.?.renderGlyph(alloc, atlas, glyph_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +178,7 @@ test {
|
|||||||
var lib = try Library.init();
|
var lib = try Library.init();
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var group = try init(alloc, lib);
|
var group = try init(alloc, lib, .{ .points = 12 });
|
||||||
defer group.deinit(alloc);
|
defer group.deinit(alloc);
|
||||||
|
|
||||||
try group.addFace(alloc, .regular, DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12 })));
|
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
|
// Initialize the group with the deferred face
|
||||||
var lib = try Library.init();
|
var lib = try Library.init();
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
var group = try init(alloc, lib);
|
var group = try init(alloc, lib, .{ .points = 12 });
|
||||||
defer group.deinit(alloc);
|
defer group.deinit(alloc);
|
||||||
try group.addFace(alloc, .regular, (try it.next()).?);
|
try group.addFace(alloc, .regular, (try it.next()).?);
|
||||||
|
|
||||||
|
@ -218,7 +218,11 @@ test {
|
|||||||
var lib = try Library.init();
|
var lib = try Library.init();
|
||||||
defer lib.deinit();
|
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);
|
defer cache.deinit(alloc);
|
||||||
|
|
||||||
// Setup group
|
// Setup group
|
||||||
|
@ -596,7 +596,11 @@ fn testShaper(alloc: Allocator) !TestShaper {
|
|||||||
|
|
||||||
var cache_ptr = try alloc.create(GroupCache);
|
var cache_ptr = try alloc.create(GroupCache);
|
||||||
errdefer alloc.destroy(cache_ptr);
|
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);
|
errdefer cache_ptr.*.deinit(alloc);
|
||||||
|
|
||||||
// Setup group
|
// Setup group
|
||||||
|
@ -39,7 +39,11 @@ pub const Descriptor = struct {
|
|||||||
pub fn toFcPattern(self: Descriptor) *fontconfig.Pattern {
|
pub fn toFcPattern(self: Descriptor) *fontconfig.Pattern {
|
||||||
const pat = fontconfig.Pattern.create();
|
const pat = fontconfig.Pattern.create();
|
||||||
assert(pat.add(.family, .{ .string = self.family }, false));
|
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(
|
if (self.bold) assert(pat.add(
|
||||||
.weight,
|
.weight,
|
||||||
.{ .integer = @enumToInt(fontconfig.Weight.bold) },
|
.{ .integer = @enumToInt(fontconfig.Weight.bold) },
|
||||||
@ -64,6 +68,10 @@ pub const Fontconfig = struct {
|
|||||||
return .{ .fc_config = fontconfig.initLoadConfigAndFonts() };
|
return .{ .fc_config = fontconfig.initLoadConfigAndFonts() };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Fontconfig) void {
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
|
||||||
/// Discover fonts from a descriptor. This returns an iterator that can
|
/// Discover fonts from a descriptor. This returns an iterator that can
|
||||||
/// be used to build up the deferred fonts.
|
/// be used to build up the deferred fonts.
|
||||||
pub fn discover(self: *Fontconfig, desc: Descriptor) !DiscoverIterator {
|
pub fn discover(self: *Fontconfig, desc: Descriptor) !DiscoverIterator {
|
||||||
@ -84,7 +92,6 @@ pub const Fontconfig = struct {
|
|||||||
.set = res.fs,
|
.set = res.fs,
|
||||||
.fonts = res.fs.fonts(),
|
.fonts = res.fs.fonts(),
|
||||||
.i = 0,
|
.i = 0,
|
||||||
.req_size = @floatToInt(u16, (try pat.get(.size, 0)).double),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +101,6 @@ pub const Fontconfig = struct {
|
|||||||
set: *fontconfig.FontSet,
|
set: *fontconfig.FontSet,
|
||||||
fonts: []*fontconfig.Pattern,
|
fonts: []*fontconfig.Pattern,
|
||||||
i: usize,
|
i: usize,
|
||||||
req_size: u16,
|
|
||||||
|
|
||||||
pub fn deinit(self: *DiscoverIterator) void {
|
pub fn deinit(self: *DiscoverIterator) void {
|
||||||
self.set.destroy();
|
self.set.destroy();
|
||||||
@ -122,7 +128,6 @@ pub const Fontconfig = struct {
|
|||||||
.pattern = font_pattern,
|
.pattern = font_pattern,
|
||||||
.charset = (try font_pattern.get(.charset, 0)).char_set,
|
.charset = (try font_pattern.get(.charset, 0)).char_set,
|
||||||
.langset = (try font_pattern.get(.lang, 0)).lang_set,
|
.langset = (try font_pattern.get(.lang, 0)).lang_set,
|
||||||
.req_size = self.req_size,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user