Skip to content

fix(docx): hold an auto column's editor slack in its cells' margins - #944

Merged
DemchaAV merged 2 commits into
2.5-devfrom
fix/docx-table-column-slack
Oct 22, 2026
Merged

DemchaAV merged 2 commits into
2.5-devfrom
fix/docx-table-column-slack

Conversation

@DemchaAV

@DemchaAV DemchaAV commented Oct 22, 2026 •

Copy link
Copy Markdown
Owner

Why

A table column sized to its content (DocumentTableColumn.auto()) is exactly as wide as its widest unwrapped cell. An editor setting that cell in its own face can wrap it, so the export gives each auto column's text a point of slack (withEditorSlack). The slack widened the column. Every rule and fill right of it, the text of the columns after it, and the table's right end stood a point right of the page's. The report did not say so.

Measured against the page on Windows:

  • In Word, the rules right of the auto column in Classic and Modern Invoice (both lengths) and Modern Proposal stood 0.94 to 1.06pt right of the page's.
  • In LibreOffice, 0.66 to 1.06pt.

What changed

  • Slack in the cells' margins (slackTheMarginsHold, givingTheSlack):
    • A text cell gives its column's slack from the side its text does not lean on: the right where it is set left, the left where it is set right, and half from each where it is centred (leanOf, the cell's anchor read with its direction). Its text keeps the room the slack gave it, so the line breaks are the same. The column keeps the page's width.
    • A cell spanning more than one column given slack shares its margin among them.
    • A composed cell gives none. A paragraph in it may run past its text into the margin (measureAtWordsSize). With the margin taken, it would run past the cell's edge, where Word cuts it off.
    • A side gives only what it has past the inner half of the cell's rule, as wide as Word draws it (ruleTwips). Taken further, a line an editor's face sets wider would run onto the rule: a cell padded 1pt beside a 1pt rule gives half a point.
    • A column holds the least any of its cells gives. The rest widens it, as before.
  • right end note (applyTableWidth): a table whose auto columns are widened by a tenth of a point or more, in all, is named. Its right end, and what stands right of them, is up to that much further right. It is named whether or not the table paints there, since the text of the columns after a widened one moves with it. In the corpus, these are Orange Ops's aside headings: one-column tables with no padding, a composed heading over a filled accent rule. Word draws their rules 0.98 to 1.05pt longer than the page.
  • applyTableWidth returns what each column's cells' margins hold, and the row loop writes each cell's padding less its share.
  • An indented table (indentTable) is indented by its first cell's written left margin, as before, now less what that cell gives. Word and LibreOffice measure the indent to that cell's text. Measured in a section padded 20pt, with the first auto column set right, centred and left: the left rule stood 0.06pt right of the page's in Word and on it in LibreOffice, in all three.
  • Example preview: assets/readme/examples/word-export-companion.docx is re-rendered. WordExportExample's quarterly table has three auto columns. Its grid and its cells' right margins are a point narrower each, and nothing else in the document changes.
  • Docs:
    • the recipe's Tables row;
    • the capability matrix's Table rows row;
    • the CHANGELOG (Public API).
  • Ledgers:
    • DocumentTableColumn.type, DocumentTableColumn.Type.AUTO and TableNode.columns name the margins and the right end note;
    • DocumentTableStyle.padding says a text cell's padding in an auto column is written less the slack.

Verification

  • DocxEditorSlackTest (+12 table tests, two rewritten):
    • Set left, the right margin gives the point: the grid is the layout's width, and the text room is the layout's plus the point. No note.
    • Set right, the left margin gives it. Centred, half from each side. A centred cell with 0.5pt sides holds it whole.
    • A right-to-left cell with no anchor gives it from its left margin, and one anchored left from its right.
    • Padding thinner than the point gives what it has, and the column widens by the rest and is named. This is tested on the right of a left-set cell and on the left of a right-set one.
    • A side padded 1pt beside a 1pt rule gives half a point, and the column widens by the other half, named. The tests of thin padding are unruled.
    • A header padded thinner than the body holds the whole column to what it gives.
    • A cell spanning two rows gives the point in the merge's covered position too.
    • A composed cell keeps its margins. Its column takes the point and is named, while the other column holds its own.
    • A cell spanning two auto columns shares its 1pt margin: half of each column's point is held, half widens it.
    • An indented table's w:tblInd is the inset and the margin its set-right first cell keeps.
    • A fixed column, and a table with a stated width, keep their margins.
  • DocxCellPaddingTest:
    • 11 tests on auto-column tables expect the right margin less the point (SLACK). Their vertical margins are unchanged.
    • In one of them, a cell padded 1pt under a 2pt rule keeps its right margin: the rule's half is the whole of it.
  • Example preview: CommittedAssetDriftTest (examples) passes with the re-rendered DOCX, and failed without it.
  • Fail-closed: 14 sabotages, each run alone, all caught. They cover:
    • no slack held, or the grid widened all the same;
    • the wrong side for a cell set right, centred or right to left;
    • a composed cell giving;
    • a span's margin not shared, or given from its first column alone;
    • a centred cell holding its thinner side once;
    • the rule's inner half given too;
    • the note missing, or written where the margins hold it all.
  • Word and LibreOffice on Windows, the 5 changed documents against the export before:
    • Word: the rules right of the auto column were 0.94 to 1.06pt right of the page's and are now within 0.12pt. LibreOffice: 0.66 to 1.06pt, and now with the tables' other rules (Modern Invoice's stand 0.3pt left in LibreOffice before and after).
    • No line breaks and no word moves down the page in either editor. The words right of the auto column (7 to 216 per document) move 1.0 to 1.1pt left, back to where the page sets them.
  • Corpus: 5 of 62 DOCX change (Classic and Modern Invoice, both lengths, and Modern Proposal). Notes go from 1359 to 1363, the 4 Orange Ops headings' right end.
  • Gate: ./mvnw -B -ntp clean verify -pl <core, render-pdf, render-docx, render-pptx, templates, testing, qa, coverage> -am → BUILD SUCCESS: core 821, render-pdf 339, render-docx 2062, testing 5, render-pptx 142, templates 127, qa 1828. The JDK 17 knowledge checks pass, and core javadoc has 0 warnings. ./mvnw -f examples/pom.xml test → BUILD SUCCESS, 93 tests.

Lane: shared-engine (render-docx): no public API change.

- A table column sized to its content gives its text a point of slack
  so an editor's face keeps the page's line breaks. It widened the
  column, moving every rule and fill right of it, and the table's right
  end, a point right of the page's. It now comes out of the column's
  text cells' margins, on the side their text does not lean on, and the
  column keeps the page's width.
- A cell spanning more than one such column shares its margin among
  them. A composed cell keeps its margins; what a column's cells do not
  hold widens it and is named (right end).
- An indented table is indented by the margin its first cell keeps,
  which both editors measure the indent to.
- Measured on Windows: Word stood the rules right of the auto column
  0.94 to 1.06pt right of the page's, now within 0.12pt; LibreOffice
  0.66 to 1.06pt, now with the tables' other rules. No line breaks
  change in either editor.
- Tests: margins by alignment, direction, span, header and thin
  padding, a composed cell widening its column with the note, an
  indented table's tblInd; cell padding tests expect the right margin
  less the slack.
@DemchaAV
DemchaAV marked this pull request as draft October 22, 2026 20:22
…slack

- A side of a text cell gives an auto column's slack only past the
  inner half of the cell's rule, as wide as Word draws it: taken
  further, a line an editor's face sets wider would run onto the rule.
  What it cannot give widens the column, named (right end).
- Re-render the Word export example's DOCX preview: its quarterly
  table's three auto columns are a point narrower each, the point in
  their cells' right margins.
- Tests: a 1pt padding beside a 1pt rule gives half a point; a cell
  spanning two rows gives the point in the merge's covered position;
  the thin-padding tests are unruled.
@DemchaAV
DemchaAV marked this pull request as ready for review October 22, 2026 20:39
@DemchaAV
DemchaAV merged commit 2defe85 into 2.5-dev Oct 22, 2026
13 checks passed
@DemchaAV
DemchaAV deleted the fix/docx-table-column-slack branch October 22, 2026 21:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant