diff --git a/src/layout/incremental.rs b/src/layout/incremental.rs index e5bad8924..60486d2f6 100644 --- a/src/layout/incremental.rs +++ b/src/layout/incremental.rs @@ -50,11 +50,11 @@ impl LayoutCache { pub fn get( &mut self, hash: u64, - regions: Regions, + regions: &Regions, ) -> Option>>> { let entries = self.frames.get_mut(&hash)?; for entry in entries { - if let Some(frames) = entry.check(regions.clone()) { + if let Some(frames) = entry.check(regions) { return Some(frames); } } @@ -136,9 +136,11 @@ impl FramesEntry { /// Checks if the cached frames are valid in the given regions and returns /// them if so. - pub fn check(&mut self, mut regions: Regions) -> Option>>> { - for (i, frame) in self.frames.iter().enumerate() { - if (i != 0 && !regions.next()) || !frame.constraints.check(®ions) { + pub fn check(&mut self, regions: &Regions) -> Option>>> { + let mut iter = regions.iter(); + for frame in &self.frames { + let (current, base) = iter.next()?; + if !frame.constraints.check(current, base, regions.expand) { return None; } } @@ -175,11 +177,13 @@ impl FramesEntry { } } -/// Carries an item that only applies to certain regions and the constraints +/// Carries an item that is only valid in certain regions and the constraints /// that describe these regions. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct Constrained { + /// The item that is only valid if the constraints are fullfilled. pub item: T, + /// Constraints on regions in which the item is valid. pub constraints: Constraints, } @@ -218,16 +222,13 @@ impl Constraints { } } - #[cfg(feature = "layout-cache")] - fn check(&self, regions: &Regions) -> bool { - if self.expand != regions.expand { - return false; - } - - let base = regions.base.to_spec(); - let current = regions.current.to_spec(); - - current.eq_by(&self.min, |x, y| y.map_or(true, |y| x.fits(y))) + /// Check whether the constraints are fullfilled in a region with the given + /// properties. + pub fn check(&self, current: Size, base: Size, expand: Spec) -> bool { + let current = current.to_spec(); + let base = base.to_spec(); + self.expand == expand + && current.eq_by(&self.min, |x, y| y.map_or(true, |y| x.fits(y))) && current.eq_by(&self.max, |x, y| y.map_or(true, |y| x < &y)) && current.eq_by(&self.exact, |x, y| y.map_or(true, |y| x.approx_eq(y))) && base.eq_by(&self.base, |x, y| y.map_or(true, |y| x.approx_eq(y))) diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 22e6e8c8b..0f88d150e 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -140,14 +140,21 @@ impl Regions { self.backlog.is_empty() && self.last.map_or(true, |size| self.current == size) } + /// An iterator that returns pairs of `(current, base)` that are equivalent + /// to what would be produced by calling [`next()`](Self::next) repeatedly + /// until all regions are exhausted. + pub fn iter(&self) -> impl Iterator + '_ { + let first = std::iter::once((self.current, self.base)); + let backlog = self.backlog.iter().rev(); + let last = self.last.iter().cycle(); + first.chain(backlog.chain(last).map(|&s| (s, s))) + } + /// Advance to the next region if there is any. - pub fn next(&mut self) -> bool { + pub fn next(&mut self) { if let Some(size) = self.backlog.pop().or(self.last) { self.current = size; self.base = size; - true - } else { - false } } diff --git a/src/layout/tree.rs b/src/layout/tree.rs index 77b01ad28..4b21e05ca 100644 --- a/src/layout/tree.rs +++ b/src/layout/tree.rs @@ -86,7 +86,7 @@ impl Layout for LayoutNode { return self.node.layout(ctx, regions); #[cfg(feature = "layout-cache")] - ctx.layouts.get(self.hash, regions.clone()).unwrap_or_else(|| { + ctx.layouts.get(self.hash, regions).unwrap_or_else(|| { ctx.level += 1; let frames = self.node.layout(ctx, regions); ctx.level -= 1; diff --git a/tests/typeset.rs b/tests/typeset.rs index 59eb008f9..3e83fcb52 100644 --- a/tests/typeset.rs +++ b/tests/typeset.rs @@ -16,12 +16,15 @@ use typst::eval::{eval, Scope, Value}; use typst::exec::{exec, State}; use typst::geom::{self, Length, PathElement, Point, Sides, Size}; use typst::image::ImageId; -use typst::layout::{layout, Element, Frame, Geometry, LayoutTree, Paint, Text}; +use typst::layout::{layout, Element, Frame, Geometry, Paint, Text}; use typst::loading::{FileId, FsLoader}; use typst::parse::{parse, LineMap, Scanner}; use typst::syntax::{Location, Pos}; use typst::Context; +#[cfg(feature = "layout-cache")] +use typst::layout::LayoutTree; + const TYP_DIR: &str = "./typ"; const REF_DIR: &str = "./ref"; const PNG_DIR: &str = "./png";