Skip to content

fix(html): give mixed-direction bordered paragraphs their own boxes when indents differ (#1155) - #1163

Merged
JSv4 merged 2 commits into
mainfrom
fix/issue-1155
Oct 16, 2026
Merged

JSv4 merged 2 commits into
mainfrom
fix/issue-1155

Conversation

@JSv4

@JSv4 JSv4 commented Oct 16, 2026

Copy link
Copy Markdown
Owner

Closes #1155

Third of a three-PR stack: #1161 (#1153), then #1154's PR, then this one. It is based on #1154's branch and will be retargeted to main as the stack merges.

Why

The converter groups consecutive bordered paragraphs into one box (with w:between borders) when their borders and indents match. A right-to-left paragraph mirrors its box: its start indent is on the right. So when start and end differ (say w:start="720" w:end="1440"), a left-to-right and a right-to-left paragraph need mirror-image boxes. One shared box put one of them's indents on the wrong sides.

What Word and LibreOffice do

LibreOffice 25.8.7.3, given three cases:

  • Equal start and end, mixed directions: one joined box with between borders.
  • Unequal start and end, mixed directions: a separate box per paragraph, each mirrored.
  • start=1440 hanging=720 end=720: one box, because the box's leading edge (start less hanging) matches its trailing edge.

Word has not been measured for this case.

How it works

BorderGroupKey decides grouping. It now appends the paragraph's direction to the key only when the paragraph is right-to-left and its box is not mirror-symmetric. Mirror-symmetric means the leading edge (leading indent less any hanging indent, exactly as CreateBorderDivs lays the box out) equals the trailing edge. So:

  • left-to-right-only documents group exactly as before;
  • right-to-left-only groups still join;
  • mixed groups split only when their boxes really differ.

DocxSession's render plan uses the same key, so it picks up the change.

Validation

  • New tests in RightToLeftParagraphBorderTests:
    • mixed directions with unequal indents get mirrored boxes, with exact margins (fails without the fix);
    • mixed directions with equal indents still share one box;
    • right-to-left paragraphs with unequal indents share one box;
    • a hanging indent that makes the box symmetric still joins.
  • Mutating the symmetry check to ignore the hanging indent fails the hanging test.
  • At the top of the stack, 1,007 converter, border, render-plan and bidi tests pass.

Adversarial review

One round of hostile review ran before opening. It probed the unequal, equal and hanging cases against LibreOffice, a group whose first paragraph is right-to-left, w:bidi w:val="0", and both indent spellings, and found them correct.

  • Fixed: the hanging term of the symmetry check was untested. The second commit adds that test.
  • Not changed: the session render plan resolves paragraph properties without the numbering level's w:ind, while the renderer includes it. That gap predates this change, but direction can now split a group too, so it shows up more. In the common case (an asymmetric indent that comes only from numbering) the plan joins what the renderer splits, which is harmless. The reverse needs a style's asymmetric indent overridden by a symmetric numbering indent. That is contrived, and it is left for a follow-up.

JSv4 added 2 commits October 16, 2026 08:04
…hen indents differ (#1155)

A right-to-left paragraph mirrors its border box, so with unequal start
and end indents it cannot share a box with a left-to-right paragraph.
BorderGroupKey now adds the direction to the key in exactly that case;
paragraphs whose boxes coincide still join, as LibreOffice joins them.
@JSv4
JSv4 merged commit 9da170a into main Oct 16, 2026
17 checks passed
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.

A bordered group that mixes text directions with unequal indents shares one box

1 participant