From 1af130c520a323574f84fb77895676b149a64640 Mon Sep 17 00:00:00 2001 From: DemchaAV Date: Mon, 26 Oct 2026 23:45:20 +0000 Subject: [PATCH 1/2] test(docx): hold a body card whose text fills it to grow with that text A painted box holding text in the body is written as a panel whose row is held at least its outline's height, so it grows when text is added to it in an editor. DocxBodyShapePanelTest held that rule only on boxes whose text leaves room to spare. A change writing exact only the row of a box its text fills, at the height a clip that cuts is written at, was seen by no test: in Word every line of the corpus card stood where it stood, in LibreOffice 24.2 the paragraph under it moved nearer the page, and the card no longer grew. The new case holds a card a quarter of a point taller than its text, as the page lays it out, to an at-least row. --- CHANGELOG.md | 8 +++++ .../semantic/docx/DocxBodyShapePanelTest.java | 36 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d28df7c99..cfd88fb37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4313,6 +4313,14 @@ follow semantic versioning; release dates are ISO 8601. ### Tests +- **A body card whose text fills its outline is held to grow with that text.** The fidelity gates + measure where lines stand. Were such a card's row written exactly as tall as its outline, every + line of it in Word would stand where it stood, the paragraph under it in LibreOffice 24.2 would + stand nearer the page, and the card would not grow when text is added to it in an editor. + `DocxBodyShapePanelTest` now holds a card whose text fills it to within a quarter of a point, + under its default clip, which cuts nothing: its row is held at least its outline's height, as is + the row of a card with room to spare. + - **The DOCX fidelity corpus holds its three body shape containers where the export now sets them.** With the boxes written as panels, Word and LibreOffice set every line of `narrow_container` and `rounded_card` at the page's words, and Word the paragraph under each box diff --git a/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxBodyShapePanelTest.java b/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxBodyShapePanelTest.java index 65ce5663c..b79eb9033 100644 --- a/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxBodyShapePanelTest.java +++ b/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxBodyShapePanelTest.java @@ -17,6 +17,7 @@ import com.demcha.compose.document.style.DocumentColor; import com.demcha.compose.document.style.DocumentInsets; import com.demcha.compose.document.style.DocumentStroke; +import com.demcha.compose.document.style.DocumentTextStyle; import com.demcha.compose.document.style.DocumentTransform; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; @@ -360,6 +361,29 @@ void aBoxWithNoClipOrNothingToCutGrowsWithItsText() throws Exception { + "them, and what follows stands up to that much lower"); } + @Test + void aCardItsTextFillsGrowsWithItsTextAsOneWithRoomToSpare() throws Exception { + // Its default clip has nothing to cut, though its text fills it. Were its row held exactly at + // its outline's height, every line in Word would stand where it stood, and in LibreOffice 24.2 + // the paragraph under it would stand nearer the page; the card would not grow when text is + // added to it. The fidelity gates, which measure lines, would not see that. + // The card just tall enough to hold its text, as the page lays it out. + double outline = export(page -> page.add(pageWideCard(200).build())).placed("Text").placementHeight() + 0.25; + Exported exported = export(page -> page + .addParagraph("Above") + .add(pageWideCard(outline).build()) + .addParagraph("Below")); + + PlacedNode box = exported.placed("Box"); + PlacedNode text = exported.placed("Text"); + // The page leaves less than half a point between the foot of its text's padding and the outline's. + assertThat(text.placementY() - box.placementY()).isBetween(0.0, 0.5); + XWPFTableRow row = onlyTable(exported.document()).getRow(0); + assertThat(ruleOf(row)).isEqualTo(STHeightRule.AT_LEAST); + assertThat(heightOf(row)).isEqualTo(Math.round(outline * 20) - 2 * 20); + assertThat(exported.report().bySubject()).doesNotContainKeys("clipped shape container", "shape container"); + } + @Test void itsPaddingStandsRoundTheOutline() throws Exception { Exported exported = export(page -> page @@ -436,6 +460,18 @@ private static ShapeContainerBuilder card(ClipPolicy clip) { .build()); } + /** A card as wide as the page between its margins, holding a heading and a paragraph. */ + private static ShapeContainerBuilder pageWideCard(double height) { + return new ShapeContainerBuilder().name("Box").roundedRect(328, height, 12).fillColor(SURFACE).stroke(BORDER) + .topLeft(new SectionBuilder().name("Text").padding(DocumentInsets.of(12)).spacing(4) + .addParagraph(p -> p.text("A rounded card").textStyle(DocumentTextStyle.builder().size(12).build())) + .addParagraph(p -> p.text("Its text runs over three lines from the card's top left corner, " + + "and the card is just tall enough to hold them with its padding " + + "round them: a line more, and the card needs to be taller.") + .textStyle(DocumentTextStyle.builder().size(10).build())) + .build()); + } + private static DocumentNode note() { return new ParagraphBuilder().name("Note").text(NOTE).build(); } From 21be04e36147225e75264c15d81990a53ed4aa78 Mon Sep 17 00:00:00 2001 From: DemchaAV Date: Tue, 27 Oct 2026 00:01:03 +0000 Subject: [PATCH 2/2] test(docx): fail the full-card case closed and word it exactly The case asserts that the first layout sets the card's text at its own height, not the taller card's: otherwise the card would be no fuller than its text leaves it. Its comment and the CHANGELOG entry say the card's text and padding fill it, and leave out a prediction of what LibreOffice would do. --- CHANGELOG.md | 6 +++--- .../backend/semantic/docx/DocxBodyShapePanelTest.java | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfd88fb37..20de0d8a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4317,9 +4317,9 @@ follow semantic versioning; release dates are ISO 8601. measure where lines stand. Were such a card's row written exactly as tall as its outline, every line of it in Word would stand where it stood, the paragraph under it in LibreOffice 24.2 would stand nearer the page, and the card would not grow when text is added to it in an editor. - `DocxBodyShapePanelTest` now holds a card whose text fills it to within a quarter of a point, - under its default clip, which cuts nothing: its row is held at least its outline's height, as is - the row of a card with room to spare. + `DocxBodyShapePanelTest` now holds a card whose text and padding fill it to within a quarter of a + point, under its default clip, which cuts nothing: its row is held at least its outline's height, + as is the row of a card with room to spare. - **The DOCX fidelity corpus holds its three body shape containers where the export now sets them.** With the boxes written as panels, Word and LibreOffice set every line of diff --git a/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxBodyShapePanelTest.java b/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxBodyShapePanelTest.java index b79eb9033..b521da205 100644 --- a/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxBodyShapePanelTest.java +++ b/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxBodyShapePanelTest.java @@ -363,12 +363,13 @@ void aBoxWithNoClipOrNothingToCutGrowsWithItsText() throws Exception { @Test void aCardItsTextFillsGrowsWithItsTextAsOneWithRoomToSpare() throws Exception { - // Its default clip has nothing to cut, though its text fills it. Were its row held exactly at - // its outline's height, every line in Word would stand where it stood, and in LibreOffice 24.2 - // the paragraph under it would stand nearer the page; the card would not grow when text is - // added to it. The fidelity gates, which measure lines, would not see that. - // The card just tall enough to hold its text, as the page lays it out. + // Its default clip has nothing to cut, though its text and padding fill it, so its row is held + // at least its outline's height and grows with text added to it. Held exactly at that height, + // it would set its lines where they stand in Word, and the fidelity gates, which measure + // lines, would not see that it no longer grows. Here it is a quarter of a point taller than + // its text and padding, as the page lays them out in a taller card. double outline = export(page -> page.add(pageWideCard(200).build())).placed("Text").placementHeight() + 0.25; + assertThat(outline).as("the text laid out at its own height, not the card's").isLessThan(200); Exported exported = export(page -> page .addParagraph("Above") .add(pageWideCard(outline).build())