Skip to content

fix(header-footer): use section-aware page numbering for odd/even parity (SD-2991)#3236

Open
luccas-harbour wants to merge 5 commits into
mainfrom
luccas/sd-2991-feature-oddeven-headers-and-footers
Open

fix(header-footer): use section-aware page numbering for odd/even parity (SD-2991)#3236
luccas-harbour wants to merge 5 commits into
mainfrom
luccas/sd-2991-feature-oddeven-headers-and-footers

Conversation

@luccas-harbour
Copy link
Copy Markdown
Contributor

Summary

  • Switches odd/even header/footer parity selection from the physical page index to a new section-aware displayNumber so headers respect OOXML <w:pgNumType w:start="…"> and per-section number restarts (ECMA-376 §17.10.1).
  • Threads a displayNumber field through the layout pipeline (PageHeaderFooterPageResolvedPageResolvedHeaderFooterPage) and stamps it from activePageCounter inside layoutDocument.
  • Adds a parityPageNumber option to the headerFooterUtils selectors (getHeaderFooterType, getHeaderFooterTypeForSection, getHeaderFooterIdForPage, resolveHeaderFooterForPage(AndSection)) so callers can override parity when needed. Also fixes the legacy single-section selector to use % 2 !== 0 for odd, so negative display numbers route to odd instead of falling through.
  • HeaderFooterSessionManager now reads displayNumber when picking header/footer variants for both per-rId layouts and inferred region variants.

Why

When a section sets <w:pgNumType w:start="2"/> (or otherwise restarts numbering), Word treats the first body page as page 2 and renders the even header on it. We were keying odd/even off the physical page index instead, so the wrong variant was selected — and downstream space reservation (header content height) used the wrong height, shifting body content vertically.

Changes by package

  • layout-engine/contracts: add optional displayNumber on Page, HeaderFooterPage, ResolvedPage, ResolvedHeaderFooterPage.
  • layout-engine/layout-engine: rename documentPageNumberparityPageNumber in getVariantTypeForPage, feed it activePageCounter, and stamp state.page.displayNumber during page creation.
  • layout-engine/layout-bridge: new parityPageNumber option threaded through every header/footer selector; existing callers default to page.displayNumber ?? page.number. Negative-odd parity now resolves to 'odd'.
  • layout-engine/layout-resolved: forward displayNumber from layout to resolved page/header-footer outputs.
  • super-editor/HeaderFooterSessionManager: use displayNumber for both region variant inference and per-rId variant lookup; preserve it when forwarding pages into header/footer layout requests.

Tests

  • layout-engine: new uses section page-numbering start for odd/even header parity test (section with numbering.start = 2 swaps body offsets on pages 1 and 2). Existing alternateHeaders tests updated to describe behavior in terms of display number.
  • layout-bridge/headerFooterUtils: new tests cover the parityPageNumber override, negative-odd handling, section-aware display-number parity, and caller-supplied parity overrides.
  • layout-resolved/resolveHeaderFooter: asserts displayNumber is preserved through resolution.
  • super-editor/HeaderFooterSessionManager: new tests verify displayNumber parity is used both when selecting per-rId header layouts and when inferring region variants.

… parity

OOXML (ECMA-376 §17.10.1) selects even/odd headers based on the printed page
number — which respects per-section numbering restarts and offsets — not the
physical page index. Track the post-restart/offset value as `displayNumber` on
each page and thread it through pagination, header/footer resolution, and the
HeaderFooterSessionManager so a section that starts at page 2 picks the `even`
variant on its first page.
@luccas-harbour luccas-harbour requested a review from a team as a code owner May 11, 2026 18:47
@linear
Copy link
Copy Markdown

linear Bot commented May 11, 2026

SD-2991

@codecov-commenter
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants