mirror of
https://github.com/typst/typst
synced 2025-05-18 11:05:28 +08:00
use exclusively snapshots for pending header orphan prevention
- delete current_header_rows
This commit is contained in:
parent
daac9bba76
commit
f6bc7f8d45
@ -45,19 +45,21 @@ pub struct GridLayouter<'a> {
|
|||||||
pub(super) rowspans: Vec<Rowspan>,
|
pub(super) rowspans: Vec<Rowspan>,
|
||||||
/// The initial size of the current region before we started subtracting.
|
/// The initial size of the current region before we started subtracting.
|
||||||
pub(super) initial: Size,
|
pub(super) initial: Size,
|
||||||
/// The amount of header rows at the start of the current region. Note that
|
/// The amount of repeated header rows at the start of the current region.
|
||||||
/// `repeating_headers` and `pending_headers` can change if we find a new
|
/// Note that `repeating_headers` and `pending_headers` can change if we
|
||||||
/// header inside the region, so this has to be stored separately for each
|
/// find a new header inside the region (not at the top), so this field
|
||||||
/// new region - we can't just reuse those.
|
/// is required to access information from the top of the region.
|
||||||
///
|
///
|
||||||
/// This is used for orphan prevention checks (if there are no rows other
|
/// This is used for orphan prevention checks (if there are no rows other
|
||||||
/// than header rows upon finishing a region, we'd have an orphan). In
|
/// than repeated header rows upon finishing a region, we'd have an orphan).
|
||||||
/// addition, this information is stored for each finished region so
|
/// Note that non-repeated and pending repeated header rows are not included
|
||||||
/// rowspans placed later can know which rows to skip at the top of the
|
/// in this number and thus use a separate mechanism for orphan prevention
|
||||||
/// region when spanning more than one page.
|
/// (`lrows_orphan_shapshot` field).
|
||||||
pub(super) current_header_rows: usize,
|
///
|
||||||
/// Similar to the above, but stopping after the last repeated row at the
|
/// In addition, this information is used on finish region to calculate the
|
||||||
/// top.
|
/// total height of resolved header rows at the top of the region, which is
|
||||||
|
/// used by multi-page rowspans so they can properly skip the header rows
|
||||||
|
/// at the top of the region during layout.
|
||||||
pub(super) current_repeating_header_rows: usize,
|
pub(super) current_repeating_header_rows: usize,
|
||||||
/// The end bound of the last repeating header at the start of the region.
|
/// The end bound of the last repeating header at the start of the region.
|
||||||
/// The last row might have disappeared due to being empty, so this is how
|
/// The last row might have disappeared due to being empty, so this is how
|
||||||
@ -187,7 +189,6 @@ impl<'a> GridLayouter<'a> {
|
|||||||
unbreakable_rows_left: 0,
|
unbreakable_rows_left: 0,
|
||||||
rowspans: vec![],
|
rowspans: vec![],
|
||||||
initial: regions.size,
|
initial: regions.size,
|
||||||
current_header_rows: 0,
|
|
||||||
current_repeating_header_rows: 0,
|
current_repeating_header_rows: 0,
|
||||||
current_last_repeated_header_end: 0,
|
current_last_repeated_header_end: 0,
|
||||||
finished: vec![],
|
finished: vec![],
|
||||||
@ -1472,7 +1473,6 @@ impl<'a> GridLayouter<'a> {
|
|||||||
if let Some(orphan_snapshot) = self.lrows_orphan_snapshot.take() {
|
if let Some(orphan_snapshot) = self.lrows_orphan_snapshot.take() {
|
||||||
if !last {
|
if !last {
|
||||||
self.lrows.truncate(orphan_snapshot);
|
self.lrows.truncate(orphan_snapshot);
|
||||||
self.current_header_rows = self.current_header_rows.min(orphan_snapshot);
|
|
||||||
self.current_repeating_header_rows =
|
self.current_repeating_header_rows =
|
||||||
self.current_repeating_header_rows.min(orphan_snapshot);
|
self.current_repeating_header_rows.min(orphan_snapshot);
|
||||||
}
|
}
|
||||||
@ -1485,13 +1485,12 @@ impl<'a> GridLayouter<'a> {
|
|||||||
{
|
{
|
||||||
// Remove the last row in the region if it is a gutter row.
|
// Remove the last row in the region if it is a gutter row.
|
||||||
self.lrows.pop().unwrap();
|
self.lrows.pop().unwrap();
|
||||||
self.current_header_rows = self.current_header_rows.min(self.lrows.len());
|
|
||||||
self.current_repeating_header_rows =
|
self.current_repeating_header_rows =
|
||||||
self.current_repeating_header_rows.min(self.lrows.len());
|
self.current_repeating_header_rows.min(self.lrows.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
let footer_would_be_widow = if let Some(last_header_row) = self
|
let footer_would_be_widow = if let Some(last_header_row) = self
|
||||||
.current_header_rows
|
.current_repeating_header_rows
|
||||||
.checked_sub(1)
|
.checked_sub(1)
|
||||||
.and_then(|last_header_index| self.lrows.get(last_header_index))
|
.and_then(|last_header_index| self.lrows.get(last_header_index))
|
||||||
{
|
{
|
||||||
@ -1503,7 +1502,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(Repeatable::as_repeated)
|
.and_then(Repeatable::as_repeated)
|
||||||
.is_none_or(|footer| footer.start != last_header_end)
|
.is_none_or(|footer| footer.start != last_header_end)
|
||||||
&& self.lrows.len() == self.current_header_rows
|
&& self.lrows.len() == self.current_repeating_header_rows
|
||||||
&& may_progress_with_offset(
|
&& may_progress_with_offset(
|
||||||
self.regions,
|
self.regions,
|
||||||
// Since we're trying to find a region where to place all
|
// Since we're trying to find a region where to place all
|
||||||
@ -1518,7 +1517,6 @@ impl<'a> GridLayouter<'a> {
|
|||||||
self.lrows.clear();
|
self.lrows.clear();
|
||||||
self.current_last_repeated_header_end = 0;
|
self.current_last_repeated_header_end = 0;
|
||||||
self.current_repeating_header_rows = 0;
|
self.current_repeating_header_rows = 0;
|
||||||
self.current_header_rows = 0;
|
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -1596,7 +1594,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let height = frame.height();
|
let height = frame.height();
|
||||||
if i < self.current_header_rows {
|
if i < self.current_repeating_header_rows {
|
||||||
header_row_height += height;
|
header_row_height += height;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1703,7 +1701,6 @@ impl<'a> GridLayouter<'a> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if !last {
|
if !last {
|
||||||
self.current_header_rows = 0;
|
|
||||||
self.current_repeating_header_rows = 0;
|
self.current_repeating_header_rows = 0;
|
||||||
self.current_last_repeated_header_end = 0;
|
self.current_last_repeated_header_end = 0;
|
||||||
self.header_height = Abs::zero();
|
self.header_height = Abs::zero();
|
||||||
|
@ -299,10 +299,6 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include both repeating and pending header rows as this number is
|
|
||||||
// used for orphan prevention.
|
|
||||||
self.current_header_rows = self.lrows.len();
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,11 +323,6 @@ impl<'a> GridLayouter<'a> {
|
|||||||
0,
|
0,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// We already take the footer into account below.
|
|
||||||
// While skipping regions, footer height won't be automatically
|
|
||||||
// re-calculated until the end.
|
|
||||||
let mut skipped_region = false;
|
|
||||||
|
|
||||||
// TODO: remove this 'unbreakable rows left check',
|
// TODO: remove this 'unbreakable rows left check',
|
||||||
// consider if we can already be in an unbreakable row group?
|
// consider if we can already be in an unbreakable row group?
|
||||||
while self.unbreakable_rows_left == 0
|
while self.unbreakable_rows_left == 0
|
||||||
@ -351,15 +342,12 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// at the top of the region, but after the repeating headers that
|
// at the top of the region, but after the repeating headers that
|
||||||
// remained (which will be automatically placed in 'finish_region').
|
// remained (which will be automatically placed in 'finish_region').
|
||||||
self.finish_region(engine, false)?;
|
self.finish_region(engine, false)?;
|
||||||
skipped_region = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.unbreakable_rows_left +=
|
self.unbreakable_rows_left +=
|
||||||
total_header_row_count(headers.iter().map(Repeatable::unwrap));
|
total_header_row_count(headers.iter().map(Repeatable::unwrap));
|
||||||
|
|
||||||
let initial_row_count = self.lrows.len();
|
let initial_row_count = self.lrows.len();
|
||||||
let placing_at_the_start =
|
|
||||||
skipped_region || initial_row_count == self.current_header_rows;
|
|
||||||
for header in headers {
|
for header in headers {
|
||||||
let header_height = self.layout_header_rows(header.unwrap(), engine, 0)?;
|
let header_height = self.layout_header_rows(header.unwrap(), engine, 0)?;
|
||||||
|
|
||||||
@ -378,11 +366,6 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if placing_at_the_start {
|
|
||||||
// Track header rows at the start of the region.
|
|
||||||
self.current_header_rows = self.lrows.len();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove new headers at the end of the region if upcoming child doesn't fit.
|
// Remove new headers at the end of the region if upcoming child doesn't fit.
|
||||||
// TODO: Short lived if footer comes afterwards
|
// TODO: Short lived if footer comes afterwards
|
||||||
if !short_lived {
|
if !short_lived {
|
||||||
|
@ -535,7 +535,7 @@ impl GridLayouter<'_> {
|
|||||||
// and unbreakable rows in general, so there is no risk
|
// and unbreakable rows in general, so there is no risk
|
||||||
// of accessing an incomplete list of rows.
|
// of accessing an incomplete list of rows.
|
||||||
let initial_header_height = self.lrows
|
let initial_header_height = self.lrows
|
||||||
[..self.current_header_rows]
|
[..self.current_repeating_header_rows]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|row| match row {
|
.map(|row| match row {
|
||||||
Row::Frame(frame, _, _) => frame.height(),
|
Row::Frame(frame, _, _) => frame.height(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user