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 Jun 3, 2024
1 parent 9afd247 commit 4848e48
Show file tree
Hide file tree
Showing 11 changed files with 66 additions and 44 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 @@ -254,7 +254,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 @@ -293,8 +293,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
21 changes: 15 additions & 6 deletions crates/typst/src/layout/inline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ struct Preparation<'a> {
cjk_latin_spacing: bool,
/// Whether font fallback is enabled for this paragraph.
fallback: bool,
/// The leading of the paragraph.
leading: Abs,
/// The line height of the paragraph.
line_height: Abs,
/// How to determine line breaks.
linebreaks: Smart<Linebreaks>,
/// The text size.
Expand Down Expand Up @@ -679,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 @@ -1289,7 +1289,7 @@ fn finalize(
if frames.len() >= 2 && !frames[1].is_empty() {
let second = frames.remove(1);
let first = &mut frames[0];
merge(first, second, p.leading);
merge(first, second, p.line_height, true);
}
}
if p.costs.widow().get() > 0.0 {
Expand All @@ -1298,19 +1298,28 @@ fn finalize(
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, false);
}
}

Ok(Fragment::frames(frames))
}

/// Merge two line frames
fn merge(first: &mut Frame, second: Frame, leading: Abs) {
fn merge(first: &mut Frame, second: Frame, line_height: Abs, based_on_second: bool) {
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();
let second_baseline = offset + second.baseline();
first.push_frame(Point::with_y(offset), second);
first.size_mut().y = total;
if based_on_second {
first.set_baseline(second_baseline);
}
}

/// Commit to a line and build its frame.
Expand Down
11 changes: 3 additions & 8 deletions crates/typst/src/math/equation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,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 @@ -292,13 +292,8 @@ fn layout_equation_inline(
let InlineItem::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 = TextElem::top_edge_in(styles).resolve(font_size, &font, None);
let descent = -TextElem::bottom_edge_in(styles).resolve(font_size, &font, None);
frame.translate(Point::with_y(ascent - frame.baseline()));
frame.size_mut().y = ascent + descent;
}
Expand Down
29 changes: 14 additions & 15 deletions crates/typst/src/math/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,12 @@ use std::iter::once;
use unicode_math_class::MathClass;

use crate::foundations::{Resolve, StyleChain};
use crate::layout::{Abs, AlignElem, Em, Frame, InlineItem, Point, Size};
use crate::math::{
alignments, scaled_font_size, spacing, EquationElem, FrameFragment, MathContext,
MathFragment, MathSize,
};
use crate::layout::{Abs, AlignElem, Frame, InlineItem, Point, Size};
use crate::math::{alignments, spacing, FrameFragment, MathContext, MathFragment};
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 +157,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
10 changes: 6 additions & 4 deletions crates/typst/src/model/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use crate::foundations::{
StyleChain, Styles,
};
use crate::layout::{
Alignment, Axes, BlockElem, Cell, CellGrid, Em, Fragment, GridLayouter, HAlignment,
Length, Regions, Sizing, Spacing, VAlignment, VElem,
Abs, Alignment, Axes, BlockElem, Cell, CellGrid, Em, Fragment, GridLayouter,
HAlignment, Length, Regions, Sizing, Spacing, VAlignment, VElem,
};
use crate::model::{Numbering, NumberingPattern, ParElem};
use crate::text::TextElem;
Expand Down Expand Up @@ -218,7 +218,8 @@ impl Show for Packed<EnumElem> {
let mut realized = BlockElem::multi_layouter(self.clone(), layout_enum).pack();

if self.tight(styles) {
let leading = ParElem::leading_in(styles);
// TODO(mgt): fix this
let leading: Abs = ParElem::line_height_in(styles);
let spacing = VElem::list_attach(leading.into()).pack();
realized = spacing + realized;
}
Expand All @@ -239,7 +240,8 @@ fn layout_enum(
let indent = elem.indent(styles);
let body_indent = elem.body_indent(styles);
let gutter = if elem.tight(styles) {
ParElem::leading_in(styles).into()
// TODO(mgt): fix this
ParElem::line_height_in(styles).into()
} else {
elem.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
6 changes: 4 additions & 2 deletions crates/typst/src/model/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ impl Show for Packed<ListElem> {
let mut realized = BlockElem::multi_layouter(self.clone(), layout_list).pack();

if self.tight(styles) {
let leading = ParElem::leading_in(styles);
// TODO(mgt): fix this
let leading = ParElem::line_height_in(styles);
let spacing = VElem::list_attach(leading.into()).pack();
realized = spacing + realized;
}
Expand All @@ -162,7 +163,8 @@ fn layout_list(
let indent = elem.indent(styles);
let body_indent = elem.body_indent(styles);
let gutter = if elem.tight(styles) {
ParElem::leading_in(styles).into()
// TODO(mgt): fix this
ParElem::line_height_in(styles).into()
} else {
elem.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 @@ -36,11 +36,11 @@ use crate::realize::StyleVec;
/// ```
#[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
6 changes: 4 additions & 2 deletions crates/typst/src/model/terms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ impl Show 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 Expand Up @@ -148,7 +149,8 @@ impl Show for Packed<TermsElem> {
.padded(padding);

if self.tight(styles) {
let leading = ParElem::leading_in(styles);
// TODO(mgt): fix this
let leading = ParElem::line_height_in(styles);
let spacing = VElem::list_attach(leading.into()).pack();
realized = spacing + realized;
}
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 4848e48

Please sign in to comment.