diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-11-16 10:41:30 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-11-16 10:41:30 +0100 |
| commit | 0e0f340502beada1cd9ee23857f48b91a0d11a90 (patch) | |
| tree | e4e4087260720adf4bab57edeac6a3d3cb5f14cf /src/layout/mod.rs | |
| parent | bc118634aca5de415d211cab38c4eaa3d3cca25f (diff) | |
Revert page and inline levels
Diffstat (limited to 'src/layout/mod.rs')
| -rw-r--r-- | src/layout/mod.rs | 109 |
1 files changed, 101 insertions, 8 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 49ceccf6..7d2837de 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1,29 +1,27 @@ -//! Layouting. +//! Layouting infrastructure. mod constraints; #[cfg(feature = "layout-cache")] mod incremental; -mod levels; mod regions; pub use constraints::*; #[cfg(feature = "layout-cache")] pub use incremental::*; -pub use levels::*; pub use regions::*; +use std::fmt::{self, Debug, Formatter}; +use std::hash::{Hash, Hasher}; use std::rc::Rc; use crate::font::FontStore; use crate::frame::Frame; use crate::image::ImageStore; +use crate::library::DocumentNode; use crate::Context; -/// Layout a page-level node into a collection of frames. -pub fn layout<T>(ctx: &mut Context, node: &T) -> Vec<Rc<Frame>> -where - T: PageLevel + ?Sized, -{ +/// Layout a document node into a collection of frames. +pub fn layout(ctx: &mut Context, node: &DocumentNode) -> Vec<Rc<Frame>> { let mut ctx = LayoutContext::new(ctx); node.layout(&mut ctx) } @@ -55,3 +53,98 @@ impl<'a> LayoutContext<'a> { } } } + +/// A node that can be layouted into a sequence of regions. +/// +/// Layout return one frame per used region alongside constraints that define +/// whether the result is reusable in other regions. +pub trait Layout: Debug { + /// Layout the node into the given regions, producing constrained frames. + fn layout( + &self, + ctx: &mut LayoutContext, + regions: &Regions, + ) -> Vec<Constrained<Rc<Frame>>>; + + /// Convert to a packed node. + fn pack(self) -> PackedNode + where + Self: Sized + Hash + 'static, + { + PackedNode { + #[cfg(feature = "layout-cache")] + hash: { + use std::any::Any; + let mut state = fxhash::FxHasher64::default(); + self.type_id().hash(&mut state); + self.hash(&mut state); + state.finish() + }, + node: Rc::new(self), + } + } +} + +/// A packed layouting node with precomputed hash. +#[derive(Clone)] +pub struct PackedNode { + node: Rc<dyn Layout>, + #[cfg(feature = "layout-cache")] + hash: u64, +} + +impl Layout for PackedNode { + fn layout( + &self, + ctx: &mut LayoutContext, + regions: &Regions, + ) -> Vec<Constrained<Rc<Frame>>> { + #[cfg(not(feature = "layout-cache"))] + return self.node.layout(ctx, regions); + + #[cfg(feature = "layout-cache")] + ctx.layouts.get(self.hash, regions).unwrap_or_else(|| { + ctx.level += 1; + let frames = self.node.layout(ctx, regions); + ctx.level -= 1; + + let entry = FramesEntry::new(frames.clone(), ctx.level); + + #[cfg(debug_assertions)] + if !entry.check(regions) { + eprintln!("node: {:#?}", self.node); + eprintln!("regions: {:#?}", regions); + eprintln!( + "constraints: {:#?}", + frames.iter().map(|c| c.cts).collect::<Vec<_>>() + ); + panic!("constraints did not match regions they were created for"); + } + + ctx.layouts.insert(self.hash, entry); + frames + }) + } + + fn pack(self) -> PackedNode + where + Self: Sized + Hash + 'static, + { + self + } +} + +impl Hash for PackedNode { + fn hash<H: Hasher>(&self, _state: &mut H) { + #[cfg(feature = "layout-cache")] + _state.write_u64(self.hash); + #[cfg(not(feature = "layout-cache"))] + unimplemented!() + } +} + +impl Debug for PackedNode { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + self.node.fmt(f) + } +} |
