Repository navigation
fix(docx): raise a cell's first line into its padding, and a row's out of the space above it - #882
Merged
Merged
Conversation
…t of the space above it - A line opening a cell has no space above it of its own, and under half a point one Word sets low was left there: a panel's padding and a table cell's are the cell's margin, and a row's columns have their space above written above the row's table. ClassicInvoice's "TOTAL DUE" stood 0.18pt low in its panel in Word and 0.2pt in LibreOffice. - Under half a point, what the line's space above cannot give comes out of the top padding of the cell it opens: a panel's, less what its top border takes, the panel's row held as much taller; a table's composed cell's, in a row whose margins even. The line owes as much below it, so what follows stays. - A row of columns' first row is lifted out of the space above its table by the most its cells' first lines call for, each line rising by its own and the space under it taking that back. Not a row the layout moves to a new page, held to a height, or whose column opens with a panel or a table. - A paragraph in a table's composed cell is raised into the space above it as anywhere else: its row is kept on one page. - Half a point and more stays the position's. - A row's margins even only where every cell opens with a paragraph: a row of columns, a painted container and a shape are written as a table first too, and keep their margin. The paragraph above a lifted table is an empty separator only where it holds no picture. - Docs: the CHANGELOG entry, the recipe's line height row and the capability matrix's paragraph row. - Fidelity: the Word and LibreOffice on Windows baselines rewritten for the documents whose lines moved. - Examples: the Word export companion's committed DOCX re-rendered, its row of columns lifted 4 twips. - Tests: DocxFirstLineSeatTest covers a panel's line and its top border, a line half a point low and more, a composed cell's line and the cell beside it, a line under the first in a composed cell, a row's lift, a cell calling for less, one Word sets high, the space given back above the next line, a call under a tenth, a lift out of the foot of the row above, a cell beside a badge, a split panel, a picture above a row, and rows on a new page, held or opening with a panel. Tests that pin a panel's or a cell's top margin, or the space above a row, count the default line's raise.
…e the held table row - A cell opening with a picture, or a spacer keeping no other layer's place, writes a paragraph first: its row's margins even again, as before the first-line raise, and the gap above a wrapped first line is taken from the cell's padding beside it. - Javadoc and docs: a table row is held at its height less the margins left, so LibreOffice 24.2 grows a table row held taller than its text by the raise, as it does a panel; the line height paragraph's rules for the panel's padding and for the space a line's position leaves now name the new sources; the row of columns' lift skips a line in any overlay. - Tests: DocxFirstLineSeatTest covers a cell beside a picture.
This was referenced Oct 12, 2026
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 and LibreOffice stand an exact line's baseline four fifths of the way down it. The page sets it its face's ascent below the line's top. A line Word sets lower is moved up into the space written above it, and that space is owed below it so what follows stays. Under half a point nothing else moves it: the position counts in half points.
A line opening a cell has no space above it of its own:
So those lines stayed as low as Word set them. By the export's own measure of Word's seat, 250 lines of the corpus stood so, a median 0.22pt low. Measured against its panel's bar,
ClassicInvoice's "TOTAL DUE" stood 0.18pt low in Word and 0.2pt in LibreOffice.What changed
In
DocxSemanticBackend:raiseIntoTheSpaceAbovetakes what the space above cannot give from the cell's top padding (paddingAbove), under half a point only. The line still owes what it rose below it.panelsMarginKeeps). Its row is held as much taller: Word adds the margin left to the height a row is held at.cellsGivingTheirPadding).evenTheRowsMarginsthen gives the cells beside it the difference as space above their first lines.opensWithAParagraph): text, a paragraph, a list, a picture, or a spacer keeping no other layer's place. It used to look for a table alone, but a row of columns, a painted container and a shape are each written as a table first too, and such a cell keeps its margin. Word gives every cell the row's largest margin, so a line beside such a cell rising into a smaller one would not rise, and would leave what it owed below.CobaltRota's 3.4pt masthead raise, whose position LibreOffice overshoots, came out 0.5 to 0.7pt lower there.inARowKeptWhole). The cell has no placement, solayout.onOnePagesaid no. Its row is kept on one page (rowsPlacedWhole, orcantSplit).noteAFirstLineLow,raiseRows,liftEachCell).giveBackBelow): above the next paragraph, or after the line where none follows.rowOpeningItsPage), a row held to a height, or a row whose column opens with a panel or a table, which would rise whole.takesRoom): its space above places the picture.Docs:
CHANGELOG.md(v2.5.0) gets a new entry.assets/readme/examples/word-export-companion.docxis re-rendered: its row of columns is lifted 4 twips (CommittedAssetDriftTest).Verification
./mvnw -B -ntp clean verify→ BUILD SUCCESS: render-docx 1410 run, 0 failures, 1 skipped (+19); qa 1820, core 818, examples 93.DocxFirstLineSeatTest, 19 new tests, one case each:Tests that pin a panel's or a cell's top margin, or the space above a row, now count the raise.
DocxPanelTailTest,DocxContainerPaintTest,DocxContainerSpacingTest,DocxComposedCellTestandDocxVerticalSpacingTestcountDocxExports.DEFAULT_LINE_RAISE.DocxSpaceOnANewPageTestthe row takes back what the line above it owes for its raise.DocxStandInMoveTestreads the rise off the strip's margin: the name rising out of the strip's padding owes the subtitle the space it rises into.DocxPanelTailTest,reachBelowreads the space the line above owes before the icon's line.Twenty-three sabotages, each caught by a test:
DOCX fidelity corpus, against the committed baselines (by median):
LumaStudioInvoice, 0.12 → 0.14pt)LumaStudioInvoice, 0.12 → 0.14pt)LumaStudioInvoice, 0.12 → 0.14pt), 194 lines nearer and 25 further. Its acceptance summary is unchanged.ClassicInvoice's header, "BILL TO", "FROM" and "TOTAL DUE" rose 0.24 to 0.36pt in Word and 0.2 to 0.4pt in LibreOffice.ConsultingInvoice's line items rose 0.24 to 0.36pt in Word and 0.35pt in LibreOffice.ModernProfessional's entries rose 0.24pt in Word and 0.2pt in LibreOffice.Notes for review
LumaStudioInvoiceis further by median in LibreOffice. Its line-items table stands 0.13 to 0.16pt high there, at its header's fill and at each row's rule. Its first lines, set low, made up for that. In their rows the header and the item titles now stand within 0.11pt of the page's in Word and 0.04pt in LibreOffice, from 0.13 to 0.25pt low in Word. The rows' drift is its own change.LumaStudioInvoice's, and the other 3 a step of its grid each. LibreOffice moved only the raised lines.ClassicInvoice's notes and payment terms still stand 0.2 to 0.26pt low in their rows. Their columns are ruled down their left side, so each is a panel in its cell with no padding above its line, and the row is not lifted.Lane: shared-engine (DOCX backend) —
render-docx; no public API.