summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/typst/src/layout/container.rs12
-rw-r--r--crates/typst/src/layout/flow/compose.rs4
-rw-r--r--crates/typst/src/layout/flow/distribute.rs12
-rw-r--r--crates/typst/src/layout/grid/repeated.rs4
-rw-r--r--crates/typst/src/layout/grid/rowspans.rs2
-rw-r--r--crates/typst/src/layout/regions.rs16
-rw-r--r--crates/typst/src/math/equation.rs9
-rw-r--r--tests/ref/issue-5044-pad-100-percent.pngbin0 -> 90 bytes
-rw-r--r--tests/suite/layout/pad.typ4
9 files changed, 39 insertions, 24 deletions
diff --git a/crates/typst/src/layout/container.rs b/crates/typst/src/layout/container.rs
index 2ff0f0fd..705a5ef7 100644
--- a/crates/typst/src/layout/container.rs
+++ b/crates/typst/src/layout/container.rs
@@ -925,18 +925,22 @@ fn breakable_pod<'a>(
/// height and a new backlog.
fn distribute<'a>(
height: Abs,
- regions: Regions,
+ mut regions: Regions,
buf: &'a mut SmallVec<[Abs; 2]>,
) -> (Abs, &'a mut [Abs]) {
// Build new region heights from old regions.
let mut remaining = height;
- for region in regions.iter() {
- let limited = region.y.min(remaining);
+ loop {
+ let limited = regions.size.y.clamp(Abs::zero(), remaining);
buf.push(limited);
remaining -= limited;
- if remaining.approx_empty() {
+ if remaining.approx_empty()
+ || !regions.may_break()
+ || (!regions.may_progress() && limited.approx_empty())
+ {
break;
}
+ regions.next();
}
// If there is still something remaining, apply it to the
diff --git a/crates/typst/src/layout/flow/compose.rs b/crates/typst/src/layout/flow/compose.rs
index cfce7d49..003e4e72 100644
--- a/crates/typst/src/layout/flow/compose.rs
+++ b/crates/typst/src/layout/flow/compose.rs
@@ -282,7 +282,7 @@ impl<'a, 'b> Composer<'a, 'b, '_, '_> {
let need = frame.height() + clearance;
// If the float doesn't fit, queue it for the next region.
- if !remaining.fits(need) && !regions.in_last() {
+ if !remaining.fits(need) && regions.may_progress() {
self.work.floats.push(placed);
return Ok(());
}
@@ -343,7 +343,7 @@ impl<'a, 'b> Composer<'a, 'b, '_, '_> {
let mut relayout = false;
let mut regions = *regions;
- let mut migratable = !breakable && !regions.in_last();
+ let mut migratable = !breakable && regions.may_progress();
for (y, elem) in notes {
// The amount of space used by the in-flow content that contains the
diff --git a/crates/typst/src/layout/flow/distribute.rs b/crates/typst/src/layout/flow/distribute.rs
index 71f9598b..65516ccd 100644
--- a/crates/typst/src/layout/flow/distribute.rs
+++ b/crates/typst/src/layout/flow/distribute.rs
@@ -194,9 +194,9 @@ impl<'a, 'b> Distributor<'a, 'b, '_, '_, '_> {
/// Processes a line of a paragraph.
fn line(&mut self, line: &'b LineChild) -> FlowResult<()> {
- // If the line doesn't fit and we're allowed to break, finish the
- // region.
- if !self.regions.size.y.fits(line.frame.height()) && !self.regions.in_last() {
+ // If the line doesn't fit and a followup region may improve things,
+ // finish the region.
+ if !self.regions.size.y.fits(line.frame.height()) && self.regions.may_progress() {
return Err(Stop::Finish(false));
}
@@ -228,9 +228,9 @@ impl<'a, 'b> Distributor<'a, 'b, '_, '_, '_> {
// Lay out the block.
let frame = single.layout(self.composer.engine, self.regions.base())?;
- // If the block doesn't fit and we're allowed to break, finish the
- // region.
- if !self.regions.size.y.fits(frame.height()) && !self.regions.in_last() {
+ // If the block doesn't fit and a followup region may improve things,
+ // finish the region.
+ if !self.regions.size.y.fits(frame.height()) && self.regions.may_progress() {
return Err(Stop::Finish(false));
}
diff --git a/crates/typst/src/layout/grid/repeated.rs b/crates/typst/src/layout/grid/repeated.rs
index acb00f04..f187d0bc 100644
--- a/crates/typst/src/layout/grid/repeated.rs
+++ b/crates/typst/src/layout/grid/repeated.rs
@@ -57,7 +57,7 @@ impl<'a> GridLayouter<'a> {
let mut skipped_region = false;
while self.unbreakable_rows_left == 0
&& !self.regions.size.y.fits(header_rows.height + self.footer_height)
- && !self.regions.in_last()
+ && self.regions.may_progress()
{
// Advance regions without any output until we can place the
// header and the footer.
@@ -124,7 +124,7 @@ impl<'a> GridLayouter<'a> {
let mut skipped_region = false;
while self.unbreakable_rows_left == 0
&& !self.regions.size.y.fits(footer_height)
- && !self.regions.in_last()
+ && self.regions.may_progress()
{
// Advance regions without any output until we can place the
// footer.
diff --git a/crates/typst/src/layout/grid/rowspans.rs b/crates/typst/src/layout/grid/rowspans.rs
index 91e7d8ef..6381ba66 100644
--- a/crates/typst/src/layout/grid/rowspans.rs
+++ b/crates/typst/src/layout/grid/rowspans.rs
@@ -1147,7 +1147,7 @@ impl<'a> RowspanSimulator<'a> {
// Skip until we reach a fitting region for both header and footer.
while !self.regions.size.y.fits(header_height + footer_height)
- && !self.regions.in_last()
+ && self.regions.may_progress()
{
self.regions.next();
self.finished += 1;
diff --git a/crates/typst/src/layout/regions.rs b/crates/typst/src/layout/regions.rs
index 68ad4b7a..385664bb 100644
--- a/crates/typst/src/layout/regions.rs
+++ b/crates/typst/src/layout/regions.rs
@@ -96,14 +96,18 @@ impl Regions<'_> {
/// Whether the first region is full and a region break is called for.
pub fn is_full(&self) -> bool {
- Abs::zero().fits(self.size.y) && !self.in_last()
+ Abs::zero().fits(self.size.y) && self.may_progress()
}
- /// Whether the first region is the last usable region.
- ///
- /// If this is true, calling `next()` will have no effect.
- pub fn in_last(&self) -> bool {
- self.backlog.is_empty() && self.last.map_or(true, |height| self.size.y == height)
+ /// Whether a region break is permitted.
+ pub fn may_break(&self) -> bool {
+ !self.backlog.is_empty() || self.last.is_some()
+ }
+
+ /// Whether calling `next()` may improve a situation where there is a lack
+ /// of space.
+ pub fn may_progress(&self) -> bool {
+ !self.backlog.is_empty() || self.last.is_some_and(|height| self.size.y != height)
}
/// Advance to the next region if there is any.
diff --git a/crates/typst/src/math/equation.rs b/crates/typst/src/math/equation.rs
index dfcb0f7b..83d3fc74 100644
--- a/crates/typst/src/math/equation.rs
+++ b/crates/typst/src/math/equation.rs
@@ -327,8 +327,9 @@ fn layout_equation_block(
let mut rows = full_equation_builder.frames.into_iter().peekable();
let mut equation_builders = vec![];
let mut last_first_pos = Point::zero();
+ let mut regions = regions;
- for region in regions.iter() {
+ loop {
// Keep track of the position of the first row in this region,
// so that the offset can be reverted later.
let Some(&(_, first_pos)) = rows.peek() else { break };
@@ -344,8 +345,9 @@ fn layout_equation_block(
// we placed at least one line _or_ we still have non-last
// regions. Crucially, we don't want to infinitely create
// new regions which are too small.
- if !region.y.fits(sub.height() + pos.y)
- && (!frames.is_empty() || !regions.in_last())
+ if !regions.size.y.fits(sub.height() + pos.y)
+ && (regions.may_progress()
+ || (regions.may_break() && !frames.is_empty()))
{
break;
}
@@ -357,6 +359,7 @@ fn layout_equation_block(
equation_builders
.push(MathRunFrameBuilder { frames, size: Size::new(width, height) });
+ regions.next();
}
// Append remaining rows to the equation builder of the last region.
diff --git a/tests/ref/issue-5044-pad-100-percent.png b/tests/ref/issue-5044-pad-100-percent.png
new file mode 100644
index 00000000..51047567
--- /dev/null
+++ b/tests/ref/issue-5044-pad-100-percent.png
Binary files differ
diff --git a/tests/suite/layout/pad.typ b/tests/suite/layout/pad.typ
index 3a7439d0..4ff9f8ec 100644
--- a/tests/suite/layout/pad.typ
+++ b/tests/suite/layout/pad.typ
@@ -28,3 +28,7 @@ Hi #box(pad(left: 10pt)[A]) there
--- pad-adding-to-100-percent ---
// Test that padding adding up to 100% does not panic.
#pad(50%)[]
+
+--- issue-5044-pad-100-percent ---
+#set page(width: 30pt, height: 30pt)
+#pad(100%, block(width: 1cm, height: 1cm, fill: red))