mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
Fix panic in spilled block layout (#5085)
This commit is contained in:
parent
04df1264ef
commit
3ec5d442d7
@ -403,6 +403,7 @@ impl<'a> MultiChild<'a> {
|
||||
full: regions.full,
|
||||
first: regions.size.y,
|
||||
backlog: vec![],
|
||||
min_backlog_len: regions.backlog.len(),
|
||||
});
|
||||
}
|
||||
|
||||
@ -474,6 +475,7 @@ pub struct MultiSpill<'a, 'b> {
|
||||
first: Abs,
|
||||
full: Abs,
|
||||
backlog: Vec<Abs>,
|
||||
min_backlog_len: usize,
|
||||
}
|
||||
|
||||
impl MultiSpill<'_, '_> {
|
||||
@ -483,17 +485,18 @@ impl MultiSpill<'_, '_> {
|
||||
engine: &mut Engine,
|
||||
regions: Regions,
|
||||
) -> SourceResult<(Frame, Option<Self>)> {
|
||||
// We build regions for the whole `MultiChild` with the sizes passed to
|
||||
// earlier parts of it plus the new regions. Then, we layout the
|
||||
// complete block, but extract only the suffix that interests us.
|
||||
// The first region becomes unchangable and committed to our backlog.
|
||||
self.backlog.push(regions.size.y);
|
||||
|
||||
// The remaining regions are ephemeral and may be replaced.
|
||||
let mut backlog: Vec<_> =
|
||||
self.backlog.iter().chain(regions.backlog).copied().collect();
|
||||
|
||||
// Remove unnecessary backlog items (also to prevent it from growing
|
||||
// unnecessarily, which would change the region's hash).
|
||||
while !backlog.is_empty() && backlog.last().copied() == regions.last {
|
||||
// Remove unnecessary backlog items to prevent it from growing
|
||||
// unnecessarily, changing the region's hash.
|
||||
while backlog.len() > self.min_backlog_len
|
||||
&& backlog.last().copied() == regions.last
|
||||
{
|
||||
backlog.pop();
|
||||
}
|
||||
|
||||
@ -513,6 +516,16 @@ impl MultiSpill<'_, '_> {
|
||||
.into_iter()
|
||||
.skip(self.backlog.len());
|
||||
|
||||
// Ensure that the backlog never shrinks, so that unwrapping below is at
|
||||
// least fairly safe. Note that the whole region juggling here is
|
||||
// fundamentally not ideal: It is a compatibility layer between the old
|
||||
// (all regions provided upfront) & new (each region provided on-demand,
|
||||
// like an iterator) layout model. This approach is not 100% correct, as
|
||||
// in the old model later regions could have an effect on earlier
|
||||
// frames, but it's the best we can do for now, until the multi
|
||||
// layouters are refactored to the new model.
|
||||
self.min_backlog_len = self.min_backlog_len.max(backlog.len());
|
||||
|
||||
// Save the first frame.
|
||||
let frame = frames.next().unwrap();
|
||||
|
||||
|
BIN
tests/ref/issue-5024-spill-backlog.png
Normal file
BIN
tests/ref/issue-5024-spill-backlog.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 270 B |
@ -76,3 +76,7 @@ Hi
|
||||
#block(rect(width: 80%, height: 80pt), breakable: false)
|
||||
#lines(6)
|
||||
]
|
||||
|
||||
--- issue-5024-spill-backlog ---
|
||||
#set page(columns: 2, height: 50pt)
|
||||
#columns(2)[Hello]
|
||||
|
Loading…
x
Reference in New Issue
Block a user