Fix: number-align
should align line/number baselines (#4024)
@ -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)
|
||||
}
|
||||
|
@ -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)>,
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
tests/ref/math-equation-number-align-monoline.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 758 B After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 510 B After Width: | Height: | Size: 518 B |
Before Width: | Height: | Size: 597 B After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
@ -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
|
||||
|