Skip to content

fix(docx): name a block Word may break inside a panel it moves down in - #932

Merged
DemchaAV merged 2 commits into
2.5-devfrom
fix/docx-panel-stack-whole
Oct 20, 2026
Merged

DemchaAV merged 2 commits into
2.5-devfrom
fix/docx-panel-stack-whole

Conversation

@DemchaAV

@DemchaAV DemchaAV commented Oct 20, 2026 •

Copy link
Copy Markdown
Owner

Why

A painted section or container (a panel) is written as a one-cell table, and its row may break
over a page unless the panel is kept together on one page. Inside a panel that the layout runs
over a page break, the layout moves a block it keeps whole, or a block kept with the next, to
the next page. Word and LibreOffice break the panel's row where its lines run out instead.

Measured in Word 16 and LibreOffice on Windows, inside a filled section ("p" = page):

Inside the panel Page Word / LibreOffice
a stack of one layer, three lines all on p2 two lines at the foot of p1, the third on p2 / same
a section of three lines kept together all on p2 two at the foot of p1 / same
a heading kept with the line under it both on p2 heading at the foot of p1, the line on p2 / same
a filled section kept together all on p2 all on p2 / same
a row holding a card all on p2 all on p2 / same

Nothing was named.

Keeps cannot fix it. With w:keepNext written on the stack's paragraphs in the panel's cell,
both editors broke the row in the same place, so the block is named rather than written. Writing
such a panel in pieces at the layout's break is a separate step. That step would also fix the
4.7pt the panel's text stands low on the next page.

What changed

  • keepThePanelMayBreak, before a block is written in writePlacedNode, makes it a
    candidate when:

    • the block is written straight in the panel's cell and is on one page in the layout;
    • it starts on a later page than the panel's last block ended on;
    • it is kept together, a layer stack or a shape container (moved whole), or kept with the next.

    A candidate moves the panel's page on, so what it holds is not a candidate again.

  • reportAKeepThePanelBreaks, after the block is written, names (APPROXIMATED) a
    candidate:

    • one kept with the next always;
    • one moved whole only when it wrote at least two pieces Word may set on different pages
      (piecesWordMaySplit). A piece is a paragraph that shows something, or a row: one for a row
      that may not split, otherwise as many as its tallest cell holds.

    So one line, one picture, a drawing or a row that may not split is not named, and a painted
    section kept together, its own row one that may not split, is not either.

  • panelLastEndPage is the panel's page:

    • writeNode updates it;
    • writePanelPiece keeps it across a panel written straight into another, whose row breaks
      before it too, and resets it for a panel in any other cell (a row's or a column's);
    • it is restored after each panel, so the next panel, or a piece after a page break, starts
      fresh, and reset per export.
  • Docs:

    • the recipe's "Keeping together" bullet under "What a panel keeps and loses", which said keeps
      in a panel carry as anywhere else;
    • CHANGELOG v2.5.0.

Verification

  • Corpus, 62 DOCX before and after: all 62 are byte-identical, and the report's 1246 notes
    are identical.
  • Example: word-export-companion.docx was regenerated. It differs from the committed one only
    in docProps/core.xml, the export's time.
  • Probe, each case above at six heights: the note fires exactly on the three that break, and
    no DOCX changes.
  • DocxPanelKeepReportTest (new, 16 tests). Each note is checked by its node's path, and
    each "not named" case first asserts the page the block starts on.
    • named:
      • a stack;
      • a section kept together;
      • a band;
      • a shape container;
      • a heading kept with the next;
      • a painted section kept together and with the next, as kept with the next;
      • a stack opening a panel inside the panel, once, though it holds a kept section;
    • not named:
      • a painted section kept together;
      • a card in a row;
      • a stack in a row's cell;
      • a stack holding a row;
      • a single line kept together;
      • one on the panel's first page;
      • one opening the piece after a page break;
      • one opening the next panel;
      • one in the flow.
  • 14 sabotages, all caught:
    • never named;
    • named in any cell;
    • named on the panel's first page;
    • never reset;
    • not restored;
    • not tracked;
    • one-layer stacks only;
    • no keep with the next;
    • named again for what it holds;
    • no shape containers;
    • no pieces counted;
    • empty paragraphs counted;
    • a row that may not split counted by its cells;
    • a single piece kept with the next dropped.
  • ./mvnw -B -ntp clean verify: BUILD SUCCESS.
  • Knowledge pack: the API surfaces, stability doc, claims and routes checks pass, and core
    javadoc passes with no warnings.

Lane: render-docx (semantic backend), report only. No DOCX bytes change.

Inside a panel the layout runs over a page break, a block it keeps
whole or with the next moves to the next page, but Word and
LibreOffice break the panel's row where its lines run out and hold no
keeps across that break. Measured in both, a stack of three lines or a
section kept together moved whole to the next page stood with two of
its lines at the foot of the page above, and a heading kept with the
line under it stood there alone. Nothing was named.

The report now names such a block. A filled section kept together and
a row, which Word moves whole, are not named.
@DemchaAV
DemchaAV marked this pull request as draft October 20, 2026 20:52
A block moved whole inside a panel was named even where Word cannot
split it: one line, one picture, a drawing, a row that may not split.
It is now named only when it wrote at least two pieces Word may set on
different pages, counted after it is written; a painted section kept
together, whose own row may not split, is one such piece.

A shape container the layout moves whole is named as a stack is, and
a painted section kept together and with the next is named as kept
with the next, which Word may leave behind.
@DemchaAV
DemchaAV marked this pull request as ready for review October 20, 2026 21:29
@DemchaAV
DemchaAV merged commit b530421 into 2.5-dev Oct 20, 2026
13 checks passed
@DemchaAV
DemchaAV deleted the fix/docx-panel-stack-whole branch October 20, 2026 21:40
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