mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 00:06:09 +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;
|
break :group group;
|
||||||
});
|
});
|
||||||
|
errdefer font_group.deinit(alloc);
|
||||||
|
|
||||||
// Load all visible ASCII characters and build our cell width based on
|
// Load all visible ASCII characters and build our cell width based on
|
||||||
// the widest character that we see.
|
// the widest character that we see.
|
||||||
const cell_width: f32 = cell_width: {
|
const metrics = try font_group.metrics(alloc);
|
||||||
var cell_width: f32 = 0;
|
log.debug("cell dimensions={}", .{metrics});
|
||||||
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 });
|
|
||||||
|
|
||||||
// Create our shader
|
// Create our shader
|
||||||
const program = try gl.Program.createVF(
|
const program = try gl.Program.createVF(
|
||||||
@ -226,8 +182,8 @@ pub fn init(
|
|||||||
// Set our cell dimensions
|
// Set our cell dimensions
|
||||||
const pbind = try program.use();
|
const pbind = try program.use();
|
||||||
defer pbind.unbind();
|
defer pbind.unbind();
|
||||||
try program.setUniform("cell_size", @Vector(2, f32){ cell_width, cell_height });
|
try program.setUniform("cell_size", @Vector(2, f32){ metrics.cell_width, metrics.cell_height });
|
||||||
try program.setUniform("glyph_baseline", cell_baseline);
|
try program.setUniform("glyph_baseline", metrics.cell_baseline);
|
||||||
|
|
||||||
// Set all of our texture indexes
|
// Set all of our texture indexes
|
||||||
try program.setUniform("text", 0);
|
try program.setUniform("text", 0);
|
||||||
@ -328,7 +284,7 @@ pub fn init(
|
|||||||
return Grid{
|
return Grid{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.cells = .{},
|
.cells = .{},
|
||||||
.cell_size = .{ .width = cell_width, .height = cell_height },
|
.cell_size = .{ .width = metrics.cell_width, .height = metrics.cell_height },
|
||||||
.size = .{ .rows = 0, .columns = 0 },
|
.size = .{ .rows = 0, .columns = 0 },
|
||||||
.program = program,
|
.program = program,
|
||||||
.vao = vao,
|
.vao = vao,
|
||||||
|
@ -11,6 +11,7 @@ const Library = @import("main.zig").Library;
|
|||||||
const Glyph = @import("main.zig").Glyph;
|
const Glyph = @import("main.zig").Glyph;
|
||||||
const Style = @import("main.zig").Style;
|
const Style = @import("main.zig").Style;
|
||||||
const Group = @import("main.zig").Group;
|
const Group = @import("main.zig").Group;
|
||||||
|
const Metrics = @import("main.zig").Metrics;
|
||||||
|
|
||||||
const log = std.log.scoped(.font_groupcache);
|
const log = std.log.scoped(.font_groupcache);
|
||||||
|
|
||||||
@ -80,6 +81,66 @@ pub fn reset(self: *GroupCache) void {
|
|||||||
self.glyphs.clearRetainingCapacity();
|
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.
|
/// Get the font index for a given codepoint. This is cached.
|
||||||
pub fn indexForCodepoint(self: *GroupCache, alloc: Allocator, style: Style, cp: u32) !?Group.FontIndex {
|
pub fn indexForCodepoint(self: *GroupCache, alloc: Allocator, style: Style, cp: u32) !?Group.FontIndex {
|
||||||
const key: CodepointKey = .{ .style = style, .codepoint = cp };
|
const key: CodepointKey = .{ .style = style, .codepoint = cp };
|
||||||
|
@ -14,16 +14,15 @@ pub const Style = enum(u2) {
|
|||||||
bold_italic = 3,
|
bold_italic = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Returns the UTF-32 codepoint for the given value.
|
/// Font metrics useful for things such as grid calculation.
|
||||||
pub fn codepoint(v: anytype) u32 {
|
pub const Metrics = struct {
|
||||||
// We need a UTF32 codepoint for freetype
|
/// The width and height of a monospace cell.
|
||||||
return switch (@TypeOf(v)) {
|
cell_width: f32,
|
||||||
u32 => v,
|
cell_height: f32,
|
||||||
comptime_int, u8 => @intCast(u32, v),
|
|
||||||
[]const u8 => @intCast(u32, try std.unicode.utfDecode(v)),
|
/// The baseline offset that can be used to place underlines.
|
||||||
else => @compileError("invalid codepoint type"),
|
cell_baseline: f32,
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@import("std").testing.refAllDecls(@This());
|
@import("std").testing.refAllDecls(@This());
|
||||||
|
Reference in New Issue
Block a user