Skip to content

fix(docx): grow a table text cell's lines where they are as tall as its face's own - #956

Merged
DemchaAV merged 2 commits into
2.5-devfrom
fix/docx-least-text-cell-lines
Oct 25, 2026
Merged

DemchaAV merged 2 commits into
2.5-devfrom
fix/docx-least-text-cell-lines

Conversation

@DemchaAV

@DemchaAV DemchaAV commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

Why

A paragraph's line that is at least as tall as its faces' own is written at a least height (w:lineRule="atLeast"), which Word grows when a reader makes the text larger. A table's text cell was not: writeCellContent wrote its lines exact, and the row's margins, its lines' heights or its text's position then moved it onto the page's baseline. An exact line keeps its height, so with Normal two points larger Word cut the top off the letters of every such cell. In the corpus that is 125 paragraphs of text cells in two invoices and two proposals, and 13 in CobaltRota, its staff names among them.

Word and LibreOffice 24.2 stand a least line's baseline its runs' descent above its foot, in top, middle and bottom aligned cells as in the body (measured to 0.15pt). That is where the page sets a cell's line, its height less its face's descent.

What changed

  • letTheCellsLinesGrow writes a text cell's paragraphs at a least height where every one of them may grow, by the rule a paragraph's line grows by (DocxGrownLines.mayGrow), and Word then stands the text within a quarter point of the page's. It is called once the cell's paragraphs are written, before its seat is read. All of a cell's paragraphs change or none do.
  • belowThePage reads Word's seat through DocxGrownLines.lineOf: four fifths of an exact line down, a least line's runs' descent above its foot. A least cell therefore calls for no more than its rounding. In a row of least cells moveTheRowsText leaves the margins as the padding, and it trades no least line for the space after it.
  • The quarter-point check is the one a paragraph's line passes. In the faces the export ships, whose descent the page and the editors measure alike, a least cell stands within its line's rounding to the twip and its size's to the half point, under a fifth of a point, so no cell is held exact by it. It keeps a least line from ever being given a position, which Word does not move it by.
  • What stays exact, and is moved as before:
    • a cell tighter than its face's own, as Poppins' are;
    • a cell in a face the document does not ship;
    • a cell set right to left;
    • a blank cell.
  • An exact cell beside a least one is left the rest of its call: the row's margins move by no more than the least cell calls for. It is then moved by its position from half a point, and by its lines' heights where it has space after them. No row of the corpus holds both.
  • Docs: the recipe's Line height row and table section, the capability matrix's table row, and the CHANGELOG. The older line-height entry no longer lists text cells among what stays exact.

Verification

  • Tests:
    • DocxGrownLinesExportTest (+5):
      • a Lato cell at the middle, the top and the bottom is least, its margins its 4pt padding, with no position and no line height note;
      • a cell of a paragraph a line, and one of lines broken in one paragraph, grows every line;
      • a Poppins cell stays exact and is moved;
      • an exact Ubuntu cell beside a least Lato one keeps the padding as margins;
      • a right-to-left cell stays exact.
    • DocxCellSeatTest: the seven tests of the exact seat that used Lato, which now grows, use Ubuntu, which Word sets a quarter point high and which stays exact. The six whose Ubuntu cell holds text state that it is exact.
  • Fail-closed: 6 sabotages, each run alone:
    • caught: no cell grows; one tighter than its face's own grows; a least cell seated as an exact one; only a cell's first paragraph grows; a right-to-left run read.
    • not caught: dropping the quarter-point check, which no shipped face reaches.
  • Corpus: 5 of 62 documents change, 138 paragraphs exact → least.
    • Where a row's margins had moved its exact lines, by 5 to 7 twips, they return to the padding: in three of the five documents. PlatformInvoice's rows held no move.
    • 13 of CobaltRota's lines no longer trade height for the space after them.
    • The report changes only in those documents' line height counts.
  • Word edit protocol, restyle-body-through-normal, on the five documents: squeezed paragraphs 181 → 84, and three of the five pass, from none. Corpus-wide this is 1041 of 1832, from 1138, with 13 documents passing, from 10.
  • Word fidelity gate (scripts/docx-visual/word-fidelity.ps1): BUILD SUCCESS.
    • Of the five documents' 334 steps from a line to the next, 27 differ from the page's by more than 0.2pt, from 34. The p90 is 0.17pt, from 0.20.
    • 18 lines stand further from the page and 16 nearer:
      • NorthlineProposal's phase cells sit in rows with composed cells, whose margins do not move. As exact lines they stood 0.24pt above the cells beside them, 0.05–0.16pt above the page. Least, they moved down those 0.24pt in Word and 0.30pt in LibreOffice and stand level with the cells beside them, 0.08–0.19pt low, as the whole row stands.
      • CobaltRota's names, which their traded lines left 0.08pt high by the export's reckoning, stand 0.12pt lower in Word, one step of its line grid, and 0.10pt in LibreOffice.
  • LibreOffice 24.2 (CI's build, in a container), base and change: of the five documents' 638 lines, 51 stand nearer the page and none further. The steps' p90 is 0.28pt, from 0.32.
  • Gate:
    • ./mvnw -B -ntp clean verify -pl <core, render-pdf, render-docx, render-pptx, templates, testing, qa, coverage> -am → BUILD SUCCESS: core 823, render-pdf 339, render-docx 2172, testing 5, render-pptx 142, templates 127, qa 1830.
    • The JDK 17 knowledge checks pass with the API surfaces unchanged, 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. Text cells' line rules and their rows' margins change in the file.

…ts face's own

- A table text cell's paragraphs are written at a least height where
  each may grow (DocxGrownLines.mayGrow) and Word then stands the text
  within a quarter point of the page's (letTheCellsLinesGrow), as a
  paragraph's lines are. In the faces the export ships a least cell
  stands where the page does, so its row keeps the padding as its
  margins and no line is traded for the space after it.
- belowThePage reads Word's seat through DocxGrownLines.lineOf, an exact
  line's or a least one's.
- A cell tighter than its face's own, in a face the document does not
  ship, or set right to left stays exact; beside a least cell, an exact
  cell is left the rest of its call, for its position and line heights.
- Tests: least cells at three anchors, a paragraph a line and lines
  broken in one paragraph, Poppins and right-to-left cells exact, an
  exact cell beside a least one; the exact seating tests move from Lato,
  which now grows, to Ubuntu, which stays exact.
@DemchaAV
DemchaAV marked this pull request as draft October 25, 2026 01:08
applyLineHeight's Javadoc gave an exact line as what it always writes,
the engine's line being shorter than the font's. A paragraph's or a text
cell's line at least as tall as its faces' own is rewritten as a least
height afterwards (letTheLinesGrow, letTheCellsLinesGrow): the Javadoc
now says so and no longer claims the line is always the shorter.
@DemchaAV
DemchaAV marked this pull request as ready for review October 25, 2026 01:18
@DemchaAV
DemchaAV merged commit 8bae176 into 2.5-dev Oct 25, 2026
13 checks passed
@DemchaAV
DemchaAV deleted the fix/docx-least-text-cell-lines branch October 25, 2026 01:39
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