font: further improve ul/st position calculations

This commit is contained in:
Qwerasd
2024-09-23 22:10:43 -06:00
parent 49a3008919
commit 7a1d304fa9
2 changed files with 30 additions and 28 deletions

View File

@ -594,7 +594,10 @@ pub const Face = struct {
// All of these metrics are based on our layout above.
const cell_height = @ceil(layout_metrics.height);
const cell_baseline = @ceil(layout_metrics.height - layout_metrics.ascent);
const underline_thickness = @ceil(@as(f32, @floatCast(ct_font.getUnderlineThickness())));
const strikethrough_thickness = underline_thickness;
const strikethrough_position = strikethrough_position: {
// This is the height of lower case letters in our font.
const ex_height = ct_font.getXHeight();
@ -608,20 +611,21 @@ pub const Face = struct {
// is the distance from the top down to the baseline, then
// we subtract half of the ex height to go back up to the
// correct height that should evenly split lowercase text.
const pos = layout_metrics.ascent - ex_height * 0.5 + 1;
const pos = layout_metrics.ascent -
ex_height * 0.5 +
strikethrough_thickness * 0.5 +
1;
break :strikethrough_position @ceil(pos);
};
const strikethrough_thickness = underline_thickness;
// Underline position reported is usually something like "-1" to
// represent the amount under the baseline. We add this to our real
// baseline to get the actual value from the bottom (+y is up).
// The final underline position is +y from the TOP (confusing)
// so we have to subtract from the cell height.
const underline_position = cell_height -
(cell_baseline + @ceil(@as(f32, @floatCast(ct_font.getUnderlinePosition())))) +
1;
const underline_position = @ceil(layout_metrics.ascent -
@as(f32, @floatCast(ct_font.getUnderlinePosition())) + 1);
// Note: is this useful?
// const units_per_em = ct_font.getUnitsPerEm();

View File

@ -660,52 +660,50 @@ pub const Face = struct {
// is reversed.
const cell_baseline = -1 * f26dot6ToFloat(size_metrics.descender);
const underline_thickness = @max(@as(f32, 1), fontUnitsToPxY(
face,
face.handle.*.underline_thickness,
));
// The underline position. This is a value from the top where the
// underline should go.
const underline_position: f32 = underline_pos: {
// The ascender is already scaled for scalable fonts, but the
// underline position is not.
const ascender_px = @as(i32, @intCast(size_metrics.ascender)) >> 6;
const declared_px = freetype.mulFix(
const declared_px = @as(f32, @floatFromInt(freetype.mulFix(
face.handle.*.underline_position,
@intCast(face.handle.*.size.*.metrics.y_scale),
) >> 6;
))) / 64;
// We use the declared underline position if its available
const declared = ascender_px - declared_px;
const declared = cell_height - cell_baseline - declared_px;
if (declared > 0)
break :underline_pos @floatFromInt(declared);
break :underline_pos declared;
// If we have no declared underline position, we go slightly under the
// cell height (mainly: non-scalable fonts, i.e. emoji)
break :underline_pos cell_height - 1;
};
const underline_thickness = @max(@as(f32, 1), fontUnitsToPxY(
face,
face.handle.*.underline_thickness,
));
// The strikethrough position. We use the position provided by the
// font if it exists otherwise we calculate a best guess.
const strikethrough: struct {
pos: f32,
thickness: f32,
} = if (face.getSfntTable(.os2)) |os2| .{
.pos = pos: {
// Ascender is scaled, strikeout pos is not
const ascender_px = @as(i32, @intCast(size_metrics.ascender)) >> 6;
const declared_px = freetype.mulFix(
os2.yStrikeoutPosition,
@as(i32, @intCast(face.handle.*.size.*.metrics.y_scale)),
) >> 6;
} = if (face.getSfntTable(.os2)) |os2| st: {
const thickness = @max(@as(f32, 1), fontUnitsToPxY(face, os2.yStrikeoutSize));
break :pos @floatFromInt(ascender_px - declared_px);
},
.thickness = @max(@as(f32, 1), fontUnitsToPxY(face, os2.yStrikeoutSize)),
const pos = @as(f32, @floatFromInt(freetype.mulFix(
os2.yStrikeoutPosition,
@as(i32, @intCast(face.handle.*.size.*.metrics.y_scale)),
))) / 64;
break :st .{
.pos = @ceil(cell_height - cell_baseline - pos + thickness + 1),
.thickness = thickness,
};
} else .{
// Exactly 50% of the ex height so that our strikethrough is
// centered through lowercase text. This is a common choice.
.pos = cell_baseline - ex_height * 0.5 + 1,
.pos = @ceil(cell_height - cell_baseline - ex_height * 0.5 + underline_thickness),
.thickness = underline_thickness,
};