summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/eval/mod.rs9
-rw-r--r--src/eval/template.rs59
-rw-r--r--src/layout/mod.rs110
-rw-r--r--src/lib.rs17
4 files changed, 94 insertions, 101 deletions
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index aa75f8b7..22bea7d1 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -40,7 +40,7 @@ use unicode_segmentation::UnicodeSegmentation;
use crate::diag::{At, Error, StrResult, Trace, Tracepoint, TypResult};
use crate::geom::{Angle, Color, Fractional, Length, Paint, Relative};
use crate::image::ImageStore;
-use crate::layout::RootNode;
+use crate::layout::Layout;
use crate::library::{self, DecoLine, TextNode};
use crate::loading::Loader;
use crate::parse;
@@ -66,13 +66,6 @@ pub struct Module {
pub template: Template,
}
-impl Module {
- /// Convert this module's template into a layout tree.
- pub fn into_root(self) -> RootNode {
- self.template.into_root()
- }
-}
-
/// Evaluate an expression.
pub trait Eval {
/// The output of evaluating the expression.
diff --git a/src/eval/template.rs b/src/eval/template.rs
index 6515c271..90a751f3 100644
--- a/src/eval/template.rs
+++ b/src/eval/template.rs
@@ -8,11 +8,13 @@ use std::ops::{Add, AddAssign};
use super::{Property, StyleMap, Styled};
use crate::diag::StrResult;
use crate::geom::SpecAxis;
-use crate::layout::{Layout, PackedNode, RootNode};
+use crate::layout::{Layout, PackedNode};
+use crate::library::prelude::*;
use crate::library::{
FlowChild, FlowNode, PageNode, ParChild, ParNode, PlaceNode, SpacingKind, TextNode,
};
use crate::util::EcoString;
+use crate::Context;
/// Composable representation of styled content.
///
@@ -89,6 +91,18 @@ impl Template {
Self::Block(node.pack())
}
+ /// Layout this template into a collection of pages.
+ pub fn layout(&self, ctx: &mut Context) -> Vec<Arc<Frame>> {
+ let (mut ctx, styles) = LayoutContext::new(ctx);
+ let mut packer = Packer::new(true);
+ packer.walk(self.clone(), StyleMap::new());
+ packer
+ .into_root()
+ .iter()
+ .flat_map(|styled| styled.item.layout(&mut ctx, styled.map.chain(&styles)))
+ .collect()
+ }
+
/// Style this template with a single property.
pub fn styled<P: Property>(mut self, key: P, value: P::Value) -> Self {
if let Self::Styled(_, map) = &mut self {
@@ -123,24 +137,6 @@ impl Template {
Ok(Self::Sequence(vec![self.clone(); count]))
}
-
- /// Convert to a type-erased block-level node.
- pub fn pack(self) -> PackedNode {
- if let Template::Block(packed) = self {
- packed
- } else {
- let mut packer = Packer::new(false);
- packer.walk(self, StyleMap::new());
- packer.into_block()
- }
- }
-
- /// Lift to a root layout tree node.
- pub fn into_root(self) -> RootNode {
- let mut packer = Packer::new(true);
- packer.walk(self, StyleMap::new());
- packer.into_root()
- }
}
impl Default for Template {
@@ -185,6 +181,27 @@ impl Sum for Template {
}
}
+impl Layout for Template {
+ fn layout(
+ &self,
+ ctx: &mut LayoutContext,
+ regions: &Regions,
+ styles: StyleChain,
+ ) -> Vec<Constrained<Arc<Frame>>> {
+ let mut packer = Packer::new(false);
+ packer.walk(self.clone(), StyleMap::new());
+ packer.into_block().layout(ctx, regions, styles)
+ }
+
+ fn pack(self) -> PackedNode {
+ if let Template::Block(packed) = self {
+ packed
+ } else {
+ PackedNode::new(self)
+ }
+ }
+}
+
/// Packs a [`Template`] into a flow or root node.
struct Packer {
/// Whether this packer produces a root node.
@@ -215,9 +232,9 @@ impl Packer {
}
/// Finish up and return the resulting root node.
- fn into_root(mut self) -> RootNode {
+ fn into_root(mut self) -> Vec<Styled<PageNode>> {
self.pagebreak();
- RootNode(self.pages)
+ self.pages
}
/// Consider a template with the given styles.
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 538bcd73..3cccee28 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -15,36 +15,14 @@ use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
-use crate::eval::{StyleChain, Styled};
+use crate::eval::StyleChain;
use crate::font::FontStore;
use crate::frame::{Element, Frame, Geometry, Shape, Stroke};
use crate::geom::{Align, Linear, Paint, Point, Sides, Size, Spec};
use crate::image::ImageStore;
-use crate::library::{AlignNode, Move, PadNode, PageNode, TransformNode};
+use crate::library::{AlignNode, Move, PadNode, TransformNode};
use crate::Context;
-/// The root layout node, a document consisting of top-level page runs.
-#[derive(Hash)]
-pub struct RootNode(pub Vec<Styled<PageNode>>);
-
-impl RootNode {
- /// Layout the document into a sequence of frames, one per page.
- pub fn layout(&self, ctx: &mut Context) -> Vec<Arc<Frame>> {
- let (mut ctx, styles) = LayoutContext::new(ctx);
- self.0
- .iter()
- .flat_map(|styled| styled.item.layout(&mut ctx, styled.map.chain(&styles)))
- .collect()
- }
-}
-
-impl Debug for RootNode {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.write_str("Root ")?;
- f.debug_list().entries(&self.0).finish()
- }
-}
-
/// A node that can be layouted into a sequence of regions.
///
/// Layout return one frame per used region alongside constraints that define
@@ -63,11 +41,7 @@ pub trait Layout {
where
Self: Debug + Hash + Sized + Sync + Send + 'static,
{
- PackedNode {
- #[cfg(feature = "layout-cache")]
- hash: self.hash64(),
- node: Arc::new(self),
- }
+ PackedNode::new(self)
}
}
@@ -86,8 +60,8 @@ pub struct LayoutContext<'a> {
}
impl<'a> LayoutContext<'a> {
- /// Create a new layout context.
- fn new(ctx: &'a mut Context) -> (Self, StyleChain<'a>) {
+ /// Create a new layout context and style chain.
+ pub fn new(ctx: &'a mut Context) -> (Self, StyleChain<'a>) {
let this = Self {
fonts: &mut ctx.fonts,
images: &mut ctx.images,
@@ -100,27 +74,7 @@ impl<'a> LayoutContext<'a> {
}
}
-/// A layout node that produces an empty frame.
-///
-/// The packed version of this is returned by [`PackedNode::default`].
-#[derive(Debug, Hash)]
-pub struct EmptyNode;
-
-impl Layout for EmptyNode {
- fn layout(
- &self,
- _: &mut LayoutContext,
- regions: &Regions,
- _: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
- let size = regions.expand.select(regions.current, Size::zero());
- let mut cts = Constraints::new(regions.expand);
- cts.exact = regions.current.filter(regions.expand);
- vec![Frame::new(size).constrain(cts)]
- }
-}
-
-/// A packed layouting node with a precomputed hash.
+/// A type-erased layouting node with a precomputed hash.
#[derive(Clone)]
pub struct PackedNode {
/// The type-erased node.
@@ -131,6 +85,18 @@ pub struct PackedNode {
}
impl PackedNode {
+ /// Pack any layoutable node.
+ pub fn new<T>(node: T) -> Self
+ where
+ T: Layout + Debug + Hash + Sync + Send + 'static,
+ {
+ Self {
+ #[cfg(feature = "layout-cache")]
+ hash: node.hash64(),
+ node: Arc::new(node),
+ }
+ }
+
/// Check whether the contained node is a specific layout node.
pub fn is<T: 'static>(&self) -> bool {
self.node.as_any().is::<T>()
@@ -293,7 +259,7 @@ trait Bounds: Layout + Debug + Sync + Send + 'static {
impl<T> Bounds for T
where
- T: Layout + Hash + Debug + Sync + Send + 'static,
+ T: Layout + Debug + Hash + Sync + Send + 'static,
{
fn as_any(&self) -> &dyn Any {
self
@@ -309,13 +275,33 @@ where
}
}
+/// A layout node that produces an empty frame.
+///
+/// The packed version of this is returned by [`PackedNode::default`].
+#[derive(Debug, Hash)]
+struct EmptyNode;
+
+impl Layout for EmptyNode {
+ fn layout(
+ &self,
+ _: &mut LayoutContext,
+ regions: &Regions,
+ _: StyleChain,
+ ) -> Vec<Constrained<Arc<Frame>>> {
+ let size = regions.expand.select(regions.current, Size::zero());
+ let mut cts = Constraints::new(regions.expand);
+ cts.exact = regions.current.filter(regions.expand);
+ vec![Frame::new(size).constrain(cts)]
+ }
+}
+
/// Fix the size of a node.
#[derive(Debug, Hash)]
-pub struct SizedNode {
+struct SizedNode {
/// How to size the node horizontally and vertically.
- pub sizing: Spec<Option<Linear>>,
+ sizing: Spec<Option<Linear>>,
/// The node to be sized.
- pub child: PackedNode,
+ child: PackedNode,
}
impl Layout for SizedNode {
@@ -365,11 +351,11 @@ impl Layout for SizedNode {
/// Fill the frames resulting from a node.
#[derive(Debug, Hash)]
-pub struct FillNode {
+struct FillNode {
/// How to fill the frames resulting from the `child`.
- pub fill: Paint,
+ fill: Paint,
/// The node to fill.
- pub child: PackedNode,
+ child: PackedNode,
}
impl Layout for FillNode {
@@ -390,11 +376,11 @@ impl Layout for FillNode {
/// Stroke the frames resulting from a node.
#[derive(Debug, Hash)]
-pub struct StrokeNode {
+struct StrokeNode {
/// How to stroke the frames resulting from the `child`.
- pub stroke: Stroke,
+ stroke: Stroke,
/// The node to stroke.
- pub child: PackedNode,
+ child: PackedNode,
}
impl Layout for StrokeNode {
diff --git a/src/lib.rs b/src/lib.rs
index 32938cda..99958aac 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,14 +2,13 @@
//!
//! # Steps
//! - **Parsing:** The parsing step first transforms a plain string into an
-//! [iterator of tokens][tokens]. This token stream is [parsed] into a
-//! [green tree]. The green tree itself is untyped, but a typed layer over it
-//! is provided in the [AST] module.
+//! [iterator of tokens][tokens]. This token stream is [parsed] into a [green
+//! tree]. The green tree itself is untyped, but a typed layer over it is
+//! provided in the [AST] module.
//! - **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 node can be
-//! converted into a [layout tree], a hierarchical, styled representation of
-//! the document. The nodes of this tree are well structured and
+//! and a [template], a hierarchical, styled representation with the contents
+//! of the module. The nodes of this tree are well structured and
//! order-independent and thus much better suited for layouting than the raw
//! markup.
//! - **Layouting:** Next, the tree is [layouted] into a portable version of the
@@ -26,8 +25,7 @@
//! [evaluate]: Context::evaluate
//! [module]: eval::Module
//! [template]: eval::Template
-//! [layout tree]: layout::RootNode
-//! [layouted]: layout::RootNode::layout
+//! [layouted]: eval::Template::layout
//! [cache]: layout::LayoutCache
//! [PDF]: export::pdf
@@ -127,8 +125,7 @@ impl Context {
/// information.
pub fn typeset(&mut self, id: SourceId) -> TypResult<Vec<Arc<Frame>>> {
let module = self.evaluate(id)?;
- let tree = module.into_root();
- let frames = tree.layout(self);
+ let frames = module.template.layout(self);
Ok(frames)
}