This commit is contained in:
Martin 2021-06-18 13:00:36 +02:00
parent 2a30c20f0e
commit 7db78d83be
4 changed files with 37 additions and 9 deletions

View File

@ -20,6 +20,19 @@ impl LayoutCache {
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.frames.clear(); self.frames.clear();
} }
/// Retains all elements for which the closure on the level returns `true`.
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(usize) -> bool,
{
self.frames.retain(|_, b| f(b.level));
}
/// Amount of items in the cache.
pub fn len(&self) -> usize {
self.frames.len()
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -27,6 +40,8 @@ impl LayoutCache {
pub struct FramesEntry { pub struct FramesEntry {
/// The cached frames for a node. /// The cached frames for a node.
pub frames: Vec<Constrained<Frame>>, pub frames: Vec<Constrained<Frame>>,
/// How nested the frame was in the context is was originally appearing in.
pub level: usize,
} }
impl FramesEntry { impl FramesEntry {

View File

@ -32,7 +32,7 @@ use crate::loading::Loader;
/// Layout a tree into a collection of frames. /// Layout a tree into a collection of frames.
pub fn layout(loader: &mut dyn Loader, cache: &mut Cache, tree: &Tree) -> Vec<Frame> { pub fn layout(loader: &mut dyn Loader, cache: &mut Cache, tree: &Tree) -> Vec<Frame> {
tree.layout(&mut LayoutContext { loader, cache }) tree.layout(&mut LayoutContext { loader, cache, level: 0 })
} }
/// A tree of layout nodes. /// A tree of layout nodes.
@ -98,19 +98,23 @@ impl Layout for AnyNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
) -> Vec<Constrained<Frame>> { ) -> Vec<Constrained<Frame>> {
ctx.cache ctx.level += 1;
let frames = ctx
.cache
.layout .layout
.frames .frames
.get(&self.hash) .get(&self.hash)
.and_then(|x| x.check(regions.clone())) .and_then(|x| x.check(regions.clone()))
.unwrap_or_else(|| { .unwrap_or_else(|| {
let frames = self.node.layout(ctx, regions); let frames = self.node.layout(ctx, regions);
ctx.cache ctx.cache.layout.frames.insert(self.hash, FramesEntry {
.layout frames: frames.clone(),
.frames level: ctx.level - 1,
.insert(self.hash, FramesEntry { frames: frames.clone() }); });
frames
});
ctx.level -= 1;
frames frames
})
} }
} }
@ -184,6 +188,8 @@ pub struct LayoutContext<'a> {
pub loader: &'a mut dyn Loader, pub loader: &'a mut dyn Loader,
/// A cache for loaded fonts and artifacts from past layouting. /// A cache for loaded fonts and artifacts from past layouting.
pub cache: &'a mut Cache, pub cache: &'a mut Cache,
/// How deeply nested is the current layout tree position.
pub level: usize,
} }
/// A sequence of regions to layout into. /// A sequence of regions to layout into.

View File

@ -2,7 +2,9 @@ use ::image::GenericImageView;
use super::*; use super::*;
use crate::image::ImageId; use crate::image::ImageId;
use crate::layout::{AnyNode, Constrained, Constraints, Element, Frame, Layout, LayoutContext, Regions}; use crate::layout::{
AnyNode, Constrained, Constraints, Element, Frame, Layout, LayoutContext, Regions,
};
/// `image`: An image. /// `image`: An image.
/// ///
@ -52,7 +54,11 @@ struct ImageNode {
} }
impl Layout for ImageNode { impl Layout for ImageNode {
fn layout(&self, _: &mut LayoutContext, regions: &Regions) -> Vec<Constrained<Frame>> { fn layout(
&self,
_: &mut LayoutContext,
regions: &Regions,
) -> Vec<Constrained<Frame>> {
let Regions { current, base, .. } = regions; let Regions { current, base, .. } = regions;
let mut constraints = Constraints::new(regions.expand); let mut constraints = Constraints::new(regions.expand);
constraints.set_base_using_linears(Spec::new(self.width, self.height), regions); constraints.set_base_using_linears(Spec::new(self.width, self.height), regions);

View File

@ -225,6 +225,7 @@ fn test_part(
state.page.margins = Sides::splat(Some(Length::pt(10.0).into())); state.page.margins = Sides::splat(Some(Length::pt(10.0).into()));
let mut pass = typst::typeset(loader, cache, Some(src_path), &src, &scope, state); let mut pass = typst::typeset(loader, cache, Some(src_path), &src, &scope, state);
if !compare_ref { if !compare_ref {
pass.output.clear(); pass.output.clear();
} }