Skip to content

Commit

Permalink
Use line height based spacing model
Browse files Browse the repository at this point in the history
  • Loading branch information
Enter-tainer committed May 25, 2024
1 parent 34f1a23 commit 9052a0f
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 41 deletions.
10 changes: 8 additions & 2 deletions crates/typst/src/layout/flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ impl<'a> FlowLayouter<'a> {
styles: StyleChain,
) -> SourceResult<()> {
let align = AlignElem::alignment_in(styles).resolve(styles);
let leading = ParElem::leading_in(styles);
let line_height = ParElem::line_height_in(styles);
let consecutive = self.last_was_par;
let lines = par
.layout(
Expand Down Expand Up @@ -319,8 +319,14 @@ impl<'a> FlowLayouter<'a> {
}
}

for (i, mut frame) in lines.into_iter().enumerate() {
for (i, mut frame) in lines.clone().into_iter().enumerate() {
if i > 0 {
let leading =
if lines[i - 1].descent().abs() + frame.ascent() > line_height {
Abs::pt(1.0)
} else {
line_height - lines[i - 1].descent().abs() - frame.ascent()
};
self.layout_item(engine, FlowItem::Absolute(leading, true))?;
}

Expand Down
34 changes: 21 additions & 13 deletions crates/typst/src/layout/inline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,9 @@ struct Preparation<'a> {
cjk_latin_spacing: bool,
/// Whether font fallback is enabled for this paragraph.
fallback: bool,
/// The leading of the paragraph.
leading: Abs,
#[allow(unused)]
/// The line height of the paragraph.
line_height: Abs,
/// How to determine line breaks.
linebreaks: Smart<Linebreaks>,
/// The text size.
Expand Down Expand Up @@ -678,7 +679,7 @@ fn prepare<'a>(
hang: ParElem::hanging_indent_in(styles),
cjk_latin_spacing,
fallback: TextElem::fallback_in(styles),
leading: ParElem::leading_in(styles),
line_height: ParElem::line_height_in(styles),
linebreaks: ParElem::linebreaks_in(styles),
size: TextElem::size_in(styles),
})
Expand Down Expand Up @@ -1283,29 +1284,36 @@ fn finalize(
.collect::<SourceResult<_>>()?;

// Positive ratios enable prevention, while zero and negative ratios disable it.
if p.costs.orphan().get() > 0.0 {
// Prevent orphans.
if frames.len() >= 2 && !frames[1].is_empty() {
let second = frames.remove(1);
let first = &mut frames[0];
merge(first, second, p.leading);
}
}
// if p.costs.orphan().get() > 0.0 {
// // Prevent orphans.
// if frames.len() >= 2 && !frames[1].is_empty() {
// let second = frames.remove(1);
// let first = &mut frames[0];
// merge(first, second, p.line_height);
// }
// }
// TODO: re-enable them
if p.costs.widow().get() > 0.0 {
// Prevent widows.
let len = frames.len();
if len >= 2 && !frames[len - 2].is_empty() {
let second = frames.pop().unwrap();
let first = frames.last_mut().unwrap();
merge(first, second, p.leading);
merge(first, second, p.line_height);
}
}

Ok(Fragment::frames(frames))
}

#[allow(unused)]
/// Merge two line frames
fn merge(first: &mut Frame, second: Frame, leading: Abs) {
fn merge(first: &mut Frame, second: Frame, line_height: Abs) {
let leading = if first.descent().abs() + second.ascent().abs() > line_height {
Abs::pt(1.0)
} else {
line_height - first.descent().abs() - second.ascent().abs()
};
let offset = first.height() + leading;
let total = offset + second.height();
first.push_frame(Point::with_y(offset), second);
Expand Down
7 changes: 3 additions & 4 deletions crates/typst/src/math/equation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::layout::{
use crate::math::{
scaled_font_size, LayoutMath, MathContext, MathRunFrameBuilder, MathSize, MathVariant,
};
use crate::model::{Numbering, Outlinable, ParElem, Refable, Supplement};
use crate::model::{Numbering, Outlinable, Refable, Supplement};
use crate::syntax::Span;
use crate::text::{
families, variant, Font, FontFamily, FontList, FontWeight, LocalName, TextElem,
Expand Down Expand Up @@ -233,13 +233,12 @@ impl Packed<EquationElem> {
let MathParItem::Frame(frame) = item else { continue };

let font_size = scaled_font_size(&ctx, styles);
let slack = ParElem::leading_in(styles) * 0.7;
let top_edge = TextElem::top_edge_in(styles).resolve(font_size, &font, None);
let bottom_edge =
-TextElem::bottom_edge_in(styles).resolve(font_size, &font, None);

let ascent = top_edge.max(frame.ascent() - slack);
let descent = bottom_edge.max(frame.descent() - slack);
let ascent = top_edge.max(frame.ascent());
let descent = bottom_edge.max(frame.descent());
frame.translate(Point::with_y(ascent - frame.baseline()));
frame.size_mut().y = ascent + descent;
}
Expand Down
27 changes: 14 additions & 13 deletions crates/typst/src/math/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,14 @@ use std::iter::once;
use unicode_math_class::MathClass;

use crate::foundations::{Resolve, StyleChain};
use crate::layout::{Abs, AlignElem, Em, Frame, Point, Size};
use crate::layout::{Abs, AlignElem, Frame, Point, Size};
use crate::math::{
alignments, scaled_font_size, spacing, EquationElem, FrameFragment, MathContext,
MathFragment, MathParItem, MathSize,
alignments, spacing, FrameFragment, MathContext, MathFragment, MathParItem,
};
use crate::model::ParElem;

use super::fragment::SpacingFragment;

pub const TIGHT_LEADING: Em = Em::new(0.25);

/// A linear collection of [`MathFragment`]s.
#[derive(Debug, Default, Clone)]
pub struct MathRun(Vec<MathFragment>);
Expand Down Expand Up @@ -162,27 +159,31 @@ impl MathRun {
ctx: &MathContext,
styles: StyleChain,
) -> MathRunFrameBuilder {
let _ = ctx;
let rows: Vec<_> = self.rows();
let row_count = rows.len();
let alignments = alignments(&rows);

let leading = if EquationElem::size_in(styles) >= MathSize::Text {
ParElem::leading_in(styles)
} else {
let font_size = scaled_font_size(ctx, styles);
TIGHT_LEADING.at(font_size)
};
let line_height = ParElem::line_height_in(styles);

let align = AlignElem::alignment_in(styles).resolve(styles).x;
let mut frames: Vec<(Frame, Point)> = vec![];
let mut size = Size::zero();
for (i, row) in rows.into_iter().enumerate() {
for (i, row) in rows.clone().into_iter().enumerate() {
if i == row_count - 1 && row.0.is_empty() {
continue;
}

let sub = row.into_line_frame(&alignments.points, LeftRightAlternator::Right);
let sub = row
.clone()
.into_line_frame(&alignments.points, LeftRightAlternator::Right);
if i > 0 {
let leading =
if rows[i - 1].descent().abs() + row.ascent().abs() > line_height {
Abs::pt(1.0)
} else {
line_height - rows[i - 1].descent().abs() - row.ascent().abs()
};
size.y += leading;
}

Expand Down
3 changes: 2 additions & 1 deletion crates/typst/src/model/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ impl LayoutMultiple for Packed<EnumElem> {
let indent = self.indent(styles);
let body_indent = self.body_indent(styles);
let gutter = if self.tight(styles) {
ParElem::leading_in(styles).into()
// TODO(mgt): fix this
ParElem::line_height_in(styles).into()
} else {
self.spacing(styles)
.unwrap_or_else(|| *BlockElem::below_in(styles).amount())
Expand Down
4 changes: 2 additions & 2 deletions crates/typst/src/model/footnote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,9 @@ impl Show for Packed<FootnoteEntry> {
impl ShowSet for Packed<FootnoteEntry> {
fn show_set(&self, _: StyleChain) -> Styles {
let text_size = Em::new(0.85);
let leading = Em::new(0.5);
let line_height = Em::new(1.158203125);
let mut out = Styles::new();
out.set(ParElem::set_leading(leading.into()));
out.set(ParElem::set_line_height(line_height.into()));
out.set(TextElem::set_size(TextSize(text_size.into())));
out
}
Expand Down
3 changes: 2 additions & 1 deletion crates/typst/src/model/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ impl LayoutMultiple for Packed<ListElem> {
let indent = self.indent(styles);
let body_indent = self.body_indent(styles);
let gutter = if self.tight(styles) {
ParElem::leading_in(styles).into()
// TODO(mgt): fix this
ParElem::line_height_in(styles).into()
} else {
self.spacing(styles)
.unwrap_or_else(|| *BlockElem::below_in(styles).amount())
Expand Down
6 changes: 3 additions & 3 deletions crates/typst/src/model/par.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ use crate::layout::{Em, Fragment, Length, Size};
/// ```
#[elem(title = "Paragraph", Debug, Construct)]
pub struct ParElem {
/// The spacing between lines.
/// The spacing between baselines.
#[resolve]
#[ghost]
#[default(Em::new(0.65).into())]
pub leading: Length,
#[default(Em::new(1.308203125).into())]
pub line_height: Length,

/// Whether to justify text in its line.
///
Expand Down
3 changes: 2 additions & 1 deletion crates/typst/src/model/terms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ impl LayoutMultiple for Packed<TermsElem> {
let indent = self.indent(styles);
let hanging_indent = self.hanging_indent(styles);
let gutter = if self.tight(styles) {
ParElem::leading_in(styles).into()
// TODO(mgt): fix this
ParElem::line_height_in(styles).into()
} else {
self.spacing(styles)
.unwrap_or_else(|| *BlockElem::below_in(styles).amount())
Expand Down
3 changes: 2 additions & 1 deletion crates/typst/src/realize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,8 @@ impl<'a> FlowBuilder<'a> {
};

if !last_was_parbreak && is_tight_list {
let leading = ParElem::leading_in(styles);
// TODO(mgt): fix this
let leading = ParElem::line_height_in(styles);
let spacing = VElem::list_attach(leading.into());
self.0.push(arenas.store(spacing.pack()), styles);
}
Expand Down
Binary file added tests/ref/par-inline-math-overlap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions tests/suite/model/par.typ
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,10 @@ Welcome \ here. Does this work well?
#set text(dir: rtl)
لآن وقد أظلم الليل وبدأت النجوم
تنضخ وجه الطبيعة التي أعْيَتْ من طول ما انبعثت في النهار

--- par-inline-math-overlap ---
#lorem(1) $1/123456$ #lorem(2) $12345667/1/1$

#lorem(3) $sum_(x=0)^n$ #lorem(3)

#lorem(3) $display((a+b)/(c+d))$ #lorem(2) $display((a/b+1)/c+1)$ #lorem(7)

0 comments on commit 9052a0f

Please sign in to comment.