mirror of
https://github.com/storytold/wordcraft.git
synced 2026-11-10 20:51:50 +00:00
This commit is contained in:
commit
ec16888bab
2 files changed
+81
-1
No files matched your search
@@ -1183,6 +1183,11 @@ fn layout_box(
|
||||
let mut excl: Vec<WrapArea> = Vec::new();
|
||||
// Areas of the box's floating tables, which other floating tables may have to avoid.
|
||||
let mut float_tables: Vec<Rect> = Vec::new();
|
||||
// Deepest a floating picture or shape that takes part in the text flow reaches, so the box
|
||||
// (a table cell especially) grows to hold it instead of letting it hang past the box's own
|
||||
// bottom edge (#3108). Behind-text and in-front-of-text objects don't: a page-anchored logo or
|
||||
// watermark behind a cell's text must not stretch its row (see `align_h` in table.rs).
|
||||
let mut float_objects_bottom = 0.0f32;
|
||||
let mut table_areas = Vec::new();
|
||||
let mut page_table_wraps = Vec::new();
|
||||
let mut y = 0.0f32;
|
||||
@@ -1287,6 +1292,13 @@ fn layout_box(
|
||||
if !p.objects.is_empty() {
|
||||
let at = ObjFrame { page: frame, col: (0.0, width), para_y: y, table_chr: table.map(|t| &t.chr), pinned: Some(&pinned) };
|
||||
let (back, front) = place_objects(ctx, story, &path, p, &pl, (0, pl.lines.len()), (0.0, y + lead), &at, &floats, depth);
|
||||
for placed in back.iter().chain(front.iter()) {
|
||||
if let Placed::Object { rect, spin, wrap, .. } = placed
|
||||
&& !matches!(wrap, Wrap::Inline | Wrap::BehindText | Wrap::InFrontOfText)
|
||||
{
|
||||
float_objects_bottom = float_objects_bottom.max(spin.bounds(*rect).bottom());
|
||||
}
|
||||
}
|
||||
let at = behind.min(items.len());
|
||||
behind += back.len();
|
||||
items.splice(at..at, back);
|
||||
@@ -1347,7 +1359,7 @@ fn layout_box(
|
||||
}
|
||||
}
|
||||
}
|
||||
let floats_bottom = float_tables.iter().map(|r| r.bottom()).fold(0.0, f32::max);
|
||||
let floats_bottom = float_tables.iter().map(|r| r.bottom()).fold(float_objects_bottom, f32::max);
|
||||
ctx.hide_deleted = outer_hide;
|
||||
BoxLayout { items, height: y.max(0.0), floats_bottom, last_top: last_top.max(0.0), table_areas, page_table_wraps }
|
||||
}
|
||||
|
||||
@@ -5137,6 +5137,74 @@ fn a_floating_table_in_a_cell_takes_no_room_and_the_cell_holds_it() {
|
||||
assert!(below_y > last_y + 10.0, "text below the outer table at {below_y}, the inner table's last row at {last_y}");
|
||||
}
|
||||
|
||||
/// A floating (anchored, non-inline) picture in a cell grows the row to hold it too, the same
|
||||
/// way a floating table does: it must not hang past the row's own bottom edge and overlap
|
||||
/// whatever follows the table (#3108).
|
||||
#[test]
|
||||
fn a_floating_picture_in_a_cell_grows_the_row_to_hold_it() {
|
||||
use wordcraft_doc::para::{Anchor, Float, Wrap};
|
||||
let mut t = Table::new(1, 1, 468.0);
|
||||
let mut cp = wordcraft_doc::Paragraph::with_text("Caption", Default::default());
|
||||
// Short text alone would need one line (well under 100pt); the floated picture is much
|
||||
// taller than that, so only its own height should set the row's height.
|
||||
let picture = Float { wrap: Wrap::Square, h_rel: Anchor::Margin, v_rel: Anchor::Margin, x: 0.0, y: 0.0, ..Default::default() };
|
||||
cp.insert_object(0, rect_shape(200.0, 300.0, picture), &Default::default()).unwrap();
|
||||
t.rows[0].cells[0].blocks = vec![wordcraft_doc::para_block(cp)];
|
||||
let mut d = Document::from_text("Below the table");
|
||||
d.insert_block(StoryRef::Body, &Path::top(0), wordcraft_doc::Block::Table(t)).unwrap();
|
||||
let l = lay(&d);
|
||||
let [(_, row_y, _)] = para_at(&l, &[0, 0, 0, 0])[..] else { panic!("cell text line missing") };
|
||||
let [(_, below_y, _)] = para_at(&l, &[1])[..] else { panic!("line after the table missing") };
|
||||
assert!(below_y - row_y > 290.0, "text after the table at {below_y}, the row's text at {row_y}: the row didn't grow for the 300pt picture");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_rotated_floating_picture_grows_the_row_by_its_rotated_extent() {
|
||||
use wordcraft_doc::para::{Anchor, Float, Wrap};
|
||||
let mut t = Table::new(1, 1, 468.0);
|
||||
let mut cp = wordcraft_doc::Paragraph::with_text("Caption", Default::default());
|
||||
// Unrotated this shape's own `rect.bottom()` is only 40pt down. Rotated 90° about its centre
|
||||
// (`Spin::bounds`: width and height swap), its drawn bottom moves to (w+h)/2 = 220pt down —
|
||||
// using the unrotated rect here would undergrow the row to a fraction of that.
|
||||
let picture = Float { wrap: Wrap::Square, h_rel: Anchor::Margin, v_rel: Anchor::Margin, x: 0.0, y: 0.0, rot: 90.0, ..Default::default() };
|
||||
cp.insert_object(0, rect_shape(400.0, 40.0, picture), &Default::default()).unwrap();
|
||||
t.rows[0].cells[0].blocks = vec![wordcraft_doc::para_block(cp)];
|
||||
let mut d = Document::from_text("Below the table");
|
||||
d.insert_block(StoryRef::Body, &Path::top(0), wordcraft_doc::Block::Table(t)).unwrap();
|
||||
let l = lay(&d);
|
||||
let [(_, row_y, _)] = para_at(&l, &[0, 0, 0, 0])[..] else { panic!("cell text line missing") };
|
||||
let [(_, below_y, _)] = para_at(&l, &[1])[..] else { panic!("line after the table missing") };
|
||||
assert!(
|
||||
below_y - row_y > 150.0,
|
||||
"text after the table at {below_y}, the row's text at {row_y}: the row didn't grow for the picture's rotated extent (unrotated bottom is only 40pt, rotated should reach ~220pt)"
|
||||
);
|
||||
}
|
||||
|
||||
/// #3108 review: only floats that take part in the text flow grow the row. A behind-text (or
|
||||
/// in-front-of-text) picture taller than the cell's text leaves the row at the text's height, as
|
||||
/// in Word — a page-anchored logo or watermark behind a cell must not stretch its row.
|
||||
#[test]
|
||||
fn a_behind_or_in_front_of_text_picture_in_a_cell_leaves_the_row_alone() {
|
||||
use wordcraft_doc::para::{Anchor, Float, Wrap};
|
||||
let row_gap = |wrap: Wrap| {
|
||||
let mut t = Table::new(1, 1, 468.0);
|
||||
let mut cp = wordcraft_doc::Paragraph::with_text("Caption", Default::default());
|
||||
let picture = Float { wrap, h_rel: Anchor::Margin, v_rel: Anchor::Margin, x: 0.0, y: 0.0, ..Default::default() };
|
||||
cp.insert_object(0, rect_shape(200.0, 300.0, picture), &Default::default()).unwrap();
|
||||
t.rows[0].cells[0].blocks = vec![wordcraft_doc::para_block(cp)];
|
||||
let mut d = Document::from_text("Below the table");
|
||||
d.insert_block(StoryRef::Body, &Path::top(0), wordcraft_doc::Block::Table(t)).unwrap();
|
||||
let l = lay(&d);
|
||||
let [(_, row_y, _)] = para_at(&l, &[0, 0, 0, 0])[..] else { panic!("cell text line missing") };
|
||||
let [(_, below_y, _)] = para_at(&l, &[1])[..] else { panic!("line after the table missing") };
|
||||
below_y - row_y
|
||||
};
|
||||
for wrap in [Wrap::BehindText, Wrap::InFrontOfText] {
|
||||
let gap = row_gap(wrap);
|
||||
assert!(gap < 60.0, "{wrap:?}: text after the table is {gap}pt below the cell's text; the 300pt picture grew the row");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn autofit_sizes_columns_by_their_content() {
|
||||
let text = |s: &str| wordcraft_doc::para_block(wordcraft_doc::Paragraph::with_text(s, Default::default()));
|
||||
|
||||
Reference in new issue
Block a user