mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
move cell metrics calculation out into src/font
This commit is contained in:
56
src/Grid.zig
56
src/Grid.zig
@ -166,56 +166,12 @@ pub fn init(
|
||||
|
||||
break :group group;
|
||||
});
|
||||
errdefer font_group.deinit(alloc);
|
||||
|
||||
// Load all visible ASCII characters and build our cell width based on
|
||||
// the widest character that we see.
|
||||
const cell_width: f32 = cell_width: {
|
||||
var cell_width: f32 = 0;
|
||||
var i: u32 = 32;
|
||||
while (i <= 126) : (i += 1) {
|
||||
const index = (try font_group.indexForCodepoint(alloc, .regular, i)).?;
|
||||
const face = font_group.group.faceFromIndex(index);
|
||||
const glyph_index = face.glyphIndex(i).?;
|
||||
const glyph = try font_group.renderGlyph(alloc, index, glyph_index);
|
||||
if (glyph.advance_x > cell_width) {
|
||||
cell_width = @ceil(glyph.advance_x);
|
||||
}
|
||||
}
|
||||
|
||||
break :cell_width cell_width;
|
||||
};
|
||||
|
||||
// The cell height is the vertical height required to render underscore
|
||||
// '_' which should live at the bottom of a cell.
|
||||
const cell_height: f32 = cell_height: {
|
||||
// Get the '_' char for height
|
||||
const index = (try font_group.indexForCodepoint(alloc, .regular, '_')).?;
|
||||
const face = font_group.group.faceFromIndex(index);
|
||||
const glyph_index = face.glyphIndex('_').?;
|
||||
const glyph = try font_group.renderGlyph(alloc, index, glyph_index);
|
||||
|
||||
// This is the height reported by the font face
|
||||
const face_height: i32 = face.unitsToPxY(face.face.handle.*.height);
|
||||
|
||||
// Determine the height of the underscore char
|
||||
var res: i32 = face.unitsToPxY(face.face.handle.*.ascender);
|
||||
res -= glyph.offset_y;
|
||||
res += @intCast(i32, glyph.height);
|
||||
|
||||
// We take whatever is larger to account for some fonts that
|
||||
// put the underscore outside f the rectangle.
|
||||
if (res < face_height) res = face_height;
|
||||
|
||||
break :cell_height @intToFloat(f32, res);
|
||||
};
|
||||
const cell_baseline = cell_baseline: {
|
||||
const face = font_group.group.faces.get(.regular).items[0];
|
||||
break :cell_baseline cell_height - @intToFloat(
|
||||
f32,
|
||||
face.unitsToPxY(face.face.handle.*.ascender),
|
||||
);
|
||||
};
|
||||
log.debug("cell dimensions w={d} h={d} baseline={d}", .{ cell_width, cell_height, cell_baseline });
|
||||
const metrics = try font_group.metrics(alloc);
|
||||
log.debug("cell dimensions={}", .{metrics});
|
||||
|
||||
// Create our shader
|
||||
const program = try gl.Program.createVF(
|
||||
@ -226,8 +182,8 @@ pub fn init(
|
||||
// Set our cell dimensions
|
||||
const pbind = try program.use();
|
||||
defer pbind.unbind();
|
||||
try program.setUniform("cell_size", @Vector(2, f32){ cell_width, cell_height });
|
||||
try program.setUniform("glyph_baseline", cell_baseline);
|
||||
try program.setUniform("cell_size", @Vector(2, f32){ metrics.cell_width, metrics.cell_height });
|
||||
try program.setUniform("glyph_baseline", metrics.cell_baseline);
|
||||
|
||||
// Set all of our texture indexes
|
||||
try program.setUniform("text", 0);
|
||||
@ -328,7 +284,7 @@ pub fn init(
|
||||
return Grid{
|
||||
.alloc = alloc,
|
||||
.cells = .{},
|
||||
.cell_size = .{ .width = cell_width, .height = cell_height },
|
||||
.cell_size = .{ .width = metrics.cell_width, .height = metrics.cell_height },
|
||||
.size = .{ .rows = 0, .columns = 0 },
|
||||
.program = program,
|
||||
.vao = vao,
|
||||
|
@ -11,6 +11,7 @@ const Library = @import("main.zig").Library;
|
||||
const Glyph = @import("main.zig").Glyph;
|
||||
const Style = @import("main.zig").Style;
|
||||
const Group = @import("main.zig").Group;
|
||||
const Metrics = @import("main.zig").Metrics;
|
||||
|
||||
const log = std.log.scoped(.font_groupcache);
|
||||
|
||||
@ -80,6 +81,66 @@ pub fn reset(self: *GroupCache) void {
|
||||
self.glyphs.clearRetainingCapacity();
|
||||
}
|
||||
|
||||
/// Calculate the metrics for this group. This also warms the cache
|
||||
/// since this preloads all the ASCII characters.
|
||||
pub fn metrics(self: *GroupCache, alloc: Allocator) !Metrics {
|
||||
// Load all visible ASCII characters and build our cell width based on
|
||||
// the widest character that we see.
|
||||
const cell_width: f32 = cell_width: {
|
||||
var cell_width: f32 = 0;
|
||||
var i: u32 = 32;
|
||||
while (i <= 126) : (i += 1) {
|
||||
const index = (try self.indexForCodepoint(alloc, .regular, i)).?;
|
||||
const face = self.group.faceFromIndex(index);
|
||||
const glyph_index = face.glyphIndex(i).?;
|
||||
const glyph = try self.renderGlyph(alloc, index, glyph_index);
|
||||
if (glyph.advance_x > cell_width) {
|
||||
cell_width = @ceil(glyph.advance_x);
|
||||
}
|
||||
}
|
||||
|
||||
break :cell_width cell_width;
|
||||
};
|
||||
|
||||
// The cell height is the vertical height required to render underscore
|
||||
// '_' which should live at the bottom of a cell.
|
||||
const cell_height: f32 = cell_height: {
|
||||
// Get the '_' char for height
|
||||
const index = (try self.indexForCodepoint(alloc, .regular, '_')).?;
|
||||
const face = self.group.faceFromIndex(index);
|
||||
const glyph_index = face.glyphIndex('_').?;
|
||||
const glyph = try self.renderGlyph(alloc, index, glyph_index);
|
||||
|
||||
// This is the height reported by the font face
|
||||
const face_height: i32 = face.unitsToPxY(face.face.handle.*.height);
|
||||
|
||||
// Determine the height of the underscore char
|
||||
var res: i32 = face.unitsToPxY(face.face.handle.*.ascender);
|
||||
res -= glyph.offset_y;
|
||||
res += @intCast(i32, glyph.height);
|
||||
|
||||
// We take whatever is larger to account for some fonts that
|
||||
// put the underscore outside f the rectangle.
|
||||
if (res < face_height) res = face_height;
|
||||
|
||||
break :cell_height @intToFloat(f32, res);
|
||||
};
|
||||
|
||||
const cell_baseline = cell_baseline: {
|
||||
const face = self.group.faces.get(.regular).items[0];
|
||||
break :cell_baseline cell_height - @intToFloat(
|
||||
f32,
|
||||
face.unitsToPxY(face.face.handle.*.ascender),
|
||||
);
|
||||
};
|
||||
|
||||
return Metrics{
|
||||
.cell_width = cell_width,
|
||||
.cell_height = cell_height,
|
||||
.cell_baseline = cell_baseline,
|
||||
};
|
||||
}
|
||||
|
||||
/// Get the font index for a given codepoint. This is cached.
|
||||
pub fn indexForCodepoint(self: *GroupCache, alloc: Allocator, style: Style, cp: u32) !?Group.FontIndex {
|
||||
const key: CodepointKey = .{ .style = style, .codepoint = cp };
|
||||
|
@ -14,16 +14,15 @@ pub const Style = enum(u2) {
|
||||
bold_italic = 3,
|
||||
};
|
||||
|
||||
/// Returns the UTF-32 codepoint for the given value.
|
||||
pub fn codepoint(v: anytype) u32 {
|
||||
// We need a UTF32 codepoint for freetype
|
||||
return switch (@TypeOf(v)) {
|
||||
u32 => v,
|
||||
comptime_int, u8 => @intCast(u32, v),
|
||||
[]const u8 => @intCast(u32, try std.unicode.utfDecode(v)),
|
||||
else => @compileError("invalid codepoint type"),
|
||||
/// Font metrics useful for things such as grid calculation.
|
||||
pub const Metrics = struct {
|
||||
/// The width and height of a monospace cell.
|
||||
cell_width: f32,
|
||||
cell_height: f32,
|
||||
|
||||
/// The baseline offset that can be used to place underlines.
|
||||
cell_baseline: f32,
|
||||
};
|
||||
}
|
||||
|
||||
test {
|
||||
@import("std").testing.refAllDecls(@This());
|
||||
|
Reference in New Issue
Block a user