@@ -826,6 +826,92 @@ describe('layoutDocument', () => {
826826 expect ( section2Page ! . margins . top ) . toBeGreaterThanOrEqual ( 72 + tallFirst - 1 ) ;
827827 } ) ;
828828
829+ it ( 'uses physical page number for even/odd variant selection when oddEvenHeadersFooters is enabled' , ( ) => {
830+ const m = { top : 72 , bottom : 72 , left : 72 , right : 72 , header : 36 , footer : 36 } ;
831+
832+ // Single section with alternateHeaders. Odd physical pages get 'odd' variant,
833+ // even physical pages get 'even' variant. Each variant has a different header
834+ // height so we can verify the correct one drives margin inflation.
835+ const sb0 : FlowBlock = {
836+ kind : 'sectionBreak' ,
837+ id : 'sb-0' ,
838+ type : 'continuous' ,
839+ margins : m ,
840+ headerRefs : { default : 'd0' , even : 'e0' , odd : 'o0' } ,
841+ attrs : { isFirstSection : true , sectionIndex : 0 } ,
842+ } ;
843+
844+ const lineHeight = 20 ;
845+ const blocks : FlowBlock [ ] = [ sb0 , { kind : 'paragraph' , id : 'p0' , runs : [ ] } ] ;
846+ const measures : Measure [ ] = [
847+ { kind : 'sectionBreak' } ,
848+ makeMeasure ( Array ( 80 ) . fill ( lineHeight ) ) , // enough content for multiple pages
849+ ] ;
850+
851+ const evenHeight = 120 ;
852+ const oddHeight = 80 ;
853+ const sectionMetadata : SectionMetadata [ ] = [
854+ { sectionIndex : 0 , headerRefs : { default : 'd0' , even : 'e0' , odd : 'o0' } } ,
855+ ] ;
856+
857+ const layout = layoutDocument ( blocks , measures , {
858+ pageSize : { w : 612 , h : 792 } ,
859+ margins : m ,
860+ sectionMetadata,
861+ oddEvenHeadersFooters : true ,
862+ headerContentHeightsByRId : new Map ( [
863+ [ 'e0' , evenHeight ] ,
864+ [ 'o0' , oddHeight ] ,
865+ ] ) ,
866+ } ) ;
867+
868+ expect ( layout . pages . length ) . toBeGreaterThanOrEqual ( 2 ) ;
869+
870+ // Page 1 (physical 1, odd): odd variant → margin inflated by oddHeight
871+ const page1 = layout . pages [ 0 ] ;
872+ expect ( page1 . margins . top ) . toBeGreaterThanOrEqual ( 36 + oddHeight - 1 ) ;
873+
874+ // Page 2 (physical 2, even): even variant → margin inflated by evenHeight
875+ const page2 = layout . pages [ 1 ] ;
876+ expect ( page2 . margins . top ) . toBeGreaterThanOrEqual ( 36 + evenHeight - 1 ) ;
877+ // Even margin should be larger than odd margin since evenHeight > oddHeight
878+ expect ( page2 . margins . top ) . toBeGreaterThan ( page1 . margins . top ) ;
879+ } ) ;
880+
881+ it ( 'does not use even/odd variants when oddEvenHeadersFooters is not set' , ( ) => {
882+ const m = { top : 72 , bottom : 72 , left : 72 , right : 72 , header : 36 , footer : 36 } ;
883+ const sb0 : FlowBlock = {
884+ kind : 'sectionBreak' ,
885+ id : 'sb-0' ,
886+ type : 'continuous' ,
887+ margins : m ,
888+ headerRefs : { default : 'd0' , even : 'e0' } ,
889+ attrs : { isFirstSection : true , sectionIndex : 0 } ,
890+ } ;
891+
892+ const lineHeight = 20 ;
893+ const blocks : FlowBlock [ ] = [ sb0 , { kind : 'paragraph' , id : 'p0' , runs : [ ] } ] ;
894+ const measures : Measure [ ] = [ { kind : 'sectionBreak' } , makeMeasure ( Array ( 80 ) . fill ( lineHeight ) ) ] ;
895+
896+ const tallEven = 200 ;
897+ const layout = layoutDocument ( blocks , measures , {
898+ pageSize : { w : 612 , h : 792 } ,
899+ margins : m ,
900+ sectionMetadata : [ { sectionIndex : 0 , headerRefs : { default : 'd0' , even : 'e0' } } ] ,
901+ // oddEvenHeadersFooters NOT set
902+ headerContentHeightsByRId : new Map ( [
903+ [ 'e0' , tallEven ] ,
904+ [ 'd0' , 10 ] ,
905+ ] ) ,
906+ } ) ;
907+
908+ // Without oddEvenHeadersFooters, all pages use 'default' variant —
909+ // margins should NOT be inflated by the even header height
910+ for ( const page of layout . pages ) {
911+ expect ( page . margins . top ) . toBeLessThan ( 36 + tallEven ) ;
912+ }
913+ } ) ;
914+
829915 it ( 'applies section break margins to subsequent pages' , ( ) => {
830916 const sectionBreakBlock : FlowBlock = {
831917 kind : 'sectionBreak' ,
0 commit comments