fix(docx): put a header or footer as far from its page edge as the page does - #714
Merged
Merged
Conversation
…ge does Nothing was written for the distance, so Word used its own 36pt and the probe corpus's footer sat 14.5pt higher than the page draws it, on every page. The engine does not state the distance either: a zone is a band of a given height against the edge, with its content laid out inside it from the top. So the distance is read from where the zone's content landed in the resolved layout — the lowest edge of a footer's fragments, the highest of a header's — and written as w:pgMar/@w:footer or @w:header. Without a layout, the zone's own padding on that edge stands in. Measured through LibreOffice, the footer now lands within 0.6pt of the page. The recipe also stopped claiming that headers and footers are ignored: the text slots are, a page zone has not been since it shipped.
placeZone parsed the page height back out of the XML it had just written, which CodeQL flags as a NumberFormatException nothing catches. It never needed the XML: the page geometry was written from the canvas, so the height now comes from the canvas. The same parse-it-back pattern sat in three older places — the spacing accumulator, a cell's margin reader, and a nested table's usable width — each flagged the same way when it landed. XmlBeans hands a measure back as the schema's union, which may legally be a unit string or a percentage; this export only ever writes plain twips, and those come back as a Number. So a written value is read as a Number and anything else is reported as unknown, with no parsing left in these paths.
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 export never wrote how far a header or footer sits from its page edge, so Word used its
own distance — 36pt. On the probe corpus that put the footer 14.5pt higher than the page
draws it, on both pages:
What changed
The distance is read from the resolved layout, not rebuilt from the zone's parts. A zone
is a band of a given height against its edge, and its content is laid out inside the band
from the top — so for a footer, neither the band's height nor its padding is the distance to
the text.
DocxLayoutMetrics.zoneDistanceFromEdgefinds the zone's fragments by the@page-zone[0][index]prefix they are spliced in under and takes the lowest edge of afooter's, or the highest of a header's;
placeZonewrites that asw:pgMar/@w:footeror@w:header.Without a layout, the zone's own padding on that edge stands in — exact for a header,
whose content starts at its padding, and the nearer estimate for a footer. It is reached
only when the document could not be laid out at all.
Written twips are read back as numbers, not parsed.
placeZonefirst parsed the pageheight back out of the XML it had just written, which CodeQL flagged as an uncaught
NumberFormatException. It never needed the XML — the page geometry is written from thecanvas, so the height now comes from the canvas. The same parse-it-back pattern sat in three
older places (the spacing accumulator, a cell's margin reader, a nested table's usable width),
each flagged the same way when it landed; XmlBeans hands a measure back as the schema's union,
which may legally be a unit string or a percentage, and this export only ever writes plain
twips, which come back as a
Number. So a written value is read as aNumberand anythingelse is reported as unknown. No parsing is left on these paths.
The recipe said headers and footers are ignored. The text slots are; a page zone has
exported as a real Word header or footer part since it shipped, and the recipe now says so.
Verification
./mvnw -B -ntp clean verifyover the eight-module gate → BUILD SUCCESS (core 815,render-pdf 337, render-docx 230, testing 5, render-pptx 140, templates 127, qa 1784).
./mvnw -B -ntp test -f examples/pom.xml→ 93 tests, BUILD SUCCESS; no committed previewdrifted.
Same corpus, same editor, after the change: the footer lands at 817.5 against the page's
818.1 on both pages — −0.6pt. The written value is
w:footer="443"(22.2pt). The worstline anywhere in the document is now the billing table's
Totalrow, 2.0pt low.render-docx goes from 227 to 230 tests.
DocxPageZonePositionTestasserts relations thathold whatever the font measures: a band 30pt taller puts its footer exactly 600 twips further
from the edge, and inside the band rather than at Word's 720; a header's distance is its top
padding; and without a layout a footer falls back to its bottom padding.
Lane: canonical —
document.backend.semantic.docxonly. No public API change.