diff --git a/Cargo.lock b/Cargo.lock index 9d56853c5..f3dca3db4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1345,7 +1345,6 @@ dependencies = [ [[package]] name = "krilla" version = "0.3.0" -source = "git+https://github.com/LaurenzV/krilla?rev=399dc59#399dc596fdb27fde3ca1eef27b74625affed199a" dependencies = [ "base64", "bumpalo", diff --git a/Cargo.toml b/Cargo.toml index 35278d18b..acaaca107 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,7 @@ if_chain = "1" image = { version = "0.25.5", default-features = false, features = ["png", "jpeg", "gif"] } indexmap = { version = "2", features = ["serde"] } kamadak-exif = "0.6" -krilla = { git = "https://github.com/LaurenzV/krilla", rev = "399dc59", features = ["svg", "raster-images", "comemo", "rayon"] } +krilla = { path = "../krilla/crates/krilla", features = ["svg", "raster-images", "comemo", "rayon"] } kurbo = "0.11" libfuzzer-sys = "0.4" lipsum = "0.9" diff --git a/crates/typst-layout/src/inline/shaping.rs b/crates/typst-layout/src/inline/shaping.rs index 159619eb3..26e38bd3f 100644 --- a/crates/typst-layout/src/inline/shaping.rs +++ b/crates/typst-layout/src/inline/shaping.rs @@ -826,8 +826,47 @@ fn shape_segment<'a>( if info.glyph_id != 0 && is_covered(cluster) { // Determine the text range of the glyph. let start = base + cluster; + // Assume we have the following sequence of (glyph_id, cluster): + // [(120, 0), (80, 0), (3, 3), (755, 4), (69, 4), (424, 13), (63, 13), (193, 25), (80, 25), (3, 31) + // We then want the sequence of (glyph_id, text_range) to look as follows: + // [(120, 0..3), (80, 0..3), (3, 3..4), (755, 4..13), (69, 4..13), (424, 13..25), + // (63, 13..25), (193, 25..31), (80, 25..31), (3, 31..x)] + // i.e. each glyph in the same cluster should be assigned the full text range. This + // is necessary because only this way can krilla properly assign `ActualText` attributes + // in complex shaping scenarios. + let offset = if ltr { + let mut e = i.checked_add(1); + loop { + if let Some(index) = e { + if let Some(end_info) = infos.get(index) { + if end_info.cluster == info.cluster { + e = index.checked_add(1); + continue; + } + } + } + + break; + } + + e + } else { + let mut e = i.checked_sub(1); + while let Some(index) = e { + if let Some(end_info) = infos.get(index) { + if end_info.cluster == info.cluster { + e = index.checked_sub(1); + } else { + break; + } + } + } + + e + }; + let end = base - + if ltr { i.checked_add(1) } else { i.checked_sub(1) } + + offset .and_then(|last| infos.get(last)) .map_or(text.len(), |info| info.cluster as usize);