diff --git a/crates/typst-layout/src/grid/layouter.rs b/crates/typst-layout/src/grid/layouter.rs index 9db5657a4..5b35ca8fe 100644 --- a/crates/typst-layout/src/grid/layouter.rs +++ b/crates/typst-layout/src/grid/layouter.rs @@ -76,10 +76,14 @@ pub(super) struct Current { /// The initial size of the current region before we started subtracting. pub(super) initial: Size, /// The height of the region after repeated headers were placed and footers - /// prepared. + /// prepared. This also includes pending repeating headers from the start, + /// even if they were not repeated yet, since they will be repeated in the + /// next region anyway (bar orphan prevention). /// /// This is used to quickly tell if any additional space in the region has - /// been occupied since then. + /// been occupied since then, meaning that additional space will become + /// available after a region break (see + /// [`GridLayouter::may_progress_with_repeats`]). pub(super) initial_after_repeats: Abs, /// Whether `layouter.regions.may_progress()` was `true` at the top of the /// region. diff --git a/crates/typst-layout/src/grid/repeated.rs b/crates/typst-layout/src/grid/repeated.rs index 81ac48d1a..fbfa5dbc6 100644 --- a/crates/typst-layout/src/grid/repeated.rs +++ b/crates/typst-layout/src/grid/repeated.rs @@ -329,7 +329,12 @@ impl<'a> GridLayouter<'a> { self.current.repeated_header_rows = self.current.lrows.len(); self.current.initial_after_repeats = self.regions.size.y; + let mut has_non_repeated_pending_header = false; for header in self.pending_headers { + if matches!(header, Repeatable::NotRepeated(_)) { + self.current.initial_after_repeats = self.regions.size.y; + has_non_repeated_pending_header = true; + } let header_height = self.layout_header_rows(header.unwrap(), engine, disambiguator, false)?; if matches!(header, Repeatable::Repeated(_)) { @@ -338,6 +343,10 @@ impl<'a> GridLayouter<'a> { } } + if !has_non_repeated_pending_header { + self.current.initial_after_repeats = self.regions.size.y; + } + if !may_progress { // Flush pending headers immediately, as placing them again later // won't help. @@ -396,6 +405,8 @@ impl<'a> GridLayouter<'a> { self.current.lrows_orphan_snapshot = Some(self.current.lrows.len()); } + let mut at_top = self.regions.size.y == self.current.initial_after_repeats; + self.unbreakable_rows_left += total_header_row_count(headers.iter().map(Repeatable::unwrap)); @@ -412,6 +423,11 @@ impl<'a> GridLayouter<'a> { if !short_lived && matches!(header, Repeatable::Repeated(_)) { self.current.repeating_header_height += header_height; self.current.repeating_header_heights.push(header_height); + if at_top { + self.current.initial_after_repeats = self.regions.size.y; + } + } else { + at_top = false; } } diff --git a/tests/ref/grid-header-and-rowspan-contiguous-2.png b/tests/ref/grid-header-and-rowspan-contiguous-2.png index 555b952b3..29bc411d1 100644 Binary files a/tests/ref/grid-header-and-rowspan-contiguous-2.png and b/tests/ref/grid-header-and-rowspan-contiguous-2.png differ diff --git a/tests/ref/grid-subheaders-too-large-repeating-orphan-before-relative.png b/tests/ref/grid-subheaders-too-large-repeating-orphan-before-relative.png index 9688c4387..dfcac8500 100644 Binary files a/tests/ref/grid-subheaders-too-large-repeating-orphan-before-relative.png and b/tests/ref/grid-subheaders-too-large-repeating-orphan-before-relative.png differ