summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMitchell Hashimoto <mitchell.hashimoto@gmail.com>2024-04-02 19:32:03 -0700
committerMitchell Hashimoto <mitchell.hashimoto@gmail.com>2024-04-05 09:29:41 -0700
commitb2541d24f19f3233f8a862f10dfa20d1e16cd5c9 (patch)
treec5bb546771494a09a3a951527c8e222acc586cbe /src
parent4eccd42f6b281e06038ac3d412586a239d27209e (diff)
font: CodepointResolver style disabling test
Diffstat (limited to 'src')
-rw-r--r--src/font/CodepointResolver.zig71
-rw-r--r--src/font/Collection.zig55
2 files changed, 118 insertions, 8 deletions
diff --git a/src/font/CodepointResolver.zig b/src/font/CodepointResolver.zig
index 4efeafbbc..7a03f0e5d 100644
--- a/src/font/CodepointResolver.zig
+++ b/src/font/CodepointResolver.zig
@@ -72,6 +72,15 @@ pub fn deinit(self: *CodepointResolver, alloc: Allocator) void {
/// presentation for the codepoint.
/// 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
/// here. If this gets out of sync with the code, ask questions.
///
@@ -118,7 +127,7 @@ pub fn getIndex(
}
// Codepoint overrides.
- if (self.indexForCodepointOverride(alloc, cp)) |idx_| {
+ if (self.getIndexCodepointOverride(alloc, cp)) |idx_| {
if (idx_) |idx| return idx;
} else |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,
/// finds the override font, and returns it.
-fn indexForCodepointOverride(
+fn getIndexCodepointOverride(
self: *CodepointResolver,
alloc: Allocator,
cp: u32,
@@ -265,7 +274,7 @@ fn indexForCodepointOverride(
const idx = idx_ orelse return null;
// 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}", .{
cp,
desc.family orelse "",
@@ -385,3 +394,59 @@ test getIndex {
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);
+ }
+}
diff --git a/src/font/Collection.zig b/src/font/Collection.zig
index 4d623967a..f75356bc9 100644
--- a/src/font/Collection.zig
+++ b/src/font/Collection.zig
@@ -18,6 +18,7 @@ const Collection = @This();
const std = @import("std");
const Allocator = std.mem.Allocator;
const font = @import("main.zig");
+const options = font.options;
const DeferredFace = font.DeferredFace;
const DesiredSize = font.face.DesiredSize;
const Face = font.Face;
@@ -160,14 +161,11 @@ pub fn hasCodepoint(
self: *const Collection,
index: Index,
cp: u32,
- p: ?Presentation,
+ p_mode: PresentationMode,
) bool {
const list = self.faces.get(index.style);
if (index.idx >= list.items.len) return false;
- return list.items[index.idx].hasCodepoint(
- cp,
- if (p) |v| .{ .explicit = v } else .{ .any = {} },
- );
+ return list.items[index.idx].hasCodepoint(cp, p_mode);
}
/// Automatically create an italicized font from the regular
@@ -601,3 +599,50 @@ test setSize {
try c.setSize(.{ .points = 24 });
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
+}