mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
coretext: use alternate approach to calcaulate cell height and ascent
Fixes #174
This commit is contained in:
@ -270,7 +270,7 @@ pub const Face = struct {
|
|||||||
break :offset_y @intFromFloat(@ceil(baseline_with_offset));
|
break :offset_y @intFromFloat(@ceil(baseline_with_offset));
|
||||||
};
|
};
|
||||||
|
|
||||||
// log.warn("renderGlyph rect={} width={} height={} render_x={} render_y={} offset_y={} ascent={} cell_height={} cell_baseline={}", .{
|
// std.log.warn("renderGlyph rect={} width={} height={} render_x={} render_y={} offset_y={} ascent={} cell_height={} cell_baseline={}", .{
|
||||||
// rect,
|
// rect,
|
||||||
// width,
|
// width,
|
||||||
// height,
|
// height,
|
||||||
@ -331,95 +331,20 @@ pub const Face = struct {
|
|||||||
break :cell_width @floatCast(@ceil(max));
|
break :cell_width @floatCast(@ceil(max));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Calculate the cell height by using CoreText's layout engine
|
// Calculate the layout metrics for height/ascent by just asking
|
||||||
// to tell us after laying out some text. This is inspired by Kitty's
|
// the font. I also tried Kitty's approach at one point which is to
|
||||||
// approach. Previously we were using descent/ascent math and it wasn't
|
// use the CoreText layout engine but this led to some glyphs being
|
||||||
// quite the same with CoreText and I never figured out why.
|
// set incorrectly.
|
||||||
const layout_metrics: struct {
|
const layout_metrics: struct {
|
||||||
height: f32,
|
height: f32,
|
||||||
ascent: f32,
|
ascent: f32,
|
||||||
} = metrics: {
|
} = metrics: {
|
||||||
const unit = "AQWMH_gyl " ** 100;
|
const ascent = @round(ct_font.getAscent());
|
||||||
|
const descent = @round(ct_font.getDescent());
|
||||||
// Setup our string we'll layout. We just stylize a string of
|
const leading = @round(ct_font.getLeading());
|
||||||
// ASCII characters to setup the letters.
|
|
||||||
const string = try macos.foundation.MutableAttributedString.create(unit.len);
|
|
||||||
defer string.release();
|
|
||||||
const rep = try macos.foundation.String.createWithBytes(unit, .utf8, false);
|
|
||||||
defer rep.release();
|
|
||||||
string.replaceString(macos.foundation.Range.init(0, 0), rep);
|
|
||||||
string.setAttribute(
|
|
||||||
macos.foundation.Range.init(0, unit.len),
|
|
||||||
macos.text.StringAttribute.font,
|
|
||||||
ct_font,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create our framesetter with our string. This is used to
|
|
||||||
// emit "frames" for the layout.
|
|
||||||
const fs = try macos.text.Framesetter.createWithAttributedString(@ptrCast(string));
|
|
||||||
defer fs.release();
|
|
||||||
|
|
||||||
// Create a rectangle to fit all of this and create a frame of it.
|
|
||||||
// The rectangle needs to fit all of our text so we use some
|
|
||||||
// heuristics based on cell_width to calculate it. We are
|
|
||||||
// VERY generous with our rect here because the text must fit.
|
|
||||||
const path_rect = rect: {
|
|
||||||
// The cell width at this point is valid, so let's make it
|
|
||||||
// fit 50 characters wide.
|
|
||||||
const width = cell_width * 50;
|
|
||||||
|
|
||||||
// We are trying to calculate height so we don't know how
|
|
||||||
// high to make our frame. Well-behaved fonts will probably
|
|
||||||
// not have a height greater than 4x the width, so let's just
|
|
||||||
// generously use that metric to ensure we fit the frame.
|
|
||||||
const big_cell_height = cell_width * 4;
|
|
||||||
|
|
||||||
// If we are fitting about ~50 characters per row, we need
|
|
||||||
// unit.len / 50 rows to fit all of our text.
|
|
||||||
const rows = (unit.len / 50) * 2;
|
|
||||||
|
|
||||||
// Our final height is the number of rows times our generous height.
|
|
||||||
const height = rows * big_cell_height;
|
|
||||||
|
|
||||||
break :rect macos.graphics.Rect.init(10, 10, width, height);
|
|
||||||
};
|
|
||||||
|
|
||||||
const path = try macos.graphics.MutablePath.create();
|
|
||||||
path.addRect(null, path_rect);
|
|
||||||
defer path.release();
|
|
||||||
const frame = try fs.createFrame(
|
|
||||||
macos.foundation.Range.init(0, 0),
|
|
||||||
@ptrCast(path),
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
defer frame.release();
|
|
||||||
|
|
||||||
// Use our text layout from earlier to measure the difference
|
|
||||||
// between the lines.
|
|
||||||
var points: [2]macos.graphics.Point = undefined;
|
|
||||||
frame.getLineOrigins(macos.foundation.Range.init(0, 1), points[0..]);
|
|
||||||
frame.getLineOrigins(macos.foundation.Range.init(1, 1), points[1..]);
|
|
||||||
|
|
||||||
const lines = frame.getLines();
|
|
||||||
const line = lines.getValueAtIndex(macos.text.Line, 0);
|
|
||||||
|
|
||||||
// Get the bounds of the line to determine the ascent.
|
|
||||||
const bounds = line.getBoundsWithOptions(.{ .exclude_leading = true });
|
|
||||||
const bounds_ascent = bounds.size.height + bounds.origin.y;
|
|
||||||
const baseline = @floor(bounds_ascent + 0.5);
|
|
||||||
|
|
||||||
// This is an alternate approach to the above to calculate the
|
|
||||||
// baseline by simply using the ascender. Using this approach led
|
|
||||||
// to less accurate results, but I'm leaving it here for reference.
|
|
||||||
// var ascent: f64 = 0;
|
|
||||||
// var descent: f64 = 0;
|
|
||||||
// var leading: f64 = 0;
|
|
||||||
// _ = line.getTypographicBounds(&ascent, &descent, &leading);
|
|
||||||
//std.log.warn("ascent={} descent={} leading={}", .{ ascent, descent, leading });
|
|
||||||
|
|
||||||
break :metrics .{
|
break :metrics .{
|
||||||
.height = @floatCast(points[0].y - points[1].y),
|
.height = @floatCast(ascent + descent + leading),
|
||||||
.ascent = @floatCast(baseline),
|
.ascent = @floatCast(ascent),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -485,7 +485,6 @@ pub const Face = struct {
|
|||||||
.strikethrough_thickness = @intFromFloat(strikethrough.thickness),
|
.strikethrough_thickness = @intFromFloat(strikethrough.thickness),
|
||||||
};
|
};
|
||||||
|
|
||||||
// std.log.warn("font size size={d}", .{ct_font.getSize()});
|
|
||||||
// std.log.warn("font metrics={}", .{result});
|
// std.log.warn("font metrics={}", .{result});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
Reference in New Issue
Block a user