diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-10-10 20:54:13 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-10-10 21:04:10 +0200 |
| commit | 9ac125dea8d6ea6cc01814d04413225845b69d65 (patch) | |
| tree | c7dabcda703e5f5b2704c67920efc490f2f8fb57 | |
| parent | d4cc8c775d4c579aeac69ca2d212a604c67043b0 (diff) | |
Rename `State` to `Style` and move it into its own module
| -rw-r--r-- | benches/oneshot.rs | 2 | ||||
| -rw-r--r-- | src/eval/mod.rs | 2 | ||||
| -rw-r--r-- | src/eval/template.rs | 123 | ||||
| -rw-r--r-- | src/eval/walk.rs | 30 | ||||
| -rw-r--r-- | src/geom/paint.rs | 2 | ||||
| -rw-r--r-- | src/layout/par.rs | 8 | ||||
| -rw-r--r-- | src/layout/shaping.rs | 38 | ||||
| -rw-r--r-- | src/lib.rs | 30 | ||||
| -rw-r--r-- | src/library/elements.rs | 8 | ||||
| -rw-r--r-- | src/library/layout.rs | 54 | ||||
| -rw-r--r-- | src/library/mod.rs | 3 | ||||
| -rw-r--r-- | src/library/text.rs | 34 | ||||
| -rw-r--r-- | src/style/mod.rs (renamed from src/eval/state.rs) | 89 | ||||
| -rw-r--r-- | src/style/paper.rs (renamed from src/paper.rs) | 54 | ||||
| -rw-r--r-- | tests/typeset.rs | 13 |
15 files changed, 248 insertions, 242 deletions
diff --git a/benches/oneshot.rs b/benches/oneshot.rs index dda3c572..57e3b339 100644 --- a/benches/oneshot.rs +++ b/benches/oneshot.rs @@ -60,7 +60,7 @@ fn bench_eval(iai: &mut Iai) { fn bench_to_tree(iai: &mut Iai) { let (mut ctx, id) = context(); let module = ctx.evaluate(id).unwrap(); - iai.run(|| module.template.to_tree(ctx.state())); + iai.run(|| module.template.to_tree(ctx.style())); } fn bench_layout(iai: &mut Iai) { diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 384ebb2b..2adf785e 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -12,7 +12,6 @@ mod capture; mod function; mod ops; mod scope; -mod state; mod template; mod walk; @@ -22,7 +21,6 @@ pub use capture::*; pub use dict::*; pub use function::*; pub use scope::*; -pub use state::*; pub use template::*; pub use value::*; pub use walk::*; diff --git a/src/eval/template.rs b/src/eval/template.rs index 42b35fc3..0ea312e5 100644 --- a/src/eval/template.rs +++ b/src/eval/template.rs @@ -4,13 +4,14 @@ use std::mem; use std::ops::{Add, AddAssign}; use std::rc::Rc; -use super::{State, Str}; +use super::Str; use crate::diag::StrResult; use crate::geom::{Align, Dir, Gen, GenAxis, Length, Linear, Sides, Size}; use crate::layout::{ Decoration, LayoutNode, LayoutTree, PadNode, PageRun, ParChild, ParNode, StackChild, StackNode, }; +use crate::style::Style; use crate::util::EcoString; /// A template value: `[*Hi* there]`. @@ -33,15 +34,15 @@ enum TemplateNode { /// Spacing. Spacing(GenAxis, Linear), /// An inline node builder. - Inline(Rc<dyn Fn(&State) -> LayoutNode>, Vec<Decoration>), + Inline(Rc<dyn Fn(&Style) -> LayoutNode>, Vec<Decoration>), /// An block node builder. - Block(Rc<dyn Fn(&State) -> LayoutNode>), - /// Save the current state. + Block(Rc<dyn Fn(&Style) -> LayoutNode>), + /// Save the current style. Save, - /// Restore the last saved state. + /// Restore the last saved style. Restore, - /// A function that can modify the current state. - Modify(Rc<dyn Fn(&mut State)>), + /// A function that can modify the current style. + Modify(Rc<dyn Fn(&mut Style)>), } impl Template { @@ -53,7 +54,7 @@ impl Template { /// Create a template from a builder for an inline-level node. pub fn from_inline<F, T>(f: F) -> Self where - F: Fn(&State) -> T + 'static, + F: Fn(&Style) -> T + 'static, T: Into<LayoutNode>, { let node = TemplateNode::Inline(Rc::new(move |s| f(s).into()), vec![]); @@ -63,7 +64,7 @@ impl Template { /// Create a template from a builder for a block-level node. pub fn from_block<F, T>(f: F) -> Self where - F: Fn(&State) -> T + 'static, + F: Fn(&Style) -> T + 'static, T: Into<LayoutNode>, { let node = TemplateNode::Block(Rc::new(move |s| f(s).into())); @@ -98,7 +99,7 @@ impl Template { /// Add text, but in monospace. pub fn monospace(&mut self, text: impl Into<EcoString>) { self.save(); - self.modify(|state| state.font_mut().monospace = true); + self.modify(|style| style.text_mut().monospace = true); self.text(text); self.restore(); } @@ -126,16 +127,16 @@ impl Template { self.make_mut().push(TemplateNode::Save); } - /// Ensure that later nodes are untouched by state modifications made since + /// Ensure that later nodes are untouched by style modifications made since /// the last snapshot. pub fn restore(&mut self) { self.make_mut().push(TemplateNode::Restore); } - /// Modify the state. + /// Modify the style. pub fn modify<F>(&mut self, f: F) where - F: Fn(&mut State) + 'static, + F: Fn(&mut Style) + 'static, { self.make_mut().push(TemplateNode::Modify(Rc::new(f))); } @@ -143,7 +144,7 @@ impl Template { /// Return a new template which is modified from start to end. pub fn modified<F>(self, f: F) -> Self where - F: Fn(&mut State) + 'static, + F: Fn(&mut Style) + 'static, { let mut wrapper = Self::new(); wrapper.save(); @@ -153,18 +154,18 @@ impl Template { wrapper } - /// Build the stack node resulting from instantiating the template in the - /// given state. - pub fn to_stack(&self, state: &State) -> StackNode { - let mut builder = Builder::new(state, false); + /// Build the stack node resulting from instantiating the template with the + /// given style. + pub fn to_stack(&self, style: &Style) -> StackNode { + let mut builder = Builder::new(style, false); builder.template(self); builder.build_stack() } - /// Build the layout tree resulting from instantiating the template in the - /// given state. - pub fn to_tree(&self, state: &State) -> LayoutTree { - let mut builder = Builder::new(state, true); + /// Build the layout tree resulting from instantiating the template with the + /// given style. + pub fn to_tree(&self, style: &Style) -> LayoutTree { + let mut builder = Builder::new(style, true); builder.template(self); builder.build_tree() } @@ -238,10 +239,10 @@ impl Add<Template> for Str { /// Transforms from template to layout representation. struct Builder { - /// The active state. - state: State, - /// Snapshots of the state. - snapshots: Vec<State>, + /// The current style. + style: Style, + /// Snapshots of the style. + snapshots: Vec<Style>, /// The tree of finished page runs. tree: LayoutTree, /// When we are building the top-level layout trees, this contains metrics @@ -252,14 +253,14 @@ struct Builder { } impl Builder { - /// Create a new builder with a base state. - fn new(state: &State, pages: bool) -> Self { + /// Create a new builder with a base style. + fn new(style: &Style, pages: bool) -> Self { Self { - state: state.clone(), + style: style.clone(), snapshots: vec![], tree: LayoutTree { runs: vec![] }, - page: pages.then(|| PageBuilder::new(state, true)), - stack: StackBuilder::new(state), + page: pages.then(|| PageBuilder::new(style, true)), + stack: StackBuilder::new(style), } } @@ -273,11 +274,11 @@ impl Builder { /// Build a template node. fn node(&mut self, node: &TemplateNode) { match node { - TemplateNode::Save => self.snapshots.push(self.state.clone()), + TemplateNode::Save => self.snapshots.push(self.style.clone()), TemplateNode::Restore => { - let state = self.snapshots.pop().unwrap(); - let newpage = state.page != self.state.page; - self.state = state; + let style = self.snapshots.pop().unwrap(); + let newpage = style.page != self.style.page; + self.style = style; if newpage { self.pagebreak(true, false); } @@ -288,9 +289,9 @@ impl Builder { TemplateNode::Pagebreak(keep) => self.pagebreak(*keep, true), TemplateNode::Text(text, decos) => self.text(text, decos), TemplateNode::Spacing(axis, amount) => self.spacing(*axis, *amount), - TemplateNode::Inline(f, decos) => self.inline(f(&self.state), decos), - TemplateNode::Block(f) => self.block(f(&self.state)), - TemplateNode::Modify(f) => f(&mut self.state), + TemplateNode::Inline(f, decos) => self.inline(f(&self.style), decos), + TemplateNode::Block(f) => self.block(f(&self.style)), + TemplateNode::Modify(f) => f(&mut self.style), } } @@ -306,16 +307,16 @@ impl Builder { /// Apply a forced paragraph break. fn parbreak(&mut self) { - let amount = self.state.par_spacing(); - self.stack.finish_par(&self.state); + let amount = self.style.par_spacing(); + self.stack.finish_par(&self.style); self.stack.push_soft(StackChild::Spacing(amount.into())); } /// Apply a forced page break. fn pagebreak(&mut self, keep: bool, hard: bool) { if let Some(builder) = &mut self.page { - let page = mem::replace(builder, PageBuilder::new(&self.state, hard)); - let stack = mem::replace(&mut self.stack, StackBuilder::new(&self.state)); + let page = mem::replace(builder, PageBuilder::new(&self.style, hard)); + let stack = mem::replace(&mut self.stack, StackBuilder::new(&self.style)); self.tree.runs.extend(page.build(stack.build(), keep)); } } @@ -327,14 +328,14 @@ impl Builder { /// Push an inline node into the active paragraph. fn inline(&mut self, node: impl Into<LayoutNode>, decos: &[Decoration]) { - let align = self.state.aligns.inline; + let align = self.style.aligns.inline; self.stack.par.push(ParChild::Any(node.into(), align, decos.to_vec())); } /// Push a block node into the active stack, finishing the active paragraph. fn block(&mut self, node: impl Into<LayoutNode>) { self.parbreak(); - let aligns = self.state.aligns; + let aligns = self.style.aligns; self.stack.push(StackChild::Any(node.into(), aligns)); self.parbreak(); } @@ -343,7 +344,7 @@ impl Builder { fn spacing(&mut self, axis: GenAxis, amount: Linear) { match axis { GenAxis::Block => { - self.stack.finish_par(&self.state); + self.stack.finish_par(&self.style); self.stack.push_hard(StackChild::Spacing(amount)); } GenAxis::Inline => { @@ -365,8 +366,8 @@ impl Builder { self.tree } - /// Construct a text node with the given text and settings from the active - /// state. + /// Construct a text node with the given text and settings from the current + /// style. fn make_text_node( &self, text: impl Into<EcoString>, @@ -374,8 +375,8 @@ impl Builder { ) -> ParChild { ParChild::Text( text.into(), - self.state.aligns.inline, - Rc::clone(&self.state.font), + self.style.aligns.inline, + Rc::clone(&self.style.text), decos, ) } @@ -388,10 +389,10 @@ struct PageBuilder { } impl PageBuilder { - fn new(state: &State, hard: bool) -> Self { + fn new(style: &Style, hard: bool) -> Self { Self { - size: state.page.size, - padding: state.page.margins(), + size: style.page.size, + padding: style.page.margins(), hard, } } @@ -413,12 +414,12 @@ struct StackBuilder { } impl StackBuilder { - fn new(state: &State) -> Self { + fn new(style: &Style) -> Self { Self { - dirs: state.dirs, + dirs: Gen::new(style.dir, Dir::TTB), children: vec![], last: Last::None, - par: ParBuilder::new(state), + par: ParBuilder::new(style), } } @@ -436,8 +437,8 @@ impl StackBuilder { self.children.push(child); } - fn finish_par(&mut self, state: &State) { - let par = mem::replace(&mut self.par, ParBuilder::new(state)); + fn finish_par(&mut self, style: &Style) { + let par = mem::replace(&mut self.par, ParBuilder::new(style)); if let Some(par) = par.build() { self.push(par); } @@ -462,11 +463,11 @@ struct ParBuilder { } impl ParBuilder { - fn new(state: &State) -> Self { + fn new(style: &Style) -> Self { Self { - aligns: state.aligns, - dir: state.dirs.inline, - line_spacing: state.line_spacing(), + aligns: style.aligns, + dir: style.dir, + line_spacing: style.line_spacing(), children: vec![], last: Last::None, } diff --git a/src/eval/walk.rs b/src/eval/walk.rs index 1755dab9..90361141 100644 --- a/src/eval/walk.rs +++ b/src/eval/walk.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use super::{Eval, EvalContext, Str, Template, Value}; use crate::diag::TypResult; -use crate::geom::Gen; +use crate::geom::{Dir, Gen}; use crate::layout::{ParChild, ParNode, StackChild, StackNode}; use crate::syntax::*; use crate::util::BoolExt; @@ -28,8 +28,8 @@ impl Walk for MarkupNode { Self::Space => ctx.template.space(), Self::Linebreak(_) => ctx.template.linebreak(), Self::Parbreak(_) => ctx.template.parbreak(), - Self::Strong(_) => ctx.template.modify(|s| s.font_mut().strong.flip()), - Self::Emph(_) => ctx.template.modify(|s| s.font_mut().emph.flip()), + Self::Strong(_) => ctx.template.modify(|s| s.text_mut().strong.flip()), + Self::Emph(_) => ctx.template.modify(|s| s.text_mut().emph.flip()), Self::Text(text) => ctx.template.text(text), Self::Raw(raw) => raw.walk(ctx)?, Self::Heading(heading) => heading.walk(ctx)?, @@ -73,11 +73,11 @@ impl Walk for HeadingNode { ctx.template.parbreak(); ctx.template.save(); - ctx.template.modify(move |state| { - let font = state.font_mut(); + ctx.template.modify(move |style| { + let text = style.text_mut(); let upscale = 1.6 - 0.1 * level as f64; - font.size *= upscale; - font.strong = true; + text.size *= upscale; + text.strong = true; }); ctx.template += body; ctx.template.restore(); @@ -105,23 +105,23 @@ impl Walk for EnumNode { } fn walk_item(ctx: &mut EvalContext, label: Str, body: Template) { - ctx.template += Template::from_block(move |state| { + ctx.template += Template::from_block(move |style| { let label = ParNode { - dir: state.dirs.inline, - line_spacing: state.line_spacing(), + dir: style.dir, + line_spacing: style.line_spacing(), children: vec![ParChild::Text( (&label).into(), - state.aligns.inline, - Rc::clone(&state.font), + style.aligns.inline, + Rc::clone(&style.text), vec![], )], }; StackNode { - dirs: Gen::new(state.dirs.block, state.dirs.inline), + dirs: Gen::new(Dir::TTB, style.dir), children: vec![ StackChild::Any(label.into(), Gen::default()), - StackChild::Spacing((state.font.size / 2.0).into()), - StackChild::Any(body.to_stack(&state).into(), Gen::default()), + StackChild::Spacing((style.text.size / 2.0).into()), + StackChild::Any(body.to_stack(&style).into(), Gen::default()), ], } }); diff --git a/src/geom/paint.rs b/src/geom/paint.rs index 2ac11b56..1d82966c 100644 --- a/src/geom/paint.rs +++ b/src/geom/paint.rs @@ -59,7 +59,7 @@ impl FromStr for RgbaColor { /// - `7a03c2` (without alpha), /// - `abcdefff` (with alpha). /// - /// Both lower and upper case is fine. + /// The hashtag is optional and both lower and upper case are fine. fn from_str(hex_str: &str) -> Result<Self, Self::Err> { let hex_str = hex_str.strip_prefix('#').unwrap_or(hex_str); if !hex_str.is_ascii() { diff --git a/src/layout/par.rs b/src/layout/par.rs index 7f087eb3..cf37f005 100644 --- a/src/layout/par.rs +++ b/src/layout/par.rs @@ -6,7 +6,7 @@ use unicode_bidi::{BidiInfo, Level}; use xi_unicode::LineBreakIterator; use super::*; -use crate::eval::FontState; +use crate::style::TextStyle; use crate::util::{EcoString, RangeExt, SliceExt}; type Range = std::ops::Range<usize>; @@ -29,7 +29,7 @@ pub enum ParChild { /// Spacing between other nodes. Spacing(Linear), /// A run of text and how to align it in its line. - Text(EcoString, Align, Rc<FontState>, Vec<Decoration>), + Text(EcoString, Align, Rc<TextStyle>, Vec<Decoration>), /// Any child node and how to align it in its line. Any(LayoutNode, Align, Vec<Decoration>), } @@ -139,11 +139,11 @@ impl<'a> ParLayouter<'a> { items.push(ParItem::Spacing(resolved)); ranges.push(range); } - ParChild::Text(_, align, state, decos) => { + ParChild::Text(_, align, style, decos) => { // TODO: Also split by language and script. for (subrange, dir) in split_runs(&bidi, range) { let text = &bidi.text[subrange.clone()]; - let shaped = shape(ctx, text, dir, state); + let shaped = shape(ctx, text, dir, style); items.push(ParItem::Text(shaped, *align, decos)); ranges.push(subrange); } diff --git a/src/layout/shaping.rs b/src/layout/shaping.rs index dc680276..4580ebf5 100644 --- a/src/layout/shaping.rs +++ b/src/layout/shaping.rs @@ -4,9 +4,9 @@ use std::ops::Range; use rustybuzz::UnicodeBuffer; use super::{Element, Frame, Glyph, LayoutContext, Text}; -use crate::eval::FontState; use crate::font::{Face, FaceId, FontVariant}; use crate::geom::{Dir, Em, Length, Point, Size}; +use crate::style::TextStyle; use crate::util::SliceExt; /// Shape text into [`ShapedText`]. @@ -14,7 +14,7 @@ pub fn shape<'a>( ctx: &mut LayoutContext, text: &'a str, dir: Dir, - state: &'a FontState, + style: &'a TextStyle, ) -> ShapedText<'a> { let mut glyphs = vec![]; if !text.is_empty() { @@ -24,19 +24,19 @@ pub fn shape<'a>( 0, text, dir, - state.size, - state.variant(), - state.families(), + style.size, + style.variant(), + style.families(), None, ); } - let (size, baseline) = measure(ctx, &glyphs, state); + let (size, baseline) = measure(ctx, &glyphs, style); ShapedText { text, dir, - state, + style, size, baseline, glyphs: Cow::Owned(glyphs), @@ -54,7 +54,7 @@ pub struct ShapedText<'a> { /// The text direction. pub dir: Dir, /// The properties used for font selection. - pub state: &'a FontState, + pub style: &'a TextStyle, /// The font size. pub size: Size, /// The baseline from the top of the frame. @@ -93,9 +93,9 @@ impl<'a> ShapedText<'a> { let mut text = Text { face_id, - size: self.state.size, + size: self.style.size, width: Length::zero(), - fill: self.state.fill, + fill: self.style.fill, glyphs: vec![], }; @@ -123,17 +123,17 @@ impl<'a> ShapedText<'a> { text_range: Range<usize>, ) -> ShapedText<'a> { if let Some(glyphs) = self.slice_safe_to_break(text_range.clone()) { - let (size, baseline) = measure(ctx, glyphs, self.state); + let (size, baseline) = measure(ctx, glyphs, self.style); Self { text: &self.text[text_range], dir: self.dir, - state: self.state, + style: self.style, size, baseline, glyphs: Cow::Borrowed(glyphs), } } else { - shape(ctx, &self.text[text_range], self.dir, self.state) + shape(ctx, &self.text[text_range], self.dir, self.style) } } @@ -334,7 +334,7 @@ fn shape_segment<'a>( fn measure( ctx: &mut LayoutContext, glyphs: &[ShapedGlyph], - state: &FontState, + style: &TextStyle, ) -> (Size, Length) { let mut width = Length::zero(); let mut top = Length::zero(); @@ -342,15 +342,15 @@ fn measure( // Expand top and bottom by reading the face's vertical metrics. let mut expand = |face: &Face| { - top.set_max(face.vertical_metric(state.top_edge, state.size)); - bottom.set_max(-face.vertical_metric(state.bottom_edge, state.size)); + top.set_max(face.vertical_metric(style.top_edge, style.size)); + bottom.set_max(-face.vertical_metric(style.bottom_edge, style.size)); }; if glyphs.is_empty() { // When there are no glyphs, we just use the vertical metrics of the // first available font. - for family in state.families() { - if let Some(face_id) = ctx.fonts.select(family, state.variant) { + for family in style.families() { + if let Some(face_id) = ctx.fonts.select(family, style.variant) { expand(ctx.fonts.get(face_id)); break; } @@ -361,7 +361,7 @@ fn measure( expand(face); for glyph in group { - width += glyph.x_advance.to_length(state.size); + width += glyph.x_advance.to_length(style.size); } } } @@ -8,7 +8,7 @@ //! - **Evaluation:** The next step is to [evaluate] the markup. This produces a //! [module], consisting of a scope of values that were exported by the code //! and a template with the contents of the module. This template can be -//! [instantiated] in a state to produce a layout tree, a high-level, fully +//! [instantiated] with a style to produce a layout tree, a high-level, fully //! styled representation of the document. The nodes of this tree are //! self-contained and order-independent and thus much better suited for //! layouting than the raw markup. @@ -18,7 +18,6 @@ //! - **Exporting:** The finished layout can be exported into a supported //! format. Currently, the only supported output format is [PDF]. //! - //! [tokens]: parse::Tokens //! [parsed]: parse::parse //! [markup]: syntax::Markup @@ -40,16 +39,16 @@ pub mod image; pub mod layout; pub mod library; pub mod loading; -pub mod paper; pub mod parse; pub mod source; +pub mod style; pub mod syntax; pub mod util; use std::rc::Rc; use crate::diag::TypResult; -use crate::eval::{Module, Scope, State}; +use crate::eval::{Module, Scope}; use crate::font::FontStore; use crate::image::ImageStore; #[cfg(feature = "layout-cache")] @@ -57,6 +56,7 @@ use crate::layout::{EvictionPolicy, LayoutCache}; use crate::layout::{Frame, LayoutTree}; use crate::loading::Loader; use crate::source::{SourceId, SourceStore}; +use crate::style::Style; use crate::syntax::Markup; /// The core context which holds the loader, configuration and cached artifacts. @@ -74,8 +74,8 @@ pub struct Context { pub layouts: LayoutCache, /// The standard library scope. std: Scope, - /// The default state. - state: State, + /// The default style. + style: Style, } impl Context { @@ -94,9 +94,9 @@ impl Context { &self.std } - /// A read-only reference to the state. - pub fn state(&self) -> &State { - &self.state + /// A read-only reference to the style. + pub fn style(&self) -> &Style { + &self.style } /// Parse a source file and return the resulting markup. @@ -113,7 +113,7 @@ impl Context { /// Execute a source file and produce the resulting layout tree. pub fn execute(&mut self, id: SourceId) -> TypResult<LayoutTree> { let module = self.evaluate(id)?; - Ok(module.template.to_tree(&self.state)) + Ok(module.template.to_tree(&self.style)) } /// Typeset a source file into a collection of layouted frames. @@ -139,7 +139,7 @@ impl Context { /// This struct is created by [`Context::builder`]. pub struct ContextBuilder { std: Option<Scope>, - state: Option<State>, + style: Option<Style>, #[cfg(feature = "layout-cache")] policy: EvictionPolicy, #[cfg(feature = "layout-cache")] @@ -155,8 +155,8 @@ impl ContextBuilder { } /// The initial properties for page size, font selection and so on. - pub fn state(mut self, state: State) -> Self { - self.state = Some(state); + pub fn style(mut self, style: Style) -> Self { + self.style = Some(style); self } @@ -188,7 +188,7 @@ impl ContextBuilder { #[cfg(feature = "layout-cache")] layouts: LayoutCache::new(self.policy, self.max_size), std: self.std.unwrap_or(library::new()), - state: self.state.unwrap_or_default(), + style: self.style.unwrap_or_default(), } } } @@ -197,7 +197,7 @@ impl Default for ContextBuilder { fn default() -> Self { Self { std: None, - state: None, + style: None, #[cfg(feature = "layout-cache")] policy: EvictionPolicy::default(), #[cfg(feature = "layout-cache")] diff --git a/src/library/elements.rs b/src/library/elements.rs index 9680dfee..51f8dc98 100644 --- a/src/library/elements.rs +++ b/src/library/elements.rs @@ -61,12 +61,12 @@ fn rect_impl( fill: Option<Color>, body: Template, ) -> Value { - Value::Template(Template::from_inline(move |state| { + Value::Template(Template::from_inline(move |style| { let mut node = LayoutNode::new(FixedNode { width, height, aspect, - child: body.to_stack(state).into(), + child: body.to_stack(style).into(), }); if let Some(fill) = fill { @@ -114,7 +114,7 @@ fn ellipse_impl( fill: Option<Color>, body: Template, ) -> Value { - Value::Template(Template::from_inline(move |state| { + Value::Template(Template::from_inline(move |style| { // This padding ratio ensures that the rectangular padded region fits // perfectly into the ellipse. const PAD: f64 = 0.5 - SQRT_2 / 4.0; @@ -125,7 +125,7 @@ fn ellipse_impl( aspect, child: LayoutNode::new(PadNode { padding: Sides::splat(Relative::new(PAD).into()), - child: body.to_stack(state).into(), + child: body.to_stack(style).into(), }), }); diff --git a/src/library/layout.rs b/src/library/layout.rs index 089b80cf..c8b22f88 100644 --- a/src/library/layout.rs +++ b/src/library/layout.rs @@ -1,6 +1,6 @@ use super::*; use crate::layout::{FixedNode, GridNode, PadNode, StackChild, StackNode, TrackSizing}; -use crate::paper::{Paper, PaperClass}; +use crate::style::{Paper, PaperClass}; /// `page`: Configure pages. pub fn page(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { @@ -21,8 +21,8 @@ pub fn page(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let bottom = args.named("bottom")?; let flip = args.named("flip")?; - ctx.template.modify(move |state| { - let page = state.page_mut(); + ctx.template.modify(move |style| { + let page = style.page_mut(); if let Some(paper) = paper { page.class = paper.class(); @@ -98,13 +98,13 @@ pub fn align(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { } let realign = |template: &mut Template| { - template.modify(move |state| { + template.modify(move |style| { if let Some(horizontal) = horizontal { - state.aligns.inline = horizontal; + style.aligns.inline = horizontal; } if let Some(vertical) = vertical { - state.aligns.block = vertical; + style.aligns.block = vertical; } }); @@ -147,12 +147,12 @@ pub fn boxed(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let width = args.named("width")?; let height = args.named("height")?; let body: Template = args.eat().unwrap_or_default(); - Ok(Value::Template(Template::from_inline(move |state| { + Ok(Value::Template(Template::from_inline(move |style| { FixedNode { width, height, aspect: None, - child: body.to_stack(state).into(), + child: body.to_stack(style).into(), } }))) } @@ -160,8 +160,8 @@ pub fn boxed(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { /// `block`: Place content in a block. pub fn block(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let body: Template = args.expect("body")?; - Ok(Value::Template(Template::from_block(move |state| { - body.to_stack(state) + Ok(Value::Template(Template::from_block(move |style| { + body.to_stack(style) }))) } @@ -181,10 +181,10 @@ pub fn pad(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { bottom.or(all).unwrap_or_default(), ); - Ok(Value::Template(Template::from_block(move |state| { + Ok(Value::Template(Template::from_block(move |style| { PadNode { padding, - child: body.to_stack(&state).into(), + child: body.to_stack(&style).into(), } }))) } @@ -208,20 +208,20 @@ pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let spacing = args.named("spacing")?; let list: Vec<Child> = args.all().collect(); - Ok(Value::Template(Template::from_block(move |state| { - let mut dirs = Gen::new(None, dir).unwrap_or(state.dirs); + Ok(Value::Template(Template::from_block(move |style| { + let mut dirs = Gen::new(style.dir, dir.unwrap_or(Dir::TTB)); // If the directions become aligned, fix up the inline direction since // that's the one that is not user-defined. - if dirs.block.axis() == dirs.inline.axis() { - dirs.inline = state.dirs.block; + if dirs.inline.axis() == dirs.block.axis() { + dirs.inline = Dir::TTB; } // Use the current alignments for all children, but take care to apply // them to the correct axes (by swapping them if the stack axes are - // different from the state axes). - let mut aligns = state.aligns; - if dirs.block.axis() == state.dirs.inline.axis() { + // different from the style axes). + let mut aligns = style.aligns; + if dirs.inline.axis() != style.dir.axis() { aligns = Gen::new(aligns.block, aligns.inline); } @@ -240,7 +240,7 @@ pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { children.push(StackChild::Spacing(v)); } - let node = template.to_stack(state).into(); + let node = template.to_stack(style).into(); children.push(StackChild::Any(node, aligns)); delayed = spacing; } @@ -293,10 +293,12 @@ pub fn grid(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let children: Vec<Template> = args.all().collect(); - Ok(Value::Template(Template::from_block(move |state| { + Ok(Value::Template(Template::from_block(move |style| { // If the directions become aligned, try to fix up the direction which // is not user-defined. - let mut dirs = Gen::new(column_dir, row_dir).unwrap_or(state.dirs); + let mut dirs = + Gen::new(column_dir.unwrap_or(style.dir), row_dir.unwrap_or(Dir::TTB)); + if dirs.block.axis() == dirs.inline.axis() { let target = if column_dir.is_some() { &mut dirs.block @@ -304,15 +306,15 @@ pub fn grid(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { &mut dirs.inline }; - *target = if target.axis() == state.dirs.inline.axis() { - state.dirs.block + *target = if target.axis() == style.dir.axis() { + Dir::TTB } else { - state.dirs.inline + style.dir }; } let children = - children.iter().map(|child| child.to_stack(&state).into()).collect(); + children.iter().map(|child| child.to_stack(&style).into()).collect(); GridNode { dirs, diff --git a/src/library/mod.rs b/src/library/mod.rs index d99eb24d..7c8f4a93 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -17,10 +17,11 @@ use std::convert::TryFrom; use std::rc::Rc; use crate::diag::{At, TypResult}; -use crate::eval::{Args, Array, EvalContext, Scope, State, Str, Template, Value}; +use crate::eval::{Args, Array, EvalContext, Scope, Str, Template, Value}; use crate::font::{FontFamily, FontStretch, FontStyle, FontWeight, VerticalFontMetric}; use crate::geom::*; use crate::layout::LayoutNode; +use crate::style::Style; use crate::syntax::{Span, Spanned}; /// Construct a scope containing all standard library definitions. diff --git a/src/library/text.rs b/src/library/text.rs index b532b20b..fa334620 100644 --- a/src/library/text.rs +++ b/src/library/text.rs @@ -48,55 +48,55 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let fallback = args.named("fallback")?; let body = args.eat::<Template>(); - let f = move |state: &mut State| { - let font = state.font_mut(); + let f = move |style_: &mut Style| { + let text = style_.text_mut(); if let Some(size) = size { - font.size = size.resolve(font.size); + text.size = size.resolve(text.size); } if let Some(style) = style { - font.variant.style = style; + text.variant.style = style; } if let Some(weight) = weight { - font.variant.weight = weight; + text.variant.weight = weight; } if let Some(stretch) = stretch { - font.variant.stretch = stretch; + text.variant.stretch = stretch; } if let Some(top_edge) = top_edge { - font.top_edge = top_edge; + text.top_edge = top_edge; } if let Some(bottom_edge) = bottom_edge { - font.bottom_edge = bottom_edge; + text.bottom_edge = bottom_edge; } if let Some(fill) = fill { - font.fill = Paint::Color(fill); + text.fill = Paint::Color(fill); } if let Some(FontDef(list)) = &list { - font.families_mut().list = list.clone(); + text.families_mut().list = list.clone(); } if let Some(FamilyDef(serif)) = &serif { - font.families_mut().serif = serif.clone(); + text.families_mut().serif = serif.clone(); } if let Some(FamilyDef(sans_serif)) = &sans_serif { - font.families_mut().sans_serif = sans_serif.clone(); + text.families_mut().sans_serif = sans_serif.clone(); } if let Some(FamilyDef(monospace)) = &monospace { - font.families_mut().monospace = monospace.clone(); + text.families_mut().monospace = monospace.clone(); } if let Some(fallback) = fallback { - font.fallback = fallback; + text.fallback = fallback; } }; @@ -113,8 +113,8 @@ pub fn par(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let par_spacing = args.named("spacing")?; let line_spacing = args.named("leading")?; - ctx.template.modify(move |state| { - let par = state.par_mut(); + ctx.template.modify(move |style| { + let par = style.par_mut(); if let Some(par_spacing) = par_spacing { par.par_spacing = par_spacing; @@ -144,7 +144,7 @@ pub fn lang(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { }; if let Some(dir) = dir { - ctx.template.modify(move |state| state.dirs.inline = dir); + ctx.template.modify(move |style| style.dir = dir); } ctx.template.parbreak(); diff --git a/src/eval/state.rs b/src/style/mod.rs index 5d8d3172..f59ea32e 100644 --- a/src/eval/state.rs +++ b/src/style/mod.rs @@ -1,68 +1,73 @@ +//! Style properties. + +mod paper; + +pub use paper::*; + use std::rc::Rc; use crate::font::{ FontFamily, FontStretch, FontStyle, FontVariant, FontWeight, VerticalFontMetric, }; use crate::geom::*; -use crate::paper::{PaperClass, ISO_A4}; -/// Defines an set of properties a template can be instantiated with. +/// Defines a set of properties a template can be instantiated with. #[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct State { +pub struct Style { /// The direction for text and other inline objects. - pub dirs: Gen<Dir>, + pub dir: Dir, /// The alignments of layouts in their parents. pub aligns: Gen<Align>, /// The page settings. - pub page: Rc<PageState>, + pub page: Rc<PageStyle>, /// The paragraph settings. - pub par: Rc<ParState>, - /// The font settings. - pub font: Rc<FontState>, + pub par: Rc<ParStyle>, + /// The current text settings. + pub text: Rc<TextStyle>, } -impl State { - /// Access the `page` state mutably. - pub fn page_mut(&mut self) -> &mut PageState { +impl Style { + /// Access the `page` style mutably. + pub fn page_mut(&mut self) -> &mut PageStyle { Rc::make_mut(&mut self.page) } - /// Access the `par` state mutably. - pub fn par_mut(&mut self) -> &mut ParState { + /// Access the `par` style mutably. + pub fn par_mut(&mut self) -> &mut ParStyle { Rc::make_mut(&mut self.par) } - /// Access the `font` state mutably. - pub fn font_mut(&mut self) -> &mut FontState { - Rc::make_mut(&mut self.font) + /// Access the `text` style mutably. + pub fn text_mut(&mut self) -> &mut TextStyle { + Rc::make_mut(&mut self.text) } /// The resolved line spacing. pub fn line_spacing(&self) -> Length { - self.par.line_spacing.resolve(self.font.size) + self.par.line_spacing.resolve(self.text.size) } /// The resolved paragraph spacing. pub fn par_spacing(&self) -> Length { - self.par.par_spacing.resolve(self.font.size) + self.par.par_spacing.resolve(self.text.size) } } -impl Default for State { +impl Default for Style { fn default() -> Self { Self { - dirs: Gen::new(Dir::LTR, Dir::TTB), + dir: Dir::LTR, aligns: Gen::splat(Align::Start), - page: Rc::new(PageState::default()), - par: Rc::new(ParState::default()), - font: Rc::new(FontState::default()), + page: Rc::new(PageStyle::default()), + par: Rc::new(ParStyle::default()), + text: Rc::new(TextStyle::default()), } } } -/// Defines page properties. +/// Defines style properties of pages. #[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct PageState { +pub struct PageStyle { /// The class of this page. pub class: PaperClass, /// The width and height of the page. @@ -72,7 +77,7 @@ pub struct PageState { pub margins: Sides<Option<Linear>>, } -impl PageState { +impl PageStyle { /// The resolved margins. pub fn margins(&self) -> Sides<Linear> { let default = self.class.default_margins(); @@ -85,9 +90,9 @@ impl PageState { } } -impl Default for PageState { +impl Default for PageStyle { fn default() -> Self { - let paper = ISO_A4; + let paper = Paper::ISO_A4; Self { class: paper.class(), size: paper.size(), @@ -96,16 +101,16 @@ impl Default for PageState { } } -/// Defines paragraph properties. +/// Defines style properties of paragraphs. #[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct ParState { +pub struct ParStyle { /// The spacing between paragraphs (dependent on scaled font size). pub par_spacing: Linear, /// The spacing between lines (dependent on scaled font size). pub line_spacing: Linear, } -impl Default for ParState { +impl Default for ParStyle { fn default() -> Self { Self { par_spacing: Relative::new(1.2).into(), @@ -114,9 +119,9 @@ impl Default for ParState { } } -/// Defines font properties. +/// Defines style properties of text. #[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct FontState { +pub struct TextStyle { /// The font size. pub size: Length, /// The selected font variant (the final variant also depends on `strong` @@ -130,7 +135,7 @@ pub struct FontState { pub fill: Paint, /// A list of font families with generic class definitions (the final /// family list also depends on `monospace`). - pub families: Rc<FamilyState>, + pub families: Rc<FamilyStyle>, /// Whether 300 extra font weight should be added to what is defined by the /// `variant`. pub strong: bool, @@ -142,7 +147,7 @@ pub struct FontState { pub fallback: bool, } -impl FontState { +impl TextStyle { /// The resolved variant with `strong` and `emph` factored in. pub fn variant(&self) -> FontVariant { let mut variant = self.variant; @@ -188,13 +193,13 @@ impl FontState { head.iter().chain(core).chain(tail).map(String::as_str) } - /// Access the `families` state mutably. - pub fn families_mut(&mut self) -> &mut FamilyState { + /// Access the `families` style mutably. + pub fn families_mut(&mut self) -> &mut FamilyStyle { Rc::make_mut(&mut self.families) } } -impl Default for FontState { +impl Default for TextStyle { fn default() -> Self { Self { size: Length::pt(11.0), @@ -206,7 +211,7 @@ impl Default for FontState { top_edge: VerticalFontMetric::CapHeight, bottom_edge: VerticalFontMetric::Baseline, fill: Paint::Color(Color::Rgba(RgbaColor::BLACK)), - families: Rc::new(FamilyState::default()), + families: Rc::new(FamilyStyle::default()), strong: false, emph: false, monospace: false, @@ -215,9 +220,9 @@ impl Default for FontState { } } -/// Font family definitions. +/// Font list with family definitions. #[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct FamilyState { +pub struct FamilyStyle { /// The user-defined list of font families. pub list: Rc<Vec<FontFamily>>, /// Definition of serif font families. @@ -230,7 +235,7 @@ pub struct FamilyState { pub base: Rc<Vec<String>>, } -impl Default for FamilyState { +impl Default for FamilyStyle { fn default() -> Self { Self { list: Rc::new(vec![FontFamily::SansSerif]), diff --git a/src/paper.rs b/src/style/paper.rs index 8dbee265..bc317308 100644 --- a/src/paper.rs +++ b/src/style/paper.rs @@ -1,5 +1,3 @@ -//! Predefined papers. - use crate::geom::{Length, Linear, Relative, Sides, Size}; /// Specification of a paper. @@ -13,23 +11,6 @@ pub struct Paper { height: f64, } -impl Paper { - /// The paper with the given name. - pub fn from_name(name: &str) -> Option<Self> { - parse_paper(name) - } - - /// The class of the paper. - pub fn class(self) -> PaperClass { - self.class - } - - /// The size of the paper. - pub fn size(self) -> Size { - Size::new(Length::mm(self.width), Length::mm(self.height)) - } -} - /// Defines default margins for a class of related papers. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum PaperClass { @@ -57,21 +38,38 @@ impl PaperClass { macro_rules! papers { ($(($var:ident: $class:ident, $width:expr, $height: expr, $($pats:tt)*))*) => { - $(papers!(@$var, stringify!($($pats)*), $class, $width, $height);)* + impl Paper { + /// Parse a paper from its name. + /// + /// Both lower and upper case are fine. + pub fn from_name(name: &str) -> Option<Self> { + match name.to_lowercase().as_str() { + $($($pats)* => Some(Self::$var),)* + _ => None, + } + } + + /// The class of the paper. + pub fn class(self) -> PaperClass { + self.class + } - fn parse_paper(paper: &str) -> Option<Paper> { - match paper.to_lowercase().as_str() { - $($($pats)* => Some($var),)* - _ => None, + /// The size of the paper. + pub fn size(self) -> Size { + Size::new(Length::mm(self.width), Length::mm(self.height)) } } + + /// Predefined papers. + /// + /// Each paper is parsable from its name in kebab-case. + impl Paper { + $(papers!(@$var, stringify!($($pats)*), $class, $width, $height);)* + } }; (@$var:ident, $names:expr, $class:ident, $width:expr, $height:expr) => { - #[doc = "Paper with name `"] - #[doc = $names] - #[doc = "`."] - pub const $var: Paper = Paper { + pub const $var: Self = Self { class: PaperClass::$class, width: $width, height: $height, diff --git a/tests/typeset.rs b/tests/typeset.rs index 5ca81da5..913e172a 100644 --- a/tests/typeset.rs +++ b/tests/typeset.rs @@ -10,7 +10,7 @@ use ttf_parser::{GlyphId, OutlineBuilder}; use walkdir::WalkDir; use typst::diag::Error; -use typst::eval::{State, Value}; +use typst::eval::Value; use typst::font::Face; use typst::geom::{ self, Color, Length, Paint, PathElement, Point, RgbaColor, Sides, Size, @@ -22,6 +22,7 @@ use typst::layout::{layout, Element, Frame, Geometry, Text}; use typst::loading::FsLoader; use typst::parse::Scanner; use typst::source::SourceFile; +use typst::style::Style; use typst::syntax::{Pos, Span}; use typst::Context; @@ -62,10 +63,10 @@ fn main() { // We want to have "unbounded" pages, so we allow them to be infinitely // large and fit them to match their content. - let mut state = State::default(); - state.page_mut().size = Size::new(Length::pt(120.0), Length::inf()); - state.page_mut().margins = Sides::splat(Some(Length::pt(10.0).into())); - state.font_mut().size = Length::pt(10.0); + let mut style = Style::default(); + style.page_mut().size = Size::new(Length::pt(120.0), Length::inf()); + style.page_mut().margins = Sides::splat(Some(Length::pt(10.0).into())); + style.text_mut().size = Length::pt(10.0); // Hook up an assert function into the global scope. let mut std = typst::library::new(); @@ -83,7 +84,7 @@ fn main() { // Create loader and context. let loader = FsLoader::new().with_path(FONT_DIR).wrap(); - let mut ctx = Context::builder().std(std).state(state).build(loader); + let mut ctx = Context::builder().std(std).style(style).build(loader); // Run all the tests. let mut ok = true; |
