From 30d1e62eb2432b43f184ed790c80b1455b99ad81 Mon Sep 17 00:00:00 2001 From: mkorje Date: Tue, 10 Jun 2025 23:35:00 +1000 Subject: [PATCH] Use all glyph positioning information from the shaper --- crates/typst-layout/src/inline/shaping.rs | 4 +-- crates/typst-layout/src/math/fragment.rs | 44 ++++++++++++----------- crates/typst-layout/src/math/stretch.rs | 2 +- crates/typst-library/src/text/font/mod.rs | 12 +++++-- 4 files changed, 37 insertions(+), 25 deletions(-) diff --git a/crates/typst-layout/src/inline/shaping.rs b/crates/typst-layout/src/inline/shaping.rs index 2a1fc8586..935a86b38 100644 --- a/crates/typst-layout/src/inline/shaping.rs +++ b/crates/typst-layout/src/inline/shaping.rs @@ -952,7 +952,7 @@ pub fn create_shape_plan( /// Shape the text with tofus from the given font. fn shape_tofus(ctx: &mut ShapingContext, base: usize, text: &str, font: Font) { - let x_advance = font.advance(0).unwrap_or_default(); + let x_advance = font.x_advance(0).unwrap_or_default(); let add_glyph = |(cluster, c): (usize, char)| { let start = base + cluster; let end = start + c.len_utf8(); @@ -1045,7 +1045,7 @@ fn calculate_adjustability(ctx: &mut ShapingContext, lang: Lang, region: Option< /// Difference between non-breaking and normal space. fn nbsp_delta(font: &Font) -> Option { let nbsp = font.ttf().glyph_index('\u{00A0}')?.0; - Some(font.advance(nbsp)? - font.space_width()?) + Some(font.x_advance(nbsp)? - font.space_width()?) } /// Returns true if all glyphs in `glyphs` have ranges within the range `range`. diff --git a/crates/typst-layout/src/math/fragment.rs b/crates/typst-layout/src/math/fragment.rs index 3fd335af2..eb85eeb5d 100644 --- a/crates/typst-layout/src/math/fragment.rs +++ b/crates/typst-layout/src/math/fragment.rs @@ -23,6 +23,7 @@ use crate::modifiers::{FrameModifiers, FrameModify}; /// Maximum number of times extenders can be repeated. const MAX_REPEATS: usize = 1024; +#[allow(clippy::large_enum_variant)] #[derive(Debug, Clone)] pub enum MathFragment { Glyph(GlyphFragment), @@ -199,7 +200,7 @@ impl MathFragment { // For glyph assemblies we pick either the start or end glyph // depending on the corner. let is_vertical = - glyph.item.glyphs.iter().any(|glyph| glyph.y_advance != Em::zero()); + glyph.item.glyphs.iter().all(|glyph| glyph.y_advance != Em::zero()); let glyph_index = match (is_vertical, corner) { (true, Corner::TopLeft | Corner::TopRight) => { glyph.item.glyphs.len() - 1 @@ -240,7 +241,7 @@ impl From for MathFragment { pub struct GlyphFragment { // Text stuff. pub item: TextItem, - pub base_id: GlyphId, + pub base_glyph: Glyph, // Math stuff. pub size: Size, pub baseline: Option, @@ -318,6 +319,16 @@ impl GlyphFragment { .or_else(|| default_math_class(c)) .unwrap_or(MathClass::Normal); + let glyph = Glyph { + id: info.glyph_id as u16, + x_advance: font.to_em(pos.x_advance), + x_offset: font.to_em(pos.x_offset), + y_advance: font.to_em(pos.y_advance), + y_offset: font.to_em(pos.y_offset), + range: 0..text.len().saturating_as(), + span: (span, 0), + }; + let item = TextItem { font: font.clone(), size: TextElem::size_in(styles), @@ -326,20 +337,12 @@ impl GlyphFragment { lang: TextElem::lang_in(styles), region: TextElem::region_in(styles), text: text.into(), - glyphs: vec![Glyph { - id: info.glyph_id as u16, - x_advance: font.to_em(pos.x_advance), - x_offset: Em::zero(), - y_advance: Em::zero(), - y_offset: Em::zero(), - range: 0..text.len().saturating_as(), - span: (span, 0), - }], + glyphs: vec![glyph.clone()], }; let mut fragment = Self { item, - base_id: GlyphId(info.glyph_id as u16), + base_glyph: glyph, // Math math_size: EquationElem::size_in(styles), class, @@ -399,11 +402,7 @@ impl GlyphFragment { // base_id's. This is used to return a glyph to its unstretched state. pub fn reset_glyph(&mut self) { self.align = Abs::zero(); - self.item.glyphs = vec![Glyph { - id: self.base_id.0, - x_advance: self.item.font.advance(self.base_id.0).unwrap_or_default(), - ..self.item.glyphs[0].clone() - }]; + self.item.glyphs = vec![self.base_glyph.clone()]; self.update_glyph(); } @@ -479,7 +478,11 @@ impl GlyphFragment { if target <= best_advance || construction.assembly.is_none() { self.item.glyphs[0].id = best_id.0; self.item.glyphs[0].x_advance = - self.item.font.advance(best_id.0).unwrap_or_default(); + self.item.font.x_advance(best_id.0).unwrap_or_default(); + self.item.glyphs[0].x_offset = Em::zero(); + self.item.glyphs[0].y_advance = + self.item.font.y_advance(best_id.0).unwrap_or_default(); + self.item.glyphs[0].y_offset = Em::zero(); self.update_glyph(); return; } @@ -649,7 +652,8 @@ fn axis_height(font: &Font) -> Option { Some(font.to_em(font.ttf().tables().math?.constants?.axis_height().value)) } -pub fn stretch_axes(font: &Font, id: GlyphId) -> Axes { +pub fn stretch_axes(font: &Font, id: u16) -> Axes { + let id = GlyphId(id); let horizontal = font .ttf() .tables() @@ -783,7 +787,7 @@ fn assemble( base.size.y = full; base.size.x = glyphs .iter() - .map(|glyph| base.item.font.advance(glyph.id).unwrap_or_default()) + .map(|glyph| base.item.font.x_advance(glyph.id).unwrap_or_default()) .max() .unwrap_or_default() .at(base.item.size); diff --git a/crates/typst-layout/src/math/stretch.rs b/crates/typst-layout/src/math/stretch.rs index 2e9144f61..d4370e7b9 100644 --- a/crates/typst-layout/src/math/stretch.rs +++ b/crates/typst-layout/src/math/stretch.rs @@ -34,7 +34,7 @@ pub fn stretch_fragment( // Return if we attempt to stretch along an axis which isn't stretchable, // so that the original fragment isn't modified. - let axes = stretch_axes(&glyph.item.font, glyph.base_id); + let axes = stretch_axes(&glyph.item.font, glyph.base_glyph.id); let stretch_axis = if let Some(axis) = axis { if !axes.get(axis) { return; diff --git a/crates/typst-library/src/text/font/mod.rs b/crates/typst-library/src/text/font/mod.rs index b2afb0466..0383bfe15 100644 --- a/crates/typst-library/src/text/font/mod.rs +++ b/crates/typst-library/src/text/font/mod.rs @@ -106,16 +106,24 @@ impl Font { } /// Look up the horizontal advance width of a glyph. - pub fn advance(&self, glyph: u16) -> Option { + pub fn x_advance(&self, glyph: u16) -> Option { self.0 .ttf .glyph_hor_advance(GlyphId(glyph)) .map(|units| self.to_em(units)) } + /// Look up the vertical advance width of a glyph. + pub fn y_advance(&self, glyph: u16) -> Option { + self.0 + .ttf + .glyph_ver_advance(GlyphId(glyph)) + .map(|units| self.to_em(units)) + } + /// Look up the width of a space. pub fn space_width(&self) -> Option { - self.0.ttf.glyph_index(' ').and_then(|id| self.advance(id.0)) + self.0.ttf.glyph_index(' ').and_then(|id| self.x_advance(id.0)) } /// Lookup a name by id.