diff --git a/library/src/math/accent.rs b/library/src/math/accent.rs index 1cd844290..2a650f2e7 100644 --- a/library/src/math/accent.rs +++ b/library/src/math/accent.rs @@ -58,6 +58,8 @@ impl LayoutMath for AccentElem { let base = ctx.layout_fragment(&self.base())?; ctx.unstyle(); + // Preserve class to preserve automatic spacing. + let base_class = base.class().unwrap_or(MathClass::Normal); let base_attach = match &base { MathFragment::Glyph(base) => { attachment(ctx, base.id, base.italics_correction) @@ -93,7 +95,11 @@ impl LayoutMath for AccentElem { frame.set_baseline(baseline); frame.push_frame(accent_pos, accent); frame.push_frame(base_pos, base.into_frame()); - ctx.push(FrameFragment::new(ctx, frame).with_base_ascent(base_ascent)); + ctx.push( + FrameFragment::new(ctx, frame) + .with_class(base_class) + .with_base_ascent(base_ascent), + ); Ok(()) } diff --git a/library/src/math/cancel.rs b/library/src/math/cancel.rs index edc2ba1ea..770f3c654 100644 --- a/library/src/math/cancel.rs +++ b/library/src/math/cancel.rs @@ -90,7 +90,10 @@ pub struct CancelElem { impl LayoutMath for CancelElem { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - let mut body = ctx.layout_frame(&self.body())?; + let body = ctx.layout_fragment(&self.body())?; + // Use the same math class as the body, in order to preserve automatic spacing around it. + let body_class = body.class().unwrap_or(MathClass::Special); + let mut body = body.into_frame(); let styles = ctx.styles(); let body_size = body.size(); @@ -130,7 +133,7 @@ impl LayoutMath for CancelElem { body.push_frame(center, second_line); } - ctx.push(FrameFragment::new(ctx, body)); + ctx.push(FrameFragment::new(ctx, body).with_class(body_class)); Ok(()) } diff --git a/library/src/math/row.rs b/library/src/math/row.rs index 23c9d242e..a25178af7 100644 --- a/library/src/math/row.rs +++ b/library/src/math/row.rs @@ -95,6 +95,20 @@ impl MathRow { self.iter().map(MathFragment::descent).max().unwrap_or_default() } + pub fn class(&self) -> MathClass { + // Predict the class of the output of 'into_fragment' + if self.0.len() == 1 { + self.0 + .first() + .and_then(|fragment| fragment.class()) + .unwrap_or(MathClass::Special) + } else { + // FrameFragment::new() (inside 'into_fragment' in this branch) defaults + // to MathClass::Normal for its class. + MathClass::Normal + } + } + pub fn into_frame(self, ctx: &MathContext) -> Frame { let styles = ctx.styles(); let align = AlignElem::alignment_in(styles).x.resolve(styles); diff --git a/library/src/math/underover.rs b/library/src/math/underover.rs index 89ec5cff3..3ad2538c9 100644 --- a/library/src/math/underover.rs +++ b/library/src/math/underover.rs @@ -202,6 +202,7 @@ fn layout( ) -> SourceResult<()> { let gap = gap.scaled(ctx); let body = ctx.layout_row(body)?; + let body_class = body.class(); let glyph = GlyphFragment::new(ctx, c, span); let stretched = glyph.stretch_horizontal(ctx, body.width(), Abs::zero()); @@ -226,7 +227,7 @@ fn layout( } let frame = stack(ctx, rows, Align::Center, gap, baseline); - ctx.push(FrameFragment::new(ctx, frame)); + ctx.push(FrameFragment::new(ctx, frame).with_class(body_class)); Ok(()) } diff --git a/tests/ref/math/spacing.png b/tests/ref/math/spacing.png index 921996b01..94ca9b98e 100644 Binary files a/tests/ref/math/spacing.png and b/tests/ref/math/spacing.png differ diff --git a/tests/typ/math/spacing.typ b/tests/typ/math/spacing.typ index c1050d680..969c26c10 100644 --- a/tests/typ/math/spacing.typ +++ b/tests/typ/math/spacing.typ @@ -29,3 +29,12 @@ $a - b ident c quad (mod 2)$ // Test spacing for set comprehension. #set page(width: auto) $ { x in RR | x "is natural" and x < 10 } $ + +--- +// Test spacing for operators with decorations and modifiers on them +#set page(width: auto) +$a ident b + c - d => e log 5 op("ln") 6$ \ +$a cancel(ident) b overline(+) c arrow(-) d hat(=>) e cancel(log) 5 dot(op("ln")) 6$ \ +$a overbrace(ident) b underline(+) c grave(-) d underbracket(=>) e circle(log) 5 caron(op("ln")) 6$ \ +\ +$a attach(ident, tl: a, tr: b) b attach(limits(+), t: a, b: b) c tilde(-) d breve(=>) e attach(limits(log), t: a, b: b) 5 attach(op("ln"), tr: a, bl: b) 6$