mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
search for unknown codepoints in any available font face
If an unknown codepoint is rendered, we now will query the OS for ANY font that can satisfy the codepoint (rather than rendering `?`).
This commit is contained in:
@ -175,12 +175,12 @@ pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window {
|
|||||||
errdefer alloc.destroy(font_group);
|
errdefer alloc.destroy(font_group);
|
||||||
font_group.* = try font.GroupCache.init(alloc, group: {
|
font_group.* = try font.GroupCache.init(alloc, group: {
|
||||||
var group = try font.Group.init(alloc, font_lib, font_size);
|
var group = try font.Group.init(alloc, font_lib, font_size);
|
||||||
errdefer group.deinit(alloc);
|
errdefer group.deinit();
|
||||||
|
|
||||||
// Search for fonts
|
// Search for fonts
|
||||||
if (font.Discover != void) {
|
if (font.Discover != void) {
|
||||||
var disco = font.Discover.init();
|
var disco = font.Discover.init();
|
||||||
defer disco.deinit();
|
group.discover = disco;
|
||||||
|
|
||||||
if (config.@"font-family") |family| {
|
if (config.@"font-family") |family| {
|
||||||
var disco_it = try disco.discover(.{
|
var disco_it = try disco.discover(.{
|
||||||
|
@ -29,6 +29,9 @@ const log = std.log.scoped(.font_group);
|
|||||||
// to the user so we can change this later.
|
// to the user so we can change this later.
|
||||||
const StyleArray = std.EnumArray(Style, std.ArrayListUnmanaged(DeferredFace));
|
const StyleArray = std.EnumArray(Style, std.ArrayListUnmanaged(DeferredFace));
|
||||||
|
|
||||||
|
/// The allocator for this group
|
||||||
|
alloc: Allocator,
|
||||||
|
|
||||||
/// The library being used for all the faces.
|
/// The library being used for all the faces.
|
||||||
lib: Library,
|
lib: Library,
|
||||||
|
|
||||||
@ -39,12 +42,16 @@ size: font.face.DesiredSize,
|
|||||||
/// Instead, use the functions available on Group.
|
/// Instead, use the functions available on Group.
|
||||||
faces: StyleArray,
|
faces: StyleArray,
|
||||||
|
|
||||||
|
/// If discovery is available, we'll look up fonts where we can't find
|
||||||
|
/// the codepoint.
|
||||||
|
discover: ?font.Discover = null,
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
lib: Library,
|
lib: Library,
|
||||||
size: font.face.DesiredSize,
|
size: font.face.DesiredSize,
|
||||||
) !Group {
|
) !Group {
|
||||||
var result = Group{ .lib = lib, .size = size, .faces = undefined };
|
var result = Group{ .alloc = alloc, .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;
|
||||||
@ -56,11 +63,15 @@ pub fn init(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Group, alloc: Allocator) void {
|
pub fn deinit(self: *Group) void {
|
||||||
var it = self.faces.iterator();
|
var it = self.faces.iterator();
|
||||||
while (it.next()) |entry| {
|
while (it.next()) |entry| {
|
||||||
for (entry.value.items) |*item| item.deinit();
|
for (entry.value.items) |*item| item.deinit();
|
||||||
entry.value.deinit(alloc);
|
entry.value.deinit(self.alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font.Discover != void) {
|
||||||
|
if (self.discover) |*discover| discover.deinit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +137,7 @@ pub const FontIndex = packed struct {
|
|||||||
/// is allowed. This func will NOT determine the default presentation for
|
/// is allowed. This func will NOT determine the default presentation for
|
||||||
/// a code point.
|
/// a code point.
|
||||||
pub fn indexForCodepoint(
|
pub fn indexForCodepoint(
|
||||||
self: Group,
|
self: *Group,
|
||||||
cp: u32,
|
cp: u32,
|
||||||
style: Style,
|
style: Style,
|
||||||
p: ?Presentation,
|
p: ?Presentation,
|
||||||
@ -134,6 +145,28 @@ pub fn indexForCodepoint(
|
|||||||
// If we can find the exact value, then return that.
|
// If we can find the exact value, then return that.
|
||||||
if (self.indexForCodepointExact(cp, style, p)) |value| return value;
|
if (self.indexForCodepointExact(cp, style, p)) |value| return value;
|
||||||
|
|
||||||
|
// Try looking for another font that will satisfy this request.
|
||||||
|
if (font.Discover != void) {
|
||||||
|
if (self.discover) |*disco| discover: {
|
||||||
|
var disco_it = disco.discover(.{
|
||||||
|
.codepoint = cp,
|
||||||
|
.size = self.size.points,
|
||||||
|
.bold = style == .bold or style == .bold_italic,
|
||||||
|
.italic = style == .italic or style == .bold_italic,
|
||||||
|
}) catch break :discover;
|
||||||
|
defer disco_it.deinit();
|
||||||
|
|
||||||
|
if (disco_it.next() catch break :discover) |face| {
|
||||||
|
log.info("found codepoint 0x{x} in fallback face={s}", .{
|
||||||
|
cp,
|
||||||
|
face.name() catch "<error>",
|
||||||
|
});
|
||||||
|
self.addFace(self.alloc, style, face) catch break :discover;
|
||||||
|
if (self.indexForCodepointExact(cp, style, p)) |value| return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If this is already regular, we're done falling back.
|
// If this is already regular, we're done falling back.
|
||||||
if (style == .regular and p == null) return null;
|
if (style == .regular and p == null) return null;
|
||||||
|
|
||||||
@ -200,7 +233,7 @@ test {
|
|||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var group = try init(alloc, lib, .{ .points = 12 });
|
var group = try init(alloc, lib, .{ .points = 12 });
|
||||||
defer group.deinit(alloc);
|
defer group.deinit();
|
||||||
|
|
||||||
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 })));
|
||||||
try group.addFace(alloc, .regular, DeferredFace.initLoaded(try Face.init(lib, testEmoji, .{ .points = 12 })));
|
try group.addFace(alloc, .regular, DeferredFace.initLoaded(try Face.init(lib, testEmoji, .{ .points = 12 })));
|
||||||
@ -257,7 +290,7 @@ test "resize" {
|
|||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var group = try init(alloc, lib, .{ .points = 12, .xdpi = 96, .ydpi = 96 });
|
var group = try init(alloc, lib, .{ .points = 12, .xdpi = 96, .ydpi = 96 });
|
||||||
defer group.deinit(alloc);
|
defer group.deinit();
|
||||||
|
|
||||||
try group.addFace(alloc, .regular, DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12, .xdpi = 96, .ydpi = 96 })));
|
try group.addFace(alloc, .regular, DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12, .xdpi = 96, .ydpi = 96 })));
|
||||||
|
|
||||||
@ -311,7 +344,7 @@ test "discover monospace with fontconfig and freetype" {
|
|||||||
var lib = try Library.init();
|
var lib = try Library.init();
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
var group = try init(alloc, lib, .{ .points = 12 });
|
var group = try init(alloc, lib, .{ .points = 12 });
|
||||||
defer group.deinit(alloc);
|
defer group.deinit();
|
||||||
try group.addFace(alloc, .regular, (try it.next()).?);
|
try group.addFace(alloc, .regular, (try it.next()).?);
|
||||||
|
|
||||||
// Should find all visible ASCII
|
// Should find all visible ASCII
|
||||||
|
@ -70,7 +70,7 @@ pub fn deinit(self: *GroupCache, alloc: Allocator) void {
|
|||||||
self.glyphs.deinit(alloc);
|
self.glyphs.deinit(alloc);
|
||||||
self.atlas_greyscale.deinit(alloc);
|
self.atlas_greyscale.deinit(alloc);
|
||||||
self.atlas_color.deinit(alloc);
|
self.atlas_color.deinit(alloc);
|
||||||
self.group.deinit(alloc);
|
self.group.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset the cache. This should be called:
|
/// Reset the cache. This should be called:
|
||||||
|
Reference in New Issue
Block a user