summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorLeedehai <18319900+Leedehai@users.noreply.github.com>2024-05-07 09:46:18 -0400
committerGitHub <noreply@github.com>2024-05-07 13:46:18 +0000
commitaa38b96849e2c8a8d7a462789e1f81e9f65d45b3 (patch)
tree725aa65668754a44727c39590f5991405b66cf82 /crates
parentc0576c6b5560a4d253f0b579295a246bf7676ae7 (diff)
Fix: `number-align` should align line/number baselines (#4024)
Diffstat (limited to 'crates')
-rw-r--r--crates/typst/src/math/equation.rs109
-rw-r--r--crates/typst/src/math/row.rs4
2 files changed, 72 insertions, 41 deletions
diff --git a/crates/typst/src/math/equation.rs b/crates/typst/src/math/equation.rs
index 4e844d07..18ef5150 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::<FixedAlignment>::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<FixedAlignment>,
+ equation_align: FixedAlignment,
+ width: Abs,
+ is_multiline: bool,
+ [first, last]: [(Axes<Abs>, 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::<FixedAlignment>::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::<FixedAlignment>::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 afed8231..0ce17ce5 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)>,
}