mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-26 19:19:10 -06:00
fix(edit): require a meaningful size difference for the wider tolerance
CodeRabbit review on #3471: even with the gap >= 0.0 overlap guard, two equal-size rows with no horizontal overlap (not just overlapping ones) could still land inside the widened 50% baseline tolerance at a 5pt shift that the original 20% tolerance would have rejected, merging distinct body-text lines into one row. The wider tolerance is meant for a run distinctly smaller or larger than its neighbour (a super/subscript), not two ordinary same-size rows. Require prev.size.min(line.size) < prev.size.max(line.size) * 0.9 before taking it; equal-size runs keep the original 20% tolerance regardless of overlap. Added equal_size_rows_need_the_tighter_tolerance_even_without_overlap, confirmed it fails without this change (merges into one row/block) and passes with it, alongside the two existing regression tests from the earlier rounds of this fix. cargo test -p pdfcraft-edit (198 passed), fmt, clippy -D warnings, xtask layers and xtask assets all clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
fe2ece4675
commit
c38cdbf0be
@@ -5253,3 +5253,22 @@ fn stacked_rows_that_merely_overlap_do_not_join_into_one_row() {
|
||||
let blocks = text::text_blocks(&doc, 0).unwrap();
|
||||
assert_eq!(blocks.len(), 2, "two separate rows stay two paragraphs, not one: {blocks:?}");
|
||||
}
|
||||
|
||||
/// Two equal-size rows with no horizontal overlap must not join into one row either (#3252):
|
||||
/// the wider tolerance is for a run distinctly smaller or larger than its neighbour (a
|
||||
/// super/subscript), not for two ordinary body-text rows that happen to sit close enough
|
||||
/// vertically — here a 5pt baseline shift, inside the widened 50% tolerance but outside the
|
||||
/// original 20% one, with the second row starting just past where the first ends.
|
||||
#[test]
|
||||
fn equal_size_rows_need_the_tighter_tolerance_even_without_overlap() {
|
||||
let doc = text_page("BT /F1 12 Tf 72 700 Td (Short line one) Tj 75 -5 Td (Second line two here) Tj ET");
|
||||
let lines = text::text_lines(&doc, 0).unwrap();
|
||||
assert_eq!(lines.len(), 2);
|
||||
assert_eq!(lines[0].size, lines[1].size, "same size: no super/subscript here");
|
||||
let gap = lines[1].rect[0] - lines[0].rect[2];
|
||||
assert!(gap >= 0.0, "no horizontal overlap: {gap}");
|
||||
let baseline_shift = lines[0].rect[3] - lines[1].rect[3];
|
||||
assert!((2.4..6.0).contains(&baseline_shift), "between the old and new vertical tolerance: {baseline_shift}");
|
||||
let blocks = text::text_blocks(&doc, 0).unwrap();
|
||||
assert_eq!(blocks.len(), 2, "two separate rows stay two paragraphs, not one: {blocks:?}");
|
||||
}
|
||||
|
||||
@@ -74,12 +74,15 @@ fn group_layout(lines: &[TextLine], mixed: bool) -> Vec<TextBlock> {
|
||||
// A superscript or subscript run (a footnote marker, say) sits on the same visual
|
||||
// row as the text around it, raised or lowered by `Ts` from the body baseline
|
||||
// (#3252). That shift is typically up to half the body size, not the marker's own
|
||||
// smaller size — but only between runs with no horizontal overlap (`gap >= 0.0`):
|
||||
// two stacked rows of ordinary body text can land within that wider tolerance too
|
||||
// when horizontal compression (`Tz`) narrows the first row enough to overlap the
|
||||
// second's start, and the tighter 20% tolerance is what keeps those apart.
|
||||
// smaller size — but the wider tolerance only applies between a run and a
|
||||
// distinctly smaller or larger one, with no horizontal overlap (`gap >= 0.0`):
|
||||
// two equal-size runs can land within it too, at a baseline shift tight columns
|
||||
// or compressed text (`Tz`) can produce between genuinely separate rows, and the
|
||||
// original 20% tolerance is what keeps those apart.
|
||||
&& ((prev.frame_origin().1 - line.frame_origin().1).abs() < prev.size.min(line.size) * 0.2
|
||||
|| (gap >= 0.0 && (prev.frame_origin().1 - line.frame_origin().1).abs() < prev.size.max(line.size) * 0.5))
|
||||
|| (gap >= 0.0
|
||||
&& prev.size.min(line.size) < prev.size.max(line.size) * 0.9
|
||||
&& (prev.frame_origin().1 - line.frame_origin().1).abs() < prev.size.max(line.size) * 0.5))
|
||||
&& gap >= -prev.size.min(line.size) * 0.2
|
||||
&& gap < prev.size.max(line.size) * 1.5
|
||||
// Separate same-style text objects that merely touch or overlap, with no space
|
||||
|
||||
Reference in New Issue
Block a user