Merge pull request #2086 from ghostty-org/split

font/shaper: split text runs on common bad ligature pairs
This commit is contained in:
Mitchell Hashimoto
2024-08-11 15:40:22 -07:00
committed by GitHub
3 changed files with 58 additions and 16 deletions

View File

@ -698,6 +698,27 @@ test "run iterator" {
while (try it.next(alloc)) |_| count += 1;
try testing.expectEqual(@as(usize, 3), count);
}
// Bad ligatures
for (&[_][]const u8{ "fl", "fi", "st" }) |bad| {
// Make a screen with some data
var screen = try terminal.Screen.init(alloc, 5, 3, 0);
defer screen.deinit();
try screen.testWriteString(bad);
// Get our run iterator
var shaper = &testdata.shaper;
var it = shaper.runIterator(
testdata.grid,
&screen,
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
null,
null,
);
var count: usize = 0;
while (try it.next(alloc)) |_| count += 1;
try testing.expectEqual(@as(usize, 2), count);
}
}
test "run iterator: empty cells with background set" {

View File

@ -104,6 +104,30 @@ pub const RunIterator = struct {
if (j > self.i) style: {
const prev_cell = cells[j - 1];
// If the prev cell and this cell are both plain
// codepoints then we check if they are commonly "bad"
// ligatures and spit the run if they are.
if (prev_cell.content_tag == .codepoint and
cell.content_tag == .codepoint)
{
const prev_cp = prev_cell.codepoint();
switch (prev_cp) {
// fl, fi
'f' => {
const cp = cell.codepoint();
if (cp == 'l' or cp == 'i') break;
},
// st
's' => {
const cp = cell.codepoint();
if (cp == 't') break;
},
else => {},
}
}
// If the style is exactly the change then fast path out.
if (prev_cell.style_id == cell.style_id) break :style;

View File

@ -12,21 +12,18 @@ const font = @import("font/main.zig");
/// If true, the default font features should be disabled for the given face.
pub fn disableDefaultFontFeatures(face: *const font.Face) bool {
var buf: [64]u8 = undefined;
const name = face.name(&buf) catch |err| switch (err) {
// If the name doesn't fit in buf we know this will be false
// because we have no quirks fonts that are longer than buf!
error.OutOfMemory => return false,
};
_ = face;
// CodeNewRoman, Menlo and Monaco both have a default ligature of "fi" that
// looks really bad in terminal grids, so we want to disable ligatures
// by default for these faces.
//
// JuliaMono has a default ligature of "st" that looks bad.
return std.mem.eql(u8, name, "CodeNewRoman") or
std.mem.eql(u8, name, "CodeNewRoman Nerd Font") or
std.mem.eql(u8, name, "JuliaMono") or
std.mem.eql(u8, name, "Menlo") or
std.mem.eql(u8, name, "Monaco");
// This function used to do something, but we integrated the logic
// we checked for directly into our shaping algorithm. It's likely
// there are other broken fonts for other reasons so I'm keeping this
// around so its easy to add more checks in the future.
return false;
// var buf: [64]u8 = undefined;
// const name = face.name(&buf) catch |err| switch (err) {
// // If the name doesn't fit in buf we know this will be false
// // because we have no quirks fonts that are longer than buf!
// error.OutOfMemory => return false,
// };
}