typst/src/layout/mod.rs

115 lines
3.1 KiB
Rust

//! Layouting of documents.
pub mod nodes;
pub mod primitive;
pub use primitive::*;
use async_trait::async_trait;
use crate::font::SharedFontLoader;
use crate::geom::{Point, Rect, Size, SizeExt};
use crate::shaping::Shaped;
use nodes::Document;
/// 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.
#[derive(Debug, Clone)]
pub struct LayoutContext {
/// The font loader to query fonts from when typesetting text.
pub loader: SharedFontLoader,
}
/// 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>;
}
/// 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 {
/// The spaces to layout into.
pub spaces: Vec<LayoutSpace>,
/// Whether to spill over into copies of the last space or finish layouting
/// when the last space is used up.
pub repeat: bool,
}
/// 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,
}
/// 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![] }
}
/// 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),
}