From 2563a195a15ec61fa50b797fd054f64c47b60515 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 4 Oct 2023 21:42:03 -0700 Subject: [PATCH] font: wire up all the metric modifiers --- src/Surface.zig | 5 ++++- src/font/DeferredFace.zig | 27 +++++++++++++-------------- src/font/Group.zig | 12 ++++++------ src/font/face/coretext.zig | 15 ++++++++++----- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index 1d60177c7..5d1a190fa 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -228,7 +228,10 @@ pub fn init( group.metric_modifiers = set: { var set: font.face.Metrics.ModifierSet = .{}; errdefer set.deinit(alloc); - break :set null; + if (config.@"adjust-cell-width") |m| try set.put(alloc, .cell_width, m); + if (config.@"adjust-cell-height") |m| try set.put(alloc, .cell_height, m); + if (config.@"adjust-font-baseline") |m| try set.put(alloc, .cell_baseline, m); + break :set set; }; // If we have codepoint mappings, set those. diff --git a/src/font/DeferredFace.zig b/src/font/DeferredFace.zig index 243537002..6456f8d23 100644 --- a/src/font/DeferredFace.zig +++ b/src/font/DeferredFace.zig @@ -154,13 +154,13 @@ pub fn name(self: DeferredFace, buf: []u8) ![]const u8 { pub fn load( self: *DeferredFace, lib: Library, - size: font.face.DesiredSize, + opts: font.face.Options, ) !Face { return switch (options.backend) { - .fontconfig_freetype => try self.loadFontconfig(lib, size), - .coretext => try self.loadCoreText(lib, size), - .coretext_freetype => try self.loadCoreTextFreetype(lib, size), - .web_canvas => try self.loadWebCanvas(size), + .fontconfig_freetype => try self.loadFontconfig(lib, opts), + .coretext => try self.loadCoreText(lib, opts), + .coretext_freetype => try self.loadCoreTextFreetype(lib, opts), + .web_canvas => try self.loadWebCanvas(opts), // Unreachable because we must be already loaded or have the // proper configuration for one of the other deferred mechanisms. @@ -171,7 +171,7 @@ pub fn load( fn loadFontconfig( self: *DeferredFace, lib: Library, - size: font.face.DesiredSize, + opts: font.face.Options, ) !Face { const fc = self.fc.?; @@ -179,7 +179,7 @@ fn loadFontconfig( const filename = (try fc.pattern.get(.file, 0)).string; const face_index = (try fc.pattern.get(.index, 0)).integer; - var face = try Face.initFile(lib, filename, face_index, size); + var face = try Face.initFile(lib, filename, face_index, opts); errdefer face.deinit(); try face.setVariations(fc.variations); return face; @@ -188,18 +188,17 @@ fn loadFontconfig( fn loadCoreText( self: *DeferredFace, lib: Library, - size: font.face.DesiredSize, + opts: font.face.Options, ) !Face { _ = lib; const ct = self.ct.?; - // TODO: make options - return try Face.initFontCopy(ct.font, .{ .size = size }); + return try Face.initFontCopy(ct.font, opts); } fn loadCoreTextFreetype( self: *DeferredFace, lib: Library, - size: font.face.DesiredSize, + opts: font.face.Options, ) !Face { const ct = self.ct.?; @@ -232,15 +231,15 @@ fn loadCoreTextFreetype( // TODO: face index 0 is not correct long term and we should switch // to using CoreText for rendering, too. //std.log.warn("path={s}", .{path_slice}); - return try Face.initFile(lib, buf[0..path_slice.len :0], 0, size); + return try Face.initFile(lib, buf[0..path_slice.len :0], 0, opts); } fn loadWebCanvas( self: *DeferredFace, - size: font.face.DesiredSize, + opts: font.face.Options, ) !Face { const wc = self.wc.?; - return try Face.initNamed(wc.alloc, wc.font_str, size, wc.presentation); + return try Face.initNamed(wc.alloc, wc.font_str, opts, wc.presentation); } /// Returns true if this face can satisfy the given codepoint and diff --git a/src/font/Group.zig b/src/font/Group.zig index f257185d5..67503abf3 100644 --- a/src/font/Group.zig +++ b/src/font/Group.zig @@ -200,7 +200,7 @@ pub fn italicize(self: *Group) !void { }; // Try to italicize it. - const face = try regular.italicize(); + const face = try regular.italicize(self.faceOptions()); try italic_list.append(self.alloc, .{ .loaded = face }); var buf: [128]u8 = undefined; @@ -215,17 +215,17 @@ pub fn setSize(self: *Group, size: font.face.DesiredSize) !void { // currently handle it in any meaningful way if one face can resize // but another can't. + // Set our size for future loads + self.size = size; + // Resize all our faces that are loaded var it = self.faces.iterator(); while (it.next()) |entry| { for (entry.value.items) |*elem| switch (elem.*) { .deferred => continue, - .loaded => |*f| try f.setSize(.{ .size = size }), + .loaded => |*f| try f.setSize(self.faceOptions()), }; } - - // Set our size for future loads - self.size = size; } /// This represents a specific font in the group. @@ -471,7 +471,7 @@ pub fn faceFromIndex(self: *Group, index: FontIndex) !*Face { const item = &list.items[index.idx]; return switch (item.*) { .deferred => |*d| deferred: { - const face = try d.load(self.lib, self.size); + const face = try d.load(self.lib, self.faceOptions()); d.deinit(); item.* = .{ .loaded = face }; break :deferred &item.loaded; diff --git a/src/font/face/coretext.zig b/src/font/face/coretext.zig index fbfda7d90..803cb46b1 100644 --- a/src/font/face/coretext.zig +++ b/src/font/face/coretext.zig @@ -69,22 +69,27 @@ pub const Face = struct { ); errdefer ct_font.release(); - return try initFont(ct_font); + return try initFont(ct_font, opts); } /// Initialize a face with a CTFont. This will take ownership over /// the CTFont. This does NOT copy or retain the CTFont. - pub fn initFont(ct_font: *macos.text.Font) !Face { + pub fn initFont(ct_font: *macos.text.Font, opts: font.face.Options) !Face { var hb_font = try harfbuzz.coretext.createFont(ct_font); errdefer hb_font.destroy(); const traits = ct_font.getSymbolicTraits(); + const metrics = metrics: { + var metrics = try calcMetrics(ct_font); + if (opts.metric_modifiers) |v| metrics.apply(v.*); + break :metrics metrics; + }; var result: Face = .{ .font = ct_font, .hb_font = hb_font, .presentation = if (traits.color_glyphs) .emoji else .text, - .metrics = try calcMetrics(ct_font), + .metrics = metrics, }; result.quirks_disable_default_font_features = quirks.disableDefaultFontFeatures(&result); @@ -144,10 +149,10 @@ pub const Face = struct { /// Return a new face that is the same as this but has a transformation /// matrix applied to italicize it. - pub fn italicize(self: *const Face) !Face { + pub fn italicize(self: *const Face, opts: font.face.Options) !Face { const ct_font = try self.font.copyWithAttributes(0.0, &italic_skew, null); errdefer ct_font.release(); - return try initFont(ct_font); + return try initFont(ct_font, opts); } /// Returns the font name. If allocation is required, buf will be used,