mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
fix(renderer): use 1-wide ul/st chars, ignore null shaper cells
This makes sure that underline styles are consistent and not stretched, and avoids rendering overlapping text decorations or extraneous background cells for the right halves of wide chars.
This commit is contained in:
@ -2274,6 +2274,10 @@ fn rebuildCells(
|
||||
};
|
||||
|
||||
for (shaper_cells) |shaper_cell| {
|
||||
// The shaper can emit null glyphs representing the right half
|
||||
// of wide characters, we don't need to do anything with them.
|
||||
if (shaper_cell.glyph_index == null) continue;
|
||||
|
||||
const coord: terminal.Coordinate = .{
|
||||
.x = shaper_cell.x,
|
||||
.y = y,
|
||||
@ -2541,7 +2545,7 @@ fn updateCell(
|
||||
font.sprite_index,
|
||||
@intFromEnum(sprite),
|
||||
.{
|
||||
.cell_width = if (cell.wide == .wide) 2 else 1,
|
||||
.cell_width = 1,
|
||||
.grid_metrics = self.grid_metrics,
|
||||
},
|
||||
);
|
||||
@ -2551,7 +2555,7 @@ fn updateCell(
|
||||
try self.cells.add(self.alloc, .underline, .{
|
||||
.mode = .fg,
|
||||
.grid_pos = .{ @intCast(coord.x), @intCast(coord.y) },
|
||||
.constraint_width = cell.gridWidth(),
|
||||
.constraint_width = 1,
|
||||
.color = .{ color.r, color.g, color.b, alpha },
|
||||
.glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y },
|
||||
.glyph_size = .{ render.glyph.width, render.glyph.height },
|
||||
@ -2560,6 +2564,21 @@ fn updateCell(
|
||||
@intCast(render.glyph.offset_y),
|
||||
},
|
||||
});
|
||||
// If it's a wide cell we need to underline the right half as well.
|
||||
if (cell.gridWidth() > 1 and coord.x < self.cells.size.columns - 1) {
|
||||
try self.cells.add(self.alloc, .underline, .{
|
||||
.mode = .fg,
|
||||
.grid_pos = .{ @intCast(coord.x + 1), @intCast(coord.y) },
|
||||
.constraint_width = 1,
|
||||
.color = .{ color.r, color.g, color.b, alpha },
|
||||
.glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y },
|
||||
.glyph_size = .{ render.glyph.width, render.glyph.height },
|
||||
.bearings = .{
|
||||
@intCast(render.glyph.offset_x),
|
||||
@intCast(render.glyph.offset_y),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// If the shaper cell has a glyph, draw it.
|
||||
@ -2611,7 +2630,7 @@ fn updateCell(
|
||||
font.sprite_index,
|
||||
@intFromEnum(font.Sprite.strikethrough),
|
||||
.{
|
||||
.cell_width = if (cell.wide == .wide) 2 else 1,
|
||||
.cell_width = 1,
|
||||
.grid_metrics = self.grid_metrics,
|
||||
},
|
||||
);
|
||||
@ -2619,7 +2638,7 @@ fn updateCell(
|
||||
try self.cells.add(self.alloc, .strikethrough, .{
|
||||
.mode = .fg,
|
||||
.grid_pos = .{ @intCast(coord.x), @intCast(coord.y) },
|
||||
.constraint_width = cell.gridWidth(),
|
||||
.constraint_width = 1,
|
||||
.color = .{ colors.fg.r, colors.fg.g, colors.fg.b, alpha },
|
||||
.glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y },
|
||||
.glyph_size = .{ render.glyph.width, render.glyph.height },
|
||||
@ -2628,6 +2647,21 @@ fn updateCell(
|
||||
@intCast(render.glyph.offset_y),
|
||||
},
|
||||
});
|
||||
// If it's a wide cell we need to strike through the right half as well.
|
||||
if (cell.gridWidth() > 1 and coord.x < self.cells.size.columns - 1) {
|
||||
try self.cells.add(self.alloc, .strikethrough, .{
|
||||
.mode = .fg,
|
||||
.grid_pos = .{ @intCast(coord.x + 1), @intCast(coord.y) },
|
||||
.constraint_width = 1,
|
||||
.color = .{ colors.fg.r, colors.fg.g, colors.fg.b, alpha },
|
||||
.glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y },
|
||||
.glyph_size = .{ render.glyph.width, render.glyph.height },
|
||||
.bearings = .{
|
||||
@intCast(render.glyph.offset_x),
|
||||
@intCast(render.glyph.offset_y),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1338,6 +1338,10 @@ pub fn rebuildCells(
|
||||
};
|
||||
|
||||
for (shaper_cells) |shaper_cell| {
|
||||
// The shaper can emit null glyphs representing the right half
|
||||
// of wide characters, we don't need to do anything with them.
|
||||
if (shaper_cell.glyph_index == null) continue;
|
||||
|
||||
// If this cell falls within our preedit range then we skip it.
|
||||
// We do this so we don't have conflicting data on the same
|
||||
// cell.
|
||||
@ -1779,7 +1783,7 @@ fn updateCell(
|
||||
font.sprite_index,
|
||||
@intFromEnum(sprite),
|
||||
.{
|
||||
.cell_width = if (cell.wide == .wide) 2 else 1,
|
||||
.cell_width = 1,
|
||||
.grid_metrics = self.grid_metrics,
|
||||
},
|
||||
);
|
||||
@ -1790,7 +1794,7 @@ fn updateCell(
|
||||
.mode = .fg,
|
||||
.grid_col = @intCast(x),
|
||||
.grid_row = @intCast(y),
|
||||
.grid_width = cell.gridWidth(),
|
||||
.grid_width = 1,
|
||||
.glyph_x = render.glyph.atlas_x,
|
||||
.glyph_y = render.glyph.atlas_y,
|
||||
.glyph_width = render.glyph.width,
|
||||
@ -1806,6 +1810,29 @@ fn updateCell(
|
||||
.bg_b = bg[2],
|
||||
.bg_a = bg[3],
|
||||
});
|
||||
// If it's a wide cell we need to underline the right half as well.
|
||||
if (cell.gridWidth() > 1 and x < self.grid_size.columns - 1) {
|
||||
try self.cells.append(self.alloc, .{
|
||||
.mode = .fg,
|
||||
.grid_col = @intCast(x + 1),
|
||||
.grid_row = @intCast(y),
|
||||
.grid_width = 1,
|
||||
.glyph_x = render.glyph.atlas_x,
|
||||
.glyph_y = render.glyph.atlas_y,
|
||||
.glyph_width = render.glyph.width,
|
||||
.glyph_height = render.glyph.height,
|
||||
.glyph_offset_x = render.glyph.offset_x,
|
||||
.glyph_offset_y = render.glyph.offset_y,
|
||||
.r = color.r,
|
||||
.g = color.g,
|
||||
.b = color.b,
|
||||
.a = alpha,
|
||||
.bg_r = bg[0],
|
||||
.bg_g = bg[1],
|
||||
.bg_b = bg[2],
|
||||
.bg_a = bg[3],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// If the shaper cell has a glyph, draw it.
|
||||
@ -1866,7 +1893,7 @@ fn updateCell(
|
||||
font.sprite_index,
|
||||
@intFromEnum(font.Sprite.strikethrough),
|
||||
.{
|
||||
.cell_width = if (cell.wide == .wide) 2 else 1,
|
||||
.cell_width = 1,
|
||||
.grid_metrics = self.grid_metrics,
|
||||
},
|
||||
);
|
||||
@ -1875,7 +1902,7 @@ fn updateCell(
|
||||
.mode = .fg,
|
||||
.grid_col = @intCast(x),
|
||||
.grid_row = @intCast(y),
|
||||
.grid_width = cell.gridWidth(),
|
||||
.grid_width = 1,
|
||||
.glyph_x = render.glyph.atlas_x,
|
||||
.glyph_y = render.glyph.atlas_y,
|
||||
.glyph_width = render.glyph.width,
|
||||
@ -1891,6 +1918,29 @@ fn updateCell(
|
||||
.bg_b = bg[2],
|
||||
.bg_a = bg[3],
|
||||
});
|
||||
// If it's a wide cell we need to strike through the right half as well.
|
||||
if (cell.gridWidth() > 1 and x < self.grid_size.columns - 1) {
|
||||
try self.cells.append(self.alloc, .{
|
||||
.mode = .fg,
|
||||
.grid_col = @intCast(x + 1),
|
||||
.grid_row = @intCast(y),
|
||||
.grid_width = 1,
|
||||
.glyph_x = render.glyph.atlas_x,
|
||||
.glyph_y = render.glyph.atlas_y,
|
||||
.glyph_width = render.glyph.width,
|
||||
.glyph_height = render.glyph.height,
|
||||
.glyph_offset_x = render.glyph.offset_x,
|
||||
.glyph_offset_y = render.glyph.offset_y,
|
||||
.r = colors.fg.r,
|
||||
.g = colors.fg.g,
|
||||
.b = colors.fg.b,
|
||||
.a = alpha,
|
||||
.bg_r = bg[0],
|
||||
.bg_g = bg[1],
|
||||
.bg_b = bg[2],
|
||||
.bg_a = bg[3],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
Reference in New Issue
Block a user