Repository navigation
fix(docx): hold a canvas's height in Word, and name only what Word cannot hold - #866
Merged
Merged
Conversation
…nnot hold The page gives a canvas its height whatever it holds; the export wrote what it holds one block after another and dropped the room under it. The room under what it writes is now owed as the space below it, where it moves something, and a canvas that only draws holds its whole box where nothing round it holds it already. The report names what Word cannot hold: what it writes running past its height, a drawing in what it writes that takes no room, and a height not measured.
…t an entry's end, once A canvas that only draws held no room anywhere in a band, though the band measures only the space above its layer's first block; it now holds its box between a layer's blocks, and in a column, whose resume is measured to the drawing. It holds none of its own in a block another canvas counts as taking no room, nor owes its edges where it is not held. A timeline entry's wrapped body passes on what follows it, so a canvas ending the body holds its room above the next entry. The report names a canvas ending a cell with no layout, and a drawing inside a stack of one layer.
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
The page gives a canvas its height whatever it holds: what follows starts below it, and a cell or a layer it ends is that tall. The DOCX export writes a canvas as its contents, one block after another, and dropped the room under them. What followed stood that much higher.
The report named this only where something followed the canvas in its flow. It said nothing in four cases:
DocxNodeFieldLedgerTestcarriedCanvasLayerNode.heightas the last node field markedGAP.What changed
writeCanvaswrites a canvas and holds its room.writeContainerChildrenhands every canvas to it, since a canvas paints nothing of its own.A canvas that writes something owes the room under what it writes as space below it (
owePendingSpacingAfter): itsheightless what it writes, with the blocks stacked and their margins counted. The existing plumbing puts the space in place:below, a resumed layer and the end of a section replace it or drop it, as they do any owed space.The room is owed only where it moves something: where something follows the canvas, where the canvas ends a cell, or inside an overlay's layer, whose foot a shape container measures its space from. At the end of the body, or before a page break there, it is not owed: written below the paragraph before a break, it would stay on that page.
A canvas that writes nothing (empty, or only drawing) holds its whole box through
holdTheSpaceOf, as a stack of drawings does in the flow. Whether it holds the box or not, nothing it holds owes more: the space owed before its drawings is put back after them. So a section in it that writes nothing owes no edges, and a canvas in it holds no room of its own.It holds no room of its own where something round it measures that room already, since that would count the room twice:
bandDepthwith a pendingresumeSpacing). Between a layer's blocks, and in a layer stack's column, whose resume is measured to the drawing itself, the canvas holds its box;roomHeldAround, counted in the existing drawn-only branch ofwriteNodeContentOf);roomMeasuredRoundsays something round it measures its room. That is the case where the layout lays it over another layer (a layer of a stack of several layers, of a shape container, or of a canvas), or where it stands in a block that the canvas round it writes nothing of, and so counts as taking no room.DocxLayoutMetrics.parentOfreads a node's parent from the layout.writeInBandpasses on what follows a timeline entry's wrapped body to the body itself, so a canvas ending the body holds its room above the next entry.CanvasWritesmeasures what a canvas writes in one pass:holdsADrawingWithNoRoom, looking through sections, containers, alignments, anchors and stacks of one layer).A block the layout did not place makes the canvas unmeasured, rather than counting as none, so no room is owed that the page does not hold. No laid-out document in the tests or in the corpus reaches that case.
The report (
canvasLosses) names only what Word cannot hold:The note "its height is not held: what follows starts below what it writes" is gone, because the room is written now.
Ledger:
CanvasLayerNode.heightmoves fromGAPtoREPORTED, naming those cases. No node field isGAPany more.Docs:
Verification
./mvnw -B -ntp install -pl :graph-compose-render-docx→ BUILD SUCCESS, 1146 tests, 0 failures, 1 skipped (the property-gated fidelity probe).DocxCanvasRoomTest(new, 26 tests) reads the Word file and compares it with the layout's placements, or with the difference two layouts make. Each Word distance is read from the space above and below each paragraph and from its exact line, and the test asserts that the two paragraphs are adjacent.DocxFlowContainerReportTest:The tests fail without the code they cover. 20 sabotages were run, each breaking one thing, and each made the tests that cover it fail:
One guard breaks no test: a block of a placed canvas that the layout did not place makes the canvas unmeasured. A temporary probe across the render-docx suite and the 62 corpus documents found no such canvas, so the guard stays as fail-closed.
Corpus bytes: the 62 corpus documents were exported deterministically (
DocxFidelityCorpusTest -Dgraphcompose.docxFidelity=export) and compared by SHA-256 against the export before the change. 54 are byte-identical. 8 differ, each only in its timeline's marker cells:cv-charcoal_gold,cv-midnight_navy,cv-navy_sidebar,cv-professional_sidebar,cv-serif_headline,cv-terracotta_railandreceipt-modern: each marker is a canvas that only draws, alone in its cell, and holds its room as space above the hairline paragraph in that cell;cv-violet_grid: each entry marker is a canvas holding a dot paragraph in a box the title line's height, and holds the 1.6pt under the dot.Word and LibreOffice render all eight as before. Word 16.0.20430 and LibreOffice 26.8.0.3 converted the documents from before and after the change. In each editor every word and every drawing of all eight stands at the same coordinates, on the same single page.
The report across the corpus is unchanged: 955 notes, with the same subjects and texts.
Documentation guards: core
-Dtest='com.demcha.documentation.**'→ 166 tests, 0 failures; qa documentation guards plusDocxPageZoneTest,DocxTransparentWrapperTest,TimelineRailAcrossBackendsTestandRtlAcrossBackendsTest→ 50 tests, 0 failures.The full reactor gate was not run; no public signature, POM or workflow file changed.
Known limits
Lane: render-docx backend, plus tests and docs.