@@ -965,6 +965,69 @@ describe('computeBorderSpaceExpansion', () => {
965965 } ) ;
966966} ) ;
967967
968+ // ---------------------------------------------------------------------------
969+ // createParagraphDecorationLayers — border layer positioning
970+ // ---------------------------------------------------------------------------
971+
972+ describe ( 'createParagraphDecorationLayers — border layer positioning' , ( ) => {
973+ const PX_PER_PT = 96 / 72 ;
974+
975+ it ( 'extends borders into margins using negative offsets' , ( ) => {
976+ const attrs = {
977+ borders : {
978+ top : { style : 'solid' as const , width : 2 , space : 5 } ,
979+ bottom : { style : 'solid' as const , width : 3 , space : 10 } ,
980+ left : { style : 'dashed' as const , width : 1 , space : 4 } ,
981+ right : { style : 'dotted' as const , width : 2 , space : 6 } ,
982+ } ,
983+ } ;
984+ const { borderLayer } = createParagraphDecorationLayers ( document , 260 , attrs ) ;
985+
986+ // top: -(space*PX_PER_PT + width)
987+ expect ( parseFloat ( borderLayer ! . style . top ) ) . toBeCloseTo ( - ( 5 * PX_PER_PT + 2 ) ) ;
988+ // bottom: -(space*PX_PER_PT + width)
989+ expect ( parseFloat ( borderLayer ! . style . bottom ) ) . toBeCloseTo ( - ( 10 * PX_PER_PT + 3 ) ) ;
990+ // left: -(space*PX_PER_PT + width) (no indent)
991+ expect ( parseFloat ( borderLayer ! . style . left ) ) . toBeCloseTo ( - ( 4 * PX_PER_PT + 1 ) ) ;
992+ // width: fragmentWidth + left expansion + right expansion
993+ const leftExpansion = 4 * PX_PER_PT + 1 ;
994+ const rightExpansion = 6 * PX_PER_PT + 2 ;
995+ expect ( parseFloat ( borderLayer ! . style . width ) ) . toBeCloseTo ( 260 + leftExpansion + rightExpansion ) ;
996+ } ) ;
997+
998+ it ( 'falls back to border width of 0 when width is not specified' , ( ) => {
999+ const attrs = {
1000+ borders : {
1001+ top : { style : 'solid' as const , space : 3 } ,
1002+ bottom : { style : 'solid' as const , space : 6 } ,
1003+ } ,
1004+ } ;
1005+ const { borderLayer } = createParagraphDecorationLayers ( document , 260 , attrs ) ;
1006+
1007+ // width defaults to 0 when not specified
1008+ expect ( parseFloat ( borderLayer ! . style . top ) ) . toBeCloseTo ( - ( 3 * PX_PER_PT ) ) ;
1009+ expect ( parseFloat ( borderLayer ! . style . bottom ) ) . toBeCloseTo ( - ( 6 * PX_PER_PT ) ) ;
1010+ } ) ;
1011+
1012+ it ( 'positions border flush when space is 0' , ( ) => {
1013+ const attrs = {
1014+ borders : {
1015+ top : { style : 'solid' as const , width : 2 , space : 0 } ,
1016+ bottom : { style : 'solid' as const , width : 2 , space : 0 } ,
1017+ left : { style : 'dashed' as const , width : 2 , space : 0 } ,
1018+ right : { style : 'dotted' as const , width : 2 , space : 0 } ,
1019+ } ,
1020+ } ;
1021+ const { borderLayer } = createParagraphDecorationLayers ( document , 260 , attrs ) ;
1022+
1023+ // space=0, so offset is just the border width
1024+ expect ( parseFloat ( borderLayer ! . style . top ) ) . toBeCloseTo ( - 2 ) ;
1025+ expect ( parseFloat ( borderLayer ! . style . bottom ) ) . toBeCloseTo ( - 2 ) ;
1026+ expect ( parseFloat ( borderLayer ! . style . left ) ) . toBeCloseTo ( - 2 ) ;
1027+ expect ( parseFloat ( borderLayer ! . style . width ) ) . toBeCloseTo ( 260 + 2 + 2 ) ;
1028+ } ) ;
1029+ } ) ;
1030+
9681031// ---------------------------------------------------------------------------
9691032// Incremental update — between-border cache invalidation
9701033// ---------------------------------------------------------------------------
0 commit comments