diff --git a/crates/text/src/breaking.rs b/crates/text/src/breaking.rs index d38c38e6d..9a6028876 100644 --- a/crates/text/src/breaking.rs +++ b/crates/text/src/breaking.rs @@ -307,7 +307,8 @@ pub(crate) fn tab_segment(cells: &[Cell], i: usize) -> (f64, f64) { /// moving back, as PowerPoint does; past the last stop, to the next default stop. pub(crate) fn tab_advance(x: f64, stops: &[Tab], default_tab: f64, seg: (f64, f64)) -> f64 { // `stops` is in position order (`tabs_of`): the next stop is the first past x. - if let Some(s) = stops.get(stops.partition_point(|s| s.pos <= x + 0.5)) { + // A NaN `x` (a NaN spacing upstream) skips the lookup and takes the finite default-stop path. + if let Some(s) = stops.get(stops.partition_point(|s| s.pos <= x + 0.5)).filter(|_| !x.is_nan()) { let to = s.pos - x; return match s.align { TabAlign::Left => to, @@ -320,3 +321,15 @@ pub(crate) fn tab_advance(x: f64, stops: &[Tab], default_tab: f64, seg: (f64, f6 let next = ((x / d).floor() + 1.0) * d; (next - x).max(1.0) } + +#[cfg(test)] +mod tab_tests { + use super::*; + + #[test] + fn a_nan_position_takes_the_finite_default_stop() { + let stops = [Tab { pos: 100.0, align: TabAlign::Left }]; + assert!(tab_advance(f64::NAN, &stops, 72.0, (0.0, 0.0)).is_finite()); + assert_eq!(tab_advance(10.0, &stops, 72.0, (0.0, 0.0)), 90.0); + } +}