flush orphans and pending headers at the same time (broken)

Goal is to ensure pending headers are flushed before a region break, else non-repeating headers will appear more than once

Must not be called while laying out headers, however, so it's broken
This commit is contained in:
PgBiel 2025-04-30 01:45:50 -03:00
parent ab852a5151
commit 3ef2137619
2 changed files with 21 additions and 5 deletions

View File

@ -254,7 +254,7 @@ impl<'a> GridLayouter<'a> {
if y >= footer.start { if y >= footer.start {
if y == footer.start { if y == footer.start {
self.layout_footer(footer, engine, self.finished.len())?; self.layout_footer(footer, engine, self.finished.len())?;
self.flush_pending_headers(); self.flush_orphans();
} }
y = footer.end; y = footer.end;
continue; continue;
@ -266,7 +266,6 @@ impl<'a> GridLayouter<'a> {
// After the first non-header row is placed, pending headers are no // After the first non-header row is placed, pending headers are no
// longer orphans and can repeat, so we move them to repeating // longer orphans and can repeat, so we move them to repeating
// headers. // headers.
self.flush_pending_headers();
// //
// Note that this is usually done in `push_row`, since the call to // Note that this is usually done in `push_row`, since the call to
// `layout_row` above might trigger region breaks (for multi-page // `layout_row` above might trigger region breaks (for multi-page
@ -275,6 +274,7 @@ impl<'a> GridLayouter<'a> {
// visible output and thus does not push any rows even though it // visible output and thus does not push any rows even though it
// was successfully laid out, in which case we additionally flush // was successfully laid out, in which case we additionally flush
// here just in case. // here just in case.
self.flush_orphans();
y += 1; y += 1;
} }
@ -328,7 +328,7 @@ impl<'a> GridLayouter<'a> {
self.layout_relative_row(engine, disambiguator, v, y)? self.layout_relative_row(engine, disambiguator, v, y)?
} }
Sizing::Fr(v) => { Sizing::Fr(v) => {
self.current.lrows_orphan_snapshot = None; self.flush_orphans();
self.lrows.push(Row::Fr(v, y, disambiguator)) self.lrows.push(Row::Fr(v, y, disambiguator))
} }
} }
@ -1443,7 +1443,7 @@ impl<'a> GridLayouter<'a> {
fn push_row(&mut self, frame: Frame, y: usize, is_last: bool) { fn push_row(&mut self, frame: Frame, y: usize, is_last: bool) {
// There is now a row after the rows equipped with orphan prevention, // There is now a row after the rows equipped with orphan prevention,
// so no need to remove them anymore. // so no need to remove them anymore.
self.current.lrows_orphan_snapshot = None; self.flush_orphans();
self.regions.size.y -= frame.height(); self.regions.size.y -= frame.height();
self.lrows.push(Row::Frame(frame, y, is_last)); self.lrows.push(Row::Frame(frame, y, is_last));
} }

View File

@ -35,7 +35,7 @@ impl<'a> GridLayouter<'a> {
// headers afterwards, which basically are not headers, for all intents // headers afterwards, which basically are not headers, for all intents
// and purposes. It is therefore guaranteed that all new headers have // and purposes. It is therefore guaranteed that all new headers have
// been placed at least once. // been placed at least once.
self.flush_pending_headers(); self.flush_orphans();
// Layout each conflicting header independently, without orphan // Layout each conflicting header independently, without orphan
// prevention (as they don't go into 'pending_headers'). // prevention (as they don't go into 'pending_headers').
@ -139,10 +139,26 @@ impl<'a> GridLayouter<'a> {
Ok(()) Ok(())
} }
/// This function should be called each time an additional row has been
/// laid out in a region to indicate that orphan prevention has succeeded.
///
/// It removes the current orphan snapshot and flushes pending headers,
/// such that a non-repeating header won't try to be laid out again
/// anymore, and a repeating header will begin to be part of
/// `repeating_headers`.
pub fn flush_orphans(&mut self) {
self.current.lrows_orphan_snapshot = None;
self.flush_pending_headers();
}
/// Indicates all currently pending headers have been successfully placed /// Indicates all currently pending headers have been successfully placed
/// once, since another row has been placed after them, so they are /// once, since another row has been placed after them, so they are
/// certainly not orphans. /// certainly not orphans.
pub fn flush_pending_headers(&mut self) { pub fn flush_pending_headers(&mut self) {
if self.pending_headers.is_empty() {
return;
}
for header in self.pending_headers { for header in self.pending_headers {
if let Repeatable::Repeated(header) = header { if let Repeatable::Repeated(header) = header {
// Vector remains sorted by increasing levels: // Vector remains sorted by increasing levels: