mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
PDF import: wide even gaps and right-to-left lines keep their spaces
A line whose shared gap is over half an em is no longer read as letter spaced: capping that gap at half an em left glyphs set 0.55 em apart with no spaces. The regression now covers 0.55, 0.75 and 1 em. Whether a line is right to left is now known before its gaps are read, from its logical order: the paragraph direction is only set afterwards, so right-to-left lines were read for letter spacing too. The revision-history row moves out of the Headline table, where it had been put by mistake. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> # Conflicts: # docs/target-app-parity.md
This commit is contained in:
@@ -131,8 +131,8 @@ struct Gap {
|
||||
}
|
||||
|
||||
/// The spacing a line's letters share (letter-spaced type), in ems: the gap a third of the way up
|
||||
/// from the narrowest, of three or more along the line. Never below zero, and at most half an em:
|
||||
/// glyphs set wider apart than that are words or columns, not tracked letters.
|
||||
/// from the narrowest, of three or more along the line. Never below zero, and none at all past
|
||||
/// half an em: glyphs set wider apart than that are words or columns, not tracked letters.
|
||||
fn common_gap(gaps: &[Gap]) -> f64 {
|
||||
let mut widths: Vec<f64> = gaps.iter().filter(|g| g.on_line).map(|g| g.width / g.em).filter(|w| w.is_finite()).collect();
|
||||
if widths.len() < 3 {
|
||||
@@ -140,7 +140,7 @@ fn common_gap(gaps: &[Gap]) -> f64 {
|
||||
}
|
||||
let pivot = widths.len() / 3;
|
||||
let (_, common, _) = widths.select_nth_unstable_by(pivot, f64::total_cmp);
|
||||
common.clamp(0.0, 0.5)
|
||||
if *common > 0.5 { 0.0 } else { common.max(0.0) }
|
||||
}
|
||||
|
||||
/// A line of type being gathered: runs of glyphs on one baseline.
|
||||
@@ -386,7 +386,8 @@ impl TextLine {
|
||||
t.runs.extend(runs);
|
||||
// A gap wider than a fifth of an em, past the spacing the line's letters share, reads as a
|
||||
// space. Letter spacing is read only in text left in the file's order.
|
||||
let common = if t.para.direction.is_none() { common_gap(&self.gaps) } else { 0.0 };
|
||||
let directed = vectorcraft_text::logical_order(&t.plain_text()).is_some();
|
||||
let common = if directed { 0.0 } else { common_gap(&self.gaps) };
|
||||
let mut spaces = vec![];
|
||||
for gap in &self.gaps {
|
||||
// A word space set at exactly a fifth of an em still counts, whatever the rounding.
|
||||
|
||||
@@ -127,15 +127,21 @@ fn common_tracking_does_not_turn_gaps_into_spaces() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Glyphs set an em or more apart, each on its own, are words or columns: every gap stays a space,
|
||||
/// however evenly they are spaced.
|
||||
/// Glyphs set more than half an em apart, each on its own, are words or columns: every gap stays a
|
||||
/// space, however evenly they are spaced.
|
||||
#[test]
|
||||
fn evenly_wide_gaps_stay_spaces() {
|
||||
let lines: Vec<_> = ["1", "2", "3", "4"].iter().enumerate().map(|(i, text)| (20.0 + i as f32 * 18.0, 60.0, 12.0, *text)).collect();
|
||||
let d = import_with_report(&text_pdf(&lines, false), &ImportOptions::default()).unwrap().document;
|
||||
let t = texts(&d);
|
||||
assert_eq!(t.len(), 1, "{t:?}");
|
||||
assert_eq!(t[0].plain_text(), "1 2 3 4");
|
||||
let font = vectorcraft_text::FontDb::global().find_postscript("SourceSans3-Regular").unwrap();
|
||||
let size = 12.0_f32;
|
||||
let one = font.advance(font.glyph_for('1')) as f32 / font.units_per_em() as f32 * size;
|
||||
for gap in [0.55_f32, 0.75, 1.0] {
|
||||
let lines: Vec<_> =
|
||||
["1", "2", "3", "4"].iter().enumerate().map(|(i, text)| (20.0 + i as f32 * (one + gap * size), 60.0, size, *text)).collect();
|
||||
let d = import_with_report(&text_pdf(&lines, false), &ImportOptions::default()).unwrap().document;
|
||||
let t = texts(&d);
|
||||
assert_eq!(t.len(), 1, "gap {gap} em: {t:?}");
|
||||
assert_eq!(t[0].plain_text(), "1 2 3 4", "gap {gap} em");
|
||||
}
|
||||
}
|
||||
|
||||
/// Embedded font data is untrusted: anything that isn't a CID-keyed CFF is no table, never a panic.
|
||||
|
||||
Reference in New Issue
Block a user