summaryrefslogtreecommitdiff
path: root/crates/typst-library/src/math/row.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/typst-library/src/math/row.rs')
-rw-r--r--crates/typst-library/src/math/row.rs261
1 files changed, 0 insertions, 261 deletions
diff --git a/crates/typst-library/src/math/row.rs b/crates/typst-library/src/math/row.rs
deleted file mode 100644
index 70813598..00000000
--- a/crates/typst-library/src/math/row.rs
+++ /dev/null
@@ -1,261 +0,0 @@
-use std::iter::once;
-
-use crate::layout::AlignElem;
-
-use super::*;
-
-pub const TIGHT_LEADING: Em = Em::new(0.25);
-
-#[derive(Debug, Default, Clone)]
-pub struct MathRow(Vec<MathFragment>);
-
-impl MathRow {
- pub fn new(fragments: Vec<MathFragment>) -> Self {
- let iter = fragments.into_iter().peekable();
- let mut last: Option<usize> = None;
- let mut space: Option<MathFragment> = None;
- let mut resolved: Vec<MathFragment> = vec![];
-
- for mut fragment in iter {
- match fragment {
- // Keep space only if supported by spaced fragments.
- MathFragment::Space(_) => {
- if last.is_some() {
- space = Some(fragment);
- }
- continue;
- }
-
- // Explicit spacing disables automatic spacing.
- MathFragment::Spacing(_) => {
- last = None;
- space = None;
- resolved.push(fragment);
- continue;
- }
-
- // Alignment points are resolved later.
- MathFragment::Align => {
- resolved.push(fragment);
- continue;
- }
-
- // New line, new things.
- MathFragment::Linebreak => {
- resolved.push(fragment);
- space = None;
- last = None;
- continue;
- }
-
- _ => {}
- }
-
- // Convert variable operators into binary operators if something
- // precedes them and they are not preceded by a operator or comparator.
- if fragment.class() == Some(MathClass::Vary)
- && matches!(
- last.and_then(|i| resolved[i].class()),
- Some(
- MathClass::Normal
- | MathClass::Alphabetic
- | MathClass::Closing
- | MathClass::Fence
- )
- )
- {
- fragment.set_class(MathClass::Binary);
- }
-
- // Insert spacing between the last and this item.
- if let Some(i) = last {
- if let Some(s) = spacing(&resolved[i], space.take(), &fragment) {
- resolved.insert(i + 1, s);
- }
- }
-
- last = Some(resolved.len());
- resolved.push(fragment);
- }
-
- Self(resolved)
- }
-
- pub fn iter(&self) -> std::slice::Iter<'_, MathFragment> {
- self.0.iter()
- }
-
- /// Extract the sublines of the row.
- ///
- /// It is very unintuitive, but in current state of things, a `MathRow` can
- /// contain several actual rows. That function deconstructs it to "single"
- /// rows. Hopefully this is only a temporary hack.
- pub fn rows(&self) -> Vec<Self> {
- self.0
- .split(|frag| matches!(frag, MathFragment::Linebreak))
- .map(|slice| Self(slice.to_vec()))
- .collect()
- }
-
- pub fn ascent(&self) -> Abs {
- self.iter().map(MathFragment::ascent).max().unwrap_or_default()
- }
-
- pub fn descent(&self) -> Abs {
- self.iter().map(MathFragment::descent).max().unwrap_or_default()
- }
-
- pub fn class(&self) -> MathClass {
- // Predict the class of the output of 'into_fragment'
- if self.0.len() == 1 {
- self.0
- .first()
- .and_then(|fragment| fragment.class())
- .unwrap_or(MathClass::Special)
- } else {
- // FrameFragment::new() (inside 'into_fragment' in this branch) defaults
- // to MathClass::Normal for its class.
- MathClass::Normal
- }
- }
-
- pub fn into_frame(self, ctx: &MathContext) -> Frame {
- let styles = ctx.styles();
- let align = AlignElem::alignment_in(styles).resolve(styles).x;
- self.into_aligned_frame(ctx, &[], align)
- }
-
- pub fn into_fragment(self, ctx: &MathContext) -> MathFragment {
- if self.0.len() == 1 {
- self.0.into_iter().next().unwrap()
- } else {
- FrameFragment::new(ctx, self.into_frame(ctx)).into()
- }
- }
-
- pub fn into_aligned_frame(
- self,
- ctx: &MathContext,
- points: &[Abs],
- align: FixedAlign,
- ) -> Frame {
- if !self.iter().any(|frag| matches!(frag, MathFragment::Linebreak)) {
- return self.into_line_frame(points, align);
- }
-
- let leading = if ctx.style.size >= MathSize::Text {
- ParElem::leading_in(ctx.styles())
- } else {
- TIGHT_LEADING.scaled(ctx)
- };
-
- let mut rows: Vec<_> = self.rows();
-
- if matches!(rows.last(), Some(row) if row.0.is_empty()) {
- rows.pop();
- }
-
- let AlignmentResult { points, width } = alignments(&rows);
- let mut frame = Frame::soft(Size::zero());
-
- for (i, row) in rows.into_iter().enumerate() {
- let sub = row.into_line_frame(&points, align);
- let size = frame.size_mut();
- if i > 0 {
- size.y += leading;
- }
-
- let mut pos = Point::with_y(size.y);
- if points.is_empty() {
- pos.x = align.position(width - sub.width());
- }
- size.y += sub.height();
- size.x.set_max(sub.width());
- frame.push_frame(pos, sub);
- }
-
- frame
- }
-
- fn into_line_frame(self, points: &[Abs], align: FixedAlign) -> Frame {
- let ascent = self.ascent();
- let mut frame = Frame::soft(Size::new(Abs::zero(), ascent + self.descent()));
- frame.set_baseline(ascent);
-
- let mut next_x = {
- let mut widths = Vec::new();
- if !points.is_empty() && align != FixedAlign::Start {
- 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 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 {
- FixedAlign::Start => prev_points.next(),
- FixedAlign::End => {
- 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) {
- x = next_x().unwrap_or(x);
- continue;
- }
-
- let y = ascent - fragment.ascent();
- let pos = Point::new(x, y);
- x += fragment.width();
- frame.push_frame(pos, fragment.into_frame());
- }
-
- frame.size_mut().x = x;
- frame
- }
-}
-
-impl<T: Into<MathFragment>> From<T> for MathRow {
- fn from(fragment: T) -> Self {
- Self(vec![fragment.into()])
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-enum LeftRightAlternator {
- Left,
- Right,
-}
-
-impl Iterator for LeftRightAlternator {
- type Item = LeftRightAlternator;
-
- fn next(&mut self) -> Option<Self::Item> {
- let r = Some(*self);
- match self {
- Self::Left => *self = Self::Right,
- Self::Right => *self = Self::Left,
- }
- r
- }
-}