Skip to content

Commit

Permalink
text cursor glyph renders at native cell size
Browse files Browse the repository at this point in the history
Previously we'd use the scaled-by-line-height-and-cell-width dimensions
for the text cursor, leading to oddly dimensioned block cursors when
`line_height` or `cell_width` were configured.

This commit captures the native cell dimensions into the RenderMetrics
which makes it feasible for the glyph and sprite rendering logic to
reason about it.

The cursor rendering now renders at the native size and position by
using a transform to scale and translate into the correct spot.

We could potentially use the same technique for eg: braille or
other non-drawing characters
(#1957) although that is more
complex than just this commit.

refs: #2882
  • Loading branch information
wez committed Aug 26, 2023
1 parent 360ad2a commit 2c95b98
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 9 deletions.
3 changes: 3 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ As features stabilize some brief notes about them will accumulate here.
* macOS: system font fallback didn't always find a workable fallback font. #4099 #849
* F13-F24 keys are now supported. Thanks to @ovidiu-ionescu! #3937
* Strikethrough position was not centered when setting `line_height` #4196
* Text cursor filled the scaled-by `line_height` and `cell_width` dimensions rather
than the native font dimensions and looked weird when either config option was
not set to `1.0`. #2882

#### Updated
* Bundled harfbuzz to 8.1.1
Expand Down
79 changes: 71 additions & 8 deletions wezterm-gui/src/customglyph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,17 @@ pub enum PolyStyle {
}

impl PolyStyle {
fn apply(self, width: f32, paint: &Paint, path: &Path, pixmap: &mut PixmapMut) {
fn apply(
self,
width: f32,
paint: &Paint,
path: &Path,
pixmap: &mut PixmapMut,
transform: Transform,
) {
match self {
PolyStyle::Fill => {
pixmap.fill_path(path, paint, FillRule::Winding, Transform::identity(), None);
pixmap.fill_path(path, paint, FillRule::Winding, transform, None);
}

PolyStyle::OutlineThin | PolyStyle::Outline | PolyStyle::OutlineHeavy => {
Expand All @@ -259,7 +266,7 @@ impl PolyStyle {
} else if self == PolyStyle::OutlineThin {
stroke.width = 1.2;
}
pixmap.stroke_path(path, paint, &stroke, Transform::identity(), None);
pixmap.stroke_path(path, paint, &stroke, transform, None);
}
}
}
Expand Down Expand Up @@ -3727,6 +3734,7 @@ impl GlyphCache {
polys: &[Poly],
buffer: &mut Image,
aa: PolyAA,
transform: Transform,
) {
let (width, height) = buffer.image_dimensions();
let mut pixmap =
Expand Down Expand Up @@ -3754,7 +3762,13 @@ impl GlyphCache {
item.to_skia(width, height, metrics.underline_height as f32, &mut pb);
}
let path = pb.finish().expect("poly path to be valid");
style.apply(metrics.underline_height as f32, &paint, &path, &mut pixmap);
style.apply(
metrics.underline_height as f32,
&paint,
&path,
&mut pixmap,
transform,
);
}
}

Expand All @@ -3768,6 +3782,9 @@ impl GlyphCache {
return Ok(sprite.clone());
}

let x_scale = metrics.native_cell_size.width as f32 / metrics.cell_size.width as f32;
let y_scale = metrics.native_cell_size.height as f32 / metrics.cell_size.height as f32;

let mut metrics = metrics.scale_cell_width(width as f64);
if let Some(d) = &self.fonts.config().cursor_thickness {
metrics.underline_height = d.evaluate_as_pixels(DimensionContext {
Expand All @@ -3777,6 +3794,12 @@ impl GlyphCache {
}) as isize;
}

let thickness_scale = y_scale.max(x_scale);
let thickness = ((metrics.underline_height as f32) / thickness_scale).ceil() as isize;
let x_translate = thickness - metrics.underline_height;

metrics.underline_height = thickness;

let mut buffer = Image::new(
metrics.cell_size.width as usize,
metrics.cell_size.height as usize,
Expand All @@ -3785,10 +3808,40 @@ impl GlyphCache {
let cell_rect = Rect::new(Point::new(0, 0), metrics.cell_size);
buffer.clear_rect(cell_rect, black);

let transform = if metrics.cell_size != metrics.native_cell_size {
Transform::from_scale(x_scale, y_scale).post_translate(
// No scaled X translation because cell_width just adds blank space
// into the right of the bitmap without adjusting any x-coords.
// We just need to compensate for the line thickness scaling so
// that we don't clip it out the left side of the pixmap
x_translate as f32,
// Y translation to parallel the centering effect of line_height
(metrics.native_cell_size.height as f32 - metrics.cell_size.height as f32) / -2.,
)
} else {
Transform::identity()
};

match shape {
None => {}
Some(CursorShape::Default) => {
buffer.clear_rect(cell_rect, SrgbaPixel::rgba(0xff, 0xff, 0xff, 0xff));
self.draw_polys(
&metrics,
&[Poly {
path: &[
PolyCommand::MoveTo(BlockCoord::Zero, BlockCoord::Zero),
PolyCommand::LineTo(BlockCoord::One, BlockCoord::Zero),
PolyCommand::LineTo(BlockCoord::One, BlockCoord::One),
PolyCommand::LineTo(BlockCoord::Zero, BlockCoord::One),
PolyCommand::LineTo(BlockCoord::Zero, BlockCoord::Zero),
],
intensity: BlockAlpha::Full,
style: PolyStyle::Fill,
}],
&mut buffer,
PolyAA::MoarPixels,
transform,
);
}
Some(CursorShape::BlinkingBlock | CursorShape::SteadyBlock) => {
self.draw_polys(
Expand All @@ -3800,12 +3853,18 @@ impl GlyphCache {
PolyCommand::LineTo(BlockCoord::One, BlockCoord::One),
PolyCommand::LineTo(BlockCoord::Zero, BlockCoord::One),
PolyCommand::LineTo(BlockCoord::Zero, BlockCoord::Zero),
// An extra, seemingly redundant path segment here is
// needed to workaround tiny-skia leaving a single blank
// pixel in the top left corner when the glyph metrics
// are scaled by cell_width and/or line_height
PolyCommand::LineTo(BlockCoord::One, BlockCoord::Zero),
],
intensity: BlockAlpha::Full,
style: PolyStyle::OutlineHeavy,
}],
&mut buffer,
PolyAA::AntiAlias,
PolyAA::MoarPixels,
transform,
);
}
Some(CursorShape::BlinkingBar | CursorShape::SteadyBar) => {
Expand All @@ -3820,7 +3879,8 @@ impl GlyphCache {
style: PolyStyle::OutlineHeavy,
}],
&mut buffer,
PolyAA::AntiAlias,
PolyAA::MoarPixels,
transform,
);
}
Some(CursorShape::BlinkingUnderline | CursorShape::SteadyUnderline) => {
Expand All @@ -3835,7 +3895,8 @@ impl GlyphCache {
style: PolyStyle::OutlineHeavy,
}],
&mut buffer,
PolyAA::AntiAlias,
PolyAA::MoarPixels,
transform,
);
}
}
Expand All @@ -3862,6 +3923,7 @@ impl GlyphCache {
underline_height: *underline_height,
strike_row: 0,
cell_size: cell_size.clone(),
native_cell_size: render_metrics.native_cell_size,
},
_ => render_metrics.clone(),
};
Expand Down Expand Up @@ -4037,6 +4099,7 @@ impl GlyphCache {
} else {
PolyAA::MoarPixels
},
Transform::identity(),
);
}
}
Expand Down
12 changes: 11 additions & 1 deletion wezterm-gui/src/utilsprites.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub struct RenderMetrics {
pub underline_height: IntPixelLength,
pub strike_row: IntPixelLength,
pub cell_size: Size,
pub native_cell_size: Size,
}

impl RenderMetrics {
Expand All @@ -33,13 +34,15 @@ impl RenderMetrics {
let descender_plus_two =
(2 * underline_height + descender_row).min(cell_height as isize - underline_height);
let strike_row = descender_row / 2;
let cell_size = Size::new(cell_width as isize, cell_height as isize);

Self {
descender: metrics.descender,
descender_row,
descender_plus_two,
strike_row,
cell_size: Size::new(cell_width as isize, cell_height as isize),
cell_size,
native_cell_size: cell_size,
underline_height,
}
}
Expand All @@ -59,6 +62,7 @@ impl RenderMetrics {
underline_height: self.underline_height,
strike_row: self.strike_row,
cell_size: size,
native_cell_size: self.native_cell_size,
}
}

Expand All @@ -73,6 +77,11 @@ impl RenderMetrics {
.default_font_metrics()
.context("failed to get font metrics!?")?;

let native_cell_size = Size::new(
metrics.cell_width.get() as isize,
metrics.cell_height.get() as isize,
);

let line_height = fonts.config().line_height;
let cell_width = fonts.config().cell_width;

Expand Down Expand Up @@ -131,6 +140,7 @@ impl RenderMetrics {
strike_row,
cell_size: Size::new(cell_width as isize, cell_height as isize),
underline_height,
native_cell_size,
})
}
}
Expand Down

0 comments on commit 2c95b98

Please sign in to comment.