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:
Mitchell Hashimoto
2022-11-17 16:07:20 -08:00
parent da2942e083
commit 08bca077b2
3 changed files with 43 additions and 10 deletions

View File

@ -175,12 +175,12 @@ pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window {
errdefer alloc.destroy(font_group);
font_group.* = try font.GroupCache.init(alloc, group: {
var group = try font.Group.init(alloc, font_lib, font_size);
errdefer group.deinit(alloc);
errdefer group.deinit();
// Search for fonts
if (font.Discover != void) {
var disco = font.Discover.init();
defer disco.deinit();
group.discover = disco;
if (config.@"font-family") |family| {
var disco_it = try disco.discover(.{

View File

@ -29,6 +29,9 @@ const log = std.log.scoped(.font_group);
// to the user so we can change this later.
const StyleArray = std.EnumArray(Style, std.ArrayListUnmanaged(DeferredFace));
/// The allocator for this group
alloc: Allocator,
/// The library being used for all the faces.
lib: Library,
@ -39,12 +42,16 @@ size: font.face.DesiredSize,
/// Instead, use the functions available on Group.
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(
alloc: Allocator,
lib: Library,
size: font.face.DesiredSize,
) !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.
var i: usize = 0;
@ -56,11 +63,15 @@ pub fn init(
return result;
}
pub fn deinit(self: *Group, alloc: Allocator) void {
pub fn deinit(self: *Group) void {
var it = self.faces.iterator();
while (it.next()) |entry| {
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
/// a code point.
pub fn indexForCodepoint(
self: Group,
self: *Group,
cp: u32,
style: Style,
p: ?Presentation,
@ -134,6 +145,28 @@ pub fn indexForCodepoint(
// If we can find the exact value, then return that.
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 (style == .regular and p == null) return null;
@ -200,7 +233,7 @@ test {
defer lib.deinit();
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, testEmoji, .{ .points = 12 })));
@ -257,7 +290,7 @@ test "resize" {
defer lib.deinit();
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 })));
@ -311,7 +344,7 @@ test "discover monospace with fontconfig and freetype" {
var lib = try Library.init();
defer lib.deinit();
var group = try init(alloc, lib, .{ .points = 12 });
defer group.deinit(alloc);
defer group.deinit();
try group.addFace(alloc, .regular, (try it.next()).?);
// Should find all visible ASCII

View File

@ -70,7 +70,7 @@ pub fn deinit(self: *GroupCache, alloc: Allocator) void {
self.glyphs.deinit(alloc);
self.atlas_greyscale.deinit(alloc);
self.atlas_color.deinit(alloc);
self.group.deinit(alloc);
self.group.deinit();
}
/// Reset the cache. This should be called: