From 221934df4b586250b0063282ef8885c475dec7a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurenz=20M=C3=A4dje?= Date: Sun, 2 Jun 2019 18:01:22 +0200 Subject: [PATCH] =?UTF-8?q?Add=20margins=20with=20basic=20box=20layouter?= =?UTF-8?q?=20=F0=9F=93=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/doc.rs | 4 ++-- src/layout/boxed.rs | 37 +++++++++++++++++++++++++++++++++++++ src/layout/mod.rs | 17 +++++------------ src/layout/size.rs | 18 ++++++++++++++++++ src/layout/text.rs | 15 ++++++++++----- src/lib.rs | 23 ++++++++++++++++++----- 6 files changed, 90 insertions(+), 24 deletions(-) create mode 100644 src/layout/boxed.rs diff --git a/src/doc.rs b/src/doc.rs index d6568ecd7..a7d44897e 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -1,7 +1,7 @@ //! Representation of typesetted documents. use crate::font::Font; -use crate::layout::Size; +use crate::layout::{Size, Position}; /// A complete typesetted document, which can be exported. @@ -28,7 +28,7 @@ pub struct Page { #[derive(Debug, Clone)] pub enum TextAction { /// Move from the _start_ of the current line by an (x, y) offset. - MoveNewline(Size, Size), + MoveNewline(Position), /// Write text starting at the current position. WriteText(String), /// Set the font by index and font size. diff --git a/src/layout/boxed.rs b/src/layout/boxed.rs new file mode 100644 index 000000000..cfdf51f24 --- /dev/null +++ b/src/layout/boxed.rs @@ -0,0 +1,37 @@ +//! Layouting of layout boxes. + +use crate::doc::TextAction; +use super::{Layouter, Layout, LayoutContext, LayoutResult, Position}; + + +/// Layouts sublayouts within the constraints of a layouting context. +#[derive(Debug)] +pub struct BoxLayouter<'a, 'p> { + ctx: &'a LayoutContext<'a, 'p>, + actions: Vec, +} + +impl<'a, 'p> BoxLayouter<'a, 'p> { + /// Create a new box layouter. + pub fn new(ctx: &'a LayoutContext<'a, 'p>) -> BoxLayouter<'a, 'p> { + BoxLayouter { + ctx, + actions: vec![], + } + } + + /// Add a sublayout. + pub fn add_layout_absolute(&mut self, position: Position, layout: Layout) { + self.actions.push(TextAction::MoveNewline(position)); + self.actions.extend(layout.actions); + } +} + +impl Layouter for BoxLayouter<'_, '_> { + fn finish(self) -> LayoutResult { + Ok(Layout { + extent: self.ctx.max_extent.clone(), + actions: self.actions + }) + } +} diff --git a/src/layout/mod.rs b/src/layout/mod.rs index edcd63a78..ab27314d5 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -6,9 +6,11 @@ use crate::syntax::{SyntaxTree, Node}; mod size; mod text; +mod boxed; -pub use size::Size; +pub use size::{Size, Position, Extent}; pub use text::TextLayouter; +pub use boxed::BoxLayouter; /// Layout a syntax tree in a given context. @@ -44,7 +46,7 @@ pub fn layout(tree: &SyntaxTree, ctx: &LayoutContext) -> LayoutResult { #[derive(Debug, Clone)] pub struct Layout { /// The extent of this layout into all directions. - extent: LayoutDimensions, + extent: Extent, /// Actions composing this layout. actions: Vec, } @@ -75,20 +77,11 @@ pub struct LayoutContext<'a, 'p> { /// Loads fonts matching queries. pub loader: &'a FontLoader<'p>, /// The spacial constraints to layout in. - pub max_extent: LayoutDimensions, + pub max_extent: Extent, /// Base style to set text with. pub text_style: TextStyle, } -/// A space to layout in. -#[derive(Debug, Clone)] -pub struct LayoutDimensions { - /// Horizontal extent. - pub width: Size, - /// Vertical extent. - pub height: Size, -} - /// Default styles for text. #[derive(Debug, Clone)] pub struct TextStyle { diff --git a/src/layout/size.rs b/src/layout/size.rs index d0b557d72..c4686966e 100644 --- a/src/layout/size.rs +++ b/src/layout/size.rs @@ -6,6 +6,24 @@ use std::iter::Sum; use std::ops::*; +/// A position in 2-dimensional space. +#[derive(Debug, Copy, Clone, PartialEq, Default)] +pub struct Position { + /// The horizontal coordinate. + pub x: Size, + /// The vertical coordinate. + pub y: Size, +} + +/// Size of a box in 2-dimensional space. +#[derive(Debug, Copy, Clone, PartialEq, Default)] +pub struct Extent { + /// The horizontal extent. + pub width: Size, + /// The vertical extent. + pub height: Size, +} + /// A general spacing type. #[derive(Copy, Clone, PartialEq, Default)] pub struct Size { diff --git a/src/layout/text.rs b/src/layout/text.rs index 15da8373c..0f1055313 100644 --- a/src/layout/text.rs +++ b/src/layout/text.rs @@ -7,7 +7,7 @@ use smallvec::SmallVec; use crate::doc::TextAction; use crate::font::{Font, FontQuery}; -use super::{Layouter, Layout, LayoutError, LayoutContext, Size, LayoutResult}; +use super::{Layouter, Layout, LayoutError, LayoutContext, LayoutResult, Size, Position}; /// Layouts text within the constraints of a layouting context. @@ -208,10 +208,11 @@ impl<'a, 'p> TextFinisher<'a, 'p> { /// Move to the top-left corner of the layout space. fn move_start(&mut self) { - self.actions.push(TextAction::MoveNewline( - Size::zero(), self.layouter.ctx.max_extent.height + self.actions.push(TextAction::MoveNewline(Position { + x: Size::zero(), + y: self.layouter.ctx.max_extent.height - Size::from_points(self.layouter.ctx.text_style.font_size) - )); + })); } /// Move to the next line. A factor of 1.0 uses the default line spacing. @@ -221,7 +222,11 @@ impl<'a, 'p> TextFinisher<'a, 'p> { * self.layouter.ctx.text_style.line_spacing * factor; - self.actions.push(TextAction::MoveNewline(Size::zero(), -vertical)); + self.actions.push(TextAction::MoveNewline(Position { + x: Size::zero(), + y: -vertical + })); + self.current_width = Size::zero(); } } diff --git a/src/lib.rs b/src/lib.rs index dd0785f7b..c56cbba18 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ use std::fmt::{self, Debug, Formatter}; use crate::doc::Document; use crate::font::{Font, FontLoader, FontProvider}; use crate::func::Scope; -use crate::layout::{layout, Layout, LayoutContext, LayoutDimensions}; +use crate::layout::{layout, Layout, Layouter, LayoutContext, BoxLayouter, Extent, Position}; use crate::layout::{PageStyle, TextStyle, LayoutResult, LayoutError}; use crate::parsing::{parse, ParseContext, ParseResult, ParseError}; use crate::syntax::SyntaxTree; @@ -115,21 +115,34 @@ impl<'p> Typesetter<'p> { } /// Layout a syntax tree and return the layout and the referenced font list. - #[inline] pub fn layout(&self, tree: &SyntaxTree) -> LayoutResult<(Layout, Vec)> { let loader = FontLoader::new(&self.font_providers); + // Prepare the layouting context. let page = &self.page_style; - let ctx = LayoutContext { + let mut ctx = LayoutContext { loader: &loader, text_style: self.text_style.clone(), - max_extent: LayoutDimensions { + max_extent: Extent { width: page.width - page.margin_left - page.margin_right, height: page.height - page.margin_top - page.margin_bottom, }, }; - let layout = layout(&tree, &ctx)?; + // Layout the content of the page (without margins). + let content = layout(&tree, &ctx)?; + + // Adjust the context for adding the margins. + ctx.max_extent = Extent { + width: page.width, + height: page.height, + }; + + // Add the margins. + let mut box_layouter = BoxLayouter::new(&ctx); + let start = Position { x: page.margin_left, y: page.margin_top }; + box_layouter.add_layout_absolute(start, content); + let layout = box_layouter.finish()?; Ok((layout, loader.into_fonts())) }