@@ -883,6 +883,92 @@ describe('layoutDocument', () => {
883883 expect ( section2Page ! . margins . top ) . toBeGreaterThanOrEqual ( 72 + tallFirst - 1 ) ;
884884 } ) ;
885885
886+ it ( 'uses physical page number for even/odd variant selection when oddEvenHeadersFooters is enabled' , ( ) => {
887+ const m = { top : 72 , bottom : 72 , left : 72 , right : 72 , header : 36 , footer : 36 } ;
888+
889+ // Single section with alternateHeaders. Odd physical pages get 'odd' variant,
890+ // even physical pages get 'even' variant. Each variant has a different header
891+ // height so we can verify the correct one drives margin inflation.
892+ const sb0 : FlowBlock = {
893+ kind : 'sectionBreak' ,
894+ id : 'sb-0' ,
895+ type : 'continuous' ,
896+ margins : m ,
897+ headerRefs : { default : 'd0' , even : 'e0' , odd : 'o0' } ,
898+ attrs : { isFirstSection : true , sectionIndex : 0 } ,
899+ } ;
900+
901+ const lineHeight = 20 ;
902+ const blocks : FlowBlock [ ] = [ sb0 , { kind : 'paragraph' , id : 'p0' , runs : [ ] } ] ;
903+ const measures : Measure [ ] = [
904+ { kind : 'sectionBreak' } ,
905+ makeMeasure ( Array ( 80 ) . fill ( lineHeight ) ) , // enough content for multiple pages
906+ ] ;
907+
908+ const evenHeight = 120 ;
909+ const oddHeight = 80 ;
910+ const sectionMetadata : SectionMetadata [ ] = [
911+ { sectionIndex : 0 , headerRefs : { default : 'd0' , even : 'e0' , odd : 'o0' } } ,
912+ ] ;
913+
914+ const layout = layoutDocument ( blocks , measures , {
915+ pageSize : { w : 612 , h : 792 } ,
916+ margins : m ,
917+ sectionMetadata,
918+ oddEvenHeadersFooters : true ,
919+ headerContentHeightsByRId : new Map ( [
920+ [ 'e0' , evenHeight ] ,
921+ [ 'o0' , oddHeight ] ,
922+ ] ) ,
923+ } ) ;
924+
925+ expect ( layout . pages . length ) . toBeGreaterThanOrEqual ( 2 ) ;
926+
927+ // Page 1 (physical 1, odd): odd variant → margin inflated by oddHeight
928+ const page1 = layout . pages [ 0 ] ;
929+ expect ( page1 . margins . top ) . toBeGreaterThanOrEqual ( 36 + oddHeight - 1 ) ;
930+
931+ // Page 2 (physical 2, even): even variant → margin inflated by evenHeight
932+ const page2 = layout . pages [ 1 ] ;
933+ expect ( page2 . margins . top ) . toBeGreaterThanOrEqual ( 36 + evenHeight - 1 ) ;
934+ // Even margin should be larger than odd margin since evenHeight > oddHeight
935+ expect ( page2 . margins . top ) . toBeGreaterThan ( page1 . margins . top ) ;
936+ } ) ;
937+
938+ it ( 'does not use even/odd variants when oddEvenHeadersFooters is not set' , ( ) => {
939+ const m = { top : 72 , bottom : 72 , left : 72 , right : 72 , header : 36 , footer : 36 } ;
940+ const sb0 : FlowBlock = {
941+ kind : 'sectionBreak' ,
942+ id : 'sb-0' ,
943+ type : 'continuous' ,
944+ margins : m ,
945+ headerRefs : { default : 'd0' , even : 'e0' } ,
946+ attrs : { isFirstSection : true , sectionIndex : 0 } ,
947+ } ;
948+
949+ const lineHeight = 20 ;
950+ const blocks : FlowBlock [ ] = [ sb0 , { kind : 'paragraph' , id : 'p0' , runs : [ ] } ] ;
951+ const measures : Measure [ ] = [ { kind : 'sectionBreak' } , makeMeasure ( Array ( 80 ) . fill ( lineHeight ) ) ] ;
952+
953+ const tallEven = 200 ;
954+ const layout = layoutDocument ( blocks , measures , {
955+ pageSize : { w : 612 , h : 792 } ,
956+ margins : m ,
957+ sectionMetadata : [ { sectionIndex : 0 , headerRefs : { default : 'd0' , even : 'e0' } } ] ,
958+ // oddEvenHeadersFooters NOT set
959+ headerContentHeightsByRId : new Map ( [
960+ [ 'e0' , tallEven ] ,
961+ [ 'd0' , 10 ] ,
962+ ] ) ,
963+ } ) ;
964+
965+ // Without oddEvenHeadersFooters, all pages use 'default' variant —
966+ // margins should NOT be inflated by the even header height
967+ for ( const page of layout . pages ) {
968+ expect ( page . margins . top ) . toBeLessThan ( 36 + tallEven ) ;
969+ }
970+ } ) ;
971+
886972 it ( 'applies section break margins to subsequent pages' , ( ) => {
887973 const sectionBreakBlock : FlowBlock = {
888974 kind : 'sectionBreak' ,
0 commit comments