summaryrefslogtreecommitdiff
path: root/src/exec
diff options
context:
space:
mode:
Diffstat (limited to 'src/exec')
-rw-r--r--src/exec/context.rs51
-rw-r--r--src/exec/mod.rs15
-rw-r--r--src/exec/state.rs23
3 files changed, 47 insertions, 42 deletions
diff --git a/src/exec/context.rs b/src/exec/context.rs
index 6a1c2416..7fd72fe3 100644
--- a/src/exec/context.rs
+++ b/src/exec/context.rs
@@ -38,7 +38,7 @@ impl<'a> ExecContext<'a> {
env,
diags: DiagSet::new(),
tree: Tree { runs: vec![] },
- page: Some(PageInfo::new(&state, Softness::Hard)),
+ page: Some(PageInfo::new(&state, true)),
stack: NodeStack::new(&state),
par: NodePar::new(&state),
state,
@@ -77,7 +77,8 @@ impl<'a> ExecContext<'a> {
/// Push a layout node into the active paragraph.
///
- /// Spacing nodes will be handled according to their [`Softness`].
+ /// Spacing nodes will be handled according to their
+ /// [`softness`](NodeSpacing::softness).
pub fn push(&mut self, node: impl Into<Node>) {
push(&mut self.par.children, node.into());
}
@@ -87,7 +88,7 @@ impl<'a> ExecContext<'a> {
let em = self.state.font.font_size();
self.push(NodeSpacing {
amount: self.state.par.word_spacing.resolve(em),
- softness: Softness::Soft,
+ softness: 1,
});
}
@@ -109,15 +110,19 @@ impl<'a> ExecContext<'a> {
/// Apply a forced line break.
pub fn push_linebreak(&mut self) {
- self.finish_par();
+ let em = self.state.font.font_size();
+ self.push_into_stack(NodeSpacing {
+ amount: self.state.par.leading.resolve(em),
+ softness: 2,
+ });
}
/// Apply a forced paragraph break.
pub fn push_parbreak(&mut self) {
let em = self.state.font.font_size();
self.push_into_stack(NodeSpacing {
- amount: self.state.par.par_spacing.resolve(em),
- softness: Softness::Soft,
+ amount: self.state.par.spacing.resolve(em),
+ softness: 1,
});
}
@@ -163,11 +168,13 @@ impl<'a> ExecContext<'a> {
NodeText {
text,
- aligns: self.state.aligns,
dir: self.state.dirs.cross,
- font_size: self.state.font.font_size(),
+ aligns: self.state.aligns,
families: Rc::clone(&self.state.font.families),
variant,
+ font_size: self.state.font.font_size(),
+ top_edge: self.state.font.top_edge,
+ bottom_edge: self.state.font.bottom_edge,
}
}
@@ -192,12 +199,12 @@ impl<'a> ExecContext<'a> {
}
/// Finish the active page.
- pub fn finish_page(&mut self, keep: bool, new_softness: Softness, source: Span) {
+ pub fn finish_page(&mut self, keep: bool, hard: bool, source: Span) {
if let Some(info) = &mut self.page {
- let info = mem::replace(info, PageInfo::new(&self.state, new_softness));
+ let info = mem::replace(info, PageInfo::new(&self.state, hard));
let stack = self.finish_stack();
- if !stack.children.is_empty() || (keep && info.softness == Softness::Hard) {
+ if !stack.children.is_empty() || (keep && info.hard) {
self.tree.runs.push(NodePages {
size: info.size,
child: NodePad {
@@ -215,7 +222,7 @@ impl<'a> ExecContext<'a> {
/// Finish execution and return the created layout tree.
pub fn finish(mut self) -> Pass<Tree> {
assert!(self.page.is_some());
- self.finish_page(true, Softness::Soft, Span::default());
+ self.finish_page(true, false, Span::default());
Pass::new(self.tree, self.diags)
}
}
@@ -223,16 +230,18 @@ impl<'a> ExecContext<'a> {
/// Push a node into a list, taking care of spacing softness.
fn push(nodes: &mut Vec<Node>, node: Node) {
if let Node::Spacing(spacing) = node {
- if spacing.softness == Softness::Soft && nodes.is_empty() {
+ if nodes.is_empty() && spacing.softness > 0 {
return;
}
if let Some(&Node::Spacing(other)) = nodes.last() {
- if spacing.softness > other.softness {
- nodes.pop();
- } else if spacing.softness == Softness::Soft {
+ if spacing.softness > 0 && spacing.softness >= other.softness {
return;
}
+
+ if spacing.softness < other.softness {
+ nodes.pop();
+ }
}
}
@@ -242,7 +251,7 @@ fn push(nodes: &mut Vec<Node>, node: Node) {
/// Remove trailing soft spacing from a node list.
fn trim(nodes: &mut Vec<Node>) {
if let Some(&Node::Spacing(spacing)) = nodes.last() {
- if spacing.softness == Softness::Soft {
+ if spacing.softness > 0 {
nodes.pop();
}
}
@@ -252,15 +261,15 @@ fn trim(nodes: &mut Vec<Node>) {
struct PageInfo {
size: Size,
padding: Sides<Linear>,
- softness: Softness,
+ hard: bool,
}
impl PageInfo {
- fn new(state: &State, softness: Softness) -> Self {
+ fn new(state: &State, hard: bool) -> Self {
Self {
size: state.page.size,
padding: state.page.margins(),
- softness,
+ hard,
}
}
}
@@ -281,7 +290,7 @@ impl NodePar {
Self {
dirs: state.dirs,
aligns: state.aligns,
- line_spacing: state.par.line_spacing.resolve(em),
+ line_spacing: state.par.leading.resolve(em),
children: vec![],
}
}
diff --git a/src/exec/mod.rs b/src/exec/mod.rs
index 45abca02..35ffa2b6 100644
--- a/src/exec/mod.rs
+++ b/src/exec/mod.rs
@@ -35,15 +35,6 @@ pub fn exec(
ctx.finish()
}
-/// Defines how an item interacts with surrounding items.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
-pub enum Softness {
- /// A soft item can be skipped in some circumstances.
- Soft,
- /// A hard item is always retained.
- Hard,
-}
-
/// Execute a node.
///
/// This manipulates active styling and document state and produces layout
@@ -106,15 +97,15 @@ impl Exec for NodeRaw {
ctx.set_monospace();
let em = ctx.state.font.font_size();
- let line_spacing = ctx.state.par.line_spacing.resolve(em);
+ let leading = ctx.state.par.leading.resolve(em);
let mut children = vec![];
let mut newline = false;
for line in &self.lines {
if newline {
children.push(layout::Node::Spacing(NodeSpacing {
- amount: line_spacing,
- softness: Softness::Soft,
+ amount: leading,
+ softness: 2,
}));
}
diff --git a/src/exec/state.rs b/src/exec/state.rs
index 65f26439..aa2dde1c 100644
--- a/src/exec/state.rs
+++ b/src/exec/state.rs
@@ -2,10 +2,9 @@ use std::rc::Rc;
use fontdock::{fallback, FallbackTree, FontStretch, FontStyle, FontVariant, FontWeight};
-use crate::geom::{
- Align, Dir, LayoutAligns, LayoutDirs, Length, Linear, Relative, Sides, Size,
-};
+use crate::geom::*;
use crate::paper::{Paper, PaperClass, PAPER_A4};
+use crate::shaping::VerticalFontMetric;
/// The evaluation state.
#[derive(Debug, Clone, PartialEq)]
@@ -77,20 +76,20 @@ impl Default for PageState {
/// Defines paragraph properties.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ParState {
+ /// The spacing between paragraphs (dependent on scaled font size).
+ pub spacing: Linear,
+ /// The spacing between lines (dependent on scaled font size).
+ pub leading: Linear,
/// The spacing between words (dependent on scaled font size).
pub word_spacing: Linear,
- /// The spacing between lines (dependent on scaled font size).
- pub line_spacing: Linear,
- /// The spacing between paragraphs (dependent on scaled font size).
- pub par_spacing: Linear,
}
impl Default for ParState {
fn default() -> Self {
Self {
+ spacing: Relative::new(1.0).into(),
+ leading: Relative::new(0.5).into(),
word_spacing: Relative::new(0.25).into(),
- line_spacing: Linear::ZERO,
- par_spacing: Relative::new(0.5).into(),
}
}
}
@@ -106,6 +105,10 @@ pub struct FontState {
pub size: Length,
/// The linear to apply on the base font size.
pub scale: Linear,
+ /// The top end of the text bounding box.
+ pub top_edge: VerticalFontMetric,
+ /// The bottom end of the text bounding box.
+ pub bottom_edge: VerticalFontMetric,
/// Whether the strong toggle is active or inactive. This determines
/// whether the next `*` adds or removes font weight.
pub strong: bool,
@@ -141,6 +144,8 @@ impl Default for FontState {
stretch: FontStretch::Normal,
},
size: Length::pt(11.0),
+ top_edge: VerticalFontMetric::CapHeight,
+ bottom_edge: VerticalFontMetric::Baseline,
scale: Linear::ONE,
strong: false,
emph: false,