fix(docx): give a table cell the padding the document laid it out with - #711
Merged
Merged
Conversation
A cell never stated its padding, so Word used its own: 5.4pt at each side and nothing above or below. A row's height in Word is its content's box, so every row came out shorter than the page draws it — measured on the probe corpus through LibreOffice, each row of a five-row table sat 8.1pt short and the last row 40pt above where the page puts it. The padding a cell resolves to — the table's default, then the column's, then the row's, then the cell's own, the same cascade the paint already used — is written as w:tcMar. The same table's rows now land within 0.1pt of the page. All four sides are written, and written even when zero, because Word's default is not zero: a table asking for no padding would otherwise export with Word's side margins. A table that states nothing is written with the padding the engine lays it out with, and DocxCellPaddingTest pins that constant to the engine's own so it cannot drift unnoticed. A nested table's usable width is measured against the margins the cell now states rather than against Word's default, read back from the file the same way the column widths are.
| private static double marginPoints(CTTblWidth margin) { | ||
| return margin == null || margin.getW() == null | ||
| ? WORD_DEFAULT_CELL_MARGIN_POINTS | ||
| : Long.parseLong(String.valueOf(margin.getW())) / POINT_TO_TWIP; |
| private static long width(CTTblWidth margin) { | ||
| return margin == null || margin.getW() == null | ||
| ? -1 | ||
| : Long.parseLong(String.valueOf(margin.getW())); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A table cell never stated its padding, so Word used its own: 5.4pt at each side and
nothing above or below. A row's height in Word is its content's box, so every row came
out shorter than the page draws it.
Measured on the probe corpus through LibreOffice, against the reference PDF — each row of
the five-row billing table 8.1pt short, and the table's last row 40pt above where the page
puts it:
What changed
The padding a cell resolves to is written as
w:tcMar— the table's default, then thecolumn's, then the row's, then the cell's own, through the same
resolveCellValuecascadethe fill and the stroke already use.
All four sides, and written even when zero. Word's default is not zero, so a table that
asked for no padding would otherwise export with Word's side margins and read wider than it
is.
A table that states nothing is written with the padding the engine lays it out with
(4pt), not Word's. The engine's own default is internal and cannot be read from the backend,
so
DocxCellPaddingTestpins the two together: if the layout's default moves, that testfails rather than the export quietly drawing rows of a height nothing asked for.
A nested table's usable width is measured against the margins the cell now states, read
back from the file the same way the column widths already are, rather than against Word's
5.4pt.
Verification
./mvnw -B -ntp clean verifyover the eight-module gate → BUILD SUCCESS (core 815,render-pdf 337, render-docx 222, testing 5, render-pptx 140, templates 127, qa 1784).
./mvnw -B -ntp test -f examples/pom.xml→ 93 tests, BUILD SUCCESS.Measured again on the same corpus, same editor, after the change:
Row pitch is 20.9pt against the page's 21.0. Accumulated drift at the foot of the table goes
from −87.2 to −35.2.
render-docx goes from 217 to 222 tests.
DocxCellPaddingTestcovers a stated padding onall four sides, the engine default for a table that states nothing, the guard tying that
default to the engine's own, the cascade (a row's padding beating the table's, a cell's
beating the row's), and a table asking for no padding getting none rather than Word's.
Three existing tests changed, each because the behaviour under them did:
DocxTablePaintTestandDocxInlineBackgroundTestasserted that an unpainted cell has now:tcPr— every cell now carries one, because every cell states its margins, so they askwhether it has shading instead.
DocxComposedCellTestpinned a nested table's width as"the column less 2 × 108 twips" (Word's 5.4pt); it is now "less 2 × 80" (the cell's own 4pt).
The committed
word-export-companion.docxpreview is regenerated — the export writes cellmargins now, so its bytes moved.
Lane: canonical —
document.backend.semantic.docxonly. No public API change.Still open on the same page, each its own change: a row loses its own vertical padding
(−14, twice — a row is a table, and Word has no space above one), and the table's header row
is 5.7pt short where its body rows are 0.1.