diff --git a/library/src/math/row.rs b/library/src/math/row.rs index a25178af7..9b693bc1c 100644 --- a/library/src/math/row.rs +++ b/library/src/math/row.rs @@ -1,3 +1,5 @@ +use std::iter::once; + use crate::layout::AlignElem; use super::*; @@ -172,31 +174,46 @@ impl MathRow { fn into_line_frame(self, points: &[Abs], align: Align) -> Frame { let ascent = self.ascent(); - let descent = self.descent(); - let size = Size::new(Abs::zero(), ascent + descent); - let mut frame = Frame::new(size); - let mut x = Abs::zero(); + let mut frame = Frame::new(Size::new(Abs::zero(), ascent + self.descent())); frame.set_baseline(ascent); - if let (Some(&first), Align::Center) = (points.first(), align) { - let mut offset = first; - for fragment in self.iter() { - offset -= fragment.width(); - if matches!(fragment, MathFragment::Align) { - x = offset; - break; + let mut next_x = { + let mut widths = Vec::new(); + if !points.is_empty() && align != Align::Left { + let mut width = Abs::zero(); + for fragment in self.iter() { + if matches!(fragment, MathFragment::Align) { + widths.push(width); + width = Abs::zero(); + } else { + width += fragment.width(); + } } + widths.push(width); } - } + let widths = widths; - let fragments = self.0.into_iter().peekable(); - let mut i = 0; - for fragment in fragments { + let mut prev_points = once(Abs::zero()).chain(points.iter().copied()); + let mut point_widths = points.iter().copied().zip(widths); + let mut alternator = LeftRightAlternator::Right; + move || match align { + Align::Left => prev_points.next(), + Align::Right => point_widths.next().map(|(point, width)| point - width), + _ => point_widths + .next() + .zip(prev_points.next()) + .zip(alternator.next()) + .map(|(((point, width), prev_point), alternator)| match alternator { + LeftRightAlternator::Left => prev_point, + LeftRightAlternator::Right => point - width, + }), + } + }; + let mut x = next_x().unwrap_or_default(); + + for fragment in self.0.into_iter() { if matches!(fragment, MathFragment::Align) { - if let Some(&point) = points.get(i) { - x = point; - } - i += 1; + x = next_x().unwrap_or(x); continue; } diff --git a/src/geom/align.rs b/src/geom/align.rs index 239a6e709..69f32bee9 100644 --- a/src/geom/align.rs +++ b/src/geom/align.rs @@ -183,3 +183,22 @@ impl Fold for GenAlign { self } } + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum LeftRightAlternator { + Left, + Right, +} + +impl Iterator for LeftRightAlternator { + type Item = LeftRightAlternator; + + fn next(&mut self) -> Option { + let r = Some(*self); + match self { + Self::Left => *self = Self::Right, + Self::Right => *self = Self::Left, + } + r + } +} diff --git a/tests/ref/math/alignment.png b/tests/ref/math/alignment.png index 5d7560e1b..c92e0ea98 100644 Binary files a/tests/ref/math/alignment.png and b/tests/ref/math/alignment.png differ diff --git a/tests/ref/math/matrix-alignment.png b/tests/ref/math/matrix-alignment.png index b15412d69..b272a2906 100644 Binary files a/tests/ref/math/matrix-alignment.png and b/tests/ref/math/matrix-alignment.png differ diff --git a/tests/ref/math/multiline.png b/tests/ref/math/multiline.png index 50f611b2a..a5e53bc7e 100644 Binary files a/tests/ref/math/multiline.png and b/tests/ref/math/multiline.png differ