From 16cfb142004625abdcd63bea0cce980e65224a10 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 4 Oct 2023 21:48:51 -0700 Subject: [PATCH] font: modify font compiles for freetype --- src/font/DeferredFace.zig | 4 +-- src/font/face/freetype.zig | 55 +++++++++++++++++++++++++------------- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/font/DeferredFace.zig b/src/font/DeferredFace.zig index 6456f8d23..70dfafe7b 100644 --- a/src/font/DeferredFace.zig +++ b/src/font/DeferredFace.zig @@ -181,7 +181,7 @@ fn loadFontconfig( var face = try Face.initFile(lib, filename, face_index, opts); errdefer face.deinit(); - try face.setVariations(fc.variations); + try face.setVariations(fc.variations, opts); return face; } @@ -400,7 +400,7 @@ test "fontconfig" { try testing.expect(n.len > 0); // Load it and verify it works - const face = try def.load(lib, .{ .points = 12 }); + const face = try def.load(lib, .{ .size = .{ .points = 12 } }); try testing.expect(face.glyphIndex(' ') != null); } diff --git a/src/font/face/freetype.zig b/src/font/face/freetype.zig index 9ae861c7d..66c27aa99 100644 --- a/src/font/face/freetype.zig +++ b/src/font/face/freetype.zig @@ -43,22 +43,22 @@ pub const Face = struct { quirks_disable_default_font_features: bool = false, /// Initialize a new font face with the given source in-memory. - pub fn initFile(lib: Library, path: [:0]const u8, index: i32, size: font.face.DesiredSize) !Face { + pub fn initFile(lib: Library, path: [:0]const u8, index: i32, opts: font.face.Options) !Face { const face = try lib.lib.initFace(path, index); errdefer face.deinit(); - return try initFace(lib, face, size); + return try initFace(lib, face, opts); } /// Initialize a new font face with the given source in-memory. - pub fn init(lib: Library, source: [:0]const u8, size: font.face.DesiredSize) !Face { + pub fn init(lib: Library, source: [:0]const u8, opts: font.face.Options) !Face { const face = try lib.lib.initMemoryFace(source, 0); errdefer face.deinit(); - return try initFace(lib, face, size); + return try initFace(lib, face, opts); } - fn initFace(lib: Library, face: freetype.Face, size: font.face.DesiredSize) !Face { + fn initFace(lib: Library, face: freetype.Face, opts: font.face.Options) !Face { try face.selectCharmap(.unicode); - try setSize_(face, size); + try setSize_(face, opts.size); var hb_font = try harfbuzz.freetype.createFont(face.handle); errdefer hb_font.destroy(); @@ -68,7 +68,7 @@ pub const Face = struct { .face = face, .hb_font = hb_font, .presentation = if (face.hasColor()) .emoji else .text, - .metrics = calcMetrics(face), + .metrics = calcMetrics(face, opts.metric_modifiers), }; result.quirks_disable_default_font_features = quirks.disableDefaultFontFeatures(&result); @@ -127,9 +127,9 @@ pub const Face = struct { /// Resize the font in-place. If this succeeds, the caller is responsible /// for clearing any glyph caches, font atlas data, etc. - pub fn setSize(self: *Face, size: font.face.DesiredSize) !void { - try setSize_(self.face, size); - self.metrics = calcMetrics(self.face); + pub fn setSize(self: *Face, opts: font.face.Options) !void { + try setSize_(self.face, opts.size); + self.metrics = calcMetrics(self.face, opts.metric_modifiers); } fn setSize_(face: freetype.Face, size: font.face.DesiredSize) !void { @@ -165,6 +165,7 @@ pub const Face = struct { pub fn setVariations( self: *Face, vs: []const font.face.Variation, + opts: font.face.Options, ) !void { // If this font doesn't support variations, we can't do anything. if (!self.face.hasMultipleMasters() or vs.len == 0) return; @@ -201,7 +202,7 @@ pub const Face = struct { try self.face.setVarDesignCoordinates(coords); // We need to recalculate font metrics which may have changed. - self.metrics = calcMetrics(self.face); + self.metrics = calcMetrics(self.face, opts.metric_modifiers); } /// Returns the glyph index for the given Unicode code point. If this @@ -470,7 +471,10 @@ pub const Face = struct { /// the faces with DeferredFaces and reload on demand. A Face can't be converted /// into a DeferredFace but a Face that comes from a DeferredFace can be /// deinitialized anytime and reloaded with the deferred face. - fn calcMetrics(face: freetype.Face) font.face.Metrics { + fn calcMetrics( + face: freetype.Face, + modifiers: ?*const font.face.Metrics.ModifierSet, + ) font.face.Metrics { const size_metrics = face.handle.*.size.*.metrics; // Cell width is calculated by preferring to use 'M' as the width of a @@ -574,7 +578,7 @@ pub const Face = struct { .thickness = underline_thickness, }; - const result = font.face.Metrics{ + var result = font.face.Metrics{ .cell_width = @intFromFloat(cell_width), .cell_height = @intFromFloat(cell_height), .cell_baseline = @intFromFloat(cell_baseline), @@ -583,6 +587,7 @@ pub const Face = struct { .strikethrough_position = @intFromFloat(strikethrough.pos), .strikethrough_thickness = @intFromFloat(strikethrough.thickness), }; + if (modifiers) |m| result.apply(m.*); // std.log.warn("font metrics={}", .{result}); @@ -607,7 +612,11 @@ test { var atlas = try font.Atlas.init(alloc, 512, .greyscale); defer atlas.deinit(alloc); - var ft_font = try Face.init(lib, testFont, .{ .points = 12, .xdpi = 96, .ydpi = 96 }); + var ft_font = try Face.init( + lib, + testFont, + .{ .size = .{ .points = 12, .xdpi = 96, .ydpi = 96 } }, + ); defer ft_font.deinit(); try testing.expectEqual(Presentation.text, ft_font.presentation); @@ -623,7 +632,7 @@ test { const g1 = try ft_font.renderGlyph(alloc, &atlas, ft_font.glyphIndex('A').?, .{}); try testing.expectEqual(@as(u32, 11), g1.height); - try ft_font.setSize(.{ .points = 24, .xdpi = 96, .ydpi = 96 }); + try ft_font.setSize(.{ .size = .{ .points = 24, .xdpi = 96, .ydpi = 96 } }); const g2 = try ft_font.renderGlyph(alloc, &atlas, ft_font.glyphIndex('A').?, .{}); try testing.expectEqual(@as(u32, 21), g2.height); } @@ -639,7 +648,11 @@ test "color emoji" { var atlas = try font.Atlas.init(alloc, 512, .rgba); defer atlas.deinit(alloc); - var ft_font = try Face.init(lib, testFont, .{ .points = 12, .xdpi = 96, .ydpi = 96 }); + var ft_font = try Face.init( + lib, + testFont, + .{ .size = .{ .points = 12, .xdpi = 96, .ydpi = 96 } }, + ); defer ft_font.deinit(); try testing.expectEqual(Presentation.emoji, ft_font.presentation); @@ -665,7 +678,11 @@ test "metrics" { var atlas = try font.Atlas.init(alloc, 512, .greyscale); defer atlas.deinit(alloc); - var ft_font = try Face.init(lib, testFont, .{ .points = 12, .xdpi = 96, .ydpi = 96 }); + var ft_font = try Face.init( + lib, + testFont, + .{ .size = .{ .points = 12, .xdpi = 96, .ydpi = 96 } }, + ); defer ft_font.deinit(); try testing.expectEqual(font.face.Metrics{ @@ -679,7 +696,7 @@ test "metrics" { }, ft_font.metrics); // Resize should change metrics - try ft_font.setSize(.{ .points = 24, .xdpi = 96, .ydpi = 96 }); + try ft_font.setSize(.{ .size = .{ .points = 24, .xdpi = 96, .ydpi = 96 } }); try testing.expectEqual(font.face.Metrics{ .cell_width = 16, .cell_height = 35, @@ -701,7 +718,7 @@ test "mono to rgba" { var atlas = try font.Atlas.init(alloc, 512, .rgba); defer atlas.deinit(alloc); - var ft_font = try Face.init(lib, testFont, .{ .points = 12 }); + var ft_font = try Face.init(lib, testFont, .{ .size = .{ .points = 12 } }); defer ft_font.deinit(); // glyph 3 is mono in Noto