diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-05-26 11:59:53 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-05-26 11:59:53 +0200 |
| commit | 66d8f4569a9f13270c5f477e0730f127a22333e2 (patch) | |
| tree | ebb60254e69d7f65ec2245aeae3543f6efff0cbb /src/model/content.rs | |
| parent | 99cb655832161d4ebec73273a15453a8f6acc1b7 (diff) | |
Locate me!
Diffstat (limited to 'src/model/content.rs')
| -rw-r--r-- | src/model/content.rs | 50 |
1 files changed, 47 insertions, 3 deletions
diff --git a/src/model/content.rs b/src/model/content.rs index c09979d5..effe84ae 100644 --- a/src/model/content.rs +++ b/src/model/content.rs @@ -7,8 +7,8 @@ use std::ops::{Add, AddAssign}; use typed_arena::Arena; use super::{ - Barrier, CollapsingBuilder, Interruption, Key, Layout, LayoutNode, Property, Show, - ShowNode, StyleEntry, StyleMap, StyleVecBuilder, Target, + Barrier, CollapsingBuilder, Interruption, Key, Layout, LayoutNode, LocateNode, + Property, Show, ShowNode, StyleEntry, StyleMap, StyleVecBuilder, Target, }; use crate::diag::StrResult; use crate::library::layout::{FlowChild, FlowNode, PageNode, PlaceNode, Spacing}; @@ -20,7 +20,35 @@ use crate::library::text::{ use crate::util::EcoString; /// Layout content into a collection of pages. +/// +/// Relayouts until all pinned locations are converged. pub fn layout(ctx: &mut Context, content: &Content) -> TypResult<Vec<Arc<Frame>>> { + let mut pass = 0; + let mut frames; + + loop { + let prev = ctx.pins.clone(); + let result = layout_once(ctx, content); + ctx.pins.reset(); + frames = result?; + pass += 1; + + ctx.pins.locate(&frames); + + let count = ctx.pins.len(); + let resolved = ctx.pins.resolved(&prev); + + // Quit if we're done or if we've had five passes. + if resolved == count || pass >= 5 { + break; + } + } + + Ok(frames) +} + +/// Layout content into a collection of pages once. +fn layout_once(ctx: &mut Context, content: &Content) -> TypResult<Vec<Arc<Frame>>> { let copy = ctx.config.styles.clone(); let styles = StyleChain::with_root(©); let scratch = Scratch::default(); @@ -88,6 +116,10 @@ pub enum Content { /// A node that can be realized with styles, optionally with attached /// properties. Show(ShowNode, Option<Dict>), + /// A node that can be realized with its location on the page. + Locate(LocateNode), + /// A pin identified by index. + Pin(usize), /// Content with attached styles. Styled(Arc<(Self, StyleMap)>), /// A sequence of multiple nodes. @@ -272,6 +304,8 @@ impl Debug for Content { Self::Pagebreak { weak } => write!(f, "Pagebreak({weak})"), Self::Page(page) => page.fmt(f), Self::Show(node, _) => node.fmt(f), + Self::Locate(node) => node.fmt(f), + Self::Pin(idx) => write!(f, "Pin({idx})"), Self::Styled(styled) => { let (sub, map) = styled.as_ref(); map.fmt(f)?; @@ -388,6 +422,7 @@ impl<'a, 'ctx> Builder<'a, 'ctx> { } Content::Show(node, _) => return self.show(node, styles), + Content::Locate(node) => return self.locate(node, styles), Content::Styled(styled) => return self.styled(styled, styles), Content::Sequence(seq) => return self.sequence(seq, styles), @@ -436,6 +471,12 @@ impl<'a, 'ctx> Builder<'a, 'ctx> { Ok(()) } + fn locate(&mut self, node: &LocateNode, styles: StyleChain<'a>) -> TypResult<()> { + let realized = node.realize(self.ctx)?; + let stored = self.scratch.templates.alloc(realized); + self.accept(stored, styles) + } + fn styled( &mut self, (content, map): &'a (Content, StyleMap), @@ -641,6 +682,9 @@ impl<'a> ParBuilder<'a> { Content::Inline(node) => { self.0.supportive(ParChild::Node(node.clone()), styles); } + &Content::Pin(idx) => { + self.0.ignorant(ParChild::Pin(idx), styles); + } _ => return false, } @@ -660,7 +704,7 @@ impl<'a> ParBuilder<'a> { && children .items() .find_map(|child| match child { - ParChild::Spacing(_) => None, + ParChild::Spacing(_) | ParChild::Pin(_) => None, ParChild::Text(_) | ParChild::Quote { .. } => Some(true), ParChild::Node(_) => Some(false), }) |
