From 076e767b0ed8829d2c2ad0038b650c4809203d7a Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 7 Apr 2021 00:23:33 +0200 Subject: [PATCH] =?UTF-8?q?Do=20binary=20search=20and=20find=20the=20outer?= =?UTF-8?q?most=20glyph=20with=20the=20text=20index=20=F0=9F=94=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Martin --- Cargo.toml | 2 +- src/layout/shaping.rs | 58 ++++++++++++++++++++++++++----------- tests/ref/text/shaping.png | Bin 12609 -> 13298 bytes tests/typ/text/shaping.typ | 7 +++++ 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4841454cf..a71d27654 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ miniz_oxide = "0.3" pdf-writer = { path = "../pdf-writer" } rustybuzz = { git = "https://github.com/laurmaedje/rustybuzz" } ttf-parser = "0.12" -unicode-bidi = "0.3" +unicode-bidi = "0.3.5" unicode-xid = "0.2" xi-unicode = "0.3" anyhow = { version = "1", optional = true } diff --git a/src/layout/shaping.rs b/src/layout/shaping.rs index 14dd79b10..5a3cd292f 100644 --- a/src/layout/shaping.rs +++ b/src/layout/shaping.rs @@ -52,6 +52,12 @@ pub struct ShapedGlyph { pub safe_to_break: bool, } +/// A visual side. +enum Side { + Left, + Right, +} + impl<'a> ShapedText<'a> { /// Build the shaped text's frame. pub fn build(&self, loader: &mut FontLoader) -> Frame { @@ -106,21 +112,19 @@ impl<'a> ShapedText<'a> { /// Find the subslice of glyphs that represent the given text range if both /// sides are safe to break. fn slice_safe_to_break(&self, text_range: Range) -> Option<&[ShapedGlyph]> { - let mut start = self.find_safe_to_break(text_range.start)?; - let mut end = self.find_safe_to_break(text_range.end)?; - + let Range { mut start, mut end } = text_range; if !self.dir.is_positive() { std::mem::swap(&mut start, &mut end); } - // TODO: Expand to left and right if necessary because - // find_safe_to_break may find any glyph with the text_index. - - Some(&self.glyphs[start .. end]) + let left = self.find_safe_to_break(start, Side::Left)?; + let right = self.find_safe_to_break(end, Side::Right)?; + Some(&self.glyphs[left .. right]) } - /// Find the glyph slice offset at the text index if it's safe to break. - fn find_safe_to_break(&self, text_index: usize) -> Option { + /// Find the glyph offset matching the text index that is most towards the + /// given side and safe-to-break. + fn find_safe_to_break(&self, text_index: usize, towards: Side) -> Option { let ltr = self.dir.is_positive(); // Handle edge cases. @@ -131,16 +135,36 @@ impl<'a> ShapedText<'a> { return Some(if ltr { len } else { 0 }); } - // TODO: Do binary search. Take care that RTL needs reversed ordering. - let idx = self + // Find any glyph with the text index. + let mut idx = self .glyphs - .iter() - .position(|g| g.text_index == text_index) - .filter(|&i| self.glyphs[i].safe_to_break)?; + .binary_search_by(|g| { + let ordering = g.text_index.cmp(&text_index); + if ltr { ordering } else { ordering.reverse() } + }) + .ok()?; - // RTL needs offset one because the the start of the range should - // be exclusive and the end inclusive. - Some(if ltr { idx } else { idx + 1 }) + let next = match towards { + Side::Left => usize::checked_sub, + Side::Right => usize::checked_add, + }; + + // Search for the outermost glyph with the text index. + while let Some(next) = next(idx, 1) { + if self.glyphs.get(next).map_or(true, |g| g.text_index != text_index) { + break; + } + idx = next; + } + + // RTL needs offset one because the left side of the range should be + // exclusive and the right side inclusive, contrary to the normal + // behaviour of ranges. + if !ltr { + idx += 1; + } + + self.glyphs[idx].safe_to_break.then(|| idx) } } diff --git a/tests/ref/text/shaping.png b/tests/ref/text/shaping.png index 76058b2e2818eaa2d74e33f79427751025ab71b9..09f154ab3e0cdfd480a9bb04c0d0d6e0550c00d7 100644 GIT binary patch literal 13298 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 literal 12609 zcmb801z1$yyYEqSL>NMl7(!aQ29WLs>F%1LyM{(Yx?AZ|8l)Qpl$7okkQll<&iF!3J02;q?m^1{C=jr8y=OW|pLk-&^VTR--!OucTj4%y3l{e+IfmF4l zX=P^4ZEbRYO3Z;IO6SMFgL4sQDp_(7xBWa^cWHVWh|(4#Np(ZSJ4R6orx4GLQ!1>{ zD;GL}18=_ZRCA#xpv{;zsC(%qo z=s@?Ybgcd)Yg04hpz&r7tI$g_g}GyV0MAjOn!inyBfBSvq(yGy*~^m+Bqt|#;pUGO z&FoGg*0$AQdLtetzz9qs^f~3>SHA6TFq~9&X>vkg{BX(1UAiUS4`4qQRPzLyuh*f? zbV2lQ(&XYO1>kY;FEH7ySNRI@ltkcpb5T%VTr^ZNU$tQ&(_!Lk3sjQoRbu~NH-5M- z!OV-eRhPk>iMf3b(>Tp|d;Oj&y=bR&RMwiC59W2Mb)-cIk`rzb5Qfz(~~J z#P$vzd$+w!3~z{8>n`SEw5geklFsL?9dMKcW;%UHT0&wCx2L3}1kCZVlfn`4>-qON zJEO`OhlbsA@5oa1r_Czg%AbVKK&0Rx^iouW|*Li!xnKFPi#R-*)1V zcE#`QqhdhDqdVNT=nnQF#%3a^Bs6t-PBh34hXxYpnKS20C@dT-#0}?%5z#{ncuady z5-Ia*P$1suU%eP>6*-f|GGIA{a3Zh>W-xFAB$K z%>fY5Tf;LaDuOy|{Vu-;ZZXKG{u3Eafa-5?$OPT6*4X_-s zns#(7n};t$o0BroI&h%qhw;;~R=Pk@(NYVOsHUX@JCgK)caWsg_$3D(B5;>;LGjOK zCW$-2F_*##>pHy_{h&ywiv8xfHv{*l6q?rioH(vE23~K5QygVc(|pp`NXFD$uv@v@ zsq`o2K{utEuQB`j5M}~}af~45K~Rubktrwf=<5-Pi1HV79Q0tjcj->`lm9HT^r5$; zDFyCW?w_ol=W>gWx>*2^YatseRPo!l9uxKgNHwHC&RRPMIAq~VgJ zSfNUV6T9c)e{A|qYUX~H7JF)~K`Nm8YNZ0~dEhDq-dIO?@W6n)4bkY|0P!Lzs#igs zqSjhPAX(xw@3v(a)cw#iM4Zx@N>n(J+3ylKlMe)Ue}$mX;tmgwOz1bM(y6`ZwBm}; z^xl)S)s(!e-Kj3fUeborbdcagOAlGpjBMdyXNQ1aZ>-Umc%pN*1hSaCOAl^Ar$JSW zvgRTV#*^FUSoKle@0^JWAUvM`?TX=Exj^w?=wLFQ7Lli=V+H;4Gh?oby7+?g+^dkf zo9-y--d}`_w!GfBeral$6;eBjPGO@LMk41iT;!F8#1BJk7;=axB;jDAZ<1MbtdUePi$%d2_p z+R!fJLV~2}tkD*|z+b_!l{xNm7E#yt{;E<3PHK=zjFtp3zVbyj}NRmeI5@i z;UJDS#DxEZ=LqK2`ti@55niXXacNQSjf7y5SXs*I*@zrjq{p=TXlhPf>@Qr;aD@e> zho`z$K@!VO{wngqL%o=x^UBK(;Q?d=;myEbGhy$G{SGDL7fD#yMk}pD%7-+5@@Nq% z1_2u>u$7TFJFycL1bw0PI=fK=>84y???%iX=P6VZw;7F)u$U#CR%sZHBbFQxly@_k_Q`E`2Zl^PJeufEHaM?_0Ai3zQf;2>|#5yzG$g)RdQt8SKcjQAn zIhAciqqH5UgoHj!i@+(Yn!U1GM&;=~JSz8_lb}7jf=lb_CeXAjwYwqJ+B1}O*yNN7 z)yX!vI$FC|bDH*014Zdy57hd|r?OU?`Ge&o)hy)-?q5E8nm~h(kN;9Yx&Fw)&G+5i zT#emp?F~p4$#ta0ZO2QI`MV?CVBNSmUjkM=r3=QX2PTcb>+AxV7pHX z3{R26j!z*!L{9?0J74YhE#I)P!ccVO>0jd>?*0m)T6EyC0ioQy`0vvYb{x1BR!z5U zl8c*=z(j^`W{j4HudQ$0x_+IOLg>vsxt-tFyI#B@@CUniv1=(^)CIm!``@nyhxrEd zccvb`uvOG>gti%{A<1D;<&B32y%;?#S^isdoaHP2*Uz7#z(T>A>p!nHgYByr>z}HN+A|`5aWq;GpJI!cE>s?M3sIxo`z! zcKa7;PJ1Dw|M{%*3+V{9w^4Vw*Cd~w^u2{J%G97<%daXV9Rw~?*r@QOkujSbD(^5r z-ej?#{P20av07NL9I2%uqL45iR1uPXd2l1{Q6|aYb2=-qt}{gz0Un~P5VNam^V;iM zys{xzQq|gh3CZ%CJooHuyj<3cGyxI|T2%FlW0}oqL01{U_Sob-U7_}UllT+wnZ>Kw zu^8l@iP%DCUZ2R@<0<(o8F>m+AXbtxSp5R_$YQM7^P>3^4Rm1198*p85 zqBSlrI4hx46xajqC_RLJ)GLX}A>%eMo(f)bTc<@Hif{%=bGA^h0~fYTu!!Z>r=B zewK*F???S{UFXxLOl%Jg!i)fWUSpk;)81cW?ya`YWs=vtFcehD5IyWzJENH7j0L`n zJ*ID*55^}agY|>~ex{Ea&O_$31HIf=o--oG_xV0E`cK3{diNSI*cR2LeYTW>!NA1N zn!&T#8jq}8X+JUQP7NqUgF!pbo*BosM}PqkyUkigw?rfXw5^ z1fDo~-~<(hz!e+&FB}&exytkd*~V^<7j+|IptvchpuV2MM*67vo{rqE2wnDF3$p8> z*bIABM{a8?c;)`SIR*7}wkn|qQD8~VFG_oU(NO7E&-8)m*>$@lYN4j?X(tM#S_;ItAG$TxO}K@PpDm)X_?;ov zCj8HM+IzT3l)d)>oArRx&aLAsa2#a|Z1yr%6Sx*Kb~DS@au}f>p%hTC7#P#4`8F*s z3v6AV^iJrKQ1WRXkj}U`vKrLQ|xC zaYYP{SXz+Tc^rORI6mumpuUN#07q>;@!W{Tc!pVD=||9ke4Y&g`!(DF_6RKp(}Wr)6zLYtbXtZk%05& z8b&ytrt@qrvY+}lOB?fK>R2Ku*6>n<|; z4P@=}ZhkrYT#rsAz{&OP&RffU3j)GLo}sA-VKlO^BY2>fIB^a zH&`9JS|LPxhd<_yh$k@B^^ofu?vEM=$IiUM-Vtx7Pkh3(_tzMNY3%~Kh_h0m7bGPT zw~a5!?JDL@{r4#&9#BJL4i-t~v=M);CJ=P~H`sde6brEJD{(F{2L1L?Xs&sd<0+ae z7Te2f$gpvvlbVA)?=mU>(OeG#@#uQvNBI^g20K{M4S$* zqs|zi!bdxtOqU2|y}I~8iY38KtUB<_a(pFikjuzwJ{^g1eyrz*-Wc|+R=)Mko`@;lbwJ4LRG*_lO&7azfyP96dV8 zWV@$ibF}DhyBrQ*Ms(kMY@F|o|7989R&Dr8%G$14QTa>m#T;YzLk!=DS0h;73&wrO z!W?gh5SWA-7&c2QgbeAI6bhWo^<>;;277TTJgD)Wx6P$|e7bR7#^(w&BNJU8-d%sY zkF@+#5M-BZ8qjN~P^mqra&!xUb)jOAcR2t3>;@~E!zVT!_VSW*SlV$0E^}g$Vwb^r z(Gzc8PZ<5}u{xS>@Nf_!vXgR{Ib+0oJtWHOXp+XtAgWSLgq^38=g?&OpQ&LSLtD z5u|Qy%FVol(kFKtJLV!H2VJ*Xc>{*iq@--M@j*esohHYwiC6kfwVA+hWj?za=?Pxk z21HTf0sZvV@?BS?cD!9G`{;9+DFKx|?OFCNRpTT5Y+K=I^#j<9XuJ0;r56ZDq#y)X znYDLmYbT3cCV!Tr3lEk&ORV-!UA2e)VEsjhzR%_^G}+mn*p;!rIrU_f=)WAc?Tu}Q z??g47t)y8V=-sp+Q^uO8fAdK-@rdvaS9>XN4-5AZKq3ZRPaoa73pQrnd-*o{9Unmu z#(e7sOxFEC({FzZx3T#xxe#3vVKy*mvrLy};KwY_&=7E)AzK+1deXWU=F~wImn&gc z)q|n+LjLUzN6$jR3#U$)%xW}WLkv5U5c1V#MvB(o?@xi96?^x@VC$(XQd2^{l9=k# z?V={9Mcb69JiS({E)!Sc!|@GCfRELgv4U&QG9NtFku){;Z+O?8kG*;CGGFiv7%>(Z z-!w3x7#qVAOYW{PRDlCzcIjXa@{~n`lfPE(+PUmRpX*j#9mHFIdmU5Ofe}hgme+oK z>u)z)G1uT`4{bot5gYiU0i_SnaHFU;S9JGwaxzDw^Dg3ND1Fk9MpSJ4iqg-TV>G-! zY(rwFm}Ypm3<3tX^?Rc5-uI>Jx(wQ{JCOF@PH-x`@!@s&#bVxb+*y?Ic>G6ID~=56 zIZc4Zk~inrnmzf1aXF_J~XI-d&iA$+c8LK43<-jNB^%In8 z@sM>9-zu|pYQaX=Uj(XV40^Y%^Pe^xd1D`sg1ydW3!sZ!C-uN2F3|lAhyG@6@)I}G z?g&HqhY|hPXz%|LqEKN#VEZS6{paHh-;)&ek24quWdHlD{}ku`8(G#9ZH_ycotrwRM)zDGGCnV-@SPm-Jn zU~GW&o_B3nV3A9hKu+$SV}%CMJc*;!hZU8T6$}kjGq=n5Z8X1tat21UraFojd%5vv zPT6c=BQkU@z9+BI65+WdXx44oqb?Yp>lo|UYbMNH|BOy^x85mjID z+_S8;!xD~$-P9m7av#AI`Y@BIYhPix1R`@laN032RP5o~d>9YsXUwCl3ig@S!JQUq z7FPiEeEwxNwtL>cV1WWPaDbS-k~0^Wbj8t^HzQ#Pm@6|*QkrZ!tyEzvGvdpDSrrj6 zU6AtfXAYZHjqb|QtU2+XdHccPv>%^9VZq>d*`IdrP9JG)8MvA8KKhIh4_51T;Mjaf z6rf{HKaZ>)r_6gqGhPv!O#yWePCT{q! zNPvC)K)Ru0{7S(+1z3hf0TX^QP3LAg^2 z)M6ps7;1wi&@aFW-ZqDb=c^_NGkv6_p$T%7 z>yUF)80aPRtP1=O@b#b1dZDkkJc9z*~J6+7omAW5-aIOfqG@0@#I>kkM8ny?qq zJ3rLkymiw>;`py9G9TPArInQX4*7oVc(q`sshK=vv7TP%*=BT8Ib|b-`ts~6I9Kw@ zHD7)*L{j|tCbv$h@z>^Xhd6s~nVW1EFK)+WhFcA=4iQA6#)G4Vv;D-TueqxoG|mTB zr0HBSpwj;z+rXPxH)UdoKY4ZF3ocgZ3yC!HRa><+w!S!g=qNaD?XNNMC>JMJ zr=KHfB^M&UBQ*HNR-pLj$7o9r z+eW9np_DN0&ylR@hgHwnrBX?-1()$3W5fRZq+V&%??>A%* z&x*KXKl^A;()u-7u%r>B9|!Fj7=((APTN~QomS24Bba5E`G;=-_Ge34(5Q+`ktaJW zgfCYmY?J71b82riZt>Z;W{xt|hqr>tG9d+=<7!yKZAOP4Eer}@r+?N(amd@3!7*Ss z@$fmjcYqN=$@_`b@Ei0fYWLXAVJXv2Ckof)Hwm?{ShZG}Oum1Iv2AU81F3mgNy)(a z@vPmu%9->E$2;4T%0xy1_VO>AZG`ep8Rf<7HyWVO?p*hHoX{ZXUUxY3$c+Xv1p*-6 zb^}_Am>TtWUnzQn;-fzx&!{DK6rzW5pZ<2RX} zCNG-6NsMAdr{U81tf`U2ImJv4Sf`$XYcC1l+ZJq8)*numR32E#o)u2W;dxKotXao! z7c-avCe9R!nZ|Jh)5HZTnRLer+nXotK9kK=ZFm|F(J50FYzydW*EfPwM0iQ)f zZPwu$U%=>)gk{Vy>3r$@F{E3>3vG#z0%>3fB(qQ5?K4Hu(lr!v>{XO(l^J12OE zqok=>3hX1gj@S~4EAE2UP*SH4UQ$-zZ?APFK}Yog`(har6oeH@?S7%be?B+u3W&<) z=8Q11-K*!Ci?Y=mLphtC5+|nd1FQVtN2o<07dOy zWj{>rX~4k>ZLnW>%UW5ImkcyHZn&D!vAJg_fBf(`whyfEGvgcAXP7fbV*0cP*4Op+ z3s#iZ>rTA%@iwQd=sl(UN zs3`%EnSK7r>f343rprS`0*oIA&CUIiZu!&b?ztgZ_?48ZL1MPcJl52w$q1a8Nt<^^ zBQ}N(UP0CJc<_C*F)#pFf@W2+ z83O|YZY`Lter62|*0(c;2tx-4)_uB_tVTuM6ecDnS~(Z~OguUzjb3#MoE$c*Iz8%m zSuWya8U_)OfQP&51RCpoO@8x%Nv^#7)zj+?r9$pk=h5u`WsCVTu|~~q3@Z}SEruEz zZX-gMVYl7bK5CF6EIG2dGnq`K!X<}7>J)ooAgIlSGY@K{U!L#hRyc?qU3h0lX?P$c zc@>bA(9!dd8E|}-UrHcdXgg^k;9E|>lRISJIO+NM?bw}7^}Qe8N~7rB2zk61l4tX_ zv7&m7u8L5x?JKfe#dHwhcCXc2*5D%ogJOHTZ}&}`#gz8@+nWQYrs(ltjm&-3b`1-D z!sKn+#n~q+q03fWMp>nXT*P&H<$%f5fmVRkQXn+e4h=libi9v2hn{ids?ZM=B5r;@ zic*LQsmdkz3L6`XjNy=*1=iOxu(BoaJN0}1Z-TFhuRd- z%de)_w9l*5wk8?s6qf`E7}OR~;wTs1tFYb~e!*dj7oVP{cL?N|o}TsETyQ;X8NZKI z?N~$IdC@m&toTP5P0aUTLUUjLaOY|}yxyH}piX3{Lth{|bN1utNATQJTWG$y^kp2NL;KV-|rwbm+$M0M6-0~{CH;$e`cHWpw z&WFFAa?H9(mC`!suB~MZo#uxtda;RPKw&T9#oc|iD@m20MeA84c}z@XR9aa304G^b z6mg{AxjTEnJ8WqLPb78bofbmO3DZ{u5TZ8vA`e>wt-#oa9atM@4Z1yLq>3SCrBC{t znpUknKOTQMO0snocbZ9B5p^cl<&j^K&I=xCseBFRt=j0SN*h)_Jhb!7JDs>~0?Rky zWG$X7hFvI{Clj`tiga*)b6pX#-*w@?T*4#Q-gh|svek2ro#drJDS=oGKTi5m2+drI zR~G-Bcoz<(XUW@I(snp9VqvZ{;%f!+74lcrNc?+_j&8g+XK~` ziMk2?dVQpn_^Kh6ZVG4SZM;j&*@ay%fFFRE!j;ZdC{PTdcZ`Ov7q&JCtjp$sGcNE3 z%26rT>g4yimiuEysI&R|v(ZMn!oHIh{Nrv8a9cDiNaW%uj`N^X$HJrCPSi>M6O#l>Egaet%+0P#`O6_WX)X zotkU5jK~PKJ@nX{BI}3p5`7-+@f%L#u2TluMN4`nvb?Bl)_QI-0s6fkv2-ynvYeCu zT{ryM-Ky!vNI2NP#zwzdYB2Md93h^e-{|Aa!@VoUoF@;wgZlUS}XNeVt9~M8(-lZO=(}AStIdqel&2e6lDp@8=$MH z12lRrMl;WH0)w^C;L>;I^9f0jP;L6vhmA=2Mmqk9xn-9d_uDx#h2%|jZ=il;tN=Ok z!z6jtWphI7fa>;B;pN)Kc0`4LUH81m%lfO3x{k+BCpbn+f~!lMj)V>E{10Y>GXo<; zR8q)2EcZ}$e{=|MS7zX#gl(n^d5%}x_<>{j;NILg@SMG4a(v=06t#)ulwjKvxMr0>JlI120!Jr99X;mdzjbo9UI!~f(8U^hT_(+wLK z+|D&6-wHrk0AOi%v$i<0CGd-7+~AqWG<~>q^2$d7#u`leaA#w!1ZC8|xN>%57VLw2 zvP!a@q8lns@_OzpLT)Rg?7PcpU*Z^rAwf(~B)F=dnso-DUGh8v88ITT(|%}WD>5_f zf6y08_Gt57JA`Lvu`2k|*|3pQ-~DNqdJ(ZV)^ur#hSC_rCrnQna9n&Gpr z!uZ0!3GXz)ln-6De&5L}okP5%?x!4}ttMK&?*a-cU zbpNb_cFz&|(?Tte;VJ7(W!^gUe}I4S;;W3%hld#amUiQl@pqRKw#9;X4RwppSc5(r zb0sENRGhnE=X_oce2dzVk<0?yhP;1^2e)i7pkreV($a0}SRWBcd!zR-Gfu09#O+5K zIdrUKy7qpu?NuUvH}?zvneJO=#ZbVY&$-QIWw4uAynFt@<|CtN&taAWb2!vQILn_= zg8p^&!hRG-&75zOo_rn{xK)B@^J#R5?7xrup0l?I=xU(MqtkjH2h9&|P6Etq_Rv9g z<CF_;-Kcn(ZJ{TQXu#|QJPJ{$vcCrlmv=yiOM!! zfM5GO2!46E4Q+T(e4E7j4=(ncpx@#duC_hw+k*ba^TrVDuKlc$I`UAikgQx)2zTNo z<;oQiZ|msGncNgq&}=1H(o~SUmgOZKb}RZMybUDGyRj7A0AMc`Z1!3hxFQ}AtK zzumk1%f%5G@QCkhD=(=fz~?qx#<0SQaVCPAkz-aGEU20o8l(Z4O=dHft$J~LuH-6+ zv?=Isw}>FwzdR@5kjeA46Xz%eV^7s35ykFm)@5!bePuN&H%JV zu-f4@{IkP?P_TLSs?@Ss>^C`& zYD3xVSt|^HJ{pyz6$hdSHqBt(!j2Fyj96N`#tY9=n1h!x!ThU>MRUh~!S3C; zC4;NQ4()OMdHg&8%z@X-*n8=?f6R>FN1l*n7S@r>7Mq?7!Y#sbL(STY>n@Y;S50!Y zt$!gc-d5*cm&sYk5bErZx^_0&1;uUETJCXf;fY9|;C8L&VQIM?{Xa&s8Q+QnFfRh}uw?LAv<|+>L><_)?9ny!LZra649%P2G;JdVg&+)nr5L_3d86b$BNq z{we|u!MltWnp{gQ#~P;Wya@M~Gt@=}4G%I+sz0a&0F)!>vu3s+Bk(cF_h#?QBk47l zLCu`oJDFA_i^D&N#-#R-m2K#1ojurJed|dsPIsfuA zsux9aqN)7yPwlI8e)_HX*`DM2flbMDQ+7KZ3K|7@l$#yKPi)_^bi6%8Xb&~s4j_Xi zkR6FB#+nEXQvsY*ezN8ZGnHW?4S{DMVb46mq zXDrbphUl(I;CU8`zDz2}eTZQYiYeG=P$3J>f*Zyzj?b|MO(1Js%Cwj&50X=2xnH#` zvAUr$GBF`@xprOvniZ&ftJ0}xyU+v3Y;;7S z5{E|P-H6w5t}ecDB5oBU6~zFMoZt8DfDWhRxSh6)<4wB8@OMygqoo0z^k~!%R5)ps zPVIYOq+(}}SmLY3q>pTMtC!yATgVbdPal1y8i>m>B zNDr_Pj)YND1K+GFwNBya@F%_Lq|Yq6J@vZ*C?>80l+-Bhh7MB@S@#qqO<lpU zhpPzuXhARhS$(Xr+T8FfE$}w(K$*B%z8-@jh+yrrw{j;Dlb>mIPUjxavhog!BlYvC z-AXT>++sZCn$itX`*yRza2Di&LD>ttnmH9t(U4D{x4#~DUSd05ma&ArxO7ddwLxW+ zsuX59%L=f%)>@=ua5jr{xz>I>yWU3s+LB=!EULK%SHuBBstrK%s@}~GDwKmR^smL~ zh@dnkb$Y=qeJEfx$WI__6O}>P%L^}2i0q(0^+$N&Cg1;sqwpVUh(ql1kodIcE~n{2 z$>`5SLx2LL#7joGzGTVTiPsz`+p$o$>W1W^9tMpYrWj7BNyevZzs3tcOZba zrhvI5oOYhUM6^ftqAKk5MON<)65M#^TaAu$>443`cTJv5@eLsO0T?v6@sTJlmoAsw zQS$sXV;6V+48uu4YajvgrA2RH?kI7V+zB^W^1udZ7#X zx38LfXBwPx3L(pB=mcObh-XZCYHwTJck`=;aX~45EzE?AP_P*@F4ywA4s%j$s5h3G zLU>hnX^O`i7sMN{YEEeCAbYe_1i#H@y&%F6==%KhM(tIIA)2zo3fINnjcS=g)_6?B zYlhOg>>M3se&u|SmY)St(+LS`F3J3D67=X%CL+xw6REln<1f3X#1SxbeIXMaAlX&BAkzR8*1c10~Ht$3P3_) zf;qOit20aa0`AD(98Am>e%&j|=B`kEDEHy*{M3E0oDx`=KWz$NdIMZ8@k-k8e%ScU zpXZ%+oYQOjZB$)LR&+F5bJ@UMIn};@8)AxNzfyz4lLOATLALDA4R$W z?hy7bdg{wglQ=rh={dW4fXf|sM`a4sCrWGlY8i~GJM^pf8zeh!NSi5z0|oc*UZwvt z$Dg`QL%TZ>zkzC8K%fAKkT_bF^a-R{p^WnH>Ge+_huiT|qQ^m#O_01?{}iTuP)3`$ z+J$}2(r!AC=o=2`()c(KvJ9wVrIlN|C0*h8`!yKcc8-Qy$awTNw)BZS`6GSm{T>Yk p)cF5S`q^iJe;@cy$GBAC?W3fZw^cscu;D+ym6KAEtPnT(_-_Kw2&@1A diff --git a/tests/typ/text/shaping.typ b/tests/typ/text/shaping.typ index 5a469a456..ba543e715 100644 --- a/tests/typ/text/shaping.typ +++ b/tests/typ/text/shaping.typ @@ -36,3 +36,10 @@ Aب😀🏞سمB // Tofus are rendered with the first font. A🐈中文B + +--- +// Test reshaping. + +#font("Noto Serif Hebrew") +#lang("he") +ס \ טֶ