From ea5272bb2b6461757f25c6b59d3ea9eb02e92dbc Mon Sep 17 00:00:00 2001 From: "Y.D.X." <73375426+YDX-2147483647@users.noreply.github.com> Date: Wed, 16 Jul 2025 16:10:21 +0800 Subject: [PATCH] Support setting fonts repeatedly with different `covers` (#6604) --- crates/typst-layout/src/inline/shaping.rs | 9 ++++++- tests/ref/text-font-covers-repeat.png | Bin 0 -> 467 bytes tests/ref/text-font-covers-riffle.png | Bin 0 -> 1603 bytes tests/suite/text/font.typ | 28 ++++++++++++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/ref/text-font-covers-repeat.png create mode 100644 tests/ref/text-font-covers-riffle.png diff --git a/crates/typst-layout/src/inline/shaping.rs b/crates/typst-layout/src/inline/shaping.rs index d1e748da8..a8f2bcaba 100644 --- a/crates/typst-layout/src/inline/shaping.rs +++ b/crates/typst-layout/src/inline/shaping.rs @@ -719,6 +719,10 @@ fn glyphs_width(glyphs: &[ShapedGlyph]) -> Abs { struct ShapingContext<'a, 'v> { engine: &'a Engine<'v>, glyphs: Vec, + /// Font families that have been used with unlimited coverage. + /// + /// These font families are considered exhausted and will not be used again, + /// even if they are declared again (e.g., during fallback after normal selection). used: Vec, styles: StyleChain<'a>, size: Abs, @@ -777,7 +781,10 @@ fn shape_segment<'a>( return; }; - ctx.used.push(font.clone()); + // This font has been exhausted and will not be used again. + if covers.is_none() { + ctx.used.push(font.clone()); + } // Fill the buffer with our text. let mut buffer = UnicodeBuffer::new(); diff --git a/tests/ref/text-font-covers-repeat.png b/tests/ref/text-font-covers-repeat.png new file mode 100644 index 0000000000000000000000000000000000000000..aceb8d007934e2747f6d2282a9f73d90d56098db GIT binary patch literal 467 zcmV;^0WAKBP)-q_@$7+zzKD;I8dF-qxu{(;}!6Tv4Hp}-2Pz+VsETqab`^^b=Wn^I#N;%sSz zs;!c@-8kWVOazz37bZN%umSsC2B8uSyy-Bt406bH4cfP}!-TWujj{8@bBMmI%)x8f^F|S{Xmpl(Z+!cQq>LJS={EN^` z-lk}v%Um>kBB6Eg3ZKw9U4k3~A5F$?`nUIqeUho_wG4>@4|*?0>N( zgn&R3Xfgs#pb0b?fi8E@N;)GaQ%NPgU?y_nDJ46%l~d_hQYq>P5$JpiO0wSNcZZ@2 zW+KPp6O~McZD%~;XReUWDHgiH7begz*qGH-cl%-2xB-7}jZDsyiRhKi$H=_W^*H-q zRbOo%c=f$Q%MKi0cCdE&{+fzC2UqUcy=L=P)w*@x|Iw58@w6K@| zs;WZJnoFk`<%z3jr+&KZ9_mSkgJl8wnJd64bAlFM2rA4^qR}Y+%CdaEeb5(?+3$gh zmXpdX=)1jZ-rBah`khtVcCN18vF6R{$_<-9xhQBLo&$Z(a_=`(cf>MN`koN4{*tDaGv-8(D0S_7jzW^v`FDT)HhY~63LpK0wn(bS=L`myDptMY8o zpfwGrqJpWEL33U1oG_w1&0Z0*@b={!oHDoGNi#A}w{-XEtz1c<*F2&5;n>GtTqx=Y zA%UA;^B8aqH?M&&1X|*VOBHk^p3K$dZmscjOV7ow;akJnyiEKCD0ZtqjQkIOY2$jG zYt}$y$`xeZHg3Ay{Wsqt#M5x^J^A#YrLDP)+B-BAym{cd%+!FJlt^jq{tNdWvD!6z zL!UHvFv_AR7X4bhcgAdi0fPrmmE3bhmO|57rWIw^M+5Y?J;NuVY1as(ZXC;gEa>xGLN>zD0;h&LRYFGo=V zL9wVKL{D%s0!^UF2sD8v&}0OfW`;B~q?sYj3~6RaGeepg(#()%hBPyznIX*#X=X?> zLz)@V%#db=G&7_pI2nN^&}0OfKoe*(0!^UF2=q%1I+0AZcJ`fbY-+lDAM0#3n^Mwd zmrrN0BN~dzf;Z?2hO{QT6i?*8(FJF4P|deGlc1h77IlN*o@aPi`k+DfdP~RkmUgSt z^Xr}aU@a$728Y+^^p2YZXF$Z(5z-)+)XS7^6Z3~zo{2}c(Rn*Dn^&r1_DR}3ur)#IK0BYX>* zzEITY@Tm3XSUd@hhFz*9IpEJ4tm zGWZUtwYks{odfOVpiK<4NkFlC|9qg{{yrQIm`4At+;b zSo-Z9$O17dZQO*KXNKHp;brLbzi=7Ca1#zJRiV0>hTuMA=g5h~;_#<>bH~6491C`W z5Gpr!rd9f&SsQ0_dU6$m8~Qou1~eL?%-TC>G}=3OY_7f2?E45EG}mkB23v