use typst_library::diag::{SourceResult, warning}; use typst_library::foundations::{Packed, StyleChain}; use typst_library::layout::{Abs, Axis, Rel}; use typst_library::math::StretchElem; use typst_utils::Get; use super::{MathContext, MathFragment, stretch_axes}; /// Lays out a [`StretchElem`]. #[typst_macros::time(name = "math.stretch", span = elem.span())] pub fn layout_stretch( elem: &Packed, ctx: &mut MathContext, styles: StyleChain, ) -> SourceResult<()> { let mut fragment = ctx.layout_into_fragment(&elem.body, styles)?; stretch_fragment( ctx, &mut fragment, None, None, elem.size.resolve(styles), Abs::zero(), ); ctx.push(fragment); Ok(()) } /// Attempts to stretch the given fragment by/to the amount given in stretch. pub fn stretch_fragment( ctx: &mut MathContext, fragment: &mut MathFragment, axis: Option, relative_to: Option, stretch: Rel, short_fall: Abs, ) { let size = fragment.size(); let MathFragment::Glyph(glyph) = fragment else { return }; // 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_glyph.id); let stretch_axis = if let Some(axis) = axis { if !axes.get(axis) { return; } axis } else { match (axes.x, axes.y) { (true, false) => Axis::X, (false, true) => Axis::Y, (false, false) => return, (true, true) => { // As far as we know, there aren't any glyphs that have both // vertical and horizontal constructions. So for the time being, we // will assume that a glyph cannot have both. ctx.engine.sink.warn(warning!( glyph.item.glyphs[0].span.0, "glyph has both vertical and horizontal constructions"; hint: "this is probably a font bug"; hint: "please file an issue at https://github.com/typst/typst/issues" )); return; } } }; let relative_to_size = relative_to.unwrap_or_else(|| size.get(stretch_axis)); glyph.stretch(ctx, stretch.relative_to(relative_to_size) - short_fall, stretch_axis); if stretch_axis == Axis::Y { glyph.center_on_axis(); } }