diff --git a/src/font/face/coretext.zig b/src/font/face/coretext.zig index cb6e6b1f7..a85c94430 100644 --- a/src/font/face/coretext.zig +++ b/src/font/face/coretext.zig @@ -806,14 +806,41 @@ pub const Face = struct { const ic_width: ?f64 = ic_width: { const glyph = self.glyphIndex('水') orelse break :ic_width null; - var advances: [1]macos.graphics.Size = undefined; - _ = ct_font.getAdvancesForGlyphs( + const advance = ct_font.getAdvancesForGlyphs( .horizontal, &.{@intCast(glyph)}, - &advances, + null, ); - break :ic_width advances[0].width; + const bounds = ct_font.getBoundingRectsForGlyphs( + .horizontal, + &.{@intCast(glyph)}, + null, + ); + + // If the advance of the glyph is less than the width of the actual + // glyph then we just treat it as invalid since it's probably wrong + // and using it for size normalization will instead make the font + // way too big. + // + // This can sometimes happen if there's a CJK font that has been + // patched with the nerd fonts patcher and it butchers the advance + // values so the advance ends up half the width of the actual glyph. + if (bounds.size.width > advance) { + var buf: [1024]u8 = undefined; + const font_name = self.name(&buf) catch ""; + log.warn( + "(getMetrics) Width of glyph '水' for font \"{s}\" is greater than its advance ({d} > {d}), discarding ic_width metric.", + .{ + font_name, + bounds.size.width, + advance, + }, + ); + break :ic_width null; + } + + break :ic_width advance; }; return .{ diff --git a/src/font/face/freetype.zig b/src/font/face/freetype.zig index 6c888672b..1d8d2efff 100644 --- a/src/font/face/freetype.zig +++ b/src/font/face/freetype.zig @@ -1007,7 +1007,31 @@ pub const Face = struct { .no_svg = true, }) catch break :ic_width null; - break :ic_width f26dot6ToF64(face.handle.*.glyph.*.advance.x); + const ft_glyph = face.handle.*.glyph; + + // If the advance of the glyph is less than the width of the actual + // glyph then we just treat it as invalid since it's probably wrong + // and using it for size normalization will instead make the font + // way too big. + // + // This can sometimes happen if there's a CJK font that has been + // patched with the nerd fonts patcher and it butchers the advance + // values so the advance ends up half the width of the actual glyph. + if (ft_glyph.*.metrics.width > ft_glyph.*.advance.x) { + var buf: [1024]u8 = undefined; + const font_name = self.name(&buf) catch ""; + log.warn( + "(getMetrics) Width of glyph '水' for font \"{s}\" is greater than its advance ({d} > {d}), discarding ic_width metric.", + .{ + font_name, + f26dot6ToF64(ft_glyph.*.metrics.width), + f26dot6ToF64(ft_glyph.*.advance.x), + }, + ); + break :ic_width null; + } + + break :ic_width f26dot6ToF64(ft_glyph.*.advance.x); }; return .{