diff --git a/crates/typst/src/layout/inline/shaping.rs b/crates/typst/src/layout/inline/shaping.rs index 80fe476a0..b91d0b0bf 100644 --- a/crates/typst/src/layout/inline/shaping.rs +++ b/crates/typst/src/layout/inline/shaping.rs @@ -240,24 +240,24 @@ impl<'a> ShapedText<'a> { } let pos = Point::new(offset, top + shift - y_offset.at(self.size)); - let glyphs = group + let glyphs: Vec = group .iter() - .map(|glyph| { + .map(|shaped: &ShapedGlyph| { let adjustability_left = if justification_ratio < 0.0 { - glyph.shrinkability().0 + shaped.shrinkability().0 } else { - glyph.stretchability().0 + shaped.stretchability().0 }; let adjustability_right = if justification_ratio < 0.0 { - glyph.shrinkability().1 + shaped.shrinkability().1 } else { - glyph.stretchability().1 + shaped.stretchability().1 }; let justification_left = adjustability_left * justification_ratio; let mut justification_right = adjustability_right * justification_ratio; - if glyph.is_justifiable() { + if shaped.is_justifiable() { justification_right += Em::from_length(extra_justification, self.size) } @@ -265,15 +265,33 @@ impl<'a> ShapedText<'a> { frame.size_mut().x += justification_left.at(self.size) + justification_right.at(self.size); + // |<---- a Glyph ---->| + // -->|ShapedGlyph|<-- + // +---+-----------+---+ + // | | *********| | + // | | * | | + // | | * ****| | + // | | * *| | + // | | *********| | + // +---+--+--------+---+ + // A B C D + // Note A, B, D could be positive, zero, or negative. + // A: justification_left + // B: ShapedGlyph's x_offset + // (though a small part of the glyph may go inside B) + // B+C: ShapedGlyph's x_advance + // D: justification_right + // A+B: Glyph's x_offset + // A+B+C+D: Glyph's x_advance Glyph { - id: glyph.glyph_id, - x_advance: glyph.x_advance + id: shaped.glyph_id, + x_advance: shaped.x_advance + justification_left + justification_right, - x_offset: glyph.x_offset + justification_left, - range: (glyph.range.start - range.start).saturating_as() - ..(glyph.range.end - range.start).saturating_as(), - span: glyph.span, + x_offset: shaped.x_offset + justification_left, + range: (shaped.range.start - range.start).saturating_as() + ..(shaped.range.end - range.start).saturating_as(), + span: shaped.span, } }) .collect(); diff --git a/crates/typst/src/text/item.rs b/crates/typst/src/text/item.rs index 081b06d72..49ed78517 100644 --- a/crates/typst/src/text/item.rs +++ b/crates/typst/src/text/item.rs @@ -21,7 +21,8 @@ pub struct TextItem { pub lang: Lang, /// The item's plain text. pub text: EcoString, - /// The glyphs. + /// The glyphs. The number of glyphs may be different from the number of + /// characters in the plain text due to e.g. ligatures. pub glyphs: Vec, } @@ -49,7 +50,8 @@ pub struct Glyph { pub x_advance: Em, /// The horizontal offset of the glyph. pub x_offset: Em, - /// The range of the glyph in its item's text. + /// The range of the glyph in its item's text. The range's length may + /// be more than one due to multi-byte UTF-8 encoding or ligatures. pub range: Range, /// The source code location of the text. pub span: (Span, u16),