From acb96658ea75066fe0c6cc709e2f97d20a21b607 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Wed, 11 Nov 2026 13:16:42 +0000 Subject: [PATCH] address review: blank lines use the same scaled leading tolerance --- crates/svg/src/import/text.rs | 11 ++++++++--- crates/svg/tests/it/import_text.rs | 10 ++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/crates/svg/src/import/text.rs b/crates/svg/src/import/text.rs index 6487be5b3..962b61db8 100644 --- a/crates/svg/src/import/text.rs +++ b/crates/svg/src/import/text.rs @@ -903,6 +903,12 @@ fn justify_of(anchor: f64) -> Justify { } } +/// How far a line's leading may differ from its spacing and still count as it: 0.01 absolute, but +/// never more than a thousandth of the spacing itself (tiny type has tiny gaps). +fn leading_tolerance(spacing: f64) -> f64 { + 0.01_f64.min(spacing.abs() * 1e-3) +} + /// Point type: line breaks, baseline shifts and kerning from the positioning lists. Returns the /// justification, the x of the first line's left (or anchor) edge and, when no character is /// placed on its own, each line's first character and anchor x. @@ -950,8 +956,7 @@ fn lines( // A line's characters take its spacing as leading unless it is their auto leading. for (k, b) in breaks.iter().enumerate() { let end = breaks.get(k + 1).map_or(n, |nb| nb.at); - // 0.01 absolute, but never more than a thousandth of the spacing itself (tiny type has tiny gaps). - let tolerance = 0.01_f64.min(b.leading.abs() * 1e-3); + let tolerance = leading_tolerance(b.leading); if cells[b.at..end].iter().any(|c| (c.style.effective_leading() - b.leading).abs() > tolerance) { for c in &mut cells[b.at..end] { c.style.leading = Some(b.leading); @@ -1076,7 +1081,7 @@ fn assemble(cells: &[Cell], breaks: &[Break]) -> (Runs, Vec) { let key = (prev.fill, prev.stroke); push(&mut out, '\n', prev.final_style(), key); let mut blank = prev.final_style(); - if (blank.effective_leading() - b.leading).abs() > 0.01 { + if (blank.effective_leading() - b.leading).abs() > leading_tolerance(b.leading) { blank.leading = Some(b.leading); } for _ in 1..b.count { diff --git a/crates/svg/tests/it/import_text.rs b/crates/svg/tests/it/import_text.rs index 9a64e9b2d..30d55448c 100644 --- a/crates/svg/tests/it/import_text.rs +++ b/crates/svg/tests/it/import_text.rs @@ -241,6 +241,16 @@ fn a_small_line_gap_in_tiny_type_keeps_its_leading() { assert!(two.is_some_and(|l| close(l, 0.0085, 1e-9)), "{two:?}"); } +#[test] +fn blank_lines_in_tiny_type_keep_their_own_spacing() { + // B sits 0.0085 below A (kept as its leading); C is three 0.006 lines below B, so the two blank + // lines between them must be 0.006 apart, not carry B's 0.0085. + let d = open(r#"ABC"#); + let t = only_text(&d); + let blank = t.runs.iter().find(|r| r.text == "\n\n").expect("a run of the two blank lines"); + assert!(blank.style.leading.is_some_and(|l| close(l, 0.006, 1e-9)), "{:?}", blank.style.leading); +} + #[test] fn tspan_lines_dx_and_baseline_shift() { let d = open(