From c340c2792410664d438b1ece6e2cb8caf1d83ec4 Mon Sep 17 00:00:00 2001 From: "Y.D.X." <73375426+YDX-2147483647@users.noreply.github.com> Date: Thu, 4 Sep 2025 17:17:00 +0800 Subject: [PATCH] Fix CJ-Latin space at manual line breaks (#6700) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Laurenz Mädje --- crates/typst-layout/src/inline/line.rs | 10 ++++++++-- ...539-cjk-latin-spacing-at-manual-linebreak.png | Bin 0 -> 1532 bytes tests/suite/layout/inline/cjk.typ | 13 +++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 tests/ref/issue-6539-cjk-latin-spacing-at-manual-linebreak.png diff --git a/crates/typst-layout/src/inline/line.rs b/crates/typst-layout/src/inline/line.rs index ca991467..0010c585 100644 --- a/crates/typst-layout/src/inline/line.rs +++ b/crates/typst-layout/src/inline/line.rs @@ -149,6 +149,7 @@ pub fn line<'a>( // Trim the line at the end, if necessary for this breakpoint. let trim = range.start + breakpoint.trim(full).len(); + let trimmed_range = range.start..trim; // Collect the items for the line. let mut items = Items::new(); @@ -179,7 +180,8 @@ pub fn line<'a>( trim_weak_spacing(&mut items); // Deal with CJ characters at line boundaries. - adjust_cj_at_line_boundaries(p, full, &mut items); + // Use the trimmed range for robust boundary checks. + adjust_cj_at_line_boundaries(p, trimmed_range, &mut items); // Compute the line's width. let width = items.iter().map(Item::natural_width).sum(); @@ -319,7 +321,11 @@ fn collect_range<'a>( /// /// See Requirements for Chinese Text Layout, Section 3.1.6.3 Compression of /// punctuation marks at line start or line end. -fn adjust_cj_at_line_boundaries(p: &Preparation, text: &str, items: &mut Items) { +/// +/// The `range` should only contain regular texts, with linebreaks trimmed. +fn adjust_cj_at_line_boundaries(p: &Preparation, range: Range, items: &mut Items) { + let text = &p.text[range]; + if text.starts_with(BEGIN_PUNCT_PAT) || (p.config.cjk_latin_spacing && text.starts_with(is_of_cj_script)) { diff --git a/tests/ref/issue-6539-cjk-latin-spacing-at-manual-linebreak.png b/tests/ref/issue-6539-cjk-latin-spacing-at-manual-linebreak.png new file mode 100644 index 0000000000000000000000000000000000000000..cc572f7aeae4f0a0ceb979c4f51144b2aa68a627 GIT binary patch literal 1532 zcmV$m>?{@U8w-QC^$`}^_n@vpD1rKP3p?CkRL z@}8cagoK3O-`~T-!_d&sgvyMYo13w*vF+{ctgNi#W_xHfSz*SXMnVFfR zqoaw5iPqNEc6N5ZzrPa`6Jlaw{r&x`678bm`ykB2mTwGj$fPi~@dr3)24Gj%SN=mi0wU3XFE-o%i zOiZupws3H8P*70J%*@Kl%KG~H+uPd^5D=@YtG2eb+}zxqot=k=hoGRK)YQ~LK|y(W zd6<}(ySuxUm6d&ceW|Ibi;IhIZ*Q)yu3B1JPEJm}y}jb%;^pP#sHmvY($d%0*K>1o z@bK`Bjg5MGdh_%1>+9?3>FJS?k!EIQfq{WmR#tz1e|&s=S65fY#>SA4kk!@I)6-j9TU}jUmgS$YOifJy z00Xc|L_t(|+U?s%S6W*b#_?x+fQuA~Aab#H(|fkHw;~7XS_OP{gy6FYN!f^UFnGnS(7H-BtyO zhWYa?>$t+!D_#(K;`TnaVSaP~QfIlm`uyL#lxvu~kKMinU`6*7_b~5Ve`<7e^z^GP zEEnV)`*vCZl2rRxg=andiy(h64fEoqHTN&h1Kg|m0=LK=&cRdXLMD1hYZ zdJJh;C;t=_sJpkKD9YE^i$3vHVMvgX80K1GAz&>nEnPn}^P>_pVfqKAuNJbLPP*S; zyT|Wuq+wqBtm7Wr=f_Ux!9z~xatG)l&;zdUG;m-Xm;ep)P;ZtmoT=!FP#8$Ho&j6< zW-Bnykl{b|(6h!8wy*<|4141yGu6)0p#2^o6Wg^>wWAwd}L$W!$&ea-{`w!M7hEP^fB&Kex_#A>@$^4r?Wwq zNyGek(v)F7GQ|0PuF8!Yc)!n;ALa`zD z7_ZYarUu7;;~3^-JOY4*`G3JRZFD-ZhUp?;2YZ;VK1*t|<~;HKwJ;(4*0pm+g3$Kb`z;bB1}iZoWywe33cB{OL;%<1p_(o;7Efx3^V5x**6K i_FmwZK0e&8cK69PGMU@P+g0000