Part of #2384: imported PDF text keeps its place after wide gaps between words

PDF import reads a gap wider than a fifth of an em between two glyphs
as a space, and a space that the line's tracking cannot place gets
tracking of its own. That tracking was clamped to 1000 thousandths of
an em, while type takes tracking from -1000 to 10000. A gap wider than
an em plus the width of a space came in short by the excess, so the
words after it sat to the left of where the file put them, and each
further wide gap added to the shift.

The tracking that import sets for such a space, and for the line around
it, now has the same range as type's.
This commit is contained in:
dotCooCoo
2026-10-17 13:20:23 +07:00
committed by bflatastic
parent 7c80b286c7
commit fbcb217789
2 changed files with 15 additions and 1 deletions
+1 -1
View File
@@ -494,7 +494,7 @@ fn spacing(laid: &TextLayout, gaps: &[(usize, f64)], extra: f64, chars: usize, s
tracking = if rest >= 1.0 { (extra - own.iter().map(|(_, need)| need).sum::<f64>()) / rest } else { 0.0 };
}
own.sort_by_key(|(b, _)| *b);
let em = |pts: f64| (pts / size * 1000.0).clamp(-1000.0, 1000.0).round();
let em = |pts: f64| (pts / size * 1000.0).clamp(-1000.0, 10000.0).round();
(em(tracking), own.into_iter().map(|(b, need)| (b, em(need - tracking))).collect())
}
+14
View File
@@ -191,6 +191,20 @@ fn spaces_read_from_wide_gaps_keep_the_glyphs_after_them_in_place() {
assert!((at(9) - f64::from(x2)).abs() < 0.05, "the third group starts where the file has it: {} vs {x2}", at(9));
}
#[test]
fn words_set_ems_apart_keep_their_place() {
// Gaps of about 1.75 and 2.6 em (#2384): each space's own tracking is more than an em.
let (x1, x2) = (48.0, 84.0);
let bytes = source_sans(&[(20.0, 50.0, 10.0, "ab"), (x1, 50.0, 10.0, "cd"), (x2, 50.0, 10.0, "ef")]);
let t = texts(&import(&bytes).unwrap());
assert_eq!(t.len(), 1);
assert_eq!(t[0].plain_text(), "ab cd ef");
let laid = vectorcraft_text::layout(vectorcraft_text::FontDb::global(), &t[0]);
let at = |byte: usize| (t[0].xf * laid.glyphs.iter().find(|g| g.byte == byte).unwrap().origin).x;
assert!((at(3) - f64::from(x1)).abs() < 0.05, "the second word starts where the file has it: {} vs {x1}", at(3));
assert!((at(6) - f64::from(x2)).abs() < 0.05, "the third word starts where the file has it: {} vs {x2}", at(6));
}
/// A document of area type `text` (Source Sans 3, 10 pt) `width` wide at (20, 30).
fn area_doc(text: &str, justify: Justify, width: f64, space_before: f64) -> Document {
let style = CharStyle { size: 10.0, fill: Paint::solid(Color::BLACK), ..Default::default() };