diff --git a/crates/typst/src/layout/container.rs b/crates/typst/src/layout/container.rs index 9fdef0be4..cc1559c66 100644 --- a/crates/typst/src/layout/container.rs +++ b/crates/typst/src/layout/container.rs @@ -487,7 +487,7 @@ impl Packed { engine: &mut Engine, locator: Locator, styles: StyleChain, - base: Size, + region: Region, ) -> SourceResult { // Fetch sizing properties. let width = self.width(styles); @@ -495,7 +495,7 @@ impl Packed { let inset = self.inset(styles).unwrap_or_default(); // Build the pod regions. - let pod = unbreakable_pod(&width.into(), &height, &inset, styles, base); + let pod = unbreakable_pod(&width.into(), &height, &inset, styles, region.size); // Layout the body. let body = self.body(styles); @@ -518,6 +518,8 @@ impl Packed { // If we have a child that wants to layout with full region access, // we layout it. Some(BlockBody::MultiLayouter(callback)) => { + let expand = (pod.expand | region.expand) & pod.size.map(Abs::is_finite); + let pod = Region { expand, ..pod }; callback.call(engine, locator, styles, pod.into())?.into_frame() } }; diff --git a/crates/typst/src/layout/flow/collect.rs b/crates/typst/src/layout/flow/collect.rs index a477c3347..efb16427f 100644 --- a/crates/typst/src/layout/flow/collect.rs +++ b/crates/typst/src/layout/flow/collect.rs @@ -173,6 +173,7 @@ impl<'a> Collector<'a, '_, '_> { fn block(&mut self, elem: &'a Packed, styles: StyleChain<'a>) { let locator = self.locator.next(&elem.span()); let align = AlignElem::alignment_in(styles).resolve(styles); + let alone = self.children.len() == 1; let sticky = elem.sticky(styles); let breakable = elem.breakable(styles); let fr = match elem.height(styles) { @@ -193,6 +194,7 @@ impl<'a> Collector<'a, '_, '_> { self.output.push(Child::Single(self.boxed(SingleChild { align, sticky, + alone, fr, elem, styles, @@ -200,7 +202,6 @@ impl<'a> Collector<'a, '_, '_> { cell: CachedCell::new(), }))); } else { - let alone = self.children.len() == 1; self.output.push(Child::Multi(self.boxed(MultiChild { align, sticky, @@ -318,6 +319,7 @@ pub struct LineChild { pub struct SingleChild<'a> { pub align: Axes, pub sticky: bool, + pub alone: bool, pub fr: Option, elem: &'a Packed, styles: StyleChain<'a>, @@ -327,8 +329,10 @@ pub struct SingleChild<'a> { impl SingleChild<'_> { /// Build the child's frame given the region's base size. - pub fn layout(&self, engine: &mut Engine, base: Size) -> SourceResult { - self.cell.get_or_init(base, |base| { + pub fn layout(&self, engine: &mut Engine, region: Region) -> SourceResult { + self.cell.get_or_init(region, |mut region| { + // Vertical expansion is only kept if this block is the only child. + region.expand.y &= self.alone; layout_single_impl( engine.world, engine.introspector, @@ -338,7 +342,7 @@ impl SingleChild<'_> { self.elem, self.locator.track(), self.styles, - base, + region, ) }) } @@ -356,7 +360,7 @@ fn layout_single_impl( elem: &Packed, locator: Tracked, styles: StyleChain, - base: Size, + region: Region, ) -> SourceResult { let link = LocatorLink::new(locator); let locator = Locator::link(&link); @@ -368,7 +372,7 @@ fn layout_single_impl( route: Route::extend(route), }; - elem.layout_single(&mut engine, locator, styles, base) + elem.layout_single(&mut engine, locator, styles, region) .map(|frame| frame.post_processed(styles)) } diff --git a/crates/typst/src/layout/flow/distribute.rs b/crates/typst/src/layout/flow/distribute.rs index a30b71bac..a738b3e67 100644 --- a/crates/typst/src/layout/flow/distribute.rs +++ b/crates/typst/src/layout/flow/distribute.rs @@ -226,7 +226,10 @@ impl<'a, 'b> Distributor<'a, 'b, '_, '_, '_> { } // Lay out the block. - let frame = single.layout(self.composer.engine, self.regions.base())?; + let frame = single.layout( + self.composer.engine, + Region::new(self.regions.base(), self.regions.expand), + )?; // If the block doesn't fit and a followup region may improve things, // finish the region. @@ -422,8 +425,8 @@ impl<'a, 'b> Distributor<'a, 'b, '_, '_, '_> { for item in &self.items { let Item::Fr(v, Some(single)) = item else { continue }; let length = v.share(frs, fr_space); - let base = Size::new(region.size.x, length); - let frame = single.layout(self.composer.engine, base)?; + let pod = Region::new(Size::new(region.size.x, length), region.expand); + let frame = single.layout(self.composer.engine, pod)?; used.x.set_max(frame.width()); fr_frames.push(frame); } diff --git a/tests/ref/issue-5160-unbreakable-pad.png b/tests/ref/issue-5160-unbreakable-pad.png new file mode 100644 index 000000000..f370870a5 Binary files /dev/null and b/tests/ref/issue-5160-unbreakable-pad.png differ diff --git a/tests/suite/layout/pad.typ b/tests/suite/layout/pad.typ index 4ff9f8ec4..e9830cf79 100644 --- a/tests/suite/layout/pad.typ +++ b/tests/suite/layout/pad.typ @@ -32,3 +32,7 @@ Hi #box(pad(left: 10pt)[A]) there --- issue-5044-pad-100-percent --- #set page(width: 30pt, height: 30pt) #pad(100%, block(width: 1cm, height: 1cm, fill: red)) + +--- issue-5160-unbreakable-pad --- +#set block(breakable: false) +#block(width: 100%, pad(x: 20pt, align(right)[A]))