Repository navigation
fix(docx): end a rule where the page ends it in Word - #946
Merged
Merged
Conversation
- A line, a divider or a thin bar is written as an empty paragraph's bottom border, its ends the paragraph's indents. Word draws a paragraph's border past both indents, so every rule stood about 1.4pt longer at its left and 1.5pt at its right. - Each indent is taken in by Word's reach (wordsRuleReach): 1.42pt at the left, 1.51pt at the right, measured on nine rules 0.5 to 4pt thick in the body, a row's column and a table cell (1.36 to 1.49, 1.44 to 1.59). A rule running past its width stays held at the width's edge, less only what Word draws further than the page ends it. A rule shorter than both keeps a tenth of a point of its paragraph. LibreOffice, which draws the border between the indents, sets each rule that much short at each end. - Re-render the Word export example's DOCX preview: its divider's indents. - Measured on the corpus: in Word 280 strokes nearer the page's, 13 further, rules whose column already starts right of the page's; in LibreOffice 281 rules moved in; no word moves. - Tests: indents with the reach, its two values, a short rule, a rule past its width, a rule in a cell whose width is Word's, with and without a padded container.
DemchaAV
marked this pull request as draft
October 23, 2026 00:33
- LibreOffice now sets each end of a rule further in by Word's reach, not short of the page's by it: in the body it drew a rule's right end short of its indent already. - The reach is stated as measured: nine rules in the body, half a point to 4pt thick; rules of 1 and 3pt in a row's column and a table cell in the same range; a dashed and a dotted rule reaching as far as a solid one. - Tests: a rule hung 1pt left of its row column's text takes the reach in before the cell holds it at its text; the hung dash's left indent is the reach.
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 horizontal line, a divider or a thin filled bar is exported as an empty paragraph whose bottom border is the stroke (
writeRule). The rule's ends are the paragraph's left and right indents. Word draws a paragraph's border past both indents, and LibreOffice draws it between them. So in Word every rule stood about 1.4pt longer at its left and 1.5pt at its right. Subscription Invoice's separators stood 1.32pt left and 1.57pt right of the page's, and its four-coloured strip's segments ran that far into each other.Measured on Windows, on nine synthetic rules in the body (half a point to 4pt thick, indented from nothing to 61.7pt), Word drew the border:
Neither the size of the paragraph's mark nor a left and right border written as
none/nilchanged it. Rules of 1 and 3pt in a row's column and in a table cell fell in the same range, and a dashed (4/2) and a dotted (1/1) rule reached as far as a solid one. In the corpus there are 304 paragraph bottom borders in 43 of the 62 documents.One indent cannot put a rule right in both editors, so the export now writes it for Word.
What changed
wordsRuleReach: each of a rule's indents is taken in by Word's reach.WORD_RULE_REACH_LEFT_POINTS(1.42pt) andWORD_RULE_REACH_RIGHT_POINTS(1.51pt), the means of the measurements.SHORTEST_RULE_PARAGRAPH_POINTS). Measured, rules of 1, 2 and 3pt then stood 3.0, 2.88 and 3.12pt long in Word, each centred within 0.05pt of where the page centres it.writeRuleapplies it in both branches: a rule composed in a cell, written where its cell drawing is, and a rule in the flow.max(0, gap + reach)), so such a rule does not end short.applyInset) is kept, and the reach is added to it.assets/readme/examples/word-export-companion.docxis re-rendered. Its divider's indents are the only change: left 0 → 28 twips, right 1580 → 1610.writeRule's javadoc;Verification
DocxRuleTest(+6 new tests, 4 updated). The updated ones now expect the indents plus the reach. The new ones cover:DocxCellRuleTest(2 updated) andDocxHangingLeftTest(1 updated) expect the reach. The hung dash's test also pins its left indent: the reach, from its cell's text.withRowEditorSlack). They now start 1pt right where they started 0.45pt left../mvnw -B -ntp clean verify -pl <core, render-pdf, render-docx, render-pptx, templates, testing, qa, coverage> -am→ BUILD SUCCESS: core 821, render-pdf 339, render-docx 2068, testing 5, render-pptx 142, templates 127, qa 1828../mvnw -f examples/pom.xml test→ BUILD SUCCESS, 93 tests.CommittedAssetDriftTestfailed before the preview was re-rendered.Notes for review:
max(0, gap + reach). No test builds a cell drawing that ends in its cell's margin.Lane: shared-engine (render-docx): no public API change.