From be93f3b82da4b9e902b2044ff68033ddd9545496 Mon Sep 17 00:00:00 2001 From: MarekSpodBiedry <73122968+MarekSpodBiedry@users.noreply.github.com> Date: Wed, 14 Oct 2026 19:31:21 +0200 Subject: [PATCH] Tables: a table with its own width is not squeezed to the margins (#1721) --- crates/layout/src/table.rs | 3 ++- crates/layout/src/tests.rs | 23 +++++++++++++++++++++++ docs/layout-parity.md | 3 ++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/crates/layout/src/table.rs b/crates/layout/src/table.rs index 2a3df74c8..099747469 100644 --- a/crates/layout/src/table.rs +++ b/crates/layout/src/table.rs @@ -350,7 +350,8 @@ pub fn layout_table(ctx: &mut Ctx, story: StoryRef, t: &Table, path: &[u32], ava grid.iter_mut().for_each(|w| *w *= k); total = tw; } - if total > avail * 1.5 && !t.props.fixed { + // A table with its own width keeps it, however far it runs past the margins (as in Word). + if target.is_none() && total > avail * 1.5 && !t.props.fixed { let k = avail / total.max(1.0); grid.iter_mut().for_each(|w| *w *= k); total = avail; diff --git a/crates/layout/src/tests.rs b/crates/layout/src/tests.rs index 7baaad370..09c9c3137 100644 --- a/crates/layout/src/tests.rs +++ b/crates/layout/src/tests.rs @@ -5741,3 +5741,26 @@ fn space_after_stays_clear_before_a_numbered_paragraph_without_a_label() { wordcraft_doc::resolve::AUTO_SPACING, ); } + +/// A table with its own width keeps it when it is over 1.5 times the text width (#1721); one +/// without is still squeezed to the margins. +#[test] +fn table_with_its_own_width_is_not_squeezed_to_the_margins() { + let text = |s: &str| wordcraft_doc::para_block(wordcraft_doc::Paragraph::with_text(s, Default::default())); + let second_column_x = |own: Option| { + let mut t = Table::new(1, 3, 936.0); + t.props.width = own; + t.rows[0].cells[1].blocks = vec![text("Address")]; + let mut d = Document::from_text("After"); + d.insert_block(StoryRef::Body, &Path::top(0), wordcraft_doc::Block::Table(t)).unwrap(); + let l = lay(&d); + let [(x, _, _)] = para_at(&l, &[0, 0, 1, 0])[..] else { panic!("second cell missing") }; + x + }; + // 936pt (twice the 468pt of text) of its own: the columns stay 312pt wide, past the margin. + let x = second_column_x(Some(936.0)); + assert!(x > 72.0 + 300.0, "the second column starts at {x}, squeezed"); + // The same columns with an automatic table width are squeezed to 156pt each. + let x = second_column_x(None); + assert!(x < 72.0 + 200.0, "the second column starts at {x}, not squeezed"); +} diff --git a/docs/layout-parity.md b/docs/layout-parity.md index e02d4908d..1b6f0c7e2 100644 --- a/docs/layout-parity.md +++ b/docs/layout-parity.md @@ -41,7 +41,7 @@ font can't match Word's metrics. | Body top below a tall header, footer pushes body up | ✅ | #138 | — | | Footnotes at the page bottom, endnotes at the end, note numbering | 🟡 | A long note continues onto the next page at a line boundary (its first line stays with the reference), first in that page's note area under a full-width continuation separator (#352); the document's own separator, continuation separator and continuation notice are drawn (the notice under a note that continues; endnotes use the document's separator but don't continue onto a page of their own); each section's note options: footnotes below the text, endnotes at the end of each section, start at, numbering restarted each section or each page (counted from where the notes land, at most three passes) (#385) | 1–2 | | Tables: row heights (at least/exact), rows split across pages, header rows repeat, Can't Split | ✅ | 2026-10-06, #138; every cell in a row gets the row's largest top and bottom margin; an exact height covers the top border, top margin and text, the bottom margin comes on top, and an exact row never splits; a row split across pages keeps its cells' bottom margin, border and last space after on the first page, widow/orphan control applies in its cells, each cell continues at the top of the next page and an at-least row keeps its minimum (`layout::tests::a_row_shares_its_largest_top_and_bottom_margins`, `…_a_split_row_keeps_its_bottom_margin_and_widow_control`, `…_split_row_cells_each_continue_at_the_top`) | — | -| Tables: autofit to contents/window, fixed widths, Word 2013 edge | 🟡 | #137; #44: AutoFit Contents measures each column's narrowest and widest text and shares the width like Word, once (not live as you type); cell preferred widths and spans still differ | 3–5 | +| Tables: autofit to contents/window, fixed widths, Word 2013 edge | 🟡 | #137; #44: AutoFit Contents measures each column's narrowest and widest text and shares the width like Word, once (not live as you type); a table with its own preferred width keeps it, however far past the margin, and only an automatic-width table over 1.5× the text width is squeezed to the margins (Word squeezes it as soon as it is wider) (#1721); cell preferred widths and spans still differ | 3–5 | | Floating tables (`w:tblpPr`) | 🟡 | #137; one placed on the page or margin that would cover the text before it and doesn't fit below it moves to the next page (#534); overlap rules untested | 2–3 | | Nested tables | 🟡 | render; polish missing | 2–4 | | Floating pictures/shapes placement (relative to page/margin/column/paragraph/line/character) | ✅ | #136 | — | @@ -84,6 +84,7 @@ font can't match Word's metrics. | 2026-10-12 | trivial | a list label moves with its first line when the paragraph is centred or end-aligned (#1159) | | 2026-10-13 | trivial | A paragraph ending with a page break keeps its space after on the old page with its mark: the next page starts with the next paragraph at the top (it started that much too low, and a page break before after it opened a blank page) | | 2026-10-13 | trivial | Table rows: every cell gets the row's largest top and bottom margin; exact rows add the bottom margin on top and never split; a split row keeps its cells' bottom margin, border and space after on the first page, applies widow control in its cells and continues each cell at the top of the next page | +| 2026-10-14 | trivial | A table with its own preferred width keeps it past the margin instead of being squeezed to the margins when over 1.5× the text width (#1721) | | 2026-10-13 | trivial | PAGE fields after a page break inside their paragraph, or on a page the paragraph runs onto, show that page's number (#1352) | | 2026-10-12 | trivial | Spaces, tabs and ideographic spaces don't count toward a line's height, as in Word (a line of only them takes the paragraph mark's) | | 2026-10-12 | trivial | A list label's font raises the first line's ascent but never its descent (Word keeps the text's descent below the baseline) |