Align stretched glyphs to cell, not face

pull/8990/head
Daniel Wennberg 2025-09-30 21:15:13 -07:00 committed by Mitchell Hashimoto
parent 32f8c71be3
commit 50bdd3bac6
3 changed files with 52 additions and 17 deletions

View File

@ -244,6 +244,39 @@ pub const RenderOptions = struct {
) GlyphSize {
if (!self.doesAnything()) return glyph;
switch (self.size) {
.stretch => {
// Stretched glyphs are usually meant to align across cell
// boundaries, which works best if they're scaled and
// aligned to the grid rather than the face. This is most
// easily done by inserting this little fib in the metrics.
var m = metrics;
m.face_width = @floatFromInt(m.cell_width);
m.face_height = @floatFromInt(m.cell_height);
m.face_y = 0.0;
// Negative padding for stretched glyphs is a band-aid to
// avoid gaps due to pixel rounding, but at the cost of
// unsightly overlap artifacts. Since we scale and align to
// the grid rather than the face, we don't need it.
var c = self;
c.pad_bottom = @max(0, c.pad_bottom);
c.pad_top = @max(0, c.pad_top);
c.pad_left = @max(0, c.pad_left);
c.pad_right = @max(0, c.pad_right);
return c.constrainInner(glyph, m, constraint_width);
},
else => return self.constrainInner(glyph, metrics, constraint_width),
}
}
fn constrainInner(
self: Constraint,
glyph: GlyphSize,
metrics: Metrics,
constraint_width: u2,
) GlyphSize {
// For extra wide font faces, never stretch glyphs across two cells.
// This mirrors font_patcher.
const min_constraint_width: u2 = if ((self.size == .stretch) and (metrics.face_width > 0.9 * metrics.face_height))

View File

@ -338,14 +338,7 @@ pub const Face = struct {
const cell_height: f64 = @floatFromInt(metrics.cell_height);
// Next we apply any constraints to get the final size of the glyph.
var constraint = opts.constraint;
// We eliminate any negative vertical padding since these overlap
// values aren't needed with how precisely we apply constraints,
// and they can lead to extra height that looks bad for things like
// powerline glyphs.
constraint.pad_top = @max(0.0, constraint.pad_top);
constraint.pad_bottom = @max(0.0, constraint.pad_bottom);
const constraint = opts.constraint;
// We need to add the baseline position before passing to the constrain
// function since it operates on cell-relative positions, not baseline.
@ -385,6 +378,18 @@ pub const Face = struct {
y = @round(y);
}
// We center all glyphs within the pixel-rounded and adjusted
// cell width if it's larger than the face width, so that they
// aren't weirdly off to the left.
//
// We don't do this if the glyph has a stretch constraint,
// since in that case the position was already calculated with the
// new cell width in mind.
if ((constraint.size != .stretch) and (metrics.face_width < cell_width)) {
// We add half the difference to re-center.
x += (cell_width - metrics.face_width) / 2;
}
// We make an assumption that font smoothing ("thicken")
// adds no more than 1 extra pixel to any edge. We don't
// add extra size if it's a sbix color font though, since

View File

@ -463,14 +463,7 @@ pub const Face = struct {
const cell_height: f64 = @floatFromInt(metrics.cell_height);
// Next we apply any constraints to get the final size of the glyph.
var constraint = opts.constraint;
// We eliminate any negative vertical padding since these overlap
// values aren't needed with how precisely we apply constraints,
// and they can lead to extra height that looks bad for things like
// powerline glyphs.
constraint.pad_top = @max(0.0, constraint.pad_top);
constraint.pad_bottom = @max(0.0, constraint.pad_bottom);
const constraint = opts.constraint;
// We need to add the baseline position before passing to the constrain
// function since it operates on cell-relative positions, not baseline.
@ -495,7 +488,11 @@ pub const Face = struct {
// We center all glyphs within the pixel-rounded and adjusted
// cell width if it's larger than the face width, so that they
// aren't weirdly off to the left.
if (metrics.face_width < cell_width) {
//
// We don't do this if the glyph has a stretch constraint,
// since in that case the position was already calculated with the
// new cell width in mind.
if ((constraint.size != .stretch) and (metrics.face_width < cell_width)) {
// We add half the difference to re-center.
//
// NOTE: We round this to a whole-pixel amount because under