Skip to main content

typst_layout/
document.rs

1use std::hash::{Hash, Hasher};
2use std::sync::Arc;
3
4use ecow::EcoVec;
5use typst_library::diag::SourceResult;
6use typst_library::engine::Engine;
7use typst_library::foundations::{Content, Output, Smart, StyleChain, Target};
8use typst_library::introspection::Introspector;
9use typst_library::layout::{Abs, Frame, Sides};
10use typst_library::model::{Document, DocumentInfo, Numbering};
11use typst_library::visualize::{Color, Paint};
12
13use crate::PagedIntrospector;
14
15/// A finished document with metadata and page frames.
16#[derive(Debug, Clone)]
17pub struct PagedDocument {
18    pages: EcoVec<Page>,
19    info: DocumentInfo,
20    introspector: Arc<PagedIntrospector>,
21}
22
23impl PagedDocument {
24    /// Creates a new paged document from its parts.
25    ///
26    /// Internally builds the introspector.
27    pub fn new(pages: EcoVec<Page>, info: DocumentInfo) -> Self {
28        let introspector = PagedIntrospector::new(&pages);
29        Self { pages, info, introspector: Arc::new(introspector) }
30    }
31
32    /// The document's finished pages.
33    pub fn pages(&self) -> &[Page] {
34        &self.pages
35    }
36
37    /// Details about the document, mutably.
38    pub fn info_mut(&mut self) -> &mut DocumentInfo {
39        &mut self.info
40    }
41
42    /// Provides the ability to execute queries on the document.
43    pub fn introspector(&self) -> &Arc<PagedIntrospector> {
44        &self.introspector
45    }
46}
47
48impl Hash for PagedDocument {
49    fn hash<H: Hasher>(&self, state: &mut H) {
50        // The introspector is fully derived from the pages. Thus, there is
51        // no need to hash it.
52        self.pages.hash(state);
53        self.info.hash(state);
54    }
55}
56
57impl Document for PagedDocument {
58    fn info(&self) -> &DocumentInfo {
59        &self.info
60    }
61}
62
63impl Output for PagedDocument {
64    fn introspector(&self) -> &dyn Introspector {
65        self.introspector.as_ref()
66    }
67
68    fn target() -> Target {
69        Target::Paged
70    }
71
72    fn create(
73        engine: &mut Engine,
74        content: &Content,
75        styles: StyleChain,
76    ) -> SourceResult<Self> {
77        crate::layout_document(engine, content, styles)
78    }
79}
80
81/// A finished page.
82#[derive(Debug, Clone, Hash)]
83pub struct Page {
84    /// The frame that defines the page.
85    pub frame: Frame,
86    /// The bleed amount to be added on each side of the page. The bleed is not
87    /// included in frame.
88    pub bleed: Sides<Abs>,
89    /// How the page is filled.
90    ///
91    /// - When `None`, the background is transparent.
92    /// - When `Auto`, the background is transparent for PDF and white
93    ///   for raster and SVG targets.
94    ///
95    /// Exporters should access the resolved value of this property through
96    /// `fill_or_transparent()` or `fill_or_white()`.
97    pub fill: Smart<Option<Paint>>,
98    /// The page's numbering.
99    pub numbering: Option<Numbering>,
100    /// The page's supplement.
101    pub supplement: Content,
102    /// The logical page number (controlled by `counter(page)` and may thus not
103    /// match the physical number).
104    pub number: u64,
105}
106
107impl Page {
108    /// Get the configured background or `None` if it is `Auto`.
109    ///
110    /// This is used in PDF export.
111    pub fn fill_or_transparent(&self) -> Option<Paint> {
112        self.fill.clone().unwrap_or(None)
113    }
114
115    /// Get the configured background or white if it is `Auto`.
116    ///
117    /// This is used in raster and SVG export.
118    pub fn fill_or_white(&self) -> Option<Paint> {
119        self.fill.clone().unwrap_or_else(|| Some(Color::WHITE.into()))
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126
127    #[test]
128    fn test_paged_document_is_send_and_sync() {
129        fn ensure_send_and_sync<T: Send + Sync>() {}
130        ensure_send_and_sync::<PagedDocument>();
131    }
132}