diff options
Diffstat (limited to 'crates/typst-layout/src/inline')
| -rw-r--r-- | crates/typst-layout/src/inline/shaping.rs | 42 |
1 files changed, 31 insertions, 11 deletions
diff --git a/crates/typst-layout/src/inline/shaping.rs b/crates/typst-layout/src/inline/shaping.rs index c2b892d8..d6b7632b 100644 --- a/crates/typst-layout/src/inline/shaping.rs +++ b/crates/typst-layout/src/inline/shaping.rs @@ -11,8 +11,8 @@ use typst_library::engine::Engine; use typst_library::foundations::{Smart, StyleChain}; use typst_library::layout::{Abs, Dir, Em, Frame, FrameItem, Point, Size}; use typst_library::text::{ - families, features, is_default_ignorable, variant, Font, FontVariant, Glyph, Lang, - Region, TextEdgeBounds, TextElem, TextItem, + families, features, is_default_ignorable, variant, Font, FontFamily, FontVariant, + Glyph, Lang, Region, TextEdgeBounds, TextElem, TextItem, }; use typst_library::World; use typst_utils::SliceExt; @@ -351,7 +351,7 @@ impl<'a> ShapedText<'a> { for family in families(self.styles) { if let Some(font) = world .book() - .select(family, self.variant) + .select(family.as_str(), self.variant) .and_then(|id| world.font(id)) { expand(&font, TextEdgeBounds::Zero); @@ -463,7 +463,8 @@ impl<'a> ShapedText<'a> { None }; let mut chain = families(self.styles) - .map(|family| book.select(family, self.variant)) + .filter(|family| family.covers().map_or(true, |c| c.is_match("-"))) + .map(|family| book.select(family.as_str(), self.variant)) .chain(fallback_func.iter().map(|f| f())) .flatten(); @@ -719,7 +720,7 @@ fn shape_segment<'a>( ctx: &mut ShapingContext, base: usize, text: &str, - mut families: impl Iterator<Item = &'a str> + Clone, + mut families: impl Iterator<Item = &'a FontFamily> + Clone, ) { // Don't try shaping newlines, tabs, or default ignorables. if text @@ -732,11 +733,18 @@ fn shape_segment<'a>( // Find the next available family. let world = ctx.engine.world; let book = world.book(); - let mut selection = families.find_map(|family| { - book.select(family, ctx.variant) + let mut selection = None; + let mut covers = None; + for family in families.by_ref() { + selection = book + .select(family.as_str(), ctx.variant) .and_then(|id| world.font(id)) - .filter(|font| !ctx.used.contains(font)) - }); + .filter(|font| !ctx.used.contains(font)); + if selection.is_some() { + covers = family.covers(); + break; + } + } // Do font fallback if the families are exhausted and fallback is enabled. if selection.is_none() && ctx.fallback { @@ -795,6 +803,16 @@ fn shape_segment<'a>( let pos = buffer.glyph_positions(); let ltr = ctx.dir.is_positive(); + // Whether the character at the given offset is covered by the coverage. + let is_covered = |offset| { + let end = text[offset..] + .char_indices() + .nth(1) + .map(|(i, _)| offset + i) + .unwrap_or(text.len()); + covers.map_or(true, |cov| cov.is_match(&text[offset..end])) + }; + // Collect the shaped glyphs, doing fallback and shaping parts again with // the next font if necessary. let mut i = 0; @@ -803,7 +821,7 @@ fn shape_segment<'a>( let cluster = info.cluster as usize; // Add the glyph to the shaped output. - if info.glyph_id != 0 { + if info.glyph_id != 0 && is_covered(cluster) { // Determine the text range of the glyph. let start = base + cluster; let end = base @@ -836,7 +854,9 @@ fn shape_segment<'a>( } else { // First, search for the end of the tofu sequence. let k = i; - while infos.get(i + 1).is_some_and(|info| info.glyph_id == 0) { + while infos.get(i + 1).is_some_and(|info| { + info.glyph_id == 0 || !is_covered(info.cluster as usize) + }) { i += 1; } |
