mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-29 20:56:47 -06:00
Text wrap: the minimum gap applies only where a wrap object reaches the column
free_slot held a column to the minimum gap width (1.5 em) whenever a wrap object overlapped the line's band vertically, even if the object sat beside another column of the frame: in a frame of narrow columns, an object beside column 2 dropped column 1's lines. The minimum now applies only when the object reaches the column itself (aiongg's review on #589). Test: wrap_object_beside_one_narrow_column_leaves_the_other_alone (two 18 pt columns in a 14 pt paragraph, an object beside column 2) fails before (overset) and passes after. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CgGsJkVe5GYG9qK6VFdECa
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
2307b28c72
commit
1278957455
@@ -2080,8 +2080,8 @@ fn line_metrics(
|
||||
|
||||
/// Widest free horizontal interval of `col` in the band, or None if blocked. A gap a wrap object
|
||||
/// cuts narrower than 1.5 em of `size` is skipped (a sliver beside the object); when no object
|
||||
/// reaches the band the whole column is free, however narrow (a one-character frame such as an
|
||||
/// article's closing tombstone).
|
||||
/// reaches the column in the band the whole column is free, however narrow (a one-character frame
|
||||
/// such as an article's closing tombstone, or a narrow column beside another that wraps).
|
||||
fn free_slot(f: &FrameSpec, col: Rect, y0: f64, y1: f64, size: f64) -> Option<(f64, f64)> {
|
||||
let mut free = vec![(col.x0, col.x1)];
|
||||
let mut cut = false;
|
||||
@@ -2092,7 +2092,9 @@ fn free_slot(f: &FrameSpec, col: Rect, y0: f64, y1: f64, size: f64) -> Option<(f
|
||||
WrapMode::JumpToNextColumn if y1 > r.y0 && r.x0 < col.x1 && r.x1 > col.x0 => return None,
|
||||
WrapMode::JumpObject if overlaps_band && r.x0 < col.x1 && r.x1 > col.x0 => return None,
|
||||
WrapMode::BoundingBox | WrapMode::Contour if overlaps_band => {
|
||||
cut = true;
|
||||
// Held to the minimum width only when the object reaches this column: one beside
|
||||
// another column of the frame leaves this one whole, however narrow.
|
||||
cut |= r.x0 < col.x1 && r.x1 > col.x0;
|
||||
let mut next = Vec::new();
|
||||
for (a, b) in free {
|
||||
if r.x1 <= a || r.x0 >= b {
|
||||
|
||||
@@ -184,6 +184,25 @@ fn narrow_frame_sets_lines_no_wrap_object_reaches() {
|
||||
assert!(baseline - top < 20.0, "on the first line: {baseline} (text area from {top})");
|
||||
}
|
||||
|
||||
/// In a frame of narrow columns, a wrap object beside column 2 leaves column 1 alone: only a gap
|
||||
/// the object cuts in its own column is held to the minimum width (it was dropped, as the object
|
||||
/// overlapped the line's band, and the text went past column 1).
|
||||
#[test]
|
||||
fn wrap_object_beside_one_narrow_column_leaves_the_other_alone() {
|
||||
// Two 18 pt columns (12 pt gutter): narrower than 1.5 em of the 14 pt paragraph.
|
||||
let (mut d, sid) = tombstone(Rect::new(300.0, 300.0, 348.0, 340.0), Rect::new(336.0, 300.0, 380.0, 340.0));
|
||||
let fid = d.spreads[0].items.iter().find(|i| i.text_frame().is_some_and(|t| t.story == sid)).unwrap().id;
|
||||
d.item_mut(fid).unwrap().text_frame_mut().unwrap().options.columns = 2;
|
||||
let cs = compose_story(&d, sid, &ComposeOptions::default());
|
||||
let f = &cs.frames[0];
|
||||
assert_eq!(f.columns.len(), 2);
|
||||
assert!(f.columns[0].width() < 21.0, "column 1 is narrower than 1.5 em: {}", f.columns[0].width());
|
||||
assert!(!cs.is_overset());
|
||||
let l = &f.lines[0];
|
||||
assert_eq!(l.column, 0, "set in column 1");
|
||||
assert!(l.baseline - f.columns[0].y0 < 20.0, "on its first line: {}", l.baseline);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paragraph_composer_is_no_worse_than_greedy() {
|
||||
// Sum of squared slack over lines (excluding last) should not exceed the greedy result.
|
||||
|
||||
Reference in New Issue
Block a user