summaryrefslogtreecommitdiff
path: root/src/model/mod.rs
blob: 7458dc3ce6cef2cc7de112f0c4caf4ebd9d8abfe (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//! The document model.

mod content;
mod element;
mod introspect;
mod realize;
mod styles;

pub use self::content::*;
pub use self::element::*;
pub use self::introspect::*;
pub use self::realize::*;
pub use self::styles::*;

pub use typst_macros::element;

use comemo::{Constraint, Track, Tracked, TrackedMut};

use crate::diag::SourceResult;
use crate::doc::Document;
use crate::eval::Tracer;
use crate::World;

/// Typeset content into a fully layouted document.
#[comemo::memoize]
pub fn typeset(
    world: Tracked<dyn World>,
    mut tracer: TrackedMut<Tracer>,
    content: &Content,
) -> SourceResult<Document> {
    let library = world.library();
    let styles = StyleChain::new(&library.styles);

    let mut document;
    let mut iter = 0;
    let mut introspector = Introspector::new(&[]);

    // Relayout until all introspections stabilize.
    // If that doesn't happen within five attempts, we give up.
    loop {
        let constraint = Constraint::new();
        let mut provider = StabilityProvider::new();
        let mut vt = Vt {
            world,
            tracer: TrackedMut::reborrow_mut(&mut tracer),
            provider: provider.track_mut(),
            introspector: introspector.track_with(&constraint),
        };

        document = (library.items.layout)(&mut vt, content, styles)?;
        iter += 1;

        introspector = Introspector::new(&document.pages);

        if iter >= 5 || introspector.valid(&constraint) {
            break;
        }
    }

    Ok(document)
}

/// A virtual typesetter.
///
/// Holds the state needed to [typeset] content.
pub struct Vt<'a> {
    /// The compilation environment.
    pub world: Tracked<'a, dyn World>,
    /// The tracer for inspection of the values an expression produces.
    pub tracer: TrackedMut<'a, Tracer>,
    /// Provides stable identities to elements.
    pub provider: TrackedMut<'a, StabilityProvider>,
    /// Provides access to information about the document.
    pub introspector: Tracked<'a, Introspector>,
}

impl Vt<'_> {
    /// Mutably reborrow with a shorter lifetime.
    pub fn reborrow_mut(&mut self) -> Vt<'_> {
        Vt {
            world: self.world,
            tracer: TrackedMut::reborrow_mut(&mut self.tracer),
            provider: TrackedMut::reborrow_mut(&mut self.provider),
            introspector: self.introspector,
        }
    }
}