diff --git a/crates/typst/src/math/equation.rs b/crates/typst/src/math/equation.rs index 4e844d076..18ef51508 100644 --- a/crates/typst/src/math/equation.rs +++ b/crates/typst/src/math/equation.rs @@ -389,18 +389,17 @@ fn add_equation_number( region_size_x: Abs, full_number_width: Abs, ) -> Frame { - let first = equation_builder - .frames - .first() - .map_or((equation_builder.size, Point::zero()), |(frame, point)| { - (frame.size(), *point) - }); - let last = equation_builder - .frames - .last() - .map_or((equation_builder.size, Point::zero()), |(frame, point)| { - (frame.size(), *point) - }); + let first = + equation_builder.frames.first().map_or( + (equation_builder.size, Point::zero(), Abs::zero()), + |(frame, pos)| (frame.size(), *pos, frame.baseline()), + ); + let last = + equation_builder.frames.last().map_or( + (equation_builder.size, Point::zero(), Abs::zero()), + |(frame, pos)| (frame.size(), *pos, frame.baseline()), + ); + let line_count = equation_builder.frames.len(); let mut equation = equation_builder.build(); let width = if region_size_x.is_finite() { @@ -408,23 +407,16 @@ fn add_equation_number( } else { equation.width() + 2.0 * full_number_width }; - let height = match number_align.y { - FixedAlignment::Start => { - let (size, point) = first; - let excess_above = (number.height() - size.y) / 2.0 - point.y; - equation.height() + Abs::zero().max(excess_above) - } - FixedAlignment::Center => equation.height().max(number.height()), - FixedAlignment::End => { - let (size, point) = last; - let excess_below = - (number.height() + size.y) / 2.0 - equation.height() + point.y; - equation.height() + Abs::zero().max(excess_below) - } - }; - let resizing_offset = equation.resize( - Size::new(width, height), - Axes::::new(equation_align, number_align.y.inv()), + + let is_multiline = line_count >= 2; + let resizing_offset = resize_equation( + &mut equation, + &number, + number_align, + equation_align, + width, + is_multiline, + [first, last], ); equation.translate(Point::with_x(match (equation_align, number_align.x) { (FixedAlignment::Start, FixedAlignment::Start) => full_number_width, @@ -437,19 +429,58 @@ fn add_equation_number( FixedAlignment::End => equation.width() - number.width(), _ => unreachable!(), }; - let dh = |h1: Abs, h2: Abs| (h1 - h2) / 2.0; - let y = match number_align.y { - FixedAlignment::Start => { - let (size, point) = first; - resizing_offset.y + point.y + dh(size.y, number.height()) - } - FixedAlignment::Center => dh(equation.height(), number.height()), - FixedAlignment::End => { - let (size, point) = last; - resizing_offset.y + point.y + dh(size.y, number.height()) + let y = { + let align_baselines = |(_, pos, baseline): (_, Point, Abs), number: &Frame| { + resizing_offset.y + pos.y + baseline - number.baseline() + }; + match number_align.y { + FixedAlignment::Start => align_baselines(first, &number), + FixedAlignment::Center if !is_multiline => align_baselines(first, &number), + // In this case, the center lines (not baselines) of the number frame + // and the equation frame shall be aligned. + FixedAlignment::Center => (equation.height() - number.height()) / 2.0, + FixedAlignment::End => align_baselines(last, &number), } }; equation.push_frame(Point::new(x, y), number); equation } + +/// Resize the equation's frame accordingly so that it emcompasses the number. +fn resize_equation( + equation: &mut Frame, + number: &Frame, + number_align: Axes, + equation_align: FixedAlignment, + width: Abs, + is_multiline: bool, + [first, last]: [(Axes, Point, Abs); 2], +) -> Point { + if matches!(number_align.y, FixedAlignment::Center if is_multiline) { + // In this case, the center lines (not baselines) of the number frame + // and the equation frame shall be aligned. + let height = equation.height().max(number.height()); + return equation.resize( + Size::new(width, height), + Axes::::new(equation_align, FixedAlignment::Center), + ); + } + + let excess_above = Abs::zero().max({ + let (.., baseline) = first; + number.baseline() - baseline + }); + let excess_below = Abs::zero().max({ + let (size, .., baseline) = last; + (number.height() - number.baseline()) - (size.y - baseline) + }); + let height = equation.height() + excess_above + excess_below; + + let resizing_offset = equation.resize( + Size::new(width, height), + Axes::::new(equation_align, FixedAlignment::Start), + ); + equation.translate(Point::with_y(excess_above)); + resizing_offset + Point::with_y(excess_above) +} diff --git a/crates/typst/src/math/row.rs b/crates/typst/src/math/row.rs index afed82316..0ce17ce55 100644 --- a/crates/typst/src/math/row.rs +++ b/crates/typst/src/math/row.rs @@ -375,8 +375,8 @@ impl Iterator for LeftRightAlternator { pub struct MathRunFrameBuilder { /// The size of the resulting frame. pub size: Size, - /// Sub frames for each row, and the positions where they should be pushed into - /// the resulting frame. + /// Each row's frame, and the position where the frame should + /// be pushed into the resulting frame. pub frames: Vec<(Frame, Point)>, } diff --git a/tests/ref/math-equation-align-numbered.png b/tests/ref/math-equation-align-numbered.png index e43054c8c..11d4b3b18 100644 Binary files a/tests/ref/math-equation-align-numbered.png and b/tests/ref/math-equation-align-numbered.png differ diff --git a/tests/ref/math-equation-number-align-end.png b/tests/ref/math-equation-number-align-end.png index f60a15ec1..857d56f60 100644 Binary files a/tests/ref/math-equation-number-align-end.png and b/tests/ref/math-equation-number-align-end.png differ diff --git a/tests/ref/math-equation-number-align-left.png b/tests/ref/math-equation-number-align-left.png index a8ed40a5e..ec6cfca00 100644 Binary files a/tests/ref/math-equation-number-align-left.png and b/tests/ref/math-equation-number-align-left.png differ diff --git a/tests/ref/math-equation-number-align-monoline.png b/tests/ref/math-equation-number-align-monoline.png new file mode 100644 index 000000000..681997d42 Binary files /dev/null and b/tests/ref/math-equation-number-align-monoline.png differ diff --git a/tests/ref/math-equation-number-align-multiline-bottom.png b/tests/ref/math-equation-number-align-multiline-bottom.png index cb0e5daa9..08c80f974 100644 Binary files a/tests/ref/math-equation-number-align-multiline-bottom.png and b/tests/ref/math-equation-number-align-multiline-bottom.png differ diff --git a/tests/ref/math-equation-number-align-multiline-expand.png b/tests/ref/math-equation-number-align-multiline-expand.png index 3c3cdc051..b65464331 100644 Binary files a/tests/ref/math-equation-number-align-multiline-expand.png and b/tests/ref/math-equation-number-align-multiline-expand.png differ diff --git a/tests/ref/math-equation-number-align-multiline-top-start.png b/tests/ref/math-equation-number-align-multiline-top-start.png index 43346de95..6a3dad50a 100644 Binary files a/tests/ref/math-equation-number-align-multiline-top-start.png and b/tests/ref/math-equation-number-align-multiline-top-start.png differ diff --git a/tests/ref/math-equation-number-align-right.png b/tests/ref/math-equation-number-align-right.png index e3d588c4e..63daed6ce 100644 Binary files a/tests/ref/math-equation-number-align-right.png and b/tests/ref/math-equation-number-align-right.png differ diff --git a/tests/ref/math-equation-number-align-start.png b/tests/ref/math-equation-number-align-start.png index 67ed3c4c2..769f3b825 100644 Binary files a/tests/ref/math-equation-number-align-start.png and b/tests/ref/math-equation-number-align-start.png differ diff --git a/tests/ref/math-equation-number-align.png b/tests/ref/math-equation-number-align.png index f60a15ec1..857d56f60 100644 Binary files a/tests/ref/math-equation-number-align.png and b/tests/ref/math-equation-number-align.png differ diff --git a/tests/ref/math-equation-numbering.png b/tests/ref/math-equation-numbering.png index b1e6b10e3..3210da236 100644 Binary files a/tests/ref/math-equation-numbering.png and b/tests/ref/math-equation-numbering.png differ diff --git a/tests/ref/outline.png b/tests/ref/outline.png index e5c24a980..71dd6e1a9 100644 Binary files a/tests/ref/outline.png and b/tests/ref/outline.png differ diff --git a/tests/ref/ref-supplements.png b/tests/ref/ref-supplements.png index 46d1524a1..3bd8a30ff 100644 Binary files a/tests/ref/ref-supplements.png and b/tests/ref/ref-supplements.png differ diff --git a/tests/suite/math/equation.typ b/tests/suite/math/equation.typ index dd2745d13..d5771f956 100644 --- a/tests/suite/math/equation.typ +++ b/tests/suite/math/equation.typ @@ -152,6 +152,16 @@ $ a + b = c $ // Error: 52-67 expected `start`, `left`, `right`, or `end`, found center #set math.equation(numbering: "(1)", number-align: center + bottom) +--- math-equation-number-align-monoline --- +#set math.equation(numbering: "(1)") +$ p = sum_k k ln a $ + +#set math.equation(numbering: "(1)", number-align: top) +$ p = sum_k k ln a $ + +#set math.equation(numbering: "(1)", number-align: bottom) +$ p = sum_k k ln a $ + --- math-equation-number-align-multiline --- #set math.equation(numbering: "(1)") @@ -163,13 +173,17 @@ $ p &= ln a b \ $ p &= ln a b \ &= ln a + ln b $ +$ q &= sum_k k ln a \ + &= sum_k ln A $ --- math-equation-number-align-multiline-bottom --- #show math.equation: set align(left) #set math.equation(numbering: "(1)", number-align: bottom) -$ q &= ln sqrt(a b) \ - &= 1/2 (ln a + ln b) $ +$ p &= ln a b \ + &= ln a + ln b $ +$ q &= sum_k ln A \ + &= sum_k k ln a $ --- math-equation-number-align-multiline-expand --- // Tests that if the numbering's layout box vertically exceeds the box of