diff --git a/crates/typst/src/math/fragment.rs b/crates/typst/src/math/fragment.rs index fb1420bfe..d176dd962 100644 --- a/crates/typst/src/math/fragment.rs +++ b/crates/typst/src/math/fragment.rs @@ -297,6 +297,7 @@ impl GlyphFragment { span: self.span, limits: self.limits, frame: self.into_frame(), + mid_stretched: None, } } @@ -360,6 +361,7 @@ pub struct VariantFragment { pub class: Option, pub span: Span, pub limits: Limits, + pub mid_stretched: Option, } impl VariantFragment { diff --git a/crates/typst/src/math/lr.rs b/crates/typst/src/math/lr.rs index 93e5a43c6..1631623ba 100644 --- a/crates/typst/src/math/lr.rs +++ b/crates/typst/src/math/lr.rs @@ -57,6 +57,7 @@ impl LayoutMath for LrElem { .resolve(ctx.styles()) .relative_to(2.0 * max_extent); + // Scale up fragments at both ends. match fragments.as_mut_slice() { [one] => scale(ctx, one, height, None), [first, .., last] => { @@ -66,12 +67,58 @@ impl LayoutMath for LrElem { _ => {} } + // Handle MathFragment::Variant fragments that should be scaled up. + for fragment in &mut fragments { + if let MathFragment::Variant(ref mut variant) = fragment { + if variant.mid_stretched == Some(false) { + variant.mid_stretched = Some(true); + scale(ctx, fragment, height, Some(MathClass::Large)); + } + } + } + ctx.extend(fragments); Ok(()) } } +/// Scales contents vertically to the nearest surrounding lr() group. +/// +/// ```example +/// $ { x mid(|) sum_(i=1)^oo phi_i (x) < 1 } $ +/// ``` +#[elem(LayoutMath)] +pub struct MidElem { + /// The content to be scaled. + #[required] + pub body: Content, +} + +impl LayoutMath for MidElem { + #[tracing::instrument(skip(ctx))] + fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { + let mut fragments = ctx.layout_fragments(self.body())?; + + for fragment in &mut fragments { + match fragment { + MathFragment::Glyph(glyph) => { + let mut new = glyph.clone().into_variant(); + new.mid_stretched = Some(false); + *fragment = MathFragment::Variant(new); + } + MathFragment::Variant(variant) => { + variant.mid_stretched = Some(false); + } + _ => {} + } + } + + ctx.extend(fragments); + Ok(()) + } +} + /// Scale a math fragment to a height. fn scale( ctx: &mut MathContext, diff --git a/crates/typst/src/math/mod.rs b/crates/typst/src/math/mod.rs index d84d9b403..85227fc12 100644 --- a/crates/typst/src/math/mod.rs +++ b/crates/typst/src/math/mod.rs @@ -161,6 +161,7 @@ pub fn module() -> Module { math.define_elem::(); math.define_elem::(); math.define_elem::(); + math.define_elem::(); math.define_elem::(); math.define_elem::(); math.define_elem::(); diff --git a/crates/typst/src/math/stretch.rs b/crates/typst/src/math/stretch.rs index a8e22af45..bfeb80efc 100644 --- a/crates/typst/src/math/stretch.rs +++ b/crates/typst/src/math/stretch.rs @@ -187,6 +187,7 @@ fn assemble( class: base.class, span: base.span, limits: base.limits, + mid_stretched: None, } } diff --git a/tests/ref/math/delimited.png b/tests/ref/math/delimited.png index c83764ec2..1a67cd1d7 100644 Binary files a/tests/ref/math/delimited.png and b/tests/ref/math/delimited.png differ diff --git a/tests/typ/math/delimited.typ b/tests/typ/math/delimited.typ index e5b93cd6a..6607c3028 100644 --- a/tests/typ/math/delimited.typ +++ b/tests/typ/math/delimited.typ @@ -43,3 +43,10 @@ $ lr( text("(", fill: #green) a/b text(")", fill: #blue) ) $ + +--- +// Test middle functions +$ { x mid(|) sum_(i=1)^oo phi_i (x) < 1 } \ + { integral |x| dif x + mid(bar.v.double) + floor(hat(A) mid(|) { x mid(|) y } mid(|) A) } $