diff --git a/CHANGELOG.md b/CHANGELOG.md index bfe39695e..6c70ee8c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,16 @@ follow semantic versioning; release dates are ISO 8601. ### Public API +- **A row's fixed columns keep their widths in DOCX when they add up to less than the row.** + The last column ran to the row's edge: `EditorialProposal`'s deliverables, a 194pt column in a + 535pt band, came out 272pt wide, and Word set "Responsive design for desktop, tablet & mobile" + on one line where the page wraps it, and every item under it a line higher. The scope of work's + descriptions and `PaymentsInvoice`'s item text, both the last of a row's fixed columns, wrapped + later than the page the same way. The last column now keeps its stated width, and the table is + no wider than its columns. In Word, + `EditorialProposal` finds 128 of its 132 lines where it found 120, and those more than 2pt off + fall from 22 to 19; `PaymentsInvoice` finds 104 of 104, none past 2pt, where it found 100. + - **`MidnightNavy`'s sidebar stands where the page sets it in Word.** Three causes, each its own: - Its monogram centres two initials in a 76pt ring, two layers of one shape container. Only a container of one layer was set in from its outline, so the initials were written from the diff --git a/docs/recipes/docx-export.md b/docs/recipes/docx-export.md index ae7d3c722..f682332dc 100644 --- a/docs/recipes/docx-export.md +++ b/docs/recipes/docx-export.md @@ -74,7 +74,7 @@ creation date is real metadata. | Inline chips (`inlineCode(...)`, `inlineChip(...)`, `highlight(...)`) | The chip's fill becomes the run's own `w:shd`, in a paragraph and in a list item alike. Its shape does not travel — see "What a chip keeps and loses" below | | Images | Embedded pictures at the node's declared size | | Links and anchors | A `linkTarget` becomes a `w:hyperlink` — a relationship for an address, `w:anchor` for one of the document's own anchors — and a run's own link wins over the paragraph's — in a list item as much as in a paragraph. An `anchor(...)` becomes a bookmark wrapping that paragraph's text, named as Word requires; on a section, container, table or image it wraps everything the block wrote, from the start of its first paragraph to the end of its last, so a link to a block lands on its first line. A `bookmark(...)` outline level becomes Word's own `HeadingN` style, which is what puts the paragraph in the Navigation Pane, the outline view and a generated table of contents. The style states the outline level and nothing else, so the paragraph keeps its own formatting. The role comes from what the document declared, never from how big the text is | -| Rows | A one-row table spanning the content width, so editors keep the side-by-side layout. The row's slots become the column grid when they are weights, an even split or fixed columns; the gap and the row's padding ride in the neighbouring column and come back out as that cell's margin; a cell holds whatever its child is, written as it is anywhere else. The row's `verticalAlign` is every cell's `w:vAlign`, so a child shorter than the row sits at its middle or bottom as on the page — a table of contents' leader on its entry's baseline. The row is kept whole across a page break, as the layout keeps it. A row is held at least as tall as the page makes it inside a painted panel, and anywhere its tallest child is a drawing Word holds nothing of in its cell — a badge beside a heading. A section or other container in any cell — a row's, a table's, a panel's — that pulls its first line up with a negative top edge writes that one-line paragraph as much shorter, its text seated where the page sets it — no more than the room above its letters, as Word draws an exact line's text only inside the line | +| Rows | A one-row table spanning the content width — or only its columns, where fixed columns leave part of the row empty — so editors keep the side-by-side layout. The row's slots become the column grid when they are weights, an even split or fixed columns; fixed columns that add up to less than the row leave the rest of it empty, the last one at its own width and the table no wider than its columns, so its text wraps where the page wraps it; the gap and the row's padding ride in the neighbouring column and come back out as that cell's margin; a cell holds whatever its child is, written as it is anywhere else. The row's `verticalAlign` is every cell's `w:vAlign`, so a child shorter than the row sits at its middle or bottom as on the page — a table of contents' leader on its entry's baseline. The row is kept whole across a page break, as the layout keeps it. A row is held at least as tall as the page makes it inside a painted panel, and anywhere its tallest child is a drawing Word holds nothing of in its cell — a badge beside a heading. A section or other container in any cell — a row's, a table's, a panel's — that pulls its first line up with a negative top edge writes that one-line paragraph as much shorter, its text seated where the page sets it — no more than the room above its letters, as Word draws an exact line's text only inside the line | | Sections / containers | Children written in order. A timeline with its markers on the rail (`markerOnRail()`) lays each entry's body out in the header row's content column, below the row; the body is written in the flow, indented to that column where the page puts it. A container with a fill, per-side borders or a uniform stroke is a one-cell table carrying them, its padding as the cell's margins, so a card keeps its panel — see "What a panel keeps and loses" below. A `keepTogether()` or `keepWithNext()` block the layout placed on one page stays on one page in Word too (`w:keepLines` + `w:keepNext`, and a row that may not split for a panel) | | Spacers | An empty paragraph a tenth of a point tall; the spacer's height is the space above the next block, or below this paragraph when a table follows | | Page breaks | Explicit Word page breaks | 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 ff334efe1..b144ecc91 100644 --- a/qa/src/test/resources/docx-fidelity/libreoffice-windows-lines.tsv +++ b/qa/src/test/resources/docx-fidelity/libreoffice-windows-lines.tsv @@ -3061,7 +3061,9 @@ invoice-payments 0:1a7b308d8df6 0.24 quantity invoice-payments 0:d1062d072acd 0.24 unitprice invoice-payments 0:7c512b48ba8a 0.24 vat invoice-payments 0:2da123241332 0.24 amount(gbp) -invoice-payments 0:3ab6c1099bcc 5.43 subscriptionbilling +invoice-payments 0:3ab6c1099bcc 0.43 subscriptionbilling +invoice-payments 0:c8e69cd6e074 0.57 subscriptionmanagementandrecurri +invoice-payments 0:0c95c7ece1ce 0.41 billing invoice-payments 0:96d6b62c061d 0.40 £250.00 invoice-payments 0:96d6b62c061d#1 0.41 £250.00 invoice-payments 0:dc934fe30a94 0.40 20% @@ -3070,7 +3072,9 @@ invoice-payments 0:dc934fe30a94#2 0.42 20% invoice-payments 0:dc934fe30a94#3 0.41 20% invoice-payments 0:dc934fe30a94#4 0.40 20% invoice-payments 0:dc934fe30a94#5 0.59 20% -invoice-payments 0:0a9acaea6477 5.43 paymentprocessing +invoice-payments 0:0a9acaea6477 0.43 paymentprocessing +invoice-payments 0:b8a3c21545b4 0.57 onlinecardpaymentsprocessing +invoice-payments 0:b42561a38a06 0.41 (volumetier) invoice-payments 0:351704ebff51 0.40 £1,180.00 invoice-payments 0:351704ebff51#1 0.41 £1,180.00 invoice-payments 0:b3bc34f90a55 0.42 fraudscreening @@ -3618,7 +3622,11 @@ proposal-editorial 0:e8228bfeba0e 0.15 foundationforfuture proposal-editorial 0:1fa35c7a1402 -0.85 growth. proposal-editorial 0:bc981abcdf59 -1.33 scopeofwork proposal-editorial 0:28450edd9a4f -0.25 discovery&research +proposal-editorial 0:ce9012b74aa2 0.00 stakeholderinterviews,brandaudit +proposal-editorial 0:730c3e278933 -0.28 audienceinsightstoinformstrategy proposal-editorial 0:12bff3036b66 -0.16 visualidentityrefinement +proposal-editorial 0:937ad523a90c 0.09 refinelogosystem,colorpalette,ty +proposal-editorial 0:9b232e66f46c -0.19 guidelinesforacohesive,modernide proposal-editorial 0:fc5134bf5fd1 -0.07 websiteux/uidesign proposal-editorial 0:5d58b01c7096 0.18 designaresponsive,accessibility- proposal-editorial 0:5d6068f6a879 -0.10 navigationandclearconversionpath @@ -3626,6 +3634,8 @@ proposal-editorial 0:32001e20b2ed 0.02 contentstructure&messaging proposal-editorial 0:b3c948ec3e36 0.27 definesitearchitecture,keymessag proposal-editorial 0:231428fde7aa -0.01 communicatevalueandbuildtrust. proposal-editorial 0:8c7703bb6fb7 0.11 launchsupport +proposal-editorial 0:34f9fe468474 0.36 developerhandoff,qasupport,train +proposal-editorial 0:2b4cf15f6f16 0.08 toensureasmoothlaunch. proposal-editorial 0:026890c58de9 0.01 northlinestudio|northlinestudio. proposal-editorial 1:e35c32bb5ed8 -46.41 deliverables proposal-editorial 1:23eb79a19b39 -45.38 brandstrategysummary @@ -3633,9 +3643,11 @@ proposal-editorial 1:aaa2a6073d69 -45.38 refinedlogosuite&brandguidelines proposal-editorial 1:d626f7532564 -45.38 color,typography&designsystem proposal-editorial 1:018ec557a513 -45.38 websiteuxwireframes proposal-editorial 1:5ed4970fa285 -45.38 high-fidelitywebsitedesigns -proposal-editorial 1:8b712e7e93bf -57.80 contentstrategy&pagetemplates -proposal-editorial 1:e9bf06d9b130 -57.80 developer-readyassets&specificat -proposal-editorial 1:e93e7ba95ceb -57.80 launchchecklist&trainingsession +proposal-editorial 1:a579d6d1c12e -45.48 responsivedesignfordesktop,table +proposal-editorial 1:d524c1a0811d -45.13 mobile +proposal-editorial 1:8b712e7e93bf -44.40 contentstrategy&pagetemplates +proposal-editorial 1:e9bf06d9b130 -44.40 developer-readyassets&specificat +proposal-editorial 1:e93e7ba95ceb -44.40 launchchecklist&trainingsession proposal-editorial 1:94d192b3a326 -46.32 timeline proposal-editorial 1:02195b8e9896 -45.06 phase proposal-editorial 1:c51faa148557 -45.06 focus diff --git a/qa/src/test/resources/docx-fidelity/libreoffice-windows.tsv b/qa/src/test/resources/docx-fidelity/libreoffice-windows.tsv index 2e8f8ded2..364e41a97 100644 --- a/qa/src/test/resources/docx-fidelity/libreoffice-windows.tsv +++ b/qa/src/test/resources/docx-fidelity/libreoffice-windows.tsv @@ -37,7 +37,7 @@ invoice-metered 1 1 99 99 0.25 0.69 0 invoice-modern 1 1 54 54 0.32 0.52 0 invoice-modern_long 2 2 162 162 0.35 0.52 0 invoice-obsidian 1 1 81 81 0.29 0.84 0 -invoice-payments 1 1 104 100 0.41 0.91 2 +invoice-payments 1 1 104 104 0.41 0.90 0 invoice-platform 1 1 111 111 0.27 0.43 0 invoice-subscription 1 1 81 81 0.42 0.73 0 invoice-workspace 1 1 90 90 0.35 1.17 0 @@ -56,7 +56,7 @@ letter-nordic_clean 1 1 15 15 0.16 0.38 0 letter-panel 1 1 13 13 0.15 0.21 0 letter-sidebar_portrait 1 1 12 12 0.43 0.51 0 letter-timeline_minimal 1 1 15 15 1.32 1.52 0 -proposal-editorial 2 2 132 119 43.27 45.18 68 +proposal-editorial 2 2 132 127 43.26 45.15 70 proposal-indigo 1 1 72 70 0.57 27.88 16 proposal-modern 1 1 44 44 0.41 0.75 0 proposal-northline 2 2 132 132 0.38 1.62 6 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 81fef0e11..801f21357 100644 --- a/qa/src/test/resources/docx-fidelity/word-windows-lines.tsv +++ b/qa/src/test/resources/docx-fidelity/word-windows-lines.tsv @@ -3159,7 +3159,9 @@ invoice-payments 0:1a7b308d8df6 0.33 quantity invoice-payments 0:d1062d072acd 0.33 unitprice invoice-payments 0:7c512b48ba8a 0.33 vat invoice-payments 0:2da123241332 0.33 amount(gbp) -invoice-payments 0:3ab6c1099bcc 5.47 subscriptionbilling +invoice-payments 0:3ab6c1099bcc 0.55 subscriptionbilling +invoice-payments 0:c8e69cd6e074 0.72 subscriptionmanagementandrecurri +invoice-payments 0:0c95c7ece1ce 0.52 billing invoice-payments 0:96d6b62c061d 0.54 £250.00 invoice-payments 0:96d6b62c061d#1 0.50 £250.00 invoice-payments 0:dc934fe30a94 0.54 20% @@ -3168,7 +3170,9 @@ invoice-payments 0:dc934fe30a94#2 0.51 20% invoice-payments 0:dc934fe30a94#3 0.51 20% invoice-payments 0:dc934fe30a94#4 0.51 20% invoice-payments 0:dc934fe30a94#5 0.62 20% -invoice-payments 0:0a9acaea6477 5.52 paymentprocessing +invoice-payments 0:0a9acaea6477 0.48 paymentprocessing +invoice-payments 0:b8a3c21545b4 0.64 onlinecardpaymentsprocessing +invoice-payments 0:b42561a38a06 0.56 (volumetier) invoice-payments 0:351704ebff51 0.47 £1,180.00 invoice-payments 0:351704ebff51#1 0.54 £1,180.00 invoice-payments 0:b3bc34f90a55 0.48 fraudscreening @@ -3716,7 +3720,11 @@ proposal-editorial 0:e8228bfeba0e 0.33 foundationforfuture proposal-editorial 0:1fa35c7a1402 -0.68 growth. proposal-editorial 0:bc981abcdf59 0.10 scopeofwork proposal-editorial 0:28450edd9a4f -0.19 discovery&research +proposal-editorial 0:ce9012b74aa2 0.14 stakeholderinterviews,brandaudit +proposal-editorial 0:730c3e278933 -0.07 audienceinsightstoinformstrategy proposal-editorial 0:12bff3036b66 0.00 visualidentityrefinement +proposal-editorial 0:937ad523a90c 0.21 refinelogosystem,colorpalette,ty +proposal-editorial 0:9b232e66f46c -0.03 guidelinesforacohesive,modernide proposal-editorial 0:fc5134bf5fd1 0.04 websiteux/uidesign proposal-editorial 0:5d58b01c7096 0.37 designaresponsive,accessibility- proposal-editorial 0:5d6068f6a879 0.01 navigationandclearconversionpath @@ -3724,6 +3732,8 @@ proposal-editorial 0:32001e20b2ed 0.08 contentstructure&messaging proposal-editorial 0:b3c948ec3e36 0.41 definesitearchitecture,keymessag proposal-editorial 0:231428fde7aa 0.17 communicatevalueandbuildtrust. proposal-editorial 0:8c7703bb6fb7 0.24 launchsupport +proposal-editorial 0:34f9fe468474 0.45 developerhandoff,qasupport,train +proposal-editorial 0:2b4cf15f6f16 0.21 toensureasmoothlaunch. proposal-editorial 0:026890c58de9 0.12 northlinestudio|northlinestudio. proposal-editorial 1:5205c2a261bc 0.41 northline proposal-editorial 1:da0daaba4b15 0.32 studio @@ -3734,9 +3744,11 @@ proposal-editorial 1:aaa2a6073d69 0.10 refinedlogosuite&brandguidelines proposal-editorial 1:d626f7532564 0.06 color,typography&designsystem proposal-editorial 1:018ec557a513 0.14 websiteuxwireframes proposal-editorial 1:5ed4970fa285 0.10 high-fidelitywebsitedesigns -proposal-editorial 1:8b712e7e93bf -12.28 contentstrategy&pagetemplates -proposal-editorial 1:e9bf06d9b130 -12.32 developer-readyassets&specificat -proposal-editorial 1:e93e7ba95ceb -12.36 launchchecklist&trainingsession +proposal-editorial 1:a579d6d1c12e 0.38 responsivedesignfordesktop,table +proposal-editorial 1:d524c1a0811d 0.65 mobile +proposal-editorial 1:8b712e7e93bf 1.04 contentstrategy&pagetemplates +proposal-editorial 1:e9bf06d9b130 1.12 developer-readyassets&specificat +proposal-editorial 1:e93e7ba95ceb 1.08 launchchecklist&trainingsession proposal-editorial 1:94d192b3a326 0.47 timeline proposal-editorial 1:02195b8e9896 0.50 phase proposal-editorial 1:c51faa148557 0.50 focus diff --git a/qa/src/test/resources/docx-fidelity/word-windows.tsv b/qa/src/test/resources/docx-fidelity/word-windows.tsv index fe09d08a7..1775a22fb 100644 --- a/qa/src/test/resources/docx-fidelity/word-windows.tsv +++ b/qa/src/test/resources/docx-fidelity/word-windows.tsv @@ -37,7 +37,7 @@ invoice-metered 1 1 99 99 0.37 0.77 0 invoice-modern 1 1 54 54 0.31 0.57 0 invoice-modern_long 2 2 162 162 0.44 0.60 0 invoice-obsidian 1 1 81 81 0.26 0.62 0 -invoice-payments 1 1 104 100 0.50 1.10 2 +invoice-payments 1 1 104 104 0.51 1.02 0 invoice-platform 1 1 111 111 0.19 0.41 0 invoice-subscription 1 1 81 81 0.47 0.64 0 invoice-workspace 1 1 90 90 0.44 1.26 0 @@ -56,7 +56,7 @@ letter-nordic_clean 1 1 15 15 0.16 0.35 0 letter-panel 1 1 13 13 0.17 0.25 0 letter-sidebar_portrait 1 1 12 12 0.41 0.52 0 letter-timeline_minimal 1 1 15 15 1.30 1.63 0 -proposal-editorial 2 2 132 120 0.58 2.20 22 +proposal-editorial 2 2 132 128 0.50 2.09 19 proposal-indigo 1 1 72 70 0.43 27.75 16 proposal-modern 1 1 44 44 0.35 0.73 0 proposal-northline 2 2 132 132 0.36 1.75 6 diff --git a/render-docx/src/main/java/com/demcha/compose/document/backend/semantic/docx/DocxSemanticBackend.java b/render-docx/src/main/java/com/demcha/compose/document/backend/semantic/docx/DocxSemanticBackend.java index 57e65468b..c58a84058 100644 --- a/render-docx/src/main/java/com/demcha/compose/document/backend/semantic/docx/DocxSemanticBackend.java +++ b/render-docx/src/main/java/com/demcha/compose/document/backend/semantic/docx/DocxSemanticBackend.java @@ -8851,8 +8851,9 @@ private void writeRowCellChild(XWPFTableCell cell, DocumentNode child) throws Ex * *
A row occupies the whole width it is offered — {@code measureRow} returns the * available width unconditionally, whatever its children measure — so the carrier - * gets the content width. Left at POI's size-to-content default the pair collapses - * around its text instead.
+ * gets the content width, unless fixed columns add up to less and leave the rest of + * the row empty ({@link #holdTheLastFixedColumn}): then it is as wide as its columns. + * Left at POI's size-to-content default the pair collapses around its text instead. * *How that width divides is arithmetic the document already carries, for every
* distribution except one. Weights, an even split and fixed columns are shares of the
@@ -8882,8 +8883,9 @@ private RowGeometry applyRowGeometry(XWPFTable table, RowNode node, double hang)
// The layout placed each child, so every way a row can divide — the two that
// measure their children included — is already answered.
List Fixed columns that add up to less than the row leave the rest of it empty, and the
+ * last column's text wraps at its own width: {@code EditorialProposal}'s deliverables, a
+ * column of 194pt in a band of 535, wrapped "Responsive design for desktop, tablet &
+ * mobile" onto two lines. Run to the row's edge, the cell was 272pt wide, and Word set the
+ * item on one line and every item under it a line higher.