mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Better block caching (#5046)
This commit is contained in:
parent
839983a0a7
commit
01af4308d3
@ -4,12 +4,15 @@ use std::hash::Hash;
|
|||||||
|
|
||||||
use bumpalo::boxed::Box as BumpBox;
|
use bumpalo::boxed::Box as BumpBox;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
use comemo::{Track, Tracked, TrackedMut};
|
||||||
use once_cell::unsync::Lazy;
|
use once_cell::unsync::Lazy;
|
||||||
|
|
||||||
use crate::diag::{bail, SourceResult};
|
use crate::diag::{bail, SourceResult};
|
||||||
use crate::engine::Engine;
|
use crate::engine::{Engine, Route, Sink, Traced};
|
||||||
use crate::foundations::{Packed, Resolve, Smart, StyleChain};
|
use crate::foundations::{Packed, Resolve, Smart, StyleChain};
|
||||||
use crate::introspection::{Locator, SplitLocator, Tag, TagElem};
|
use crate::introspection::{
|
||||||
|
Introspector, Locator, LocatorLink, SplitLocator, Tag, TagElem,
|
||||||
|
};
|
||||||
use crate::layout::{
|
use crate::layout::{
|
||||||
layout_frame, Abs, AlignElem, Alignment, Axes, BlockElem, ColbreakElem,
|
layout_frame, Abs, AlignElem, Alignment, Axes, BlockElem, ColbreakElem,
|
||||||
FixedAlignment, FlushElem, Fr, Fragment, Frame, PagebreakElem, PlaceElem,
|
FixedAlignment, FlushElem, Fr, Fragment, Frame, PagebreakElem, PlaceElem,
|
||||||
@ -18,6 +21,7 @@ use crate::layout::{
|
|||||||
use crate::model::ParElem;
|
use crate::model::ParElem;
|
||||||
use crate::realize::Pair;
|
use crate::realize::Pair;
|
||||||
use crate::text::TextElem;
|
use crate::text::TextElem;
|
||||||
|
use crate::World;
|
||||||
|
|
||||||
/// Collects all elements of the flow into prepared children. These are much
|
/// Collects all elements of the flow into prepared children. These are much
|
||||||
/// simpler to handle than the raw elements.
|
/// simpler to handle than the raw elements.
|
||||||
@ -324,13 +328,49 @@ impl SingleChild<'_> {
|
|||||||
/// Build the child's frame given the region's base size.
|
/// Build the child's frame given the region's base size.
|
||||||
pub fn layout(&self, engine: &mut Engine, base: Size) -> SourceResult<Frame> {
|
pub fn layout(&self, engine: &mut Engine, base: Size) -> SourceResult<Frame> {
|
||||||
self.cell.get_or_init(base, |base| {
|
self.cell.get_or_init(base, |base| {
|
||||||
self.elem
|
layout_single_impl(
|
||||||
.layout_single(engine, self.locator.relayout(), self.styles, base)
|
engine.world,
|
||||||
.map(|frame| frame.post_processed(self.styles))
|
engine.introspector,
|
||||||
|
engine.traced,
|
||||||
|
TrackedMut::reborrow_mut(&mut engine.sink),
|
||||||
|
engine.route.track(),
|
||||||
|
self.elem,
|
||||||
|
self.locator.track(),
|
||||||
|
self.styles,
|
||||||
|
base,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The cached, internal implementation of [`SingleChild::layout`].
|
||||||
|
#[comemo::memoize]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn layout_single_impl(
|
||||||
|
world: Tracked<dyn World + '_>,
|
||||||
|
introspector: Tracked<Introspector>,
|
||||||
|
traced: Tracked<Traced>,
|
||||||
|
sink: TrackedMut<Sink>,
|
||||||
|
route: Tracked<Route>,
|
||||||
|
elem: &Packed<BlockElem>,
|
||||||
|
locator: Tracked<Locator>,
|
||||||
|
styles: StyleChain,
|
||||||
|
base: Size,
|
||||||
|
) -> SourceResult<Frame> {
|
||||||
|
let link = LocatorLink::new(locator);
|
||||||
|
let locator = Locator::link(&link);
|
||||||
|
let mut engine = Engine {
|
||||||
|
world,
|
||||||
|
introspector,
|
||||||
|
traced,
|
||||||
|
sink,
|
||||||
|
route: Route::extend(route),
|
||||||
|
};
|
||||||
|
|
||||||
|
elem.layout_single(&mut engine, locator, styles, base)
|
||||||
|
.map(|frame| frame.post_processed(styles))
|
||||||
|
}
|
||||||
|
|
||||||
/// A child that encapsulates a prepared breakable block.
|
/// A child that encapsulates a prepared breakable block.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MultiChild<'a> {
|
pub struct MultiChild<'a> {
|
||||||
@ -349,7 +389,7 @@ impl<'a> MultiChild<'a> {
|
|||||||
engine: &mut Engine,
|
engine: &mut Engine,
|
||||||
regions: Regions,
|
regions: Regions,
|
||||||
) -> SourceResult<(Frame, Option<MultiSpill<'a, 'b>>)> {
|
) -> SourceResult<(Frame, Option<MultiSpill<'a, 'b>>)> {
|
||||||
let fragment = self.layout_impl(engine, regions)?;
|
let fragment = self.layout_full(engine, regions)?;
|
||||||
|
|
||||||
// Extract the first frame.
|
// Extract the first frame.
|
||||||
let mut frames = fragment.into_iter();
|
let mut frames = fragment.into_iter();
|
||||||
@ -371,7 +411,7 @@ impl<'a> MultiChild<'a> {
|
|||||||
|
|
||||||
/// The shared internal implementation of [`Self::layout`] and
|
/// The shared internal implementation of [`Self::layout`] and
|
||||||
/// [`MultiSpill::layout`].
|
/// [`MultiSpill::layout`].
|
||||||
fn layout_impl(
|
fn layout_full(
|
||||||
&self,
|
&self,
|
||||||
engine: &mut Engine,
|
engine: &mut Engine,
|
||||||
regions: Regions,
|
regions: Regions,
|
||||||
@ -379,18 +419,54 @@ impl<'a> MultiChild<'a> {
|
|||||||
self.cell.get_or_init(regions, |mut regions| {
|
self.cell.get_or_init(regions, |mut regions| {
|
||||||
// Vertical expansion is only kept if this block is the only child.
|
// Vertical expansion is only kept if this block is the only child.
|
||||||
regions.expand.y &= self.alone;
|
regions.expand.y &= self.alone;
|
||||||
self.elem
|
layout_multi_impl(
|
||||||
.layout_multiple(engine, self.locator.relayout(), self.styles, regions)
|
engine.world,
|
||||||
.map(|mut fragment| {
|
engine.introspector,
|
||||||
for frame in &mut fragment {
|
engine.traced,
|
||||||
frame.post_process(self.styles);
|
TrackedMut::reborrow_mut(&mut engine.sink),
|
||||||
}
|
engine.route.track(),
|
||||||
fragment
|
self.elem,
|
||||||
})
|
self.locator.track(),
|
||||||
|
self.styles,
|
||||||
|
regions,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The cached, internal implementation of [`MultiChild::layout_full`].
|
||||||
|
#[comemo::memoize]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn layout_multi_impl(
|
||||||
|
world: Tracked<dyn World + '_>,
|
||||||
|
introspector: Tracked<Introspector>,
|
||||||
|
traced: Tracked<Traced>,
|
||||||
|
sink: TrackedMut<Sink>,
|
||||||
|
route: Tracked<Route>,
|
||||||
|
elem: &Packed<BlockElem>,
|
||||||
|
locator: Tracked<Locator>,
|
||||||
|
styles: StyleChain,
|
||||||
|
regions: Regions,
|
||||||
|
) -> SourceResult<Fragment> {
|
||||||
|
let link = LocatorLink::new(locator);
|
||||||
|
let locator = Locator::link(&link);
|
||||||
|
let mut engine = Engine {
|
||||||
|
world,
|
||||||
|
introspector,
|
||||||
|
traced,
|
||||||
|
sink,
|
||||||
|
route: Route::extend(route),
|
||||||
|
};
|
||||||
|
|
||||||
|
elem.layout_multiple(&mut engine, locator, styles, regions)
|
||||||
|
.map(|mut fragment| {
|
||||||
|
for frame in &mut fragment {
|
||||||
|
frame.post_process(styles);
|
||||||
|
}
|
||||||
|
fragment
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// The spilled remains of a `MultiChild` that broke across two regions.
|
/// The spilled remains of a `MultiChild` that broke across two regions.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MultiSpill<'a, 'b> {
|
pub struct MultiSpill<'a, 'b> {
|
||||||
@ -433,7 +509,7 @@ impl MultiSpill<'_, '_> {
|
|||||||
// Extract the not-yet-processed frames.
|
// Extract the not-yet-processed frames.
|
||||||
let mut frames = self
|
let mut frames = self
|
||||||
.multi
|
.multi
|
||||||
.layout_impl(engine, pod)?
|
.layout_full(engine, pod)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.skip(self.backlog.len());
|
.skip(self.backlog.len());
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ pub fn layout_frame(
|
|||||||
.map(Fragment::into_frame)
|
.map(Fragment::into_frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The internal implementation of [`layout_fragment`].
|
/// The cached, internal implementation of [`layout_fragment`].
|
||||||
#[comemo::memoize]
|
#[comemo::memoize]
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn layout_fragment_impl(
|
fn layout_fragment_impl(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user