gfx: font: account for glyph bearings

Helps hexops/mach#877

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
Stephen Gutekanst 2023-10-05 18:20:00 -07:00
parent dfbf3e3603
commit 34259ed1b8
2 changed files with 21 additions and 13 deletions

View file

@ -36,16 +36,18 @@ pub fn shape(f: *const Font, r: *TextRun) anyerror!void {
// Guess text segment properties.
r.buffer.guessSegmentProps();
// TODO: Optionally override specific text segment properties?
// buffer.setDirection(.ltr);
// buffer.setScript(.latin);
// buffer.setLanguage(harfbuzz.Language.fromString("en"));
// r.buffer.setDirection(.ltr);
// r.buffer.setScript(.latin);
// r.buffer.setLanguage(harfbuzz.Language.fromString("en"));
const font_size_pt = r.font_size_px / px_per_pt;
const font_size_pt_frac: i32 = @intFromFloat(font_size_pt * 64.0);
f.face.setCharSize(font_size_pt_frac, font_size_pt_frac, 0, 0) catch return error.RenderError;
const hb_face = harfbuzz.Face.fromFreetypeFace(f.face);
const hb_font = harfbuzz.Font.init(hb_face);
defer hb_font.deinit();
const font_size_pt = r.font_size_px / px_per_pt;
const font_size_pt_frac: i32 = @intFromFloat(font_size_pt * 256.0);
hb_font.setScale(font_size_pt_frac, font_size_pt_frac);
hb_font.setPTEM(font_size_pt);
@ -55,14 +57,20 @@ pub fn shape(f: *const Font, r: *TextRun) anyerror!void {
r.index = 0;
r.infos = r.buffer.getGlyphInfos();
r.positions = r.buffer.getGlyphPositions() orelse return error.OutOfMemory;
for (r.positions, r.infos) |*pos, info| {
const glyph_index = info.codepoint;
f.face.loadGlyph(glyph_index, .{ .render = false }) catch return error.RenderError;
const glyph = f.face.glyph();
const metrics = glyph.metrics();
pos.*.x_offset += @intCast(metrics.horiBearingX);
pos.*.y_offset += @intCast(metrics.horiBearingY);
// TODO: use vertBearingX / vertBearingY for vertical layouts
}
}
pub fn render(f: *Font, allocator: std.mem.Allocator, glyph_index: u32, opt: RenderOptions) anyerror!RenderedGlyph {
// TODO: DPI configuration
const dpi = 72;
const font_size_pt = opt.font_size_px / px_per_pt;
const font_size_pt_frac: i32 = @intFromFloat(font_size_pt * 64.0);
f.face.setCharSize(font_size_pt_frac, font_size_pt_frac, dpi, dpi) catch return error.RenderError;
_ = opt;
f.face.loadGlyph(glyph_index, .{ .render = true }) catch return error.RenderError;
const glyph = f.face.glyph();

View file

@ -14,7 +14,7 @@ px_density: u8 = 1,
buffer: harfbuzz.Buffer,
index: usize = 0,
infos: []harfbuzz.GlyphInfo = undefined,
positions: []harfbuzz.Position = undefined,
positions: []harfbuzz.GlyphPosition = undefined,
pub fn init() anyerror!TextRun {
return TextRun{
@ -37,8 +37,8 @@ pub fn next(s: *TextRun) ?Glyph {
// .var1 = @intCast(info.var1),
// .var2 = @intCast(info.var2),
.cluster = info.cluster,
.advance = vec2(@floatFromInt(pos.x_advance), @floatFromInt(pos.y_advance)).div(&Vec2.splat(256.0)),
.offset = vec2(@floatFromInt(pos.x_offset), @floatFromInt(pos.y_offset)).div(&Vec2.splat(256.0)),
.advance = vec2(@floatFromInt(pos.x_advance), @floatFromInt(pos.y_advance)).div(&Vec2.splat(64.0)),
.offset = vec2(@floatFromInt(pos.x_offset), @floatFromInt(pos.y_offset)).div(&Vec2.splat(64.0)),
};
}