font: CodepointResolver style disabling test

This commit is contained in:
Mitchell Hashimoto
2024-04-02 19:32:03 -07:00
parent 4eccd42f6b
commit b2541d24f1
2 changed files with 118 additions and 8 deletions

View File

@ -72,6 +72,15 @@ pub fn deinit(self: *CodepointResolver, alloc: Allocator) void {
/// presentation for the codepoint. /// presentation for the codepoint.
/// a code point. /// a code point.
/// ///
/// An allocator is required because certain functionality (codepoint
/// mapping, fallback fonts, etc.) may require memory allocation. Curiously,
/// this function cannot error! If an error occurs for any reason, including
/// memory allocation, the associated functionality is ignored and the
/// resolver attempts to use a different method to satisfy the codepoint.
/// This behavior is intentional to make the resolver apply best-effort
/// logic to satisfy the codepoint since its better to render something
/// than nothing.
///
/// This logic is relatively complex so the exact algorithm is documented /// This logic is relatively complex so the exact algorithm is documented
/// here. If this gets out of sync with the code, ask questions. /// here. If this gets out of sync with the code, ask questions.
/// ///
@ -118,7 +127,7 @@ pub fn getIndex(
} }
// Codepoint overrides. // Codepoint overrides.
if (self.indexForCodepointOverride(alloc, cp)) |idx_| { if (self.getIndexCodepointOverride(alloc, cp)) |idx_| {
if (idx_) |idx| return idx; if (idx_) |idx| return idx;
} else |err| { } else |err| {
log.warn("codepoint override failed codepoint={} err={}", .{ cp, err }); log.warn("codepoint override failed codepoint={} err={}", .{ cp, err });
@ -208,7 +217,7 @@ pub fn getIndex(
/// Checks if the codepoint is in the map of codepoint overrides, /// Checks if the codepoint is in the map of codepoint overrides,
/// finds the override font, and returns it. /// finds the override font, and returns it.
fn indexForCodepointOverride( fn getIndexCodepointOverride(
self: *CodepointResolver, self: *CodepointResolver,
alloc: Allocator, alloc: Allocator,
cp: u32, cp: u32,
@ -265,7 +274,7 @@ fn indexForCodepointOverride(
const idx = idx_ orelse return null; const idx = idx_ orelse return null;
// We need to verify that this index has the codepoint we want. // We need to verify that this index has the codepoint we want.
if (self.collection.hasCodepoint(idx, cp, null)) { if (self.collection.hasCodepoint(idx, cp, .{ .any = {} })) {
log.debug("codepoint override based on config codepoint={} family={s}", .{ log.debug("codepoint override based on config codepoint={} family={s}", .{
cp, cp,
desc.family orelse "", desc.family orelse "",
@ -385,3 +394,59 @@ test getIndex {
try testing.expect(r.getIndex(alloc, 0x1FB00, .regular, null) == null); try testing.expect(r.getIndex(alloc, 0x1FB00, .regular, null) == null);
} }
} }
test "getIndex disabled font style" {
const testing = std.testing;
const alloc = testing.allocator;
const testFont = @import("test.zig").fontRegular;
var atlas_greyscale = try font.Atlas.init(alloc, 512, .greyscale);
defer atlas_greyscale.deinit(alloc);
var lib = try Library.init();
defer lib.deinit();
var c = try Collection.init(alloc);
c.load_options = .{ .library = lib };
_ = try c.add(alloc, .regular, .{ .loaded = try Face.init(
lib,
testFont,
.{ .size = .{ .points = 12, .xdpi = 96, .ydpi = 96 } },
) });
_ = try c.add(alloc, .bold, .{ .loaded = try Face.init(
lib,
testFont,
.{ .size = .{ .points = 12, .xdpi = 96, .ydpi = 96 } },
) });
_ = try c.add(alloc, .italic, .{ .loaded = try Face.init(
lib,
testFont,
.{ .size = .{ .points = 12, .xdpi = 96, .ydpi = 96 } },
) });
var r: CodepointResolver = .{ .collection = c };
defer r.deinit(alloc);
r.styles.set(.bold, false); // Disable bold
// Regular should work fine
{
const idx = r.getIndex(alloc, 'A', .regular, null).?;
try testing.expectEqual(Style.regular, idx.style);
try testing.expectEqual(@as(Collection.Index.IndexInt, 0), idx.idx);
}
// Bold should go to regular
{
const idx = r.getIndex(alloc, 'A', .bold, null).?;
try testing.expectEqual(Style.regular, idx.style);
try testing.expectEqual(@as(Collection.Index.IndexInt, 0), idx.idx);
}
// Italic should still work
{
const idx = r.getIndex(alloc, 'A', .italic, null).?;
try testing.expectEqual(Style.italic, idx.style);
try testing.expectEqual(@as(Collection.Index.IndexInt, 0), idx.idx);
}
}

View File

@ -18,6 +18,7 @@ const Collection = @This();
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const font = @import("main.zig"); const font = @import("main.zig");
const options = font.options;
const DeferredFace = font.DeferredFace; const DeferredFace = font.DeferredFace;
const DesiredSize = font.face.DesiredSize; const DesiredSize = font.face.DesiredSize;
const Face = font.Face; const Face = font.Face;
@ -160,14 +161,11 @@ pub fn hasCodepoint(
self: *const Collection, self: *const Collection,
index: Index, index: Index,
cp: u32, cp: u32,
p: ?Presentation, p_mode: PresentationMode,
) bool { ) bool {
const list = self.faces.get(index.style); const list = self.faces.get(index.style);
if (index.idx >= list.items.len) return false; if (index.idx >= list.items.len) return false;
return list.items[index.idx].hasCodepoint( return list.items[index.idx].hasCodepoint(cp, p_mode);
cp,
if (p) |v| .{ .explicit = v } else .{ .any = {} },
);
} }
/// Automatically create an italicized font from the regular /// Automatically create an italicized font from the regular
@ -601,3 +599,50 @@ test setSize {
try c.setSize(.{ .points = 24 }); try c.setSize(.{ .points = 24 });
try testing.expectEqual(@as(u32, 24), c.load_options.?.size.points); try testing.expectEqual(@as(u32, 24), c.load_options.?.size.points);
} }
test hasCodepoint {
const testing = std.testing;
const alloc = testing.allocator;
const testFont = @import("test.zig").fontRegular;
var lib = try Library.init();
defer lib.deinit();
var c = try init(alloc);
defer c.deinit(alloc);
c.load_options = .{ .library = lib };
const idx = try c.add(alloc, .regular, .{ .loaded = try Face.init(
lib,
testFont,
.{ .size = .{ .points = 12, .xdpi = 96, .ydpi = 96 } },
) });
try testing.expect(c.hasCodepoint(idx, 'A', .{ .any = {} }));
try testing.expect(!c.hasCodepoint(idx, '🥸', .{ .any = {} }));
}
test "hasCodepoint emoji default graphical" {
if (options.backend != .fontconfig_freetype) return error.SkipZigTest;
const testing = std.testing;
const alloc = testing.allocator;
const testEmoji = @import("test.zig").fontEmoji;
var lib = try Library.init();
defer lib.deinit();
var c = try init(alloc);
defer c.deinit(alloc);
c.load_options = .{ .library = lib };
const idx = try c.add(alloc, .regular, .{ .loaded = try Face.init(
lib,
testEmoji,
.{ .size = .{ .points = 12, .xdpi = 96, .ydpi = 96 } },
) });
try testing.expect(!c.hasCodepoint(idx, 'A', .{ .any = {} }));
try testing.expect(c.hasCodepoint(idx, '🥸', .{ .any = {} }));
// TODO(fontmem): test explicit/implicit
}