Skip to content

fix(docx): name in the report what each written or drawn node goes without - #856

Merged
DemchaAV merged 2 commits into
2.5-devfrom
fix/docx-report-drawing-losses
Oct 5, 2026
Merged

DemchaAV merged 2 commits into
2.5-devfrom
fix/docx-report-drawing-losses

Conversation

@DemchaAV

@DemchaAV DemchaAV commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner

Why

The DOCX export wrote or drew these nodes and said nothing about what it left behind, while DocxExportReport promises to say it:

  • a linked logo became an unlinked picture;
  • a rotated photo stood upright;
  • a dashed line was drawn solid;
  • a section, table or picture lost its outline entry;
  • an anchor on a drawn shape got no bookmark, because a drawing is no paragraph a bookmark can hold: a link to it pointed at none, and a page reference to it was written as a fixed number;
  • a section or container laid out as a layer stack's column got no bookmark either, while a link or a PAGEREF to its anchor still named one.

DocxNodeFieldLedgerTest (#855) listed most of these as gaps, and the column anchor as written.

What changed

  • carriedWithout(node, drawn[, paint]) names what a node goes without:
    • its link and outline entry;
    • drawn as a shape: its anchor, a shape's gradient fill and unequal corners (drawn at the largest radius), a line's dash pattern (drawn solid);
    • a line's caps. A drawn line's outline is written with no cap, so the note says the editor ends it its own way rather than claiming a particular result. A rule's caps are lost because a border ends flat;
    • an image's transform.
  • Where each note lands:
    • Drawings (drawOwnFragments), pictures beside their text or over a badge (drawWhereThePagePutsIt) and barcodes add these losses to the note they already had. drawOwnFragments adds them for drawings only: a painted section's own losses are named where the section is written, so they are not named twice.
    • A rule, an inline picture, a table, and a section or container get one note each through reportWrittenWithout, whichever path writes them:
      • the page flow;
      • a panel;
      • a layer stack's column (writeLayerColumns, which never dispatches the layer itself). This note also names the column's anchor, since no bookmark goes round a column;
      • inside a node laid over the flow.
    • A line rule's link stays under its existing rule link subject, so it is not named twice. A table with no rows, which writes nothing, gets no note.
  • A drawing composed in a table cell (drawnByItsTable) names its link, outline entry, anchor, unequal corners and caps. The table's cell drawing note already names a gradient, a dash, a clip or a transform for every drawing its cells hold, so paint=false leaves out only the gradient and the dash.
  • A shape painted only with a gradient (no stroke) is dropped with that reason instead of "its geometry has no semantic Word analogue". In a table cell it was taken for drawn by its table, which drew nothing of it, and went unreported. paintedOnlyWithAGradient now holds it back there, as drawsAFlatColour already did for a path.
  • The ledger:
    • 21 node fields move from a gap to REPORTED.
    • Two WRITTEN fields move to REPORTED: a section's and a container's anchor, which as a layer stack's column get no bookmark.
    • 34 node-field gaps remain, each named.
  • The recipe, the capability matrix (Rectangle, Ellipse and Line rows) and the CHANGELOG say what each note now names.

Not changed: a link or a PAGEREF to a column's anchor still names a bookmark the file does not hold. Bookmarking the column changes what is written, so it is left to a change of its own. Here it is reported.

Verification

  • ./mvnw -B -ntp install -pl :graph-compose-render-docx → BUILD SUCCESS: 990 tests, 0 failures, 1 skipped (the property-gated fidelity probe).
  • DocxCarriedWithoutReportTest is new, 18 tests. Each test of a node the export writes or draws checks which path wrote it through the start of its note, such as written as a paragraph border, drawn as a shape, composed in a table cell or written over the flow as what it holds:
    • a drawn shape, ellipse and line, with every property set;
    • a bar written as a rule, with an anchor, which must not be named;
    • a rule's caps;
    • an inline picture and one beside its label;
    • a table;
    • the page flow and a panel;
    • a section as a layer stack column, and a section and a container column with anchors;
    • a section inside a sidebar laid over the flow, and a painted one, whose outline entry is named once;
    • a shape and a line in table cells: corners and caps named, the gradient left to the table's note;
    • a gradient-only shape, alone and in a table cell beside a box the table draws;
    • a document whose nodes lose nothing and get no note.
  • The new tests fail without the code they cover. Each of three guards was removed in turn and its test failed: the corners and caps of a cell drawing, the drawings-only append in drawOwnFragments, and the gradient guard in drawnByItsTable.
  • The DOCX bytes do not change. The 62 corpus documents exported deterministically are byte-identical to the export before the change: DocxFidelityCorpusTest -Dgraphcompose.docxFidelity=export, SHA-256 per file, 0 of 62 differ.
  • Documentation and qa DOCX tests:
    • -pl :graph-compose-core -Dtest='com.demcha.documentation.**' → 166 tests, 0 failures;
    • qa documentation guards plus DocxPageZoneTest, DocxTransparentWrapperTest, TimelineRailAcrossBackendsTest and RtlAcrossBackendsTest → 52 tests, 0 failures.
  • The full reactor gate was not run; no public API, POM or workflow file changed.

Lane: render-docx backend (report only, no change to what is written) plus tests and docs.

…thout

The export wrote or drew these nodes and said nothing of what it left behind:
a linked logo became an unlinked picture, a rotated photo stood upright, a
dashed line was drawn solid, an anchor on a drawn shape left a page reference
or a link to it pointing at no bookmark.

carriedWithout names, per node, a link, an outline entry, a drawn shape's
anchor, gradient fill and unequal corners, a line's dash and caps, and an
image's transform. Drawn shapes, pictures beside their text and barcodes add
these to the note they had; a rule, a picture in the flow, a table, a section
or container - the page flow, a panel, a layer stack's column, one laid over
the flow - gets a note of its own; a drawing composed in a table cell names
what no drawing carries, leaving its paint to the table's note. A shape
painted only with a gradient is dropped for that reason. A drawn line's caps
are said to be left to the editor, as its outline is written without one.

The ledger moves 21 node fields from a gap to REPORTED, and records a
section's anchor as a gap where the section is a layer stack's column: its
bookmark is not written, though a page reference to it is a PAGEREF. The DOCX
bytes do not change.
com.demcha.compose.document.node.DocumentLinkTarget link = null;
com.demcha.compose.document.node.DocumentBookmarkOptions outline = null;
String anchor = null;
if (node instanceof com.demcha.compose.document.node.ShapeNode shape) {
…ps in the report

A section or container written as a layer stack's column gets no bookmark,
while a link or a page reference to its anchor still names one; its note
now says so, and the ledger moves both anchors from written to reported.
A drawing composed in a table cell names its unequal corners and caps,
which the table's note does not; only the gradient and the dash are left
to it. A gradient-only shape in a cell is no longer taken for drawn by its
table, and is dropped for its gradient. A painted section laid over the
flow names its outline entry once. A drawn anchor's page reference is said
to be a fixed number, which is what is written.
@DemchaAV
DemchaAV merged commit 9bc4447 into 2.5-dev Oct 5, 2026
13 checks passed
@DemchaAV
DemchaAV deleted the fix/docx-report-drawing-losses branch October 5, 2026 22:31
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.

2 participants