Repository navigation
fix(docx): anchor a drawing in the paragraph whose text it stands beside, so it moves with that text - #852
Merged
Conversation
…ide, so it moves with that text A shape the page paints (a timeline's dot, an icon by a heading, a skill's bar, a badge) was placed from the page's edges, so editing the text above it moved the text and left the shape behind. DocxDrawingAnchors now anchors each shape in the nearest paragraph within 48pt that it hangs from, placed down from that paragraph's top as Word reckons it: the space above included, an exact line's baseline four fifths of the way down, raised by the run's position. In a table cell it is laid out in the cell and placed from the cell's text column. A shape beside no such paragraph stays on the page. The Word editing protocol gains a drawings-follow-text scenario.
…, not below it A cell holding a shape that hangs below its row moved the row's text in the Linux LibreOffice: an icon beside the note under a totals table, taken into the table's last cell, set two invoices' 'Total due' 2pt and 4pt up. A shape now goes into a cell only when it starts above the foot of the text written there and reaches past it by half its height at most. The tests' offset helpers fail an assertion on a value that is not a number.
…e, not to one further off The previous commit kept a shape out of a cell below the cell's text, judged by the text the export wrote there as paragraphs. That missed what a cell holds as list items or rows, and turned 23 shapes beside such text back to the page. The icon it set out to keep out stood just above the note it is beside: the note refused it, and the totals table's last cell, further off, took it. The nearest paragraph is now the only one considered; when it cannot hold the shape, the shape stays on the page. Tests pin reach at 48pt, the paragraphs that offer no top, Word's own cell margin and the nearest paragraph among several in reach. The Linux LibreOffice baseline is taken from CI: CompactMono's lines 0.1pt up, as on Windows.
…ft to the page by their nearest paragraph
…e page by their nearest paragraph
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 DOCX's drawings did not move when a reader edited the text above them. Most shapes the export draws for what the page paints were placed with
wp:positionH/positionV relativeFrom="page": a timeline's dot, an icon by a heading, a skill's bar, a badge. The exception was a drawing that is all a table cell holds. Lengthen the summary of a CV in Word, and its entries and headings move down while their dots, icons and bars stay where they were.The Word editing protocol (#847) had no scenario for this. A new one,
drawings-follow-text, lengthens the longest paragraph. It then checks that every drawing beside text the edit moved moved with that text, by as much and onto the same page. On2.5-dev, 12 of the 228 shapes beside moved text follow it.What changed
Anchoring beside the text.
DocxDrawingAnchorsholds every page-placed shape until the section ends. Then it anchors each shape in the paragraph whose text the shape stands nearest, placed down from that paragraph's top (relativeFrom="paragraph").REACH).Topof -999997, not an offset.Where Word places from (
Seat.paragraphTop). Both editors measurerelativeFrom="paragraph"from the paragraph's top, including itsspacing/@before. A probe in Word 16.0.20430 and LibreOffice agreed to 0.1pt.DocxTextBands.BASELINE_SHARE), raised by the first text run'sw:position, so the line's top isbaseline − (0.8·L − raise).TextVerticalAlignseat (seatShift).TealPulse's section rules 4.6pt high andObsidianInvoice's icon 4.8pt high. Leaving the seat out putLumaStudio's rule under a 36pt title 14.8pt high.In a table cell (
Seat.column). The shape is laid out in the cell (layoutInCell="1") and placed from the cell's text column (relativeFrom="column"). The column is the paragraph's text edge less its indent. The cell's left margin is taken off only to find the cell's edge, for whether the cell holds the shape across.layoutInCell="0", Word measured the shape from the cell's top instead of the paragraph's.Which paragraphs offer a place (
DocxSemanticBackend.offerASeat). Every paragraph written for aParagraphNodeis offered, with where the layout sets the node's first line (DocxLayoutMetrics.firstTextBox).Drawing XML.
DocxDrawings.drawingInParagraphwrites a body paragraph's shapes: placed across from the page, down from the paragraph.drawingInCellwrites a cell's.Report and docs.
docs/recipes/docx-export.md(drawings, panels);docs/recipes/timelines.md;docs/recipes/shape-as-container.md;docs/getting-started.md;docs/architecture/canonical-legacy-parity.md;CONTRIBUTING.mdlists the new protocol scenario.Verification
Editing protocol (Word 16.0.20430, the 35 corpus documents with drawings,
-Scenario drawings-follow-text):2.5-devTimelineMinimal's column-divider axis, a portrait far from its name;Where shapes stand, unedited. Each shape was matched by kind and size in the Word and LibreOffice PDFs of
2.5-devand this PR:OrangeOps's header separator. That separator now follows its line of text, which LibreOffice already sets 78pt low.Text fidelity. The Word, LibreOffice Windows and LibreOffice Linux gates pass. Lines that move:
CompactMono. All of its lines move together: −0.12pt in Word (52 lines), −0.10pt in LibreOffice (58 lines, both platforms). Its drawings left its first paragraph, whose line had held them. Its worst line goes 1.01 → 0.91pt in Word and 0.93 → 0.83pt in LibreOffice.TealPulseon Linux. Its contact line comes 0.93 → 0.08pt nearer.Baselines are committed; the Linux one is taken from this PR's CI artifact.
Tests:
DocxDrawingAnchorsTest(new, 17 tests) covers:DocxDrawingsTest:DocxCellDrawingTestcounts shapes left out of their cell.Sabotage. Each rule fails its test when broken:
render-docx: 940 tests green.
Full reactor gate:
./mvnw -B -ntp clean verify -pl :graph-compose-core,:graph-compose-render-pdf,:graph-compose-render-docx,:graph-compose-render-pptx,:graph-compose-templates,:graph-compose-testing,:graph-compose-qa,:graph-compose-coverage -am→ BUILD SUCCESS (render-docx 940, qa 1820).CommittedAssetDriftTest3 / 3 green.Notes
ParagraphNodeused in two places shares one layout path, so a shape beside its second use is anchored with its first.Lane: shared-engine (render-docx).