From 75403f86a9729d40947eeff7e175afb9fe19c77b Mon Sep 17 00:00:00 2001 From: PgBiel <9021226+PgBiel@users.noreply.github.com> Date: Sun, 6 Apr 2025 03:51:06 -0300 Subject: [PATCH] flush pending headers as soon as possible - dont wait until the end of the region, as a header can start and end in the same region (i.e. never repeat). --- crates/typst-layout/src/grid/layouter.rs | 6 ++++++ crates/typst-layout/src/grid/repeated.rs | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/crates/typst-layout/src/grid/layouter.rs b/crates/typst-layout/src/grid/layouter.rs index 600e051b5..5afc423ad 100644 --- a/crates/typst-layout/src/grid/layouter.rs +++ b/crates/typst-layout/src/grid/layouter.rs @@ -244,6 +244,7 @@ impl<'a> GridLayouter<'a> { if y >= footer.start { if y == footer.start { self.layout_footer(footer, engine, self.finished.len())?; + self.flush_pending_headers(); } continue; } @@ -251,6 +252,11 @@ impl<'a> GridLayouter<'a> { self.layout_row(y, engine, 0)?; + // After the first non-header row is placed, pending headers are no + // longer orphans and can repeat, so we move them to repeating + // headers. + self.flush_pending_headers(); + y += 1; } diff --git a/crates/typst-layout/src/grid/repeated.rs b/crates/typst-layout/src/grid/repeated.rs index 0809d0b7b..b64301b07 100644 --- a/crates/typst-layout/src/grid/repeated.rs +++ b/crates/typst-layout/src/grid/repeated.rs @@ -73,6 +73,14 @@ impl<'a> GridLayouter<'a> { )? } + // No chance of orphans as we're immediately placing conflicting + // headers afterwards, which basically are not headers, for all intents + // and purposes. It is therefore guaranteed that all new headers have + // been placed at least once. + if !conflicting_headers.is_empty() { + self.flush_pending_headers(); + } + Ok(()) } @@ -122,6 +130,13 @@ impl<'a> GridLayouter<'a> { let [first_header, ..] = headers else { return Ok(()); }; + + // Should be impossible to have two consecutive chunks of pending + // headers since they are always as long as possible, only being + // interrupted by direct conflict between consecutive headers, in which + // case we flush pending headers immediately. + assert!(self.pending_headers.is_empty()); + // Assuming non-conflicting headers sorted by increasing y, this must // be the header with the lowest level (sorted by increasing levels). let first_level = first_header.unwrap().level;