Repository navigation
fix(docx): name a table its rules stand taller in Word - #917
Merged
Merged
Conversation
Word makes room in a table's rows for its horizontal rules, half of a rule between two rows to each and the rules above and below the table whole to their row, where the page draws them over the cells' edges. The export takes that room off the cell's padding, and where the padding is thinner than its share, the row stood taller in Word and the report said nothing. Measured in Word and LibreOffice on Windows, four rows of text with no padding and 3pt rules set the paragraph under the table 15pt lower than under the same table unruled. Word sets each cell at its content and, on each side, its padding or its share of the rules where that is more, and the row at its tallest cell, which DocxRuleRoom counts row by row against the page's height: a short cell beside a taller one that sets its row adds nothing, as measured, and a header row repeated on every page counts once a page. The report names the table (cell rule) with about how much taller, or with the most it can be where the layout does not tell a row's height or measure its text. Cells built from a node, cells spanning rows, and empty cells in rows held at the page's height are not counted: in the corpus's invoices and rota, whose rows are built from nodes or hold empty cells, the rows stood within half a point of the page's in Word.
DemchaAV
marked this pull request as draft
October 18, 2026 22:34
The test reading how much taller a note names parsed whatever was left of the note when the figure was not in it; it now finds the figure, and fails naming the note where there is none. The composed table's cases assert the layout stood behind the export, as the others do. The note's Javadoc says empty cells, which is what is not counted, and two long lines are wrapped.
DemchaAV
marked this pull request as ready for review
October 18, 2026 22:37
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
Word makes room in a table's rows for its horizontal rules — half of a rule between two rows to
each, the rules above and below the table whole to their row — and the page draws them over the
cells' edges.
clearOfTheRulestakes that room off the cell's top and bottom padding; where thepadding is thinner than its share, it gives what it has and the row stood taller in Word, with
nothing in the report.
Measured in Word and LibreOffice on Windows — the paragraph under the table against the same table
unruled (an unruled table already sits ~2.65pt lower in both, a font-metric offset), to a tenth of
a point:
The two mixed rows show how Word counts: each cell at its content and, on each side, its padding
or its share where that is more; the row at its tallest cell. A short cell whose padding falls
short beside a taller cell that sets the row adds nothing; "the most any cell holds beside the
tallest content" would have said 12 for the 8.
What changed
DocxRuleRoom(new, package-private): counts each text cell of a row —count(row, placement, padding, round, textHeight)— and sums, row by row, what the tallest cell comes to past thepage's height (
taller). A row the layout does not tell the height of, or whose counted text itdoes not measure, counts the most its text cells' padding falls short of taking, and the note
says "up to"; a header row repeated on every page counts once for each page the layout places it
on.
DocxSemanticBackend:ruleShareAbove/ruleShareBelow(shared withclearOfTheRules),roundTheContent(padding or share, each side),textHeight(the engine's own cell contentheight: lines × the measured line height plus their spacing), and
nameTheRoomForTheRules—APPROXIMATED, subjectcell rule: "…and sets the table about Xpt taller than the page".held at the page's height (their line is cut to the row's room,
fitBlankLinesToTheRow). A cellof a space is written as a run and is counted. In the corpus's
MerchantInvoice,ObsidianInvoiceandCobaltRota, whose rows are built from nodes or hold empty cells and areruled past their padding, the rows stood within half a point of the page's in Word, where
counting those cells said 2–4pt.
DocxNodeFieldLedgerTest: the cell paint entry names the case. Docs: the recipe's table row, thecapability matrix's table row, CHANGELOG v2.5.0.
A row whose margins are evened to one a cell keeps (
evenTheRowsMargins: a cell opening with atable, or in a vertical merge) is counted as though each cell kept its own, which is not measured;
the Javadoc says so.
Verification
./mvnw -B -ntp test -f render-docx/pom.xml—DocxCellRuleRoomTest(new, 10, each with-layoutcase asserting the layout stood behind it): the measured tables above; a quarter-point rule
(0.75pt in all); padding that takes the rules, no rules and the engine's defaults not named;
line spacing part of a cell's height; a 2pt header over 0.5pt rows; a header repeated over pages
counting again on each; cells built from a node and empty cells not counted, a cell of a space
counted; a cell spanning rows not counted; a table composed in a cell and one with no layout
named "up to", a composed table of node cells not at all.
DocxRuleRoomTest(new, 5): a measuredrow, a row not told counting only itself at most, an unmeasured cell, an empty cell held and not,
a row placed on three pages.
text, the measured branch, the bound, the threshold, padding past a share, the share between
rows, a space, an empty cell where held and in the bound, the header's repeats, line spacing, an
unmeasured cell, the bound for one row only — all caught.
./mvnw -B -ntp clean verify— BUILD SUCCESS (core 821, render-docx 1770, examples 93, qa 1820); the knowledge pack's--checkpasses.
Lane: render-docx (semantic backend) — a report note; no output change.