From 851b154a6cb1d558b0091f1a63baa4d3414a7356 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Thu, 20 Apr 2023 10:48:11 -0700 Subject: [PATCH] Convert math alignment to single-pass algorithm (#891) --- library/src/math/align.rs | 42 ++++++++++++++++------------------- tests/ref/math/alignment.png | Bin 0 -> 9752 bytes tests/typ/math/alignment.typ | 28 +++++++++++++++++++++++ 3 files changed, 47 insertions(+), 23 deletions(-) create mode 100644 tests/ref/math/alignment.png create mode 100644 tests/typ/math/alignment.typ diff --git a/library/src/math/align.rs b/library/src/math/align.rs index d34379e22..03abeac27 100644 --- a/library/src/math/align.rs +++ b/library/src/math/align.rs @@ -16,34 +16,30 @@ impl LayoutMath for AlignPointElem { /// Determine the position of the alignment points. pub(super) fn alignments(rows: &[MathRow]) -> Vec { - let count = rows - .iter() - .map(|row| { - row.iter() - .filter(|fragment| matches!(fragment, MathFragment::Align)) - .count() - }) - .max() - .unwrap_or(0); + let mut widths = Vec::::new(); - let mut points = vec![Abs::zero(); count]; - for current in 0..count { - for row in rows { - let mut x = Abs::zero(); - let mut i = 0; - for fragment in row.iter() { - if matches!(fragment, MathFragment::Align) { - if i < current { - x = points[i]; - } else if i == current { - points[i].set_max(x); - } - i += 1; + for row in rows { + let mut width = Abs::zero(); + let mut alignment_index = 0; + for fragment in row.iter() { + if matches!(fragment, MathFragment::Align) { + if alignment_index < widths.len() { + widths[alignment_index].set_max(width); + } else { + widths.push(width); } - x += fragment.width(); + width = Abs::zero(); + alignment_index += 1; + } else { + width += fragment.width(); } } } + let mut points = widths; + for i in 1..points.len() { + let prev = points[i - 1]; + points[i] += prev; + } points } diff --git a/tests/ref/math/alignment.png b/tests/ref/math/alignment.png new file mode 100644 index 0000000000000000000000000000000000000000..45b0cd8628a6e4cd27cb9ee8f36af2edf717ecba GIT binary patch literal 9752 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