fix: a header/footer's gap to the body is inside its band, not above it
The body margin reserved the zone's height *plus* its fo:margin-top/-bottom, so every page with a footer lost a line — a fixture ran a page over. Probed against soffice: moving a footer's fo:margin-top leaves the last body line exactly where it was and only shifts the footer text down its band; style:dynamic-spacing changes neither side. The band is the declared height, the gap sits in it. One fixture paginates to LibreOffice's 63 pages again.
This commit is contained in:
1 parent
d6c3602429
commit
71ecc17a9e
2 files changed
+9
-9
No files matched your search
@@ -587,12 +587,11 @@ export class StyleResolver {
|
||||
const height = lengthToCm(props.getAttributeNS(NS.svg, 'height'))
|
||||
?? lengthToCm(props.getAttributeNS(NS.fo, 'min-height'))
|
||||
?? 0;
|
||||
// style:dynamic-spacing="true" makes the header↔body gap collapsible (the header
|
||||
// grows into it), so the body isn't pushed down by it. Only fixed (non-dynamic)
|
||||
// spacing is added to the body margin.
|
||||
const dynamic = props.getAttributeNS(NS.style, 'dynamic-spacing') === 'true';
|
||||
const spacing = dynamic ? 0 : (lengthToCm(props.getAttributeNS(NS.fo, spacingAttr)) ?? 0);
|
||||
return height + spacing;
|
||||
// The zone's gap to the body is laid out *inside* that height, not added to it
|
||||
// (probed: a footer's fo:margin-top moves its text down the band and leaves the
|
||||
// last body line where it was; style:dynamic-spacing changes neither side).
|
||||
const spacing = lengthToCm(props.getAttributeNS(NS.fo, spacingAttr)) ?? 0;
|
||||
return Math.max(height, spacing);
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -1075,9 +1075,10 @@ describe('Leg 4: foreign header/footer → importOdt', () => {
|
||||
check('foreign hf: page-number field', hPara?.content?.some((n: N) => n.type === 'pageNumber'), hPara);
|
||||
check('foreign hf: page-count field', hPara?.content?.some((n: N) => n.type === 'pageCount'), hPara);
|
||||
check('foreign hf: footer text', fhf.footer?.content?.[0]?.content?.[0]?.text === 'Confidential', fhf.footer);
|
||||
// Body top margin = page margin (1.5) + header height (0.8) + spacing (0.3) = 2.6.
|
||||
check('foreign hf: body top margin reconstructed', Math.abs((fhf.margins?.top ?? 0) - 2.6) < 0.02, fhf.margins);
|
||||
check('foreign hf: body bottom margin reconstructed', Math.abs((fhf.margins?.bottom ?? 0) - 2.4) < 0.02, fhf.margins);
|
||||
// Body top margin = page margin (1.5) + the header band (0.8): its 0.3 spacing to
|
||||
// the body is laid out inside that height, not added to it (styleResolver.ts).
|
||||
check('foreign hf: body top margin reconstructed', Math.abs((fhf.margins?.top ?? 0) - 2.3) < 0.02, fhf.margins);
|
||||
check('foreign hf: body bottom margin reconstructed', Math.abs((fhf.margins?.bottom ?? 0) - 2.1) < 0.02, fhf.margins);
|
||||
// header-first is a supported variant (Word "Different First Page" / ODF header-first).
|
||||
check('foreign hf: first-page header parsed', fhf.headerFirst?.content?.[0]?.content?.[0]?.text === 'Cover', fhf.headerFirst);
|
||||
check('foreign hf: different-first-page flag set', fhf.differentFirstPage === true, fhf.differentFirstPage);
|
||||
|
||||
Reference in new issue
Block a user