fix(font): detect and reject improper advance for icwidth (#8491)
Fixes #8481 Explained in code comments, basically the NF patcher can produce fonts that have CJK characters with 1-cell advances, which screws up fallback font scaling; fixed by not counting the ic width metric if the width of the glyph is greater than the advance width. > [!NOTE] > As follow-on work to this it may be worth setting limits for scaling, so you can't have one font scaled like twice as large as the primary font, since that's almost always going to indicate something is very wrong.pull/8462/head
commit
16e47e7586
|
|
@ -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 "<Error getting font name>";
|
||||
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 .{
|
||||
|
|
|
|||
|
|
@ -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 "<Error getting font name>";
|
||||
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 .{
|
||||
|
|
|
|||
Loading…
Reference in New Issue