Skip to content

fix(docx): cut a rule row's empty line to the room its row leaves it - #812

Merged
DemchaAV merged 2 commits into
2.5-devfrom
fix/docx-rota-cobalt-word
Oct 2, 2026
Merged

DemchaAV merged 2 commits into
2.5-devfrom
fix/docx-rota-cobalt-word

Conversation

@DemchaAV

@DemchaAV DemchaAV commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

Why

In Word, CobaltRota's sheet stood 2.48pt below the page at the median, with 119 of its 154 lines more than 2pt off. LibreOffice was the same: 2.39pt, 124 lines.

Its header opens and closes with a row that is only a rule. Each is an empty cell whose font sets the rule's thickness: a 2.3pt and a 1.95pt line under a 0.9pt border. On the page the rule's borders are drawn across that line. Word and LibreOffice keep a cell's borders outside its content. The row is written less its border (holdRowAtLeast), but the line inside it was not, so each editor grew the row to the line plus its borders. Measured in Word, the first rule stood 4.08pt where the page has 3.2. The two rules put the whole sheet under them about 1.8pt low.

What changed

  • fitBlankLinesToTheRow, after holdRowAtLeast in holdRowHeight. A cell that holds a single paragraph with no letters has its exact line cut to the room its row leaves it. The floor is a 2-twip hairline.
    • The room is the page's row, less this cell's own margins and border, and less the paragraph's space above and below. holdRowAtLeast writes the row less the most any cell takes, and Word reads that as the row's whole height. The room adds that back and takes off only what this cell takes. For the rule rows, whose cells take only the border, it is the written height.
    • "No letters" means no text and no hyperlink. It also means no drawing, picture or object in its runs, and no border or shading on the paragraph (holdsNoLetters). A rule writeRule draws as a paragraph's border keeps its line.
    • A line with letters keeps its height. Cut, Word would clip its letters to the line.
  • Baselines. word-windows and libreoffice-windows are rewritten for CobaltRota, the one document this moves.
  • Docs. CHANGELOG.md, and the Tables row of docs/recipes/docx-export.md.

Verification

  • Template corpus, line by line against 2.5-dev's baselines. Both gates pass. No other document changes in either editor.

    Editor Document Pages Lines found Past 2pt Median p90
    Word 16.0.20430 CobaltRota 1 154 of 154 119 → 0 2.48 → 0.74pt 3.22 → 1.42pt
    LibreOffice (Windows) CobaltRota 1 151 of 154 124 → 0 2.39 → 0.60pt 3.09 → 1.29pt
  • The cause, measured before the code. The rule rows' lines were cut by hand in the exported DOCX (46 → 28 and 39 → 21 twips, and separately to 2) and converted in Word. Both gave a median of 0.74pt and no line past 2pt.

  • Hidden closing paragraph ruled out. Word already gives the hidden paragraph that closes a cell after a nested table no height. Changing it moved nothing.

  • New tests, DocxRuleRowTest:

    • a rule row's empty line is written as tall as its row, no taller;
    • a row of text keeps its line, a border's width taller than its row;
    • a blank row padded 4pt keeps its line, since its padding already gives up the border's room.
  • Each rule fails its own test when taken out.

    • Without the call, the rule-row test fails.
    • With the room taken off the written height and the cell's margins only, the padded-row test fails. The line loses its padding twice.
  • Full reactor gate: ./mvnw -B -ntp clean verify -pl :graph-compose-core,:graph-compose-render-pdf,:graph-compose-render-docx,:graph-compose-render-pptx,:graph-compose-templates,:graph-compose-testing,:graph-compose-qa,:graph-compose-coverage -am gives BUILD SUCCESS. render-docx runs 781 tests, qa 1813.

Known limits

  • Staff rows with two shifts in a day still grow about 0.1–0.25pt each in Word. The outlined chip's line is cut only as far as its letters allow (cutTheLabelToItsOutline). That residue is what is left of the 0.74pt median.
  • Band titles start about 10pt left of the page in Word (MANAGEMENT, BARTENDERS, BARBACKS). The gate measures lines vertically and does not see it.
  • The Linux LibreOffice baseline is taken from this PR's CI run.

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

…margins, and leave a paragraph's border alone

The row is written less the most any cell takes above and below its
content, and Word reads it as the row's whole; the room is that height
with the left-out part added back and the cell's own margins and border
taken off. Taken off the written height alone, a padded blank row's line
lost its padding twice. A paragraph with a border or shading of its own
draws on its line and is not cut.
@DemchaAV
DemchaAV merged commit a356453 into 2.5-dev Oct 2, 2026
13 checks passed
@DemchaAV
DemchaAV deleted the fix/docx-rota-cobalt-word branch October 2, 2026 06:48
DemchaAV added a commit that referenced this pull request Oct 2, 2026
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