use crate::layout::{LayoutRoot, PageElem}; use crate::prelude::*; /// The root element of a document and its metadata. /// /// All documents are automatically wrapped in a `document` element. You cannot /// create a document element yourself. This function is only used with /// [set rules]($styling/#set-rules) to specify document metadata. Such a set /// rule must appear before any of the document's contents. /// /// ```example /// #set document(title: "Hello") /// /// This has no visible output, but /// embeds metadata into the PDF! /// ``` /// /// Note that metadata set with this function is not rendered within the /// document. Instead, it is embedded in the compiled PDF file. /// /// Display: Document /// Category: meta #[element(Construct, LayoutRoot)] pub struct DocumentElem { /// The document's title. This is often rendered as the title of the /// PDF viewer window. pub title: Option, /// The document's authors. pub author: Author, /// The page runs. #[internal] #[variadic] pub children: Vec, } impl Construct for DocumentElem { fn construct(_: &mut Vm, args: &mut Args) -> SourceResult { bail!(args.span, "can only be used in set rules") } } impl LayoutRoot for DocumentElem { /// Layout the document into a sequence of frames, one per page. #[tracing::instrument(name = "DocumentElem::layout_root", skip_all)] fn layout_root(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult { tracing::info!("Document layout"); let mut pages = vec![]; for mut child in &self.children() { let outer = styles; let mut styles = styles; if let Some((elem, local)) = child.to_styled() { styles = outer.chain(local); child = elem; } if let Some(page) = child.to::() { let number = NonZeroUsize::ONE.saturating_add(pages.len()); let fragment = page.layout(vt, styles, number)?; pages.extend(fragment); } else { bail!(child.span(), "unexpected document child"); } } Ok(Document { pages, title: self.title(styles), author: self.author(styles).0, }) } } /// A list of authors. #[derive(Debug, Default, Clone, Hash)] pub struct Author(Vec); cast! { Author, self => self.0.into_value(), v: EcoString => Self(vec![v]), v: Array => Self(v.into_iter().map(Value::cast).collect::>()?), }