summaryrefslogtreecommitdiff
path: root/src/model/content.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-05-26 11:59:53 +0200
committerLaurenz <laurmaedje@gmail.com>2022-05-26 11:59:53 +0200
commit66d8f4569a9f13270c5f477e0730f127a22333e2 (patch)
treeebb60254e69d7f65ec2245aeae3543f6efff0cbb /src/model/content.rs
parent99cb655832161d4ebec73273a15453a8f6acc1b7 (diff)
Locate me!
Diffstat (limited to 'src/model/content.rs')
-rw-r--r--src/model/content.rs50
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(&copy);
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),
})