diff --git a/library/src/math/accent.rs b/library/src/math/accent.rs index 809939258..797a4761d 100644 --- a/library/src/math/accent.rs +++ b/library/src/math/accent.rs @@ -112,13 +112,14 @@ impl LayoutMath for AccentNode { let size = Size::new(base.width(), accent.height() + gap + base.height()); let accent_pos = Point::with_x(base_attach - accent_attach); let base_pos = Point::with_y(accent.height() + gap); + let base_ascent = base.ascent(); let baseline = base_pos.y + base.ascent(); let mut frame = Frame::new(size); frame.set_baseline(baseline); frame.push_frame(accent_pos, accent); frame.push_frame(base_pos, base.to_frame(ctx)); - ctx.push(FrameFragment::new(ctx, frame)); + ctx.push(FrameFragment::new(ctx, frame).with_base_ascent(base_ascent)); Ok(()) } diff --git a/library/src/math/attach.rs b/library/src/math/attach.rs index 8a1644beb..6adbd47ad 100644 --- a/library/src/math/attach.rs +++ b/library/src/math/attach.rs @@ -51,12 +51,15 @@ impl LayoutMath for AttachNode { let base = ctx.layout_fragment(&self.base)?; ctx.style(ctx.style.for_subscript()); - let top = self.top.as_ref().map(|node| ctx.layout_frame(node)).transpose()?; + let top = self.top.as_ref().map(|node| ctx.layout_fragment(node)).transpose()?; ctx.unstyle(); ctx.style(ctx.style.for_superscript()); - let bottom = - self.bottom.as_ref().map(|node| ctx.layout_frame(node)).transpose()?; + let bottom = self + .bottom + .as_ref() + .map(|node| ctx.layout_fragment(node)) + .transpose()?; ctx.unstyle(); let render_limits = self.base.is::() @@ -145,8 +148,8 @@ impl LayoutMath for LimitsNode { fn scripts( ctx: &mut MathContext, base: MathFragment, - sup: Option, - sub: Option, + sup: Option, + sub: Option, ) -> SourceResult<()> { let sup_shift_up = if ctx.style.cramped { scaled!(ctx, superscript_shift_up_cramped) @@ -166,8 +169,13 @@ fn scripts( let mut shift_down = Abs::zero(); if let Some(sup) = &sup { + let ascent = match &base { + MathFragment::Frame(frame) => frame.base_ascent, + _ => base.ascent(), + }; + shift_up = sup_shift_up - .max(base.ascent() - sup_drop_max) + .max(ascent - sup_drop_max) .max(sup_bottom_min + sup.descent()); } @@ -222,13 +230,13 @@ fn scripts( if let Some(sup) = sup { let sup_pos = Point::new(sup_delta + base_width, ascent - shift_up - sup.ascent()); - frame.push_frame(sup_pos, sup); + frame.push_frame(sup_pos, sup.to_frame(ctx)); } if let Some(sub) = sub { let sub_pos = Point::new(sub_delta + base_width, ascent + shift_down - sub.ascent()); - frame.push_frame(sub_pos, sub); + frame.push_frame(sub_pos, sub.to_frame(ctx)); } ctx.push(FrameFragment::new(ctx, frame).with_class(class)); @@ -240,8 +248,8 @@ fn scripts( fn limits( ctx: &mut MathContext, base: MathFragment, - top: Option, - bottom: Option, + top: Option, + bottom: Option, ) -> SourceResult<()> { let upper_gap_min = scaled!(ctx, upper_limit_gap_min); let upper_rise_min = scaled!(ctx, upper_limit_baseline_rise_min); @@ -275,13 +283,13 @@ fn limits( if let Some(top) = top { let top_pos = Point::with_x((width - top.width()) / 2.0 + delta); - frame.push_frame(top_pos, top); + frame.push_frame(top_pos, top.to_frame(ctx)); } if let Some(bottom) = bottom { let bottom_pos = Point::new((width - bottom.width()) / 2.0 - delta, height - bottom.height()); - frame.push_frame(bottom_pos, bottom); + frame.push_frame(bottom_pos, bottom.to_frame(ctx)); } ctx.push(FrameFragment::new(ctx, frame).with_class(class)); diff --git a/library/src/math/fragment.rs b/library/src/math/fragment.rs index f1c374a14..843021f48 100644 --- a/library/src/math/fragment.rs +++ b/library/src/math/fragment.rs @@ -218,7 +218,7 @@ impl GlyphFragment { glyphs: vec![Glyph { id: self.id.0, c: self.c, - x_advance: Em::from_length(self.width, ctx.size), + x_advance: Em::from_length(self.width, self.font_size), x_offset: Em::zero(), }], }; @@ -256,22 +256,25 @@ impl Debug for VariantFragment { #[derive(Debug, Clone)] pub struct FrameFragment { pub frame: Frame, - pub limits: bool, - pub spaced: bool, pub style: MathStyle, pub font_size: Abs, pub class: MathClass, + pub limits: bool, + pub spaced: bool, + pub base_ascent: Abs, } impl FrameFragment { pub fn new(ctx: &MathContext, frame: Frame) -> Self { + let base_ascent = frame.ascent(); Self { frame, - limits: false, - spaced: false, font_size: ctx.size, style: ctx.style, class: MathClass::Normal, + limits: false, + spaced: false, + base_ascent, } } @@ -286,6 +289,10 @@ impl FrameFragment { pub fn with_spaced(self, spaced: bool) -> Self { Self { spaced, ..self } } + + pub fn with_base_ascent(self, base_ascent: Abs) -> Self { + Self { base_ascent, ..self } + } } /// Look up the italics correction for a glyph. diff --git a/tests/ref/math/accent.png b/tests/ref/math/accent.png index c67e0912d..bea94cab3 100644 Binary files a/tests/ref/math/accent.png and b/tests/ref/math/accent.png differ diff --git a/tests/typ/math/accent.typ b/tests/typ/math/accent.typ index 65ef9d1b5..b67614ddd 100644 --- a/tests/typ/math/accent.typ +++ b/tests/typ/math/accent.typ @@ -2,7 +2,7 @@ --- // Test function call. -$grave(a), acute(b), hat(f), tilde(§), macron(ä), diaer(a), ä, \ +$grave(a), acute(b), hat(f), tilde(§), macron(ä), diaer(a), ä \ breve(\&), dot(!), circle(a), caron(@), arrow(Z), arrow.l(Z)$ --- @@ -17,6 +17,10 @@ $sqrt(tilde(T)) + hat(f)/hat(g)$ // Test wide base. $arrow("ABC" + d), tilde(sum)$ +--- +// Test effect of accent on superscript. +$A^x != hat(A)^x != hat(hat(A))^x$ + --- // Test high base. $ tilde(integral), tilde(integral)_a^b, tilde(integral_a^b) $