diff --git a/crates/gpui_ce_parley/src/text_system.rs b/crates/gpui_ce_parley/src/text_system.rs index f6689900c9..f8a9296730 100644 --- a/crates/gpui_ce_parley/src/text_system.rs +++ b/crates/gpui_ce_parley/src/text_system.rs @@ -2164,8 +2164,11 @@ impl ParleyTextSystem { glyphs, x_range: start..start + px(glyph_run.advance()), style: PaintStyle::from(&source_runs[source_run]), - underline_offset: Some(px(run_metrics.underline_offset)), - strikethrough_offset: Some(px(run_metrics.strikethrough_offset)), + // Parley reports font metrics y-up (an underline below the + // baseline is negative); gpui adds these to `baseline_y` in + // y-down space, so flip them. + underline_offset: Some(px(-run_metrics.underline_offset)), + strikethrough_offset: Some(px(-run_metrics.strikethrough_offset)), }); } @@ -2598,6 +2601,37 @@ mod tests { }) } + #[test] + fn decoration_offsets_are_y_down_from_the_baseline() { + let system = test_system(); + for family in [IBM_PLEX.family, SOURCE_SERIF.family, LILEX.family] { + let text = "Learn how"; + let layout = layout_line(&system, text, px(16.0), &[text_run(text, family)]); + let fragment = &layout.paint_fragments[0]; + let underline = fragment.underline_offset.unwrap(); + let strikethrough = fragment.strikethrough_offset.unwrap(); + + // gpui paints at `baseline_y + offset` with y growing downward: the + // underline sits below the baseline, within the descent, and the + // strikethrough sits above it, within the ascent. + assert!(underline > px(0.0), "{family}: underline={underline:?}"); + assert!( + underline <= layout.descent, + "{family}: underline={underline:?}, descent={:?}", + layout.descent + ); + assert!( + strikethrough < px(0.0), + "{family}: strikethrough={strikethrough:?}" + ); + assert!( + -strikethrough < layout.ascent, + "{family}: strikethrough={strikethrough:?}, ascent={:?}", + layout.ascent + ); + } + } + #[test] fn explicit_rtl_sets_the_base_direction_without_rtl_characters() { let system = test_system();