font: style edits for #2985

This commit is contained in:
Mitchell Hashimoto
2024-12-16 12:29:10 -08:00
parent a06388869d
commit 2b78ac4382
2 changed files with 57 additions and 66 deletions

View File

@ -568,14 +568,14 @@ pub const Face = struct {
}; };
// Read the 'OS/2' table out of the font data if it's available. // Read the 'OS/2' table out of the font data if it's available.
const maybe_os2: ?opentype.OS2 = os2: { const os2_: ?opentype.OS2 = os2: {
const tag = macos.text.FontTableTag.init("OS/2"); const tag = macos.text.FontTableTag.init("OS/2");
const data = ct_font.copyTable(tag) orelse break :os2 null; const data = ct_font.copyTable(tag) orelse break :os2 null;
defer data.release(); defer data.release();
const ptr = data.getPointer(); const ptr = data.getPointer();
const len = data.getLength(); const len = data.getLength();
break :os2 opentype.OS2.init(ptr[0..len]) catch |err| { break :os2 opentype.OS2.init(ptr[0..len]) catch |err| {
log.warn("Error parsing OS/2 table: {any}", .{err}); log.warn("error parsing OS/2 table: {}", .{err});
break :os2 null; break :os2 null;
}; };
}; };
@ -603,19 +603,17 @@ pub const Face = struct {
const hhea_descent: f64 = @floatFromInt(hhea.descender); const hhea_descent: f64 = @floatFromInt(hhea.descender);
const hhea_line_gap: f64 = @floatFromInt(hhea.lineGap); const hhea_line_gap: f64 = @floatFromInt(hhea.lineGap);
if (maybe_os2) |os2| { if (os2_) |os2| {
const os2_ascent: f64 = @floatFromInt(os2.sTypoAscender); const os2_ascent: f64 = @floatFromInt(os2.sTypoAscender);
const os2_descent: f64 = @floatFromInt(os2.sTypoDescender); const os2_descent: f64 = @floatFromInt(os2.sTypoDescender);
const os2_line_gap: f64 = @floatFromInt(os2.sTypoLineGap); const os2_line_gap: f64 = @floatFromInt(os2.sTypoLineGap);
// If the font says to use typo metrics, trust it. // If the font says to use typo metrics, trust it.
if (os2.fsSelection.use_typo_metrics) { if (os2.fsSelection.use_typo_metrics) break :vertical_metrics .{
break :vertical_metrics .{ os2_ascent * px_per_unit,
os2_ascent * px_per_unit, os2_descent * px_per_unit,
os2_descent * px_per_unit, os2_line_gap * px_per_unit,
os2_line_gap * px_per_unit, };
};
}
// Otherwise we prefer the height metrics from 'hhea' if they // Otherwise we prefer the height metrics from 'hhea' if they
// are available, or else OS/2 sTypo* metrics, and if all else // are available, or else OS/2 sTypo* metrics, and if all else
@ -625,21 +623,17 @@ pub const Face = struct {
// account for fonts being... just weird. It's pretty much what // account for fonts being... just weird. It's pretty much what
// FreeType does to get its generic ascent and descent metrics. // FreeType does to get its generic ascent and descent metrics.
if (hhea.ascender != 0 or hhea.descender != 0) { if (hhea.ascender != 0 or hhea.descender != 0) break :vertical_metrics .{
break :vertical_metrics .{ hhea_ascent * px_per_unit,
hhea_ascent * px_per_unit, hhea_descent * px_per_unit,
hhea_descent * px_per_unit, hhea_line_gap * px_per_unit,
hhea_line_gap * px_per_unit, };
};
}
if (os2_ascent != 0 or os2_descent != 0) { if (os2_ascent != 0 or os2_descent != 0) break :vertical_metrics .{
break :vertical_metrics .{ os2_ascent * px_per_unit,
os2_ascent * px_per_unit, os2_descent * px_per_unit,
os2_descent * px_per_unit, os2_line_gap * px_per_unit,
os2_line_gap * px_per_unit, };
};
}
const win_ascent: f64 = @floatFromInt(os2.usWinAscent); const win_ascent: f64 = @floatFromInt(os2.usWinAscent);
const win_descent: f64 = @floatFromInt(os2.usWinDescent); const win_descent: f64 = @floatFromInt(os2.usWinDescent);
@ -680,44 +674,42 @@ pub const Face = struct {
// Similar logic to the underline above. // Similar logic to the underline above.
const strikethrough_position, const strikethrough_thickness = st: { const strikethrough_position, const strikethrough_thickness = st: {
if (maybe_os2) |os2| { const os2 = os2_ orelse break :st .{ null, null };
const has_broken_strikethrough = os2.yStrikeoutSize == 0;
const pos: ?f64 = if (has_broken_strikethrough and os2.yStrikeoutPosition == 0) const has_broken_strikethrough = os2.yStrikeoutSize == 0;
null
else
@as(f64, @floatFromInt(os2.yStrikeoutPosition)) * px_per_unit;
const thick: ?f64 = if (has_broken_strikethrough) const pos: ?f64 = if (has_broken_strikethrough and os2.yStrikeoutPosition == 0)
null null
else else
@as(f64, @floatFromInt(os2.yStrikeoutSize)) * px_per_unit; @as(f64, @floatFromInt(os2.yStrikeoutPosition)) * px_per_unit;
break :st .{ pos, thick }; const thick: ?f64 = if (has_broken_strikethrough)
} null
else
@as(f64, @floatFromInt(os2.yStrikeoutSize)) * px_per_unit;
break :st .{ null, null }; break :st .{ pos, thick };
}; };
// We fall back to whatever CoreText does if the // We fall back to whatever CoreText does if the
// OS/2 table doesn't specify a cap or ex height. // OS/2 table doesn't specify a cap or ex height.
const cap_height: f64, const ex_height: f64 = heights: { const cap_height: f64, const ex_height: f64 = heights: {
if (maybe_os2) |os2| { const os2 = os2_ orelse break :heights .{
break :heights .{
if (os2.sCapHeight) |sCapHeight|
@as(f64, @floatFromInt(sCapHeight)) * px_per_unit
else
ct_font.getCapHeight(),
if (os2.sxHeight) |sxHeight|
@as(f64, @floatFromInt(sxHeight)) * px_per_unit
else
ct_font.getXHeight(),
};
}
break :heights .{
ct_font.getCapHeight(), ct_font.getCapHeight(),
ct_font.getXHeight(), ct_font.getXHeight(),
}; };
break :heights .{
if (os2.sCapHeight) |sCapHeight|
@as(f64, @floatFromInt(sCapHeight)) * px_per_unit
else
ct_font.getCapHeight(),
if (os2.sxHeight) |sxHeight|
@as(f64, @floatFromInt(sxHeight)) * px_per_unit
else
ct_font.getXHeight(),
};
}; };
// Cell width is calculated by calculating the widest width of the // Cell width is calculated by calculating the widest width of the

View File

@ -628,7 +628,7 @@ pub const Face = struct {
const post = face.getSfntTable(.post) orelse return error.CopyTableError; const post = face.getSfntTable(.post) orelse return error.CopyTableError;
// Read the 'OS/2' table out of the font data. // Read the 'OS/2' table out of the font data.
const maybe_os2: ?*freetype.c.TT_OS2 = os2: { const os2_: ?*freetype.c.TT_OS2 = os2: {
const os2 = face.getSfntTable(.os2) orelse break :os2 null; const os2 = face.getSfntTable(.os2) orelse break :os2 null;
if (os2.version == 0xFFFF) break :os2 null; if (os2.version == 0xFFFF) break :os2 null;
break :os2 os2; break :os2 os2;
@ -646,7 +646,7 @@ pub const Face = struct {
const hhea_descent: f64 = @floatFromInt(hhea.Descender); const hhea_descent: f64 = @floatFromInt(hhea.Descender);
const hhea_line_gap: f64 = @floatFromInt(hhea.Line_Gap); const hhea_line_gap: f64 = @floatFromInt(hhea.Line_Gap);
if (maybe_os2) |os2| { if (os2_) |os2| {
const os2_ascent: f64 = @floatFromInt(os2.sTypoAscender); const os2_ascent: f64 = @floatFromInt(os2.sTypoAscender);
const os2_descent: f64 = @floatFromInt(os2.sTypoDescender); const os2_descent: f64 = @floatFromInt(os2.sTypoDescender);
const os2_line_gap: f64 = @floatFromInt(os2.sTypoLineGap); const os2_line_gap: f64 = @floatFromInt(os2.sTypoLineGap);
@ -724,23 +724,21 @@ pub const Face = struct {
// Similar logic to the underline above. // Similar logic to the underline above.
const strikethrough_position, const strikethrough_thickness = st: { const strikethrough_position, const strikethrough_thickness = st: {
if (maybe_os2) |os2| { const os2 = os2_ orelse break :st .{ null, null };
const has_broken_strikethrough = os2.yStrikeoutSize == 0;
const pos: ?f64 = if (has_broken_strikethrough and os2.yStrikeoutPosition == 0) const has_broken_strikethrough = os2.yStrikeoutSize == 0;
null
else
@as(f64, @floatFromInt(os2.yStrikeoutPosition)) * px_per_unit;
const thick: ?f64 = if (has_broken_strikethrough) const pos: ?f64 = if (has_broken_strikethrough and os2.yStrikeoutPosition == 0)
null null
else else
@as(f64, @floatFromInt(os2.yStrikeoutSize)) * px_per_unit; @as(f64, @floatFromInt(os2.yStrikeoutPosition)) * px_per_unit;
break :st .{ pos, thick }; const thick: ?f64 = if (has_broken_strikethrough)
} null
else
@as(f64, @floatFromInt(os2.yStrikeoutSize)) * px_per_unit;
break :st .{ null, null }; break :st .{ pos, thick };
}; };
// Cell width is calculated by calculating the widest width of the // Cell width is calculated by calculating the widest width of the
@ -774,7 +772,7 @@ pub const Face = struct {
// We use the cap and ex heights specified by the font if they're // We use the cap and ex heights specified by the font if they're
// available, otherwise we try to measure the `H` and `x` glyphs. // available, otherwise we try to measure the `H` and `x` glyphs.
const cap_height: ?f64, const ex_height: ?f64 = heights: { const cap_height: ?f64, const ex_height: ?f64 = heights: {
if (maybe_os2) |os2| { if (os2_) |os2| {
// The OS/2 table does not include these metrics in version 1. // The OS/2 table does not include these metrics in version 1.
if (os2.version >= 2) { if (os2.version >= 2) {
break :heights .{ break :heights .{
@ -783,6 +781,7 @@ pub const Face = struct {
}; };
} }
} }
break :heights .{ break :heights .{
cap: { cap: {
if (face.getCharIndex('H')) |glyph_index| { if (face.getCharIndex('H')) |glyph_index| {