summaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/mod.rs67
-rw-r--r--src/layout/tree.rs109
2 files changed, 89 insertions, 87 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 8156f596..1ee862e3 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -15,36 +15,40 @@ pub use tree::*;
use crate::geom::{Insets, Point, Rect, RectExt, Sides, Size, SizeExt};
-use crate::eval::Scope;
+use crate::eval::{PageState, State, TextState};
use crate::font::SharedFontLoader;
-use crate::style::{LayoutStyle, PageStyle, TextStyle};
use crate::syntax::SynTree;
-use crate::Pass;
+use crate::{Feedback, Pass};
/// Layout a syntax tree and return the produced layout.
pub async fn layout(
tree: &SynTree,
- style: &LayoutStyle,
- scope: &Scope,
+ state: State,
loader: SharedFontLoader,
) -> Pass<MultiLayout> {
let space = LayoutSpace {
- size: style.page.size,
- insets: style.page.insets(),
+ size: state.page.size,
+ insets: state.page.insets(),
expansion: LayoutExpansion::new(true, true),
};
- tree::layout_tree(&tree, LayoutContext {
- loader,
- scope,
- style,
+
+ let constraints = LayoutConstraints {
+ root: true,
base: space.usable(),
spaces: vec![space],
repeat: true,
- sys: LayoutSystem::new(Dir::LTR, Dir::TTB),
- align: LayoutAlign::new(GenAlign::Start, GenAlign::Start),
- root: true,
- })
- .await
+ };
+
+ let mut ctx = LayoutContext {
+ loader,
+ state,
+ constraints,
+ f: Feedback::new(),
+ };
+
+ let layouts = layout_tree(&tree, &mut ctx).await;
+
+ Pass::new(layouts, ctx.f)
}
/// A collection of layouts.
@@ -63,13 +67,22 @@ pub struct BoxLayout {
/// The context for layouting.
#[derive(Debug, Clone)]
-pub struct LayoutContext<'a> {
+pub struct LayoutContext {
/// The font loader to query fonts from when typesetting text.
pub loader: SharedFontLoader,
- /// The function scope.
- pub scope: &'a Scope,
- /// The style for pages and text.
- pub style: &'a LayoutStyle,
+ /// The active state.
+ pub state: State,
+ /// The active constraints.
+ pub constraints: LayoutConstraints,
+ /// The accumulated feedback.
+ pub f: Feedback,
+}
+
+/// The constraints for layouting a single node.
+#[derive(Debug, Clone)]
+pub struct LayoutConstraints {
+ /// Whether this layouting process is the root page-building process.
+ pub root: bool,
/// The unpadded size of this container (the base 100% for relative sizes).
pub base: Size,
/// The spaces to layout into.
@@ -77,14 +90,6 @@ pub struct LayoutContext<'a> {
/// Whether to spill over into copies of the last space or finish layouting
/// when the last space is used up.
pub repeat: bool,
- /// The system into which content is laid out.
- pub sys: LayoutSystem,
- /// The alignment of the _resulting_ layout. This does not effect the line
- /// layouting itself, but rather how the finished layout will be positioned
- /// in a parent layout.
- pub align: LayoutAlign,
- /// Whether this layouting process is the root page-building process.
- pub root: bool,
}
/// A collection of layout spaces.
@@ -156,9 +161,9 @@ pub enum Command {
BreakPage,
/// Update the text style.
- SetTextStyle(TextStyle),
+ SetTextState(TextState),
/// Update the page style.
- SetPageStyle(PageStyle),
+ SetPageState(PageState),
/// Update the alignment for future boxes added to this layouting process.
SetAlignment(LayoutAlign),
diff --git a/src/layout/tree.rs b/src/layout/tree.rs
index df174544..e26b0eb2 100644
--- a/src/layout/tree.rs
+++ b/src/layout/tree.rs
@@ -1,48 +1,45 @@
//! Layouting of syntax trees.
-use std::rc::Rc;
-
use super::*;
use crate::shaping;
-use crate::style::LayoutStyle;
use crate::syntax::{
Decoration, Expr, NodeHeading, NodeRaw, Span, SpanWith, Spanned, SynNode, SynTree,
};
-use crate::{DynFuture, Feedback, Pass};
+use crate::DynFuture;
/// Layout a syntax tree in a given context.
-pub async fn layout_tree(tree: &SynTree, ctx: LayoutContext<'_>) -> Pass<MultiLayout> {
+pub async fn layout_tree(tree: &SynTree, ctx: &mut LayoutContext) -> MultiLayout {
let mut layouter = TreeLayouter::new(ctx);
layouter.layout_tree(tree).await;
layouter.finish()
}
-/// Performs the tree layouting.
+/// Layouts trees.
struct TreeLayouter<'a> {
- ctx: LayoutContext<'a>,
+ ctx: &'a mut LayoutContext,
+ constraints: LayoutConstraints,
layouter: LineLayouter,
- style: LayoutStyle,
- feedback: Feedback,
}
impl<'a> TreeLayouter<'a> {
- fn new(ctx: LayoutContext<'a>) -> Self {
+ fn new(ctx: &'a mut LayoutContext) -> Self {
+ let layouter = LineLayouter::new(LineContext {
+ spaces: ctx.constraints.spaces.clone(),
+ sys: ctx.state.sys,
+ align: ctx.state.align,
+ repeat: ctx.constraints.repeat,
+ line_spacing: ctx.state.text.line_spacing(),
+ });
+
Self {
- layouter: LineLayouter::new(LineContext {
- spaces: ctx.spaces.clone(),
- sys: ctx.sys,
- align: ctx.align,
- repeat: ctx.repeat,
- line_spacing: ctx.style.text.line_spacing(),
- }),
- style: ctx.style.clone(),
+ layouter,
+ constraints: ctx.constraints.clone(),
ctx,
- feedback: Feedback::new(),
}
}
- fn finish(self) -> Pass<MultiLayout> {
- Pass::new(self.layouter.finish(), self.feedback)
+ fn finish(self) -> MultiLayout {
+ self.layouter.finish()
}
fn layout_tree<'t>(&'t mut self, tree: &'t SynTree) -> DynFuture<'t, ()> {
@@ -55,16 +52,16 @@ impl<'a> TreeLayouter<'a> {
async fn layout_node(&mut self, node: &Spanned<SynNode>) {
let decorate = |this: &mut Self, deco: Decoration| {
- this.feedback.decorations.push(deco.span_with(node.span));
+ this.ctx.f.decorations.push(deco.span_with(node.span));
};
match &node.v {
SynNode::Space => self.layout_space(),
SynNode::Text(text) => {
- if self.style.text.emph {
+ if self.ctx.state.text.emph {
decorate(self, Decoration::Emph);
}
- if self.style.text.strong {
+ if self.ctx.state.text.strong {
decorate(self, Decoration::Strong);
}
self.layout_text(text).await;
@@ -73,11 +70,11 @@ impl<'a> TreeLayouter<'a> {
SynNode::Linebreak => self.layouter.finish_line(),
SynNode::Parbreak => self.layout_parbreak(),
SynNode::Emph => {
- self.style.text.emph = !self.style.text.emph;
+ self.ctx.state.text.emph ^= true;
decorate(self, Decoration::Emph);
}
SynNode::Strong => {
- self.style.text.strong = !self.style.text.strong;
+ self.ctx.state.text.strong ^= true;
decorate(self, Decoration::Strong);
}
@@ -92,12 +89,12 @@ impl<'a> TreeLayouter<'a> {
fn layout_space(&mut self) {
self.layouter
- .add_primary_spacing(self.style.text.word_spacing(), SpacingKind::WORD);
+ .add_primary_spacing(self.ctx.state.text.word_spacing(), SpacingKind::WORD);
}
fn layout_parbreak(&mut self) {
self.layouter.add_secondary_spacing(
- self.style.text.paragraph_spacing(),
+ self.ctx.state.text.paragraph_spacing(),
SpacingKind::PARAGRAPH,
);
}
@@ -106,9 +103,9 @@ impl<'a> TreeLayouter<'a> {
self.layouter.add(
shaping::shape(
text,
- self.ctx.sys.primary,
- self.ctx.align,
- &self.style.text,
+ self.ctx.state.sys.primary,
+ self.ctx.state.align,
+ &self.ctx.state.text,
&mut self.ctx.loader.borrow_mut(),
)
.await,
@@ -116,17 +113,17 @@ impl<'a> TreeLayouter<'a> {
}
async fn layout_heading(&mut self, heading: &NodeHeading) {
- let style = self.style.text.clone();
+ let style = self.ctx.state.text.clone();
let factor = 1.5 - 0.1 * heading.level.v as f64;
- self.style.text.font_size.scale *= factor;
- self.style.text.strong = true;
+ self.ctx.state.text.font_size.scale *= factor;
+ self.ctx.state.text.strong = true;
self.layout_parbreak();
self.layout_tree(&heading.contents).await;
self.layout_parbreak();
- self.style.text = style;
+ self.ctx.state.text = style;
}
async fn layout_raw(&mut self, raw: &NodeRaw) {
@@ -135,9 +132,9 @@ impl<'a> TreeLayouter<'a> {
}
// TODO: Make this more efficient.
- let fallback = self.style.text.fallback.clone();
- self.style.text.fallback.list.insert(0, "monospace".to_string());
- self.style.text.fallback.flatten();
+ let fallback = self.ctx.state.text.fallback.clone();
+ self.ctx.state.text.fallback.list.insert(0, "monospace".to_string());
+ self.ctx.state.text.fallback.flatten();
let mut first = true;
for line in &raw.lines {
@@ -148,7 +145,7 @@ impl<'a> TreeLayouter<'a> {
self.layout_text(line).await;
}
- self.style.text.fallback = fallback;
+ self.ctx.state.text.fallback = fallback;
if !raw.inline {
self.layout_parbreak();
@@ -156,15 +153,15 @@ impl<'a> TreeLayouter<'a> {
}
async fn layout_expr(&mut self, expr: Spanned<&Expr>) {
- let ctx = LayoutContext {
- style: &self.style,
- spaces: self.layouter.remaining(),
+ self.ctx.constraints = LayoutConstraints {
root: false,
- loader: Rc::clone(&self.ctx.loader),
- ..self.ctx
+ base: self.constraints.base,
+ spaces: self.layouter.remaining(),
+ repeat: self.constraints.repeat,
};
- let val = expr.v.eval(&ctx, &mut self.feedback).await;
+ let val = expr.v.eval(self.ctx).await;
+
let commands = val.span_with(expr.span).into_commands();
for command in commands {
@@ -186,23 +183,23 @@ impl<'a> TreeLayouter<'a> {
BreakLine => self.layouter.finish_line(),
BreakPage => {
- if self.ctx.root {
+ if self.constraints.root {
self.layouter.finish_space(true)
} else {
error!(
- @self.feedback, span,
+ @self.ctx.f, span,
"page break cannot only be issued from root context",
);
}
}
- SetTextStyle(style) => {
+ SetTextState(style) => {
self.layouter.set_line_spacing(style.line_spacing());
- self.style.text = style;
+ self.ctx.state.text = style;
}
- SetPageStyle(style) => {
- if self.ctx.root {
- self.style.page = style;
+ SetPageState(style) => {
+ if self.constraints.root {
+ self.ctx.state.page = style;
// The line layouter has no idea of page styles and thus we
// need to recompute the layouting space resulting of the
@@ -212,20 +209,20 @@ impl<'a> TreeLayouter<'a> {
insets: style.insets(),
expansion: LayoutExpansion::new(true, true),
};
- self.ctx.base = space.usable();
+ self.constraints.base = space.usable();
self.layouter.set_spaces(vec![space], true);
} else {
error!(
- @self.feedback, span,
+ @self.ctx.f, span,
"page style cannot only be changed from root context",
);
}
}
- SetAlignment(align) => self.ctx.align = align,
+ SetAlignment(align) => self.ctx.state.align = align,
SetSystem(sys) => {
self.layouter.set_sys(sys);
- self.ctx.sys = sys;
+ self.ctx.state.sys = sys;
}
}
}