From f3cc3bdae77793e73d4a72bab55ed3331b23e2a1 Mon Sep 17 00:00:00 2001 From: PgBiel <9021226+PgBiel@users.noreply.github.com> Date: Fri, 13 Jun 2025 03:45:42 -0300 Subject: [PATCH] fix space calculation of new footers however, there are widows... --- crates/typst-layout/src/grid/layouter.rs | 12 ------------ crates/typst-layout/src/grid/repeated.rs | 9 +++++++++ tests/ref/grid-subfooters-demo.png | Bin 7234 -> 6989 bytes ...subfooters-repeat-replace-double-widow.png | Bin 1033 -> 973 bytes .../grid-subfooters-repeat-replace-gutter.png | Bin 772 -> 721 bytes ...footers-repeat-replace-multiple-levels.png | Bin 0 -> 910 bytes .../grid-subfooters-repeat-replace-widow.png | Bin 979 -> 970 bytes tests/ref/grid-subfooters-repeat-replace.png | Bin 975 -> 963 bytes 8 files changed, 9 insertions(+), 12 deletions(-) create mode 100644 tests/ref/grid-subfooters-repeat-replace-multiple-levels.png diff --git a/crates/typst-layout/src/grid/layouter.rs b/crates/typst-layout/src/grid/layouter.rs index d46040910..fd846b6e9 100644 --- a/crates/typst-layout/src/grid/layouter.rs +++ b/crates/typst-layout/src/grid/layouter.rs @@ -298,11 +298,6 @@ impl<'a> GridLayouter<'a> { self.prepare_next_repeating_footers(true, engine)?; - // Ensure rows in the first region will be aware of the possible - // presence of the footer. - self.regions.size.y -= self.current.footer_height; - self.current.initial_after_repeats = self.regions.size.y; - let mut y = 0; let mut consecutive_header_count = 0; while y < self.grid.rows.len() { @@ -1785,13 +1780,6 @@ impl<'a> GridLayouter<'a> { )?; } - // Ensure rows don't try to overrun the footer. - // Note that header layout will only subtract this again if it has - // to skip regions to fit headers, so there is no risk of - // subtracting this twice. - self.regions.size.y -= self.current.footer_height; - self.current.initial_after_repeats = self.regions.size.y; - if !self.repeating_headers.is_empty() || !self.pending_headers.is_empty() { // Add headers to the new region. self.layout_active_headers(engine)?; diff --git a/crates/typst-layout/src/grid/repeated.rs b/crates/typst-layout/src/grid/repeated.rs index 1a8733102..86506df79 100644 --- a/crates/typst-layout/src/grid/repeated.rs +++ b/crates/typst-layout/src/grid/repeated.rs @@ -632,9 +632,18 @@ impl<'a> GridLayouter<'a> { .simulate_footer_heights(footers, &self.regions, engine, disambiguator)?; } + // Ensure rows don't try to overrun the new footers. + // Note that header layout will only subtract this again if it has + // to skip regions to fit headers, so there is no risk of + // subtracting this twice. + self.regions.size.y -= expected_footer_height; self.current.footer_height += expected_footer_height; self.current.repeating_footer_heights.extend(expected_footer_heights); + if at_region_top { + self.current.initial_after_repeats = self.regions.size.y; + } + Ok(()) } diff --git a/tests/ref/grid-subfooters-demo.png b/tests/ref/grid-subfooters-demo.png index dc64e29af496dc0032c7aa32733fa2beec95b6c5..f4a3f1731bcf06c28664bf24e155716a7f734c2e 100644 GIT binary patch delta 4433 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 aKgl!M$a!^F*xP^oI?+(QgDg?D3j7b^vK%r1 delta 4680 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 AMgRZ+ diff --git a/tests/ref/grid-subfooters-repeat-replace-double-widow.png b/tests/ref/grid-subfooters-repeat-replace-double-widow.png index 86d92a83201b0679d6283dad34f8d479611d567f..37ecbca3440b915a6a7e6e3e14a65ad7cd485b21 100644 GIT binary patch delta 932 zcmeC=ILkgkrGAR1i(^Q|t+%&sdrb+HIQH?~!o?a^6F9yom>yK%ci}wMvc=$~gD|u1 zZOdhznG#Eur7jB7dS~ptRK)z|iVo=#AMd0sQm#d5b5;G7$UuA-7J~Ip+>K^bvcRSdWBce0={V|=bmG{}|S;D&5^_?DEtBTH= zA3pb${4d{TR>ti=Erp*6ZZJ7kC(iLl@sBdgyfZQ1X1g9>Tbz9DP3ZpM!?D$kY>eyO z&Rt3J`+EJa98XMar96|l_${TX%ICNEc6?c2>($(#YX5k$!-L9tVV1aartRyL9xR+V z^;>yd>8k2iZ+e9}BILiVzEI!Xkosyuu)>GeTf}E5PE7pzbi$2!ih_yz8zhCowc1#j zX4ix%Y*-y2&E0rA{wCM2y|2rSzE>)IaPf^6WGU0X;^O?EPbgZ2<($`=?{nP`9Q8~R zX0e&6)zqkb`m_kg9G%R+3zp_-H66IFTFS@xdXt=+Uvt}$tA-qFW`qjdSSIz!yZu1x z-ARm%`DRTCzAJv+P-W3^d;7?0zCjD8u-cz`iLZtIK!(o@MM-C)wiKR|5|a#7l0A-1 z=uwn>AA`hoZc>z-{FYI?o&%!#`wWA`LoMZeF_T_M>{!U~;HtyYa=}ekUgp1IVUp(C zbNqmizQm17jg6*;dfjr2*X7Ij)07i9H`)|CKREVAt?|G)+b|v-eio*Dn`?;=+zb0A z+ORU{vz}fdw&{4MRKUSywnhz&Pj@6F9QWo~W52zzv6xvVmXnJitiI{m?CXlvF+ukf z1b)2FGiIBXbMV04#}Ye~&KU+SXLz8mXtcCVr*sRSi3;0dE5i*eI}J80k5bs6`O}i9_FvT$ z*rB`BRpG<3^HOZnf*KFh7xhTg-zZzZkCW;96fb6$u+naa2dh*Jof4Khl+J>MAW8s9 zB7ze&d~=SsrLvcTNbt6(qrOF3_8e<=na{UjkWd%D4PcSteMp nc1@ubI7bP0l+XkKMfa6V delta 1011 zcmX@h-pMgRrT&7ai(^Q|t+%(Ly+smbj(@!893EIADEP!REGSmQLonn`Yuplz8A%hL zHeR`-GUd&oGhe67%3QFnJ>Pj0>aHbAF!uYeI9#^9YOdFN>tIoq zJ&S&a=x{{rdsm+L;Lvh@#SJ$f>_~ZNe%|F1y`FCEe%rmn(T`job?VEc3W^P9B`xAK^4_w_SDsW>>yu}&UB=-k%yw9zk;i|Oh z!BmF_E1A6oDlT7m&)=9GZxIxI_jT!}=vaXr+gGSDGv)V+{&aeTNExS6z4j$O`Cx(})-7`l!V}-Azz>jGz{R$5jwv^m;zn~;|mABEfnun#V{zyrM zQ-bs27m6R|7747W*gj`}XG7|u`l8-wi9;=%!vBnWc3B(;GStpY=uwn(Hfl@ZIVmy8 zP$k*p*o2<@F-V+l7BpFea&Xu?8=W&u1e*EZzMyQyt+Ht51KP(;>QAertav=DhpF*6 z|GvWqid+po)X1`h>E)lhEl_asrIWH37A^% z4^jB=DbJd1n#;ih)8u$!1eVl)lQLznsfhX&rQrP5nk7o*R_!ap4Hdab3E>NYA-`e1 zgvHlIS-jU7HdN)TuH!R0?isqE_ve{==OrSPSeW~_Cp=)=f7Xzd(R}`usv^M+bAG2? zQ7G{JQQUaoHhY-ih9?{>aXzyS9C*o?^*ffg@Oa#%Z>&bg1J^EaO}gTI@W3PWdWnji zQp~rTmKl6VT5?sK$$r(eP>wbFVvPrC)z^r==7@MU%df;KVd9QFjz7DuNHb|?3NbZ) z6$_Bd^qAT)ouk6iK=qN_{~5w*9>**}2|N)cejqXMUrQzW=z;x@d=Cm(>0&{siW!~5vM+_37c08j$lya3WFV?@JBkRt>9v%##?0u OAnrIFwih?@;R8XY)S~XV)kj3+X*XmlNvo0gTn+D zd%7J>(^-AAU+Uy6>DzVp|FviQ4%s)q{sHU#_Vjq~4EYBoNO zy?IQPbxxd~Uh0kH2T=za@0sTNFs?V-ziXl7*WYJDd24E)>|vQFapG_2!i3gBT6#w`$oH4h4_%h#SoqV8Gd%fw0>BnnoU$OLm6PZ7+ znDxVRS+nUAdUhGBY26UAPB+=`)|5A9&*H}5Tvpy3J^k>x5B{w^`dfA#L)q+4!j&gi zw6ACNVfue#!o>sEa-}S+);C_Zb25U!gaiyW=!Y-yIoC183%m)R0&0fnGK{i zd2T}^2ymXwcbk&tt zm5_vYLPV^87ZwYuvC4vkMg>I-%UERpOfjY0+#g-7Ml+{T3v3j&)RK_aG%7ZAEnCby zG;E&bcD_A@2+lq@KEEgMg74vb&hO&QsSwbqAWWDrVZ#3b-+wx|WQibPZGYb&X4J_w zIS8z^gpWbs2QJ0(jO#>L5BOWWkjNn5KxN+a2?0yb-jqP#x3%ve@YtDjR zM6hkWI)7l&0I*iI=v#!0y0z0S5ct=sBnB3%VBpYe44mi?41BHu1dqUSjQaag47`0| zM--G}^frUwrWXi!q^{!{zsH2j3)Zf?njo;(A;S>Z5&(@lu=Dpg1eT!fGuMeQVZww7 z6J|)pXH1wdVZsc_7?Lq0V@Sr3j3F6AGKORf$#WQzF(hM1RyHA--76S4jQcHz27+tv z7_*=%;)WdrcexPoXkFT@AmH??z&tMkgmr;qPG1lLd*@nuA+UVhClI(`_z{D^p2Kbv s*NHGgGKORf$+%902@@tvnD9TGzcOfwlu~$am;e9(07*qoM6N<$g2roK&;S4c diff --git a/tests/ref/grid-subfooters-repeat-replace-multiple-levels.png b/tests/ref/grid-subfooters-repeat-replace-multiple-levels.png new file mode 100644 index 0000000000000000000000000000000000000000..6247969a0c037631110f9d932a05bf770d861f7e GIT binary patch literal 910 zcmV;919AL`P)6Gt`UJk%AK7)jzz?o-9nLxT{pZ9HXv8thFvAQp zyaM>{3BN)>z;d3o4O41yy$=G*cY4l1;AVqI(G^o&{lgWWbR%F(d?0@U0h1|bmLTxE zwD%C$Q92(#j({hpq;WB(mXq;@UnL;m<%~}an6Cb|A%cPH?^i+KCbcKMlh0hyfOT8^ znF0c)n2BCk!k-!N9JgJ`7y3U24sj0kE9pZSq3qSX*l(2>fS_h=Hk$FmUG(2CmDK zh8tx7{3V%2Iv}Oa8Ut+-J()HPOi4iu9H}P=Jac*h1FH^5UFT!~EG33)KOu8`y%}^d zpIi4C0#{xu1l^AdIxw&`(YXYH9jW%c(-2re4H^(!-HL#RQlAxv5wH|?$J%FOlfevu z+jV4wz{)mIsUMu8DF`g9lt(^-y88Se1eQf51okL<6Ckj<4HS>OWCFoLO2@vl2$-gv z(_a3!$S}hUGt5CUZZ3uyW|(0Pl5voXgJc{e;~*Ia$v8;HK{5`KagdCIWdFw^C`fj- z2oxlDzL0EltW;%o(3SW!U8I_ z23rZ@QC~(8NW!zFOu<@ ki(!TtW|(1y8D7cw2MmH&+l`WNIsgCw07*qoM6N<$g8F8Nu>b%7 literal 0 HcmV?d00001 diff --git a/tests/ref/grid-subfooters-repeat-replace-widow.png b/tests/ref/grid-subfooters-repeat-replace-widow.png index 35633b0a4f828e6759be8b5f4e7d28c3710adeb7..090ebca36f18005191d64da6bc3d5ed7cbaeee99 100644 GIT binary patch delta 948 zcmcc2eu{m9O8rDn7srr_TW@bgdWR&+9RGOFIXqCrgQYTXA6Eyjv#W-wU*z+{9PYS!MF8JZj9;=-%g4R!dxKh{G@xZbN z>sx2U+ScCbY~=nF@9*XsrPZQ%(L3f&=?*prax1lApN^v z>3r|EuiW;o-679-{@2>&*7brLc;?;|=7^E}&&V`gHE-@S#X^OGvI%d+o=xaD`&x)& z&x38ujc;EnCkpJ?b!f)5S3$e0LN|}e|8=(qxavZxs39TZpT%K0drl zl1W{xDb1#2-&0|hX>DF!ayTG{AW&gUHO*ZgdykCg<16u)2tTOJL(HmynB+) zqhrp>oPQ-D;pwc}WHCnZN-L{Lf*XG1?J0M7@aTz9)8wyck092W+`~fS}|IwSUF`GZm76vxM8z{!Uv}>YHWVo zA<;=D3~Q<^vJ6k2om{ln;lb3!$r2IoIN9c9A39Ka{jD({uO_yWd9)ITSMS%|vTaIjZN|-xkPt$?IMZen`)aCYN3$>-x zLxNKom^u^NQV_viW>Db9rlIn>bKSuMSKoQ_ao9WvFHRL@daYv5&5|Cj@WAf>yxUq# zX1RS?>qNr36 zA#|ZuD#(&Qr=8TRrvhV&d@nrx4Pgg&ebxsLQ0E~^F Ak^lez delta 957 zcmX@bewlrOO8qQP7srr_TW@bgdy5oG951}@93Cj*;Zhm6GDSSD#c4@I#)L<$sa1)y zCWfdrE$Nt+#%}7bux|E}XO^b@o$N(E!7iUdrmbG7I`6vh?#-{?+3an~+x4OSP5!+D z?K9Kc(jWXU6}s@$WrjiGp_c#5=XPfH1qy5s3%cD=dF8XauRuh7_039Yrf?DILIYcecl<2s!${^T_t zC_Xn^;KnRFA(qDM)jgSSfx7#(uI7uX<ksV2l!)`|qnn#GSPgH{vt|D)f?gnV0`u zksBz*5ElFWmElR>q*gzL5054q^5~SaFrVL&@Sx4%^_HfF**07D<*?}7Xp+Y}xqZ`WN850+|w~ zJs??{)Oetfb%A96uJACYgqyM(%?hmrL2(1j9>AEwVAw@`h@WJ+NU>q&c{c_i@O1Ta JS?83{1OVastMUK< diff --git a/tests/ref/grid-subfooters-repeat-replace.png b/tests/ref/grid-subfooters-repeat-replace.png index 0d7803b8516af57beb0f5f078c2c69c8bdf4d917..95025f8b3be24b0eaa2478d2c7c9b8f0121a388e 100644 GIT binary patch literal 963 zcmeAS@N?(olHy`uVBq!ia0vp^6$}iF&Ky7n!n0;>1t(Djf+SUU*^d-O+rO$;nLK+r%cZ>l4ky%w)2rwPi9xd zy3T05POFzIj4jUh7@yxCe!*A#-x;zmdUfPDnHOl_x_;5H0@D?YU6>wam@ld z^wW-3$}pZkr}>zhuXIkA(3z7~EPLMmUdym~_42-3h6Q!^f;nPlC4IK6|)HLClccYZMSNGtbkjvbq;H~-q~{PvaG+MPSZ8PCVWcyClrkhDk@0~c8rNb=9gUDC;ihg4? zpBV;;Z7Dn_B_CLsbN?|$zG9c(!qk}FUw`mGQLw>=ePYb7*F}Fd z=Gbwebi1+`WB2lZXZ2Y0`g8?3axAy>H9no`@L=xrWQiZH6E4kN!t@}u{HF=a%)$=7 zD;zwPTapuY>PSRXwl}6Tl^Ya1l3Z#R!FpiT?3Gu5O5FS=Iy_k0%qkI} z1uVgf65jP$LSUCW8-Y`B|AV$CZ&*0)B=bu(9tfJIBvA3RYcCH|{TVH<(hZMOW^ZtO zaCO7J)dD{%dm|JIeB?5Y9nO3DR3O5~+3cPlFk-<`3Ni_u@n83c`6kO{-kN{U@`G}x Mr>mdKI;Vst0Ah-)ng9R* delta 967 zcmV;&133J{2hRtP7JmTp2mk;80HY*cumAu9mPtfGRCwC$+*wOhVHgK+ze8716i7sQ zQK@8v7oia;UTBcwg=I=uW+axCAS$NiQn_Rrnd2m>xs5tzE{O|yTvB9cTxiM}bu>{& z9d%^p%yynWK@dUygY&#!;Kz9vo|p6fc{~U-JQ!w}VTKw03xBxesx47Kz*3Z|4Kvlo zgH{MEJ@35%f$J*GiCwbV)j#zvg9!mQdD)|N2$-rOmIwlm1x`TV(FZGDGYHr)C(amU zb)1wLwj2Qg?}U7?&|(|8AD zs>7y1)qklsv=sxBuLA?S%LxK6#I0lCoFK6)UIM_Px3d)!xk;~65CmR6Fo}Wb7GYpR z2L@J$J7xt0-0mk06(e8@TvSL9xGDZUL134s1p`wND1eeahk^4W#oiPN@x{K>^BuCr zx4S__Lgytw;NsG7g1`gujTl&UY#jrS22_WvLx12zDk%ZMFKZC+NU%0`7XfeT2kkO@ zTkKN~Lg0~1%7DQ4KN6@Or;-^0Td$>b@QXRa93e)0 zGS&A!C@cLag$`!_H!xFZ>NBx9Iih8h0%;}>EMPW8W(JCy(c002ovPDHLkV1gm1qYwZ9