summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorMax <me@mkor.je>2024-08-26 14:49:24 +0000
committerGitHub <noreply@github.com>2024-08-26 14:49:24 +0000
commit0b31f6039f7529c6d1f47cd4f2593cd997157470 (patch)
treef348207e8bbccdf32f39305b8120d30fe794c8cf /crates
parent77b6c8481f234e40f261b42fa4a9d0294d3ca2a7 (diff)
Fix nested attachments when the base in `math.attach` has attachments (#4832)
Diffstat (limited to 'crates')
-rw-r--r--crates/typst/src/math/attach.rs53
1 files changed, 46 insertions, 7 deletions
diff --git a/crates/typst/src/math/attach.rs b/crates/typst/src/math/attach.rs
index 035b7812..70bf2e5e 100644
--- a/crates/typst/src/math/attach.rs
+++ b/crates/typst/src/math/attach.rs
@@ -52,20 +52,22 @@ pub struct AttachElem {
impl LayoutMath for Packed<AttachElem> {
#[typst_macros::time(name = "math.attach", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext, styles: StyleChain) -> SourceResult<()> {
- let base = ctx.layout_into_fragment(self.base(), styles)?;
+ let new_elem = merge_base(self);
+ let elem = new_elem.as_ref().unwrap_or(self);
+ let base = ctx.layout_into_fragment(elem.base(), styles)?;
let sup_style = style_for_superscript(styles);
let sup_style_chain = styles.chain(&sup_style);
- let tl = self.tl(sup_style_chain);
- let tr = self.tr(sup_style_chain);
+ let tl = elem.tl(sup_style_chain);
+ let tr = elem.tr(sup_style_chain);
let primed = tr.as_ref().is_some_and(|content| content.is::<PrimesElem>());
- let t = self.t(sup_style_chain);
+ let t = elem.t(sup_style_chain);
let sub_style = style_for_subscript(styles);
let sub_style_chain = styles.chain(&sub_style);
- let bl = self.bl(sub_style_chain);
- let br = self.br(sub_style_chain);
- let b = self.b(sub_style_chain);
+ let bl = elem.bl(sub_style_chain);
+ let br = elem.br(sub_style_chain);
+ let b = elem.b(sub_style_chain);
let limits = base.limits().active(styles);
let (t, tr) = match (t, tr) {
@@ -248,6 +250,43 @@ impl Limits {
}
}
+/// If an AttachElem's base is also an AttachElem, merge attachments into the
+/// base AttachElem where possible.
+fn merge_base(elem: &Packed<AttachElem>) -> Option<Packed<AttachElem>> {
+ // Extract from an EquationElem.
+ let mut base = elem.base();
+ if let Some(equation) = base.to_packed::<EquationElem>() {
+ base = equation.body();
+ }
+
+ // Move attachments from elem into base where possible.
+ if let Some(base) = base.to_packed::<AttachElem>() {
+ let mut elem = elem.clone();
+ let mut base = base.clone();
+
+ macro_rules! merge {
+ ($content:ident) => {
+ if base.$content.is_none() && elem.$content.is_some() {
+ base.$content = elem.$content.clone();
+ elem.$content = None;
+ }
+ };
+ }
+
+ merge!(t);
+ merge!(b);
+ merge!(tl);
+ merge!(tr);
+ merge!(bl);
+ merge!(br);
+
+ elem.base = base.pack();
+ return Some(elem);
+ }
+
+ None
+}
+
macro_rules! measure {
($e: ident, $attr: ident) => {
$e.as_ref().map(|e| e.$attr()).unwrap_or_default()