diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1c0493353..32975b74c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4269,6 +4269,41 @@ follow semantic versioning; release dates are ISO 8601.
### Tests
+- **The DOCX fidelity corpus holds three shape containers in the body, as the export writes them
+ today.**
+ - Three documents join `SyntheticDocxCorpus`, each a rounded shape container holding text,
+ between a paragraph above it and one under it:
+ - `narrow_container`: a note set left in a block centred in a box 220pt wide, which the page
+ wraps over three lines inside it;
+ - `clipped_container`: a box 60pt tall, clipped to its outline, holding 84pt of text, which
+ the page cuts at the box's foot;
+ - `rounded_card`: a card as wide as the page between its margins, its heading and text
+ filling it.
+ - Measured in Word 16 and in LibreOffice 24.2 and 26.8, which set the three alike. The export
+ draws each outline at its size, where the page draws it, and writes its text in the flow,
+ held in from the edges of the block the container stands in rather than from the outline's,
+ so the right edge of its room stands past the outline:
+ - the narrow box's note runs over two lines instead of three, up to 95pt past the box's right
+ edge, and the paragraph under the box stands 12pt high, its first line reaching 4pt into
+ the box;
+ - the clipped box's text is written whole, none of it cut, up to 124pt past the box, and the
+ paragraph under it stands 20pt high, inside the box;
+ - the card stands where the page sets it, every line within 0.1pt. Text added to it in Word
+ runs past its foot: the outline keeps its height, the card's text runs over seven lines to
+ 22pt below it, and the paragraph under it moves down 36pt.
+ - The baselines record the three as they stand. Of the narrow box and the clipped box, the
+ gate holds the lines the editors set at the page's words — the paragraph above the box, and
+ the paragraph under it, 12 and 20pt high — and none of the text inside the box, which they
+ set at other words. A change that writes a container's text inside its outline finds that
+ text and moves the paragraph under each box nearer the page, and rewrites their rows. The
+ card, which the export sets where the page does today, holds such a change to keep it there.
+ - The gate measures lines of text, not outlines. It does not see whether the text stays inside
+ the outline, or whether the card grows when text is added to it. Word's editing protocol
+ (`edit-protocol-corpus.ps1`) does not either: it passes all three, since the paragraph it
+ lengthens grows and still ends above the paragraph under it, past the outline as it is.
+ - Each baseline takes the three documents' rows alone, from the run of its editor — Linux's
+ from CI's.
+
- **Every page reference a DOCX export writes names a bookmark the file holds.**
- `DocxPageReferenceGuardTest` reads each `PAGEREF` field, bookmark and paragraph from every XML
part of the exported file — the body, its headers and footers, nested tables and text boxes.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 20a926b57..9db84b2da 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -357,7 +357,10 @@ Choose the smallest tests that match the change:
`-Dgraphcompose.docxFidelity.update=true`, and commits it with the change: its diff shows
which documents moved. A new preset joins the corpus in its family's `*DocxCorpus` class,
and so does a preset on a longer fixture; a shape no preset has — a page break inside a
- panel, a break in a row's column — goes in `SyntheticDocxCorpus`.
+ panel, a break in a row's column, a shape container narrower than the block it stands in
+ or clipped short of its text — goes in `SyntheticDocxCorpus`. Its baseline holds it as
+ the editors set it, a defect of the export included, and the change fixing that rewrites
+ its rows nearer the page.
CI runs it on Linux (the `DOCX Fidelity` job) against `libreoffice-linux.tsv`, and uploads
what it measured: LibreOffice sets text a little differently per platform, so a change that
moves documents nearer the page takes that artifact's files as the Linux baseline, and its own
diff --git a/docs/recipes/docx-export.md b/docs/recipes/docx-export.md
index 925b72e5a..9d0408a70 100644
--- a/docs/recipes/docx-export.md
+++ b/docs/recipes/docx-export.md
@@ -308,7 +308,9 @@ paragraph is the picture's block, and a list's edges go to the paragraphs around
`itemSpacing` as the gap above each item after the first. A list's left and right edges —
its margin and padding — indent its items, the level's own indent added on top, so its
markers start where the page starts them. A paragraph's and a list's sides hold under a
-layer stack or a shape container too, inside the box that places the layer. In a cell, two
+layer stack or a shape container too, inside the box that places the layer — but not in a
+shape container narrower than the block it stands in, whose layers' room runs past its
+right edge (see "Shape containers → inline layers"). In a cell, two
points of a side stay the editor's, to set a line a little wider than the page: off the
side a left-to-right line does not lean on, so it keeps the edge it is set from — the right
of a left-aligned paragraph and of a list, the left of a right-aligned one, both of a
@@ -1103,9 +1105,14 @@ recolour what is under it in Word and it keeps the colour it was flattened to.
margin opening a band stood 20pt high, and one in a later layer 7pt. A badge — a ring,
drawn, with initials centred
in it, over a spacer that keeps its place in the flow — writes its initials where
- the ring centres them and keeps its height below them. Each layer, here and in a
- shape container, is held in across to its box in the stack, with a few points to
- spare on the side its text does not lean on. A block in `addAligned(...)` is held in
+ the ring centres them and keeps its height below them. Each layer is held in across
+ to its box in the stack, with a few points to spare on the side its text does not
+ lean on. A shape container's layers are held in by as far as their box stands in
+ from the container's edges, but from the edges of the block the container stands
+ in, set in by its margin and padding: in a container narrower than that block the
+ right edge of their room runs that much further right, past its outline, so text
+ that wraps runs past the outline and centred or right-aligned text stands right of
+ where the page sets it (see "Shape containers → inline layers"). A block in `addAligned(...)` is held in
the same way, to where the alignment puts it — composed in a table cell, a paragraph
where the lines its table laid out for it stand and a picture where the alignment sets
one of its written width; any other block there, or one inside a panel or another table
@@ -1162,7 +1169,16 @@ recolour what is under it in Word and it keeps the colour it was flattened to.
- **Shape containers → inline layers.** DOCX has no portable equivalent of
a graphics-state path clip, so the container's layers are written
inline, in source order, without clipping — again with one warning per
- export, and a note on each container that writes a layer in the flow. A
+ export, and a note on each container that writes a layer in the flow.
+ The outline is drawn at its size and does not grow with what is written
+ in the flow, and the layers take the room of the flow, not of the
+ outline. Measured in Word and LibreOffice: a note the page wraps over
+ three lines inside a box 220pt wide runs over two, up to 95pt past the
+ box; a clipped box's text is written whole, past its outline; the block
+ under a container stands where the flow puts it, over the outline where
+ its layers are written shorter than the page sets them — 12pt high under
+ the narrow box, 20pt under the clipped one. In Word, text added to a card
+ runs past its foot, the outline keeping its height. A
container whose layers are all drawn — a tile, an icon, a badge holding
its glyph — writes none: each layer is drawn where the page draws it, in
the order the page stacks them, by their z-index. Word stacks drawings by
diff --git a/qa/src/test/java/com/demcha/compose/document/templates/fidelity/SyntheticDocxCorpus.java b/qa/src/test/java/com/demcha/compose/document/templates/fidelity/SyntheticDocxCorpus.java
index 312790222..c40fc9dc7 100644
--- a/qa/src/test/java/com/demcha/compose/document/templates/fidelity/SyntheticDocxCorpus.java
+++ b/qa/src/test/java/com/demcha/compose/document/templates/fidelity/SyntheticDocxCorpus.java
@@ -4,9 +4,12 @@
import com.demcha.compose.document.api.PageMarginRule;
import com.demcha.compose.document.dsl.ParagraphBuilder;
import com.demcha.compose.document.dsl.SectionBuilder;
+import com.demcha.compose.document.node.ParagraphNode;
+import com.demcha.compose.document.style.ClipPolicy;
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.DocumentTextDecoration;
import com.demcha.compose.document.style.DocumentTextStyle;
import com.demcha.compose.document.table.DocumentTableColumn;
import com.demcha.compose.document.table.DocumentTableStyle;
@@ -19,15 +22,28 @@
* Documents of the DOCX fidelity corpus built for a shape no template preset has on its own
* fixture, so that an editor setting one off the page fails the gate as a preset would.
*
- *
Each sets a way the page breaks inside a panel or a column: a page break among a panel's
+ *
Three set a way the page breaks inside a panel or a column: a page break among a panel's
* children and inside a panel nested in it, page breaks the page sets as boxes of no height in a
* row's column and in a stack's layer, and a card whose table the layout runs over three pages,
- * with other margins from the second. Their text is set in a face the export embeds, so both
- * editors break its lines at the page's words.
+ * with other margins from the second. Three others set a shape container holding text in the
+ * body: a box narrower than the page, a box clipped to its outline, and a card. Their text is
+ * set in a face the export embeds, so both editors break at the page's words the lines they
+ * set at the page's width.
+ *
+ * The baselines hold the shape containers as the export writes them now, with their text
+ * past the outline: Word and LibreOffice set the narrow box's note and the clipped box's text
+ * wider than the box, at other words, which the gate therefore does not hold, and the paragraph
+ * under each box 12 and 20pt high. A change that writes the text inside the outline finds it,
+ * moves the paragraph under each box nearer the page, and rewrites their rows. The card, which
+ * the export sets where the page does, holds such a change to keep it there. The gate reads
+ * lines of text only: whether the text stays inside the outline, and whether the card grows
+ * when text is added to it in an editor, it does not see.
*/
final class SyntheticDocxCorpus {
private static final DocumentTextStyle TEXT = DocumentTextStyle.builder().fontName(FontName.LATO).size(10).build();
+ private static final DocumentTextStyle HEADING = DocumentTextStyle.builder().fontName(FontName.LATO).size(12)
+ .decoration(DocumentTextDecoration.BOLD).build();
private static final DocumentTableStyle CELLS = DocumentTableStyle.builder().textStyle(TEXT).build();
private static final DocumentColor SURFACE = DocumentColor.rgb(238, 243, 249);
private static final DocumentColor INNER = DocumentColor.rgb(224, 233, 244);
@@ -42,7 +58,69 @@ static List documents() {
return List.of(
synthetic("break_in_panel", SyntheticDocxCorpus::breakInAPanel),
synthetic("break_in_column", SyntheticDocxCorpus::breakInAColumn),
- synthetic("card_over_pages", SyntheticDocxCorpus::cardOverPages));
+ synthetic("card_over_pages", SyntheticDocxCorpus::cardOverPages),
+ synthetic("narrow_container", SyntheticDocxCorpus::narrowContainer),
+ synthetic("clipped_container", SyntheticDocxCorpus::clippedContainer),
+ synthetic("rounded_card", SyntheticDocxCorpus::roundedCard));
+ }
+
+ /**
+ * A rounded box narrower than the page between a paragraph above it and one under it, its
+ * note set left in a block centred in the box and wrapped over three lines inside it.
+ */
+ private static void narrowContainer(DocumentSession session) {
+ session.pageSize(400, 500).margin(MARGIN);
+ session.pageFlow(page -> page.spacing(8)
+ .addParagraph(p -> text(p, "Before the box, on a line of its own."))
+ .addContainer(box -> box.roundedRect(220, 90, 10).fillColor(SURFACE).stroke(DocumentStroke.of(INK, 1))
+ .clipPolicy(ClipPolicy.OVERFLOW_VISIBLE)
+ .center(paragraph("A note centred in a box narrower than the page: the page wraps "
+ + "it over three lines inside the box, each line held within "
+ + "its outline.")))
+ .addParagraph(p -> text(p, "After the box: this paragraph stands under it on the page, "
+ + "and none of its lines runs over the box.")));
+ }
+
+ /**
+ * A rounded box clipped to its outline, holding more text than it has room for: the page
+ * centres the text across the box, sets it from the box's top, as it is taller than the box,
+ * and cuts the lines that run past its foot. A paragraph stands above the box and one under
+ * it.
+ */
+ private static void clippedContainer(DocumentSession session) {
+ session.pageSize(400, 500).margin(MARGIN);
+ session.pageFlow(page -> page.spacing(8)
+ .addParagraph(p -> text(p, "Before the clipped box, on a line of its own."))
+ .addContainer(box -> box.roundedRect(200, 60, 12).fillColor(SURFACE).stroke(DocumentStroke.of(INK, 1))
+ .clipPolicy(ClipPolicy.CLIP_PATH)
+ .center(paragraph("Clipped text in a rounded box too short to hold it. The page "
+ + "sets it from the top of the box and cuts it at the outline, so "
+ + "the lines that run past the foot of the box are not seen. Only "
+ + "the lines the box holds are read, and the box stays as tall as "
+ + "it was made, whatever it is given to hold.")))
+ .addParagraph(p -> text(p, "After the clipped box: this paragraph stands under it on the page, "
+ + "and none of its lines runs over the box.")));
+ }
+
+ /**
+ * A rounded card as wide as the page between its margins, its heading and text set from its
+ * top left corner and filling it, under its default clip, between a paragraph above it and
+ * one under it. Text added to the card in an editor needs it taller.
+ */
+ private static void roundedCard(DocumentSession session) {
+ session.pageSize(400, 500).margin(MARGIN);
+ session.pageFlow(page -> page.spacing(8)
+ .addParagraph(p -> text(p, "Before the card, on a line of its own."))
+ .addContainer(card -> card.roundedRect(328, 80, 12).fillColor(SURFACE).stroke(DocumentStroke.of(INK, 1))
+ .topLeft(new SectionBuilder().padding(DocumentInsets.of(12)).spacing(4)
+ .addParagraph(p -> p.text("A rounded card").textStyle(HEADING))
+ .addParagraph(p -> text(p, "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."))
+ .build()))
+ .addParagraph(p -> text(p, "After the card: this paragraph stands under it on the page, "
+ + "and none of its lines runs over the card.")));
}
/**
@@ -123,6 +201,10 @@ private static ParagraphBuilder text(ParagraphBuilder paragraph, String text) {
return paragraph.text(text).textStyle(TEXT);
}
+ private static ParagraphNode paragraph(String text) {
+ return text(new ParagraphBuilder(), text).build();
+ }
+
private static DocxCorpusDocument synthetic(String name, Consumer compose) {
return new DocxCorpusDocument("synthetic", name, -1, compose);
}
diff --git a/qa/src/test/resources/docx-fidelity/libreoffice-linux-lines.tsv b/qa/src/test/resources/docx-fidelity/libreoffice-linux-lines.tsv
index 5d236505f..b9cfbdfb8 100644
--- a/qa/src/test/resources/docx-fidelity/libreoffice-linux-lines.tsv
+++ b/qa/src/test/resources/docx-fidelity/libreoffice-linux-lines.tsv
@@ -1,5 +1,6 @@
# libreoffice build 420(Build:2) on linux — document, line, drift below the page (pt), drift right of the page (pt), letters
# rows of invoice-metered_long, invoice-obsidian_long, synthetic-break_in_column, synthetic-break_in_panel, synthetic-card_over_pages: libreoffice build 420(Build:2) on linux
+# rows of synthetic-clipped_container, synthetic-narrow_container, synthetic-rounded_card: libreoffice build 420(Build:2) on linux
cv-blue_banner 0:8f1010120ed6 0.02 1.90 jordanrivera
cv-blue_banner 0:8d7a2cca3060 0.00 0.14 +442055551000|jordan.rivera@exam
cv-blue_banner 0:b944906ed84c -0.20 -0.38 professionalsummary
@@ -5122,3 +5123,16 @@ synthetic-card_over_pages 2:1c49f22f6de9 1.08 7.10 413
synthetic-card_over_pages 2:f69c59b028ea 1.08 7.10 lineitem60
synthetic-card_over_pages 2:db55da3fc309 1.08 7.10 420
synthetic-card_over_pages 2:8c569b972e01 1.08 0.10 afterthecard,onitslastpage.
+synthetic-clipped_container 0:cbe6ee14976b -0.02 0.10 beforetheclippedbox,onalineofits
+synthetic-clipped_container 0:2633ce73dc24 -20.02 0.10 aftertheclippedbox:thisparagraph
+synthetic-clipped_container 0:667f8b3b3eff -20.02 0.10 noneofitslinesrunsoverthebox.
+synthetic-narrow_container 0:fa13cab3fe73 -0.02 0.10 beforethebox,onalineofitsown.
+synthetic-narrow_container 0:697e6629574d -12.02 0.10 afterthebox:thisparagraphstandsu
+synthetic-narrow_container 0:0efb534ce6c6 -12.02 0.10 linesrunsoverthebox.
+synthetic-rounded_card 0:2a3c79dd9054 -0.02 0.10 beforethecard,onalineofitsown.
+synthetic-rounded_card 0:b8608d77afb0 0.01 0.10 aroundedcard
+synthetic-rounded_card 0:bcb0465dee5d -0.02 0.10 itstextrunsoverthreelinesfromthe
+synthetic-rounded_card 0:73c347391d3b -0.02 0.10 cardisjusttallenoughtoholdthemwi
+synthetic-rounded_card 0:8993a52a9026 -0.02 0.10 linemore,andthecardneedstobetall
+synthetic-rounded_card 0:103d88aab213 -0.02 0.10 afterthecard:thisparagraphstands
+synthetic-rounded_card 0:66b11b97a20e -0.02 0.10 linesrunsoverthecard.
diff --git a/qa/src/test/resources/docx-fidelity/libreoffice-linux.tsv b/qa/src/test/resources/docx-fidelity/libreoffice-linux.tsv
index 5e7dc704d..7f45a925d 100644
--- a/qa/src/test/resources/docx-fidelity/libreoffice-linux.tsv
+++ b/qa/src/test/resources/docx-fidelity/libreoffice-linux.tsv
@@ -1,6 +1,7 @@
# libreoffice build 420(Build:2) on linux
document engine_pages editor_pages lines matched median p90 over2
# rows of invoice-metered_long, invoice-obsidian_long, synthetic-break_in_column, synthetic-break_in_panel, synthetic-card_over_pages: libreoffice build 420(Build:2) on linux
+# rows of synthetic-clipped_container, synthetic-narrow_container, synthetic-rounded_card: libreoffice build 420(Build:2) on linux
cv-blue_banner 2 2 54 52 0.16 0.25 0
cv-boxed_sections 2 2 58 58 0.06 0.11 0
cv-centered_headline 2 2 58 56 0.12 0.29 0
@@ -68,3 +69,6 @@ rota-cobalt 1 1 154 151 0.22 0.47 0
synthetic-break_in_column 1 1 7 7 0.02 0.02 0
synthetic-break_in_panel 3 3 8 8 3.02 5.02 5
synthetic-card_over_pages 3 3 114 114 0.98 1.08 0
+synthetic-clipped_container 1 1 10 3 20.02 20.02 2
+synthetic-narrow_container 1 1 6 3 12.02 12.02 2
+synthetic-rounded_card 1 1 7 7 0.02 0.02 0
diff --git a/qa/src/test/resources/docx-fidelity/libreoffice-windows-lines.tsv b/qa/src/test/resources/docx-fidelity/libreoffice-windows-lines.tsv
index 5daddd68d..4c367377a 100644
--- a/qa/src/test/resources/docx-fidelity/libreoffice-windows-lines.tsv
+++ b/qa/src/test/resources/docx-fidelity/libreoffice-windows-lines.tsv
@@ -1,5 +1,6 @@
# libreoffice build bf6ef2662401 on windows — document, line, drift below the page (pt), drift right of the page (pt), letters
# rows of invoice-metered_long, invoice-obsidian_long, synthetic-break_in_column, synthetic-break_in_panel, synthetic-card_over_pages: libreoffice build bf6ef2662401 on windows
+# rows of synthetic-clipped_container, synthetic-narrow_container, synthetic-rounded_card: libreoffice build bf6ef2662401 on windows
cv-blue_banner 0:8f1010120ed6 0.02 1.95 jordanrivera
cv-blue_banner 0:8d7a2cca3060 0.00 0.24 +442055551000|jordan.rivera@exam
cv-blue_banner 0:b944906ed84c -0.20 -0.38 professionalsummary
@@ -5016,3 +5017,16 @@ synthetic-card_over_pages 2:1c49f22f6de9 1.08 0.60 413
synthetic-card_over_pages 2:f69c59b028ea 1.08 0.60 lineitem60
synthetic-card_over_pages 2:db55da3fc309 1.08 0.60 420
synthetic-card_over_pages 2:8c569b972e01 1.08 0.10 afterthecard,onitslastpage.
+synthetic-clipped_container 0:cbe6ee14976b -0.02 0.10 beforetheclippedbox,onalineofits
+synthetic-clipped_container 0:2633ce73dc24 -20.02 0.10 aftertheclippedbox:thisparagraph
+synthetic-clipped_container 0:667f8b3b3eff -20.02 0.10 noneofitslinesrunsoverthebox.
+synthetic-narrow_container 0:fa13cab3fe73 -0.02 0.10 beforethebox,onalineofitsown.
+synthetic-narrow_container 0:697e6629574d -12.02 0.10 afterthebox:thisparagraphstandsu
+synthetic-narrow_container 0:0efb534ce6c6 -12.02 0.10 linesrunsoverthebox.
+synthetic-rounded_card 0:2a3c79dd9054 -0.02 0.10 beforethecard,onalineofitsown.
+synthetic-rounded_card 0:b8608d77afb0 0.01 0.10 aroundedcard
+synthetic-rounded_card 0:bcb0465dee5d -0.02 0.10 itstextrunsoverthreelinesfromthe
+synthetic-rounded_card 0:73c347391d3b -0.02 0.10 cardisjusttallenoughtoholdthemwi
+synthetic-rounded_card 0:8993a52a9026 -0.02 0.10 linemore,andthecardneedstobetall
+synthetic-rounded_card 0:103d88aab213 -0.02 0.10 afterthecard:thisparagraphstands
+synthetic-rounded_card 0:66b11b97a20e -0.02 0.10 linesrunsoverthecard.
diff --git a/qa/src/test/resources/docx-fidelity/libreoffice-windows.tsv b/qa/src/test/resources/docx-fidelity/libreoffice-windows.tsv
index 61faf3cd6..3c6facd2e 100644
--- a/qa/src/test/resources/docx-fidelity/libreoffice-windows.tsv
+++ b/qa/src/test/resources/docx-fidelity/libreoffice-windows.tsv
@@ -1,6 +1,7 @@
# libreoffice build bf6ef2662401 on windows
document engine_pages editor_pages lines matched median p90 over2
# rows of invoice-metered_long, invoice-obsidian_long, synthetic-break_in_column, synthetic-break_in_panel, synthetic-card_over_pages: libreoffice build bf6ef2662401 on windows
+# rows of synthetic-clipped_container, synthetic-narrow_container, synthetic-rounded_card: libreoffice build bf6ef2662401 on windows
cv-blue_banner 2 2 54 52 0.16 0.25 0
cv-boxed_sections 2 2 58 58 0.06 0.11 0
cv-centered_headline 2 2 58 56 0.12 0.29 0
@@ -68,3 +69,6 @@ rota-cobalt 1 1 154 151 0.03 0.19 0
synthetic-break_in_column 1 1 7 7 0.02 0.02 0
synthetic-break_in_panel 3 3 8 8 3.02 5.02 5
synthetic-card_over_pages 3 3 114 114 0.98 1.08 0
+synthetic-clipped_container 1 1 10 3 20.02 20.02 2
+synthetic-narrow_container 1 1 6 3 12.02 12.02 2
+synthetic-rounded_card 1 1 7 7 0.02 0.02 0
diff --git a/qa/src/test/resources/docx-fidelity/word-windows-lines.tsv b/qa/src/test/resources/docx-fidelity/word-windows-lines.tsv
index b6aef8192..9309fe866 100644
--- a/qa/src/test/resources/docx-fidelity/word-windows-lines.tsv
+++ b/qa/src/test/resources/docx-fidelity/word-windows-lines.tsv
@@ -1,5 +1,6 @@
# word 16.0 (16.0.20430) on windows — document, line, drift below the page (pt), drift right of the page (pt), letters
# rows of invoice-metered_long, invoice-obsidian_long, synthetic-break_in_column, synthetic-break_in_panel, synthetic-card_over_pages: word 16.0 (16.0.20527) on windows
+# rows of synthetic-clipped_container, synthetic-narrow_container, synthetic-rounded_card: word 16.0 (16.0.20527) on windows
cv-blue_banner 0:8f1010120ed6 -0.02 -0.08 jordanrivera
cv-blue_banner 0:8d7a2cca3060 0.00 -0.07 +442055551000|jordan.rivera@exam
cv-blue_banner 0:b944906ed84c -0.21 -1.21 professionalsummary
@@ -5136,3 +5137,16 @@ synthetic-card_over_pages 2:1c49f22f6de9 1.12 -36.37 413
synthetic-card_over_pages 2:f69c59b028ea 1.16 0.58 lineitem60
synthetic-card_over_pages 2:db55da3fc309 1.16 -36.37 420
synthetic-card_over_pages 2:8c569b972e01 1.11 0.00 afterthecard,onitslastpage.
+synthetic-clipped_container 0:cbe6ee14976b -0.01 0.02 beforetheclippedbox,onalineofits
+synthetic-clipped_container 0:2633ce73dc24 -19.97 0.02 aftertheclippedbox:thisparagraph
+synthetic-clipped_container 0:667f8b3b3eff -19.97 0.02 noneofitslinesrunsoverthebox.
+synthetic-narrow_container 0:fa13cab3fe73 -0.01 0.02 beforethebox,onalineofitsown.
+synthetic-narrow_container 0:697e6629574d -12.02 0.02 afterthebox:thisparagraphstandsu
+synthetic-narrow_container 0:0efb534ce6c6 -12.02 0.02 linesrunsoverthebox.
+synthetic-rounded_card 0:2a3c79dd9054 -0.01 0.02 beforethecard,onalineofitsown.
+synthetic-rounded_card 0:b8608d77afb0 0.10 0.02 aroundedcard
+synthetic-rounded_card 0:bcb0465dee5d -0.01 0.02 itstextrunsoverthreelinesfromthe
+synthetic-rounded_card 0:73c347391d3b -0.01 0.02 cardisjusttallenoughtoholdthemwi
+synthetic-rounded_card 0:8993a52a9026 -0.01 0.02 linemore,andthecardneedstobetall
+synthetic-rounded_card 0:103d88aab213 0.02 0.02 afterthecard:thisparagraphstands
+synthetic-rounded_card 0:66b11b97a20e 0.02 0.02 linesrunsoverthecard.
diff --git a/qa/src/test/resources/docx-fidelity/word-windows.tsv b/qa/src/test/resources/docx-fidelity/word-windows.tsv
index 21232840a..526ad56ed 100644
--- a/qa/src/test/resources/docx-fidelity/word-windows.tsv
+++ b/qa/src/test/resources/docx-fidelity/word-windows.tsv
@@ -1,6 +1,7 @@
# word 16.0 (16.0.20430) on windows
document engine_pages editor_pages lines matched median p90 over2
# rows of invoice-metered_long, invoice-obsidian_long, synthetic-break_in_column, synthetic-break_in_panel, synthetic-card_over_pages: word 16.0 (16.0.20527) on windows
+# rows of synthetic-clipped_container, synthetic-narrow_container, synthetic-rounded_card: word 16.0 (16.0.20527) on windows
cv-blue_banner 2 2 54 52 0.10 0.23 0
cv-boxed_sections 2 2 58 58 0.12 0.21 0
cv-centered_headline 2 2 58 56 0.12 0.25 0
@@ -68,3 +69,6 @@ rota-cobalt 1 1 154 154 0.14 0.26 0
synthetic-break_in_column 1 1 7 7 0.03 0.03 0
synthetic-break_in_panel 3 3 8 8 0.95 0.99 0
synthetic-card_over_pages 3 3 114 114 1.03 1.15 0
+synthetic-clipped_container 1 1 10 3 19.97 19.97 2
+synthetic-narrow_container 1 1 6 3 12.02 12.02 2
+synthetic-rounded_card 1 1 7 7 0.01 0.02 0