summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorMalo <57839069+MDLC01@users.noreply.github.com>2023-12-18 11:37:30 +0100
committerGitHub <noreply@github.com>2023-12-18 11:37:30 +0100
commit356bdeba18153efd4209657182971e22bdaf4db2 (patch)
tree3efedaf7d0795c0e54420eb04263a1bb1e9329dd /crates
parent41c0dae2097ae4368c259bd1b1b10ef6667bb850 (diff)
Do not create a block frame for out-of-flow items only (#2517)
Diffstat (limited to 'crates')
-rw-r--r--crates/typst/src/layout/flow.rs51
1 files changed, 39 insertions, 12 deletions
diff --git a/crates/typst/src/layout/flow.rs b/crates/typst/src/layout/flow.rs
index b4e7afd1..8983ccda 100644
--- a/crates/typst/src/layout/flow.rs
+++ b/crates/typst/src/layout/flow.rs
@@ -82,7 +82,7 @@ impl Layout for FlowElem {
} else if child.is::<ColbreakElem>() {
if !layouter.regions.backlog.is_empty() || layouter.regions.last.is_some()
{
- layouter.finish_region(engine)?;
+ layouter.finish_region(engine, true)?;
}
} else {
bail!(child.span(), "unexpected flow child");
@@ -160,6 +160,19 @@ impl FlowItem {
Self::Frame { frame, .. } | Self::Footnote(frame) => frame.height(),
}
}
+
+ /// Whether this item is out-of-flow.
+ ///
+ /// Out-of-flow items are guaranteed to have a [`Size::zero()`].
+ fn is_out_of_flow(&self) -> bool {
+ match self {
+ Self::Placed { float: false, .. } => true,
+ Self::Frame { frame, .. } => {
+ frame.items().all(|(_, item)| matches!(item, FrameItem::Meta(..)))
+ }
+ _ => false,
+ }
+ }
}
impl<'a> FlowLayouter<'a> {
@@ -243,7 +256,7 @@ impl<'a> FlowLayouter<'a> {
if let Some(first) = lines.first() {
if !self.regions.size.y.fits(first.height()) && !self.regions.in_last() {
let carry: Vec<_> = self.items.drain(sticky..).collect();
- self.finish_region(engine)?;
+ self.finish_region(engine, false)?;
for item in carry {
self.layout_item(engine, item)?;
}
@@ -323,7 +336,7 @@ impl<'a> FlowLayouter<'a> {
if self.regions.is_full() {
// Skip directly if region is already full.
- self.finish_region(engine)?;
+ self.finish_region(engine, false)?;
}
// How to align the block.
@@ -347,7 +360,7 @@ impl<'a> FlowLayouter<'a> {
}
if i > 0 {
- self.finish_region(engine)?;
+ self.finish_region(engine, false)?;
}
let item = FlowItem::Frame { frame, align, sticky, movable: false };
@@ -386,7 +399,7 @@ impl<'a> FlowLayouter<'a> {
FlowItem::Frame { ref frame, movable, .. } => {
let height = frame.height();
if !self.regions.size.y.fits(height) && !self.regions.in_last() {
- self.finish_region(engine)?;
+ self.finish_region(engine, false)?;
}
self.regions.size.y -= height;
@@ -396,7 +409,7 @@ impl<'a> FlowLayouter<'a> {
self.items.push(item);
if !self.handle_footnotes(engine, &mut notes, true, false)? {
let item = self.items.pop();
- self.finish_region(engine)?;
+ self.finish_region(engine, false)?;
self.items.extend(item);
self.regions.size.y -= height;
self.handle_footnotes(engine, &mut notes, true, true)?;
@@ -454,7 +467,21 @@ impl<'a> FlowLayouter<'a> {
}
/// Finish the frame for one region.
- fn finish_region(&mut self, engine: &mut Engine) -> SourceResult<()> {
+ ///
+ /// Set `force` to `true` to allow creating a frame for out-of-flow elements
+ /// only (this is used to force the creation of a frame in case the
+ /// remaining elements are all out-of-flow).
+ fn finish_region(&mut self, engine: &mut Engine, force: bool) -> SourceResult<()> {
+ if !force
+ && !self.items.is_empty()
+ && self.items.iter().all(FlowItem::is_out_of_flow)
+ {
+ self.finished.push(Frame::soft(self.initial));
+ self.regions.next();
+ self.initial = self.regions.size;
+ return Ok(());
+ }
+
// Trim weak spacing.
while self
.items
@@ -591,13 +618,13 @@ impl<'a> FlowLayouter<'a> {
fn finish(mut self, engine: &mut Engine) -> SourceResult<Fragment> {
if self.expand.y {
while !self.regions.backlog.is_empty() {
- self.finish_region(engine)?;
+ self.finish_region(engine, true)?;
}
}
- self.finish_region(engine)?;
+ self.finish_region(engine, true)?;
while !self.items.is_empty() {
- self.finish_region(engine)?;
+ self.finish_region(engine, true)?;
}
Ok(Fragment::frames(self.finished))
@@ -611,7 +638,7 @@ impl FlowLayouter<'_> {
mut notes: Vec<FootnoteElem>,
) -> SourceResult<()> {
if self.root && !self.handle_footnotes(engine, &mut notes, false, false)? {
- self.finish_region(engine)?;
+ self.finish_region(engine, false)?;
self.handle_footnotes(engine, &mut notes, false, true)?;
}
Ok(())
@@ -673,7 +700,7 @@ impl FlowLayouter<'_> {
for (i, frame) in frames.into_iter().enumerate() {
find_footnotes(notes, &frame);
if i > 0 {
- self.finish_region(engine)?;
+ self.finish_region(engine, false)?;
self.layout_footnote_separator(engine)?;
self.regions.size.y -= self.footnote_config.gap;
}