docs: the header band is max(declared height, content + its gap)
The note said a header's fo:margin-bottom just hangs into the body and does not move it. Probed against soffice on one-page fixtures: a 20mm top margin with a one-line 10pt header puts the body at 24.07mm with no gap and 29.07mm with a 5mm one, three paragraphs at 37.21, a paragraph wrapping to two lines at 33.14 (so rendered lines count, not paragraphs), and fo:min-height 20mm at 40.00 — the floor wins, the gap is not added on top. Padding counts too.
This commit is contained in:
1 parent
ae7bf878d8
commit
a7cf09a6be
1 file changed
+1
-1
@@ -49,7 +49,7 @@ The **Open .odt** button (`App.svelte`) parses an uploaded file with `importOdt(
|
||||
|
||||
## Header/footer import
|
||||
|
||||
- **Import:** `StyleResolver.masterPageHF()` reads `style:header`/`style:footer` + the header/footer-style heights; `pageGeometry()` reconstructs the body margin (page margin + zone height + spacing) and `edgeDistancesCm()` returns the raw page margins as the zone distances. `style:page-usage="mirrored"` on the page layout marks the left/right pair as **inner/outer**, so an even page swaps them (`margins.mirrored`, set only when true). `style:writing-mode` starting `rl` is a right-to-left page (`rtl`); DOCX reads the section's `w:bidi` for the same thing. The zone's gap to the body is laid out *inside* the band, not added to it, and `style:dynamic-spacing` changes neither side. The band is the declared height only as a **floor**: LibreOffice grows it to hold the zone's own lines, and a footer's first paragraph `fo:margin-top` rides the band with them — a header's `fo:margin-bottom` does not, it just hangs into the body (all probed). That growth is the runtime reach (`Editor.svelte`'s `hfReachPx`, which takes the biggest run's size as the line height and the zone paragraph's `spaceBefore`), so a page whose zone is empty keeps the floor. `convertHfZone` → single-paragraph doc (extra paragraphs → hard breaks; a text-less zone that carries a background/border rule line is kept, box props merged with the bottom rule from the last paragraph); `convertInline(…, hfFields=true)` keeps `text:page-number`/`-count` as field nodes. A master page whose `style:next-style-name` points at *another* master governs one page only (the "different first page" idiom): its own zones become the first-page variants and the successor's the running ones — read as the running header instead, a title-page master repeats on every page of its section and its height pushes each block onto its own page. A zone's positioned (non-`as-char`) frame keeps its wrap and its `svg:x`/`svg:y` from the page corner: it is out of flow (a letterhead or full-page title background), so `HeaderFooterLayer` paints it per page behind the body and the zone's reach ignores it — inline it would reserve a page-tall line of body space. Text boxes there are still dropped with a warning. `hfIsEmpty` counts a rule-/shading-only paragraph as non-empty so it renders and exports.
|
||||
- **Import:** `StyleResolver.masterPageHF()` reads `style:header`/`style:footer` + the header/footer-style heights; `pageGeometry()` reconstructs the body margin (page margin + zone height + spacing) and `edgeDistancesCm()` returns the raw page margins as the zone distances. `style:page-usage="mirrored"` on the page layout marks the left/right pair as **inner/outer**, so an even page swaps them (`margins.mirrored`, set only when true). `style:writing-mode` starting `rl` is a right-to-left page (`rtl`); DOCX reads the section's `w:bidi` for the same thing. The band LibreOffice lays out is **`max(declared height, zone content + the zone's own gap)`**, and the body starts at the page margin plus it — `style:dynamic-spacing` changes neither side. Probed on a 20mm top margin, 10pt zone: one line + `fo:margin-bottom` 0 → body at 24.07mm, the same with 5mm → 29.07, three lines → 37.21, one line under `fo:min-height="20mm"` → 40.00 (the floor wins, the gap is not added on top). A zone paragraph that *wraps* counts as the lines it renders, and its own `fo:padding` counts too. The importer folds only `max(height, gap)` into the page margin, and the runtime reach (`Editor.svelte`'s `hfReachPx`) then adds the content but not the gap, counting paragraphs rather than rendered lines — so a wrapping multi-paragraph header comes out short (measured: 14.9mm on one file, three lines and 4.99mm of gap read as two lines and none). `convertHfZone` → single-paragraph doc (extra paragraphs → hard breaks; a text-less zone that carries a background/border rule line is kept, box props merged with the bottom rule from the last paragraph); `convertInline(…, hfFields=true)` keeps `text:page-number`/`-count` as field nodes. A master page whose `style:next-style-name` points at *another* master governs one page only (the "different first page" idiom): its own zones become the first-page variants and the successor's the running ones — read as the running header instead, a title-page master repeats on every page of its section and its height pushes each block onto its own page. A zone's positioned (non-`as-char`) frame keeps its wrap and its `svg:x`/`svg:y` from the page corner: it is out of flow (a letterhead or full-page title background), so `HeaderFooterLayer` paints it per page behind the body and the zone's reach ignores it — inline it would reserve a page-tall line of body space. Text boxes there are still dropped with a warning. `hfIsEmpty` counts a rule-/shading-only paragraph as non-empty so it renders and exports.
|
||||
|
||||
## Defaults on DOCX import
|
||||
|
||||
|
||||
Reference in new issue
Block a user