summaryrefslogtreecommitdiff
path: root/src/layout/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/layout/mod.rs')
-rw-r--r--src/layout/mod.rs234
1 files changed, 66 insertions, 168 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 912ca010..f709da1a 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -1,88 +1,24 @@
-//! Layouting of syntax trees.
+//! Layouting of documents.
+pub mod nodes;
pub mod primitive;
-mod line;
-mod stack;
-mod tree;
-
-pub use line::*;
pub use primitive::*;
-pub use stack::*;
-pub use tree::*;
-use crate::diag::Diag;
+use async_trait::async_trait;
+
use crate::eval::{PageState, State, TextState};
use crate::font::SharedFontLoader;
use crate::geom::{Insets, Point, Rect, Size, SizeExt};
use crate::shaping::Shaped;
-use crate::syntax::{Deco, Spanned, SynTree};
-use crate::{Feedback, Pass};
-
-/// Layout a syntax tree and return the produced layout.
-pub async fn layout(
- tree: &SynTree,
- state: State,
- loader: SharedFontLoader,
-) -> Pass<Vec<BoxLayout>> {
- let space = LayoutSpace {
- size: state.page.size,
- insets: state.page.insets(),
- expansion: Spec2::new(true, true),
- };
-
- let constraints = LayoutConstraints {
- root: true,
- base: space.usable(),
- spaces: vec![space],
- repeat: true,
- };
-
- let mut ctx = LayoutContext {
- loader,
- state,
- constraints,
- f: Feedback::new(),
- };
-
- let layouts = layout_tree(&tree, &mut ctx).await;
- Pass::new(layouts, ctx.f)
-}
-
-/// A finished box with content at fixed positions.
-#[derive(Debug, Clone, PartialEq)]
-pub struct BoxLayout {
- /// The size of the box.
- pub size: Size,
- /// The elements composing this layout.
- pub elements: Vec<(Point, LayoutElement)>,
-}
+use crate::syntax::SynTree;
-impl BoxLayout {
- /// Create a new empty collection.
- pub fn new(size: Size) -> Self {
- Self { size, elements: vec![] }
- }
+use nodes::Document;
- /// Add an element at a position.
- pub fn push(&mut self, pos: Point, element: LayoutElement) {
- self.elements.push((pos, element));
- }
-
- /// Add all elements of another collection, placing them relative to the
- /// given position.
- pub fn push_layout(&mut self, pos: Point, more: Self) {
- for (subpos, element) in more.elements {
- self.push(pos + subpos.to_vec2(), element);
- }
- }
-}
-
-/// A layout element, the basic building block layouts are composed of.
-#[derive(Debug, Clone, PartialEq)]
-pub enum LayoutElement {
- /// Shaped text.
- Text(Shaped),
+/// Layout a document and return the produced layouts.
+pub async fn layout(document: &Document, loader: SharedFontLoader) -> Vec<BoxLayout> {
+ let mut ctx = LayoutContext { loader };
+ document.layout(&mut ctx).await
}
/// The context for layouting.
@@ -90,33 +26,43 @@ pub enum LayoutElement {
pub struct LayoutContext {
/// The font loader to query fonts from when typesetting text.
pub loader: SharedFontLoader,
- /// The active state.
- pub state: State,
- /// The active constraints.
- pub constraints: LayoutConstraints,
- /// The accumulated feedback.
- pub f: Feedback,
}
-impl LayoutContext {
- /// Add a diagnostic to the feedback.
- pub fn diag(&mut self, diag: Spanned<Diag>) {
- self.f.diags.push(diag);
- }
+/// Layout a node.
+#[async_trait(?Send)]
+pub trait Layout {
+ /// Layout the node in the given layout context.
+ ///
+ /// This signature looks pretty horrible due to async in trait methods, but
+ /// it's actually just the following:
+ /// ```rust,ignore
+ /// async fn layout(
+ /// &self,
+ /// ctx: &mut LayoutContext,
+ /// constraints: LayoutConstraints,
+ /// ) -> Vec<LayoutItem>;
+ /// ```
+ async fn layout(
+ &self,
+ ctx: &mut LayoutContext,
+ constraints: LayoutConstraints,
+ ) -> Vec<LayoutItem>;
+}
- /// Add a decoration to the feedback.
- pub fn deco(&mut self, deco: Spanned<Deco>) {
- self.f.decos.push(deco);
- }
+/// An item that is produced by [layouting] a node.
+///
+/// [layouting]: trait.Layout.html#method.layout
+#[derive(Debug, Clone, PartialEq)]
+pub enum LayoutItem {
+ /// Spacing that should be added to the parent.
+ Spacing(f64),
+ /// A box that should be aligned in the parent.
+ Box(BoxLayout, Gen2<GenAlign>),
}
/// 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.
pub spaces: Vec<LayoutSpace>,
/// Whether to spill over into copies of the last space or finish layouting
@@ -127,92 +73,44 @@ pub struct LayoutConstraints {
/// The space into which content is laid out.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct LayoutSpace {
+ /// The full size of this container (the base for relative sizes).
+ pub base: Size,
/// The maximum size of the rectangle to layout into.
pub size: Size,
- /// Padding that should be respected on each side.
- pub insets: Insets,
- /// Whether to expand the size of the resulting layout to the full size of
- /// this space or to shrink it to fit the content.
- pub expansion: Spec2<bool>,
}
-impl LayoutSpace {
- /// The position of the padded start in the space.
- pub fn start(&self) -> Point {
- Point::new(-self.insets.x0, -self.insets.y0)
+/// A finished box with content at fixed positions.
+#[derive(Debug, Clone, PartialEq)]
+pub struct BoxLayout {
+ /// The size of the box.
+ pub size: Size,
+ /// The elements composing this layout.
+ pub elements: Vec<(Point, LayoutElement)>,
+}
+
+impl BoxLayout {
+ /// Create a new empty collection.
+ pub fn new(size: Size) -> Self {
+ Self { size, elements: vec![] }
}
- /// The actually usable area (size minus padding).
- pub fn usable(&self) -> Size {
- self.size + self.insets.size()
+ /// Add an element at a position.
+ pub fn push(&mut self, pos: Point, element: LayoutElement) {
+ self.elements.push((pos, element));
}
- /// The inner layout space with size reduced by the padding, zero padding of
- /// its own and no layout expansion.
- pub fn inner(&self) -> Self {
- Self {
- size: self.usable(),
- insets: Insets::ZERO,
- expansion: Spec2::new(false, false),
+ /// Add all elements of another collection, placing them relative to the
+ /// given position.
+ pub fn push_layout(&mut self, pos: Point, more: Self) {
+ for (subpos, element) in more.elements {
+ self.push(pos + subpos.to_vec2(), element);
}
}
}
-/// Commands executable by the layouting engine.
+/// A layout element, the basic building block layouts are composed of.
#[derive(Debug, Clone, PartialEq)]
-pub enum Command {
- /// Layout the given tree in the current context (i.e. not nested). The
- /// content of the tree is not laid out into a separate box and then added,
- /// but simply laid out flatly in the active layouting process.
- ///
- /// This has the effect that the content fits nicely into the active line
- /// layouting, enabling functions to e.g. change the style of some piece of
- /// text while keeping it part of the current paragraph.
- LayoutSyntaxTree(SynTree),
-
- /// Add a finished layout.
- Add(BoxLayout, Gen2<GenAlign>),
- /// Add spacing of the given kind along the given axis. The
- /// kind defines how the spacing interacts with surrounding spacing.
- AddSpacing(f64, SpacingKind, GenAxis),
-
- /// Start a new line.
- BreakLine,
- /// Start a new page, which will be part of the finished layout even if it
- /// stays empty (since the page break is a _hard_ space break).
- BreakPage,
-
- /// Update the text style.
- SetTextState(TextState),
- /// Update the page style.
- SetPageState(PageState),
- /// Update the alignment for future boxes added to this layouting process.
- SetAlignment(Gen2<GenAlign>),
-}
-
-/// Defines how spacing interacts with surrounding spacing.
-///
-/// There are two options for interaction: Hard and soft spacing. Typically,
-/// hard spacing is used when a fixed amount of space needs to be inserted no
-/// matter what. In contrast, soft spacing can be used to insert a default
-/// spacing between e.g. two words or paragraphs that can still be overridden by
-/// a hard space.
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum SpacingKind {
- /// Hard spaces are always laid out and consume surrounding soft space.
- Hard,
- /// Soft spaces are not laid out if they are touching a hard space and
- /// consume neighbouring soft spaces with higher levels.
- Soft(u32),
-}
-
-impl SpacingKind {
- /// The standard spacing kind used for paragraph spacing.
- pub const PARAGRAPH: Self = Self::Soft(1);
-
- /// The standard spacing kind used for line spacing.
- pub const LINE: Self = Self::Soft(2);
-
- /// The standard spacing kind used for word spacing.
- pub const WORD: Self = Self::Soft(1);
+pub enum LayoutElement {
+ /// Shaped text.
+ Text(Shaped),
}