Skip to content

Commit e7d88b3

Browse files
committed
Fix outline with CJK text (#5187)
1 parent 2a956bb commit e7d88b3

File tree

4 files changed

+33
-17
lines changed

4 files changed

+33
-17
lines changed

crates/typst/src/model/outline.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ use crate::foundations::{
1010
NativeElement, Packed, Show, ShowSet, Smart, StyleChain, Styles,
1111
};
1212
use crate::introspection::{Counter, CounterKey, Locatable};
13-
use crate::layout::{BoxElem, Em, Fr, HElem, HideElem, Length, Rel, RepeatElem, Spacing};
13+
use crate::layout::{
14+
BoxElem, Dir, Em, Fr, HElem, HideElem, Length, Rel, RepeatElem, Spacing,
15+
};
1416
use crate::model::{
1517
Destination, HeadingElem, NumberingPattern, ParElem, ParbreakElem, Refable,
1618
};
@@ -499,12 +501,27 @@ impl Show for Packed<OutlineEntry> {
499501
}
500502
};
501503

502-
// The body text remains overridable.
503-
crate::text::isolate(
504-
self.body().clone().linked(Destination::Location(location)),
505-
styles,
506-
&mut seq,
507-
);
504+
// Isolate the entry body in RTL because the page number is typically
505+
// LTR. I'm not sure whether LTR should conceptually also be isolated,
506+
// but in any case we don't do it for now because the text shaping
507+
// pipeline does tend to choke a bit on default ignorables (in
508+
// particular the CJK-Latin spacing).
509+
//
510+
// See also:
511+
// - https://github.com/typst/typst/issues/4476
512+
// - https://github.com/typst/typst/issues/5176
513+
let rtl = TextElem::dir_in(styles) == Dir::RTL;
514+
if rtl {
515+
// "Right-to-Left Embedding"
516+
seq.push(TextElem::packed("\u{202B}"));
517+
}
518+
519+
seq.push(self.body().clone().linked(Destination::Location(location)));
520+
521+
if rtl {
522+
// "Pop Directional Formatting"
523+
seq.push(TextElem::packed("\u{202C}"));
524+
}
508525

509526
// Add filler symbols between the section name and page number.
510527
if let Some(filler) = self.fill() {

crates/typst/src/text/mod.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,16 +1284,6 @@ pub(crate) fn is_default_ignorable(c: char) -> bool {
12841284
DEFAULT_IGNORABLE_DATA.as_borrowed().contains(c)
12851285
}
12861286

1287-
/// Pushes `text` wrapped in LRE/RLE + PDF to `out`.
1288-
pub(crate) fn isolate(text: Content, styles: StyleChain, out: &mut Vec<Content>) {
1289-
out.push(TextElem::packed(match TextElem::dir_in(styles) {
1290-
Dir::RTL => "\u{202B}",
1291-
_ => "\u{202A}",
1292-
}));
1293-
out.push(text);
1294-
out.push(TextElem::packed("\u{202C}"));
1295-
}
1296-
12971287
/// Checks for font families that are not available.
12981288
fn check_font_list(engine: &mut Engine, list: &Spanned<FontList>) {
12991289
let book = engine.world.book();

tests/ref/issue-5176-cjk-title.png

1.22 KB
Loading

tests/suite/model/outline.typ

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,12 @@ A
171171

172172
= הוקוס Pocus
173173
= זוהי כותרת שתורגמה על ידי מחשב
174+
175+
--- issue-5176-cjk-title ---
176+
#set text(font: "Noto Serif CJK SC")
177+
#show heading: none
178+
179+
#outline(title: none)
180+
181+
= 测
182+
= 很

0 commit comments

Comments
 (0)