mirror of
https://github.com/typst/typst
synced 2025-07-02 02:02:53 +08:00
move per-region state to Current
This commit is contained in:
parent
1e3719a9ba
commit
9b5c77a3a3
@ -43,6 +43,36 @@ pub struct GridLayouter<'a> {
|
|||||||
/// Rowspans not yet laid out because not all of their spanned rows were
|
/// Rowspans not yet laid out because not all of their spanned rows were
|
||||||
/// laid out yet.
|
/// laid out yet.
|
||||||
pub(super) rowspans: Vec<Rowspan>,
|
pub(super) rowspans: Vec<Rowspan>,
|
||||||
|
/// Grid layout state for the current region.
|
||||||
|
pub(super) current: Current,
|
||||||
|
/// Frames for finished regions.
|
||||||
|
pub(super) finished: Vec<Frame>,
|
||||||
|
/// The amount and height of header rows on each finished region.
|
||||||
|
pub(super) finished_header_rows: Vec<FinishedHeaderRowInfo>,
|
||||||
|
/// Whether this is an RTL grid.
|
||||||
|
pub(super) is_rtl: bool,
|
||||||
|
/// Currently repeating headers, one per level.
|
||||||
|
/// Sorted by increasing levels.
|
||||||
|
///
|
||||||
|
/// Note that some levels may be absent, in particular level 0, which does
|
||||||
|
/// not exist (so the first level is >= 1).
|
||||||
|
pub(super) repeating_headers: Vec<&'a Header>,
|
||||||
|
/// Headers, repeating or not, awaiting their first successful layout.
|
||||||
|
/// Sorted by increasing levels.
|
||||||
|
pub(super) pending_headers: &'a [Repeatable<Header>],
|
||||||
|
pub(super) upcoming_headers: &'a [Repeatable<Header>],
|
||||||
|
/// If this is `Some`, this will receive the currently laid out row's
|
||||||
|
/// height if it is auto or relative. This is used for header height
|
||||||
|
/// calculation.
|
||||||
|
/// TODO: consider refactoring this into something nicer.
|
||||||
|
pub(super) current_row_height: Option<Abs>,
|
||||||
|
/// The span of the grid element.
|
||||||
|
pub(super) span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Grid layout state for the current region. This should be reset or updated
|
||||||
|
/// on each region break.
|
||||||
|
pub struct Current {
|
||||||
/// 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 repeated header rows at the start of the current region.
|
/// The amount of repeated header rows at the start of the current region.
|
||||||
@ -68,32 +98,6 @@ pub struct GridLayouter<'a> {
|
|||||||
///
|
///
|
||||||
/// A value of zero indicates no headers were placed.
|
/// A value of zero indicates no headers were placed.
|
||||||
pub(super) current_last_repeated_header_end: usize,
|
pub(super) current_last_repeated_header_end: usize,
|
||||||
/// Frames for finished regions.
|
|
||||||
pub(super) finished: Vec<Frame>,
|
|
||||||
/// The amount and height of header rows on each finished region.
|
|
||||||
pub(super) finished_header_rows: Vec<FinishedHeaderRowInfo>,
|
|
||||||
/// Whether this is an RTL grid.
|
|
||||||
pub(super) is_rtl: bool,
|
|
||||||
/// Currently repeating headers, one per level.
|
|
||||||
/// Sorted by increasing levels.
|
|
||||||
///
|
|
||||||
/// Note that some levels may be absent, in particular level 0, which does
|
|
||||||
/// not exist (so the first level is >= 1).
|
|
||||||
pub(super) repeating_headers: Vec<&'a Header>,
|
|
||||||
/// Headers, repeating or not, awaiting their first successful layout.
|
|
||||||
/// Sorted by increasing levels.
|
|
||||||
pub(super) pending_headers: &'a [Repeatable<Header>],
|
|
||||||
pub(super) upcoming_headers: &'a [Repeatable<Header>],
|
|
||||||
/// The height for each repeating header that was placed in this region.
|
|
||||||
/// Note that this includes headers not at the top of the region (pending
|
|
||||||
/// headers), and excludes headers removed by virtue of a new, conflicting
|
|
||||||
/// header being found.
|
|
||||||
pub(super) repeating_header_heights: Vec<Abs>,
|
|
||||||
/// If this is `Some`, this will receive the currently laid out row's
|
|
||||||
/// height if it is auto or relative. This is used for header height
|
|
||||||
/// calculation.
|
|
||||||
/// TODO: consider refactoring this into something nicer.
|
|
||||||
pub(super) current_row_height: Option<Abs>,
|
|
||||||
/// Stores the length of `lrows` before a sequence of trailing rows
|
/// Stores the length of `lrows` before a sequence of trailing rows
|
||||||
/// equipped with orphan prevention were laid out. In this case, if no more
|
/// equipped with orphan prevention were laid out. In this case, if no more
|
||||||
/// rows are laid out after those rows before the region ends, the rows
|
/// rows are laid out after those rows before the region ends, the rows
|
||||||
@ -116,11 +120,14 @@ pub struct GridLayouter<'a> {
|
|||||||
/// In particular, non-repeating headers only occupy the initial region,
|
/// In particular, non-repeating headers only occupy the initial region,
|
||||||
/// but disappear on new regions, so they can be ignored.
|
/// but disappear on new regions, so they can be ignored.
|
||||||
pub(super) repeating_header_height: Abs,
|
pub(super) repeating_header_height: Abs,
|
||||||
|
/// The height for each repeating header that was placed in this region.
|
||||||
|
/// Note that this includes headers not at the top of the region (pending
|
||||||
|
/// headers), and excludes headers removed by virtue of a new, conflicting
|
||||||
|
/// header being found.
|
||||||
|
pub(super) repeating_header_heights: Vec<Abs>,
|
||||||
/// The simulated footer height for this region.
|
/// The simulated footer height for this region.
|
||||||
/// The simulation occurs before any rows are laid out for a region.
|
/// The simulation occurs before any rows are laid out for a region.
|
||||||
pub(super) footer_height: Abs,
|
pub(super) footer_height: Abs,
|
||||||
/// The span of the grid element.
|
|
||||||
pub(super) span: Span,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
@ -188,21 +195,23 @@ impl<'a> GridLayouter<'a> {
|
|||||||
lrows: vec![],
|
lrows: vec![],
|
||||||
unbreakable_rows_left: 0,
|
unbreakable_rows_left: 0,
|
||||||
rowspans: vec![],
|
rowspans: vec![],
|
||||||
initial: regions.size,
|
|
||||||
current_repeating_header_rows: 0,
|
|
||||||
current_last_repeated_header_end: 0,
|
|
||||||
finished: vec![],
|
finished: vec![],
|
||||||
finished_header_rows: vec![],
|
finished_header_rows: vec![],
|
||||||
is_rtl: TextElem::dir_in(styles) == Dir::RTL,
|
is_rtl: TextElem::dir_in(styles) == Dir::RTL,
|
||||||
repeating_headers: vec![],
|
repeating_headers: vec![],
|
||||||
upcoming_headers: &grid.headers,
|
upcoming_headers: &grid.headers,
|
||||||
repeating_header_heights: vec![],
|
|
||||||
pending_headers: Default::default(),
|
pending_headers: Default::default(),
|
||||||
lrows_orphan_snapshot: None,
|
|
||||||
current_row_height: None,
|
current_row_height: None,
|
||||||
|
current: Current {
|
||||||
|
initial: regions.size,
|
||||||
|
current_repeating_header_rows: 0,
|
||||||
|
current_last_repeated_header_end: 0,
|
||||||
|
lrows_orphan_snapshot: None,
|
||||||
header_height: Abs::zero(),
|
header_height: Abs::zero(),
|
||||||
repeating_header_height: Abs::zero(),
|
repeating_header_height: Abs::zero(),
|
||||||
|
repeating_header_heights: vec![],
|
||||||
footer_height: Abs::zero(),
|
footer_height: Abs::zero(),
|
||||||
|
},
|
||||||
span,
|
span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,7 +224,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// Ensure rows in the first region will be aware of the possible
|
// Ensure rows in the first region will be aware of the possible
|
||||||
// presence of the footer.
|
// presence of the footer.
|
||||||
self.prepare_footer(footer, engine, 0)?;
|
self.prepare_footer(footer, engine, 0)?;
|
||||||
self.regions.size.y -= self.footer_height;
|
self.regions.size.y -= self.current.footer_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut y = 0;
|
let mut y = 0;
|
||||||
@ -344,7 +353,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.lrows_orphan_snapshot = None;
|
self.current.lrows_orphan_snapshot = None;
|
||||||
self.lrows.push(Row::Fr(v, y, disambiguator))
|
self.lrows.push(Row::Fr(v, y, disambiguator))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1094,7 +1103,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
target.set_max(
|
target.set_max(
|
||||||
region.y
|
region.y
|
||||||
- if i > 0 {
|
- if i > 0 {
|
||||||
self.repeating_header_height + self.footer_height
|
self.current.repeating_header_height + self.current.footer_height
|
||||||
} else {
|
} else {
|
||||||
Abs::zero()
|
Abs::zero()
|
||||||
},
|
},
|
||||||
@ -1325,7 +1334,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
&& !self.regions.size.y.fits(height)
|
&& !self.regions.size.y.fits(height)
|
||||||
&& may_progress_with_offset(
|
&& may_progress_with_offset(
|
||||||
self.regions,
|
self.regions,
|
||||||
self.header_height + self.footer_height,
|
self.current.header_height + self.current.footer_height,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
self.finish_region(engine, false)?;
|
self.finish_region(engine, false)?;
|
||||||
@ -1459,7 +1468,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.lrows_orphan_snapshot = None;
|
self.current.lrows_orphan_snapshot = None;
|
||||||
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));
|
||||||
}
|
}
|
||||||
@ -1470,11 +1479,11 @@ impl<'a> GridLayouter<'a> {
|
|||||||
engine: &mut Engine,
|
engine: &mut Engine,
|
||||||
last: bool,
|
last: bool,
|
||||||
) -> SourceResult<()> {
|
) -> SourceResult<()> {
|
||||||
if let Some(orphan_snapshot) = self.lrows_orphan_snapshot.take() {
|
if let Some(orphan_snapshot) = self.current.lrows_orphan_snapshot.take() {
|
||||||
if !last {
|
if !last {
|
||||||
self.lrows.truncate(orphan_snapshot);
|
self.lrows.truncate(orphan_snapshot);
|
||||||
self.current_repeating_header_rows =
|
self.current.current_repeating_header_rows =
|
||||||
self.current_repeating_header_rows.min(orphan_snapshot);
|
self.current.current_repeating_header_rows.min(orphan_snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1485,11 +1494,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_repeating_header_rows =
|
self.current.current_repeating_header_rows =
|
||||||
self.current_repeating_header_rows.min(self.lrows.len());
|
self.current.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
|
||||||
.current_repeating_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))
|
||||||
@ -1502,21 +1512,21 @@ 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_repeating_header_rows
|
&& self.lrows.len() == self.current.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
|
||||||
// repeating + pending headers, it makes sense to use
|
// repeating + pending headers, it makes sense to use
|
||||||
// 'header_height' and include even non-repeating pending
|
// 'header_height' and include even non-repeating pending
|
||||||
// headers for this check.
|
// headers for this check.
|
||||||
self.header_height + self.footer_height,
|
self.current.header_height + self.current.footer_height,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Header and footer would be alone in this region, but there are more
|
// Header and footer would be alone in this region, but there are more
|
||||||
// rows beyond the header and the footer. Push an empty region.
|
// rows beyond the header and the footer. Push an empty region.
|
||||||
self.lrows.clear();
|
self.lrows.clear();
|
||||||
self.current_last_repeated_header_end = 0;
|
self.current.current_last_repeated_header_end = 0;
|
||||||
self.current_repeating_header_rows = 0;
|
self.current.current_repeating_header_rows = 0;
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -1533,7 +1543,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// This header height isn't doing much as we just confirmed
|
// This header height isn't doing much as we just confirmed
|
||||||
// that there are no headers in this region, but let's keep
|
// that there are no headers in this region, but let's keep
|
||||||
// it here for correctness. It will add zero anyway.
|
// it here for correctness. It will add zero anyway.
|
||||||
self.header_height + self.footer_height,
|
self.current.header_height + self.current.footer_height,
|
||||||
)
|
)
|
||||||
&& footer.start != 0
|
&& footer.start != 0
|
||||||
} else {
|
} else {
|
||||||
@ -1564,9 +1574,9 @@ impl<'a> GridLayouter<'a> {
|
|||||||
|
|
||||||
// Determine the size of the grid in this region, expanding fully if
|
// Determine the size of the grid in this region, expanding fully if
|
||||||
// there are fr rows.
|
// there are fr rows.
|
||||||
let mut size = Size::new(self.width, used).min(self.initial);
|
let mut size = Size::new(self.width, used).min(self.current.initial);
|
||||||
if fr.get() > 0.0 && self.initial.y.is_finite() {
|
if fr.get() > 0.0 && self.current.initial.y.is_finite() {
|
||||||
size.y = self.initial.y;
|
size.y = self.current.initial.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The frame for the region.
|
// The frame for the region.
|
||||||
@ -1588,7 +1598,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let height = frame.height();
|
let height = frame.height();
|
||||||
if i < self.current_repeating_header_rows {
|
if i < self.current.current_repeating_header_rows {
|
||||||
header_row_height += height;
|
header_row_height += height;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1688,18 +1698,18 @@ impl<'a> GridLayouter<'a> {
|
|||||||
output,
|
output,
|
||||||
rrows,
|
rrows,
|
||||||
FinishedHeaderRowInfo {
|
FinishedHeaderRowInfo {
|
||||||
repeated: self.current_repeating_header_rows,
|
repeated: self.current.current_repeating_header_rows,
|
||||||
last_repeated_header_end: self.current_last_repeated_header_end,
|
last_repeated_header_end: self.current.current_last_repeated_header_end,
|
||||||
height: header_row_height,
|
height: header_row_height,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if !last {
|
if !last {
|
||||||
self.current_repeating_header_rows = 0;
|
self.current.current_repeating_header_rows = 0;
|
||||||
self.current_last_repeated_header_end = 0;
|
self.current.current_last_repeated_header_end = 0;
|
||||||
self.header_height = Abs::zero();
|
self.current.header_height = Abs::zero();
|
||||||
self.repeating_header_height = Abs::zero();
|
self.current.repeating_header_height = Abs::zero();
|
||||||
self.repeating_header_heights.clear();
|
self.current.repeating_header_heights.clear();
|
||||||
|
|
||||||
let disambiguator = self.finished.len();
|
let disambiguator = self.finished.len();
|
||||||
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
|
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
|
||||||
@ -1710,7 +1720,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// Note that header layout will only subtract this again if it has
|
// Note that header layout will only subtract this again if it has
|
||||||
// to skip regions to fit headers, so there is no risk of
|
// to skip regions to fit headers, so there is no risk of
|
||||||
// subtracting this twice.
|
// subtracting this twice.
|
||||||
self.regions.size.y -= self.footer_height;
|
self.regions.size.y -= self.current.footer_height;
|
||||||
|
|
||||||
if !self.repeating_headers.is_empty() || !self.pending_headers.is_empty() {
|
if !self.repeating_headers.is_empty() || !self.pending_headers.is_empty() {
|
||||||
// Add headers to the new region.
|
// Add headers to the new region.
|
||||||
@ -1732,14 +1742,14 @@ impl<'a> GridLayouter<'a> {
|
|||||||
self.finished.push(output);
|
self.finished.push(output);
|
||||||
self.rrows.push(resolved_rows);
|
self.rrows.push(resolved_rows);
|
||||||
self.regions.next();
|
self.regions.next();
|
||||||
self.initial = self.regions.size;
|
self.current.initial = self.regions.size;
|
||||||
|
|
||||||
if !self.grid.headers.is_empty() {
|
if !self.grid.headers.is_empty() {
|
||||||
self.finished_header_rows.push(header_row_info);
|
self.finished_header_rows.push(header_row_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure orphan prevention is handled before resolving rows.
|
// Ensure orphan prevention is handled before resolving rows.
|
||||||
debug_assert!(self.lrows_orphan_snapshot.is_none());
|
debug_assert!(self.current.lrows_orphan_snapshot.is_none());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,15 +142,16 @@ impl<'a> GridLayouter<'a> {
|
|||||||
|
|
||||||
// Ensure upcoming rows won't see that these headers will occupy any
|
// Ensure upcoming rows won't see that these headers will occupy any
|
||||||
// space in future regions anymore.
|
// space in future regions anymore.
|
||||||
for removed_height in self.repeating_header_heights.drain(first_conflicting_pos..)
|
for removed_height in
|
||||||
|
self.current.repeating_header_heights.drain(first_conflicting_pos..)
|
||||||
{
|
{
|
||||||
self.repeating_header_height -= removed_height;
|
self.current.repeating_header_height -= removed_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-repeating headers stop at the pending stage for orphan
|
// Non-repeating headers stop at the pending stage for orphan
|
||||||
// prevention only. Flushing pending headers, so those will no longer
|
// prevention only. Flushing pending headers, so those will no longer
|
||||||
// appear in a future region.
|
// appear in a future region.
|
||||||
self.header_height = self.repeating_header_height;
|
self.current.header_height = self.current.repeating_header_height;
|
||||||
|
|
||||||
// Let's try to place them at least once.
|
// Let's try to place them at least once.
|
||||||
// This might be a waste as we could generate an orphan and thus have
|
// This might be a waste as we could generate an orphan and thus have
|
||||||
@ -223,7 +224,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// available size for consistency with the first region, so we
|
// available size for consistency with the first region, so we
|
||||||
// need to consider the footer when evaluating if skipping yet
|
// need to consider the footer when evaluating if skipping yet
|
||||||
// another region would make a difference.
|
// another region would make a difference.
|
||||||
self.footer_height,
|
self.current.footer_height,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Advance regions without any output until we can place the
|
// Advance regions without any output until we can place the
|
||||||
@ -238,7 +239,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// if 'full' changes? (Assuming height doesn't change for now...)
|
// if 'full' changes? (Assuming height doesn't change for now...)
|
||||||
skipped_region = true;
|
skipped_region = true;
|
||||||
|
|
||||||
self.regions.size.y -= self.footer_height;
|
self.regions.size.y -= self.current.footer_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
|
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
|
||||||
@ -246,11 +247,11 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// Simulate the footer again; the region's 'full' might have
|
// Simulate the footer again; the region's 'full' might have
|
||||||
// changed.
|
// changed.
|
||||||
// TODO: maybe this should go in the loop, a bit hacky as is...
|
// TODO: maybe this should go in the loop, a bit hacky as is...
|
||||||
self.regions.size.y += self.footer_height;
|
self.regions.size.y += self.current.footer_height;
|
||||||
self.footer_height = self
|
self.current.footer_height = self
|
||||||
.simulate_footer(footer, &self.regions, engine, disambiguator)?
|
.simulate_footer(footer, &self.regions, engine, disambiguator)?
|
||||||
.height;
|
.height;
|
||||||
self.regions.size.y -= self.footer_height;
|
self.regions.size.y -= self.current.footer_height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,22 +266,22 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// within 'layout_row'.
|
// within 'layout_row'.
|
||||||
self.unbreakable_rows_left += repeating_header_rows + pending_header_rows;
|
self.unbreakable_rows_left += repeating_header_rows + pending_header_rows;
|
||||||
|
|
||||||
self.current_last_repeated_header_end =
|
self.current.current_last_repeated_header_end =
|
||||||
self.repeating_headers.last().map(|h| h.end).unwrap_or_default();
|
self.repeating_headers.last().map(|h| h.end).unwrap_or_default();
|
||||||
|
|
||||||
// Reset the header height for this region.
|
// Reset the header height for this region.
|
||||||
// It will be re-calculated when laying out each header row.
|
// It will be re-calculated when laying out each header row.
|
||||||
self.header_height = Abs::zero();
|
self.current.header_height = Abs::zero();
|
||||||
self.repeating_header_height = Abs::zero();
|
self.current.repeating_header_height = Abs::zero();
|
||||||
self.repeating_header_heights.clear();
|
self.current.repeating_header_heights.clear();
|
||||||
|
|
||||||
// Use indices to avoid double borrow. We don't mutate headers in
|
// Use indices to avoid double borrow. We don't mutate headers in
|
||||||
// 'layout_row' so this is fine.
|
// 'layout_row' so this is fine.
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while let Some(&header) = self.repeating_headers.get(i) {
|
while let Some(&header) = self.repeating_headers.get(i) {
|
||||||
let header_height = self.layout_header_rows(header, engine, disambiguator)?;
|
let header_height = self.layout_header_rows(header, engine, disambiguator)?;
|
||||||
self.header_height += header_height;
|
self.current.header_height += header_height;
|
||||||
self.repeating_header_height += header_height;
|
self.current.repeating_header_height += header_height;
|
||||||
|
|
||||||
// We assume that this vector will be sorted according
|
// We assume that this vector will be sorted according
|
||||||
// to increasing levels like 'repeating_headers' and
|
// to increasing levels like 'repeating_headers' and
|
||||||
@ -300,26 +301,26 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// headers which have now stopped repeating. They are always at
|
// headers which have now stopped repeating. They are always at
|
||||||
// the end and new pending headers respect the existing sort,
|
// the end and new pending headers respect the existing sort,
|
||||||
// so the vector will remain sorted.
|
// so the vector will remain sorted.
|
||||||
self.repeating_header_heights.push(header_height);
|
self.current.repeating_header_heights.push(header_height);
|
||||||
|
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.current_repeating_header_rows = self.lrows.len();
|
self.current.current_repeating_header_rows = self.lrows.len();
|
||||||
|
|
||||||
if !self.pending_headers.is_empty() {
|
if !self.pending_headers.is_empty() {
|
||||||
// Restore snapshot: if pending headers placed again turn out to be
|
// Restore snapshot: if pending headers placed again turn out to be
|
||||||
// orphans, remove their rows again.
|
// orphans, remove their rows again.
|
||||||
self.lrows_orphan_snapshot = Some(self.lrows.len());
|
self.current.lrows_orphan_snapshot = Some(self.lrows.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
for header in self.pending_headers {
|
for header in self.pending_headers {
|
||||||
let header_height =
|
let header_height =
|
||||||
self.layout_header_rows(header.unwrap(), engine, disambiguator)?;
|
self.layout_header_rows(header.unwrap(), engine, disambiguator)?;
|
||||||
self.header_height += header_height;
|
self.current.header_height += header_height;
|
||||||
if matches!(header, Repeatable::Repeated(_)) {
|
if matches!(header, Repeatable::Repeated(_)) {
|
||||||
self.repeating_header_height += header_height;
|
self.current.repeating_header_height += header_height;
|
||||||
self.repeating_header_heights.push(header_height);
|
self.current.repeating_header_heights.push(header_height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,7 +360,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// 'header_height == repeating_header_height' here
|
// 'header_height == repeating_header_height' here
|
||||||
// (there won't be any pending headers at this point, other
|
// (there won't be any pending headers at this point, other
|
||||||
// than the ones we are about to place).
|
// than the ones we are about to place).
|
||||||
self.header_height + self.footer_height,
|
self.current.header_height + self.current.footer_height,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Note that, after the first region skip, the new headers will go
|
// Note that, after the first region skip, the new headers will go
|
||||||
@ -382,10 +383,10 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// region, so multi-page rows and cells can effectively ignore
|
// region, so multi-page rows and cells can effectively ignore
|
||||||
// this header.
|
// this header.
|
||||||
if !short_lived {
|
if !short_lived {
|
||||||
self.header_height += header_height;
|
self.current.header_height += header_height;
|
||||||
if matches!(header, Repeatable::Repeated(_)) {
|
if matches!(header, Repeatable::Repeated(_)) {
|
||||||
self.repeating_header_height += header_height;
|
self.current.repeating_header_height += header_height;
|
||||||
self.repeating_header_heights.push(header_height);
|
self.current.repeating_header_heights.push(header_height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -393,7 +394,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// 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 {
|
||||||
self.lrows_orphan_snapshot = Some(initial_row_count);
|
self.current.lrows_orphan_snapshot = Some(initial_row_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -466,7 +467,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// That is unnecessary at the moment as 'prepare_footers' is only
|
// That is unnecessary at the moment as 'prepare_footers' is only
|
||||||
// called at the start of the region, but what about when we can have
|
// called at the start of the region, but what about when we can have
|
||||||
// footers in the middle of the region? Let's think about this then.
|
// footers in the middle of the region? Let's think about this then.
|
||||||
self.footer_height = if skipped_region {
|
self.current.footer_height = if skipped_region {
|
||||||
// Simulate the footer again; the region's 'full' might have
|
// Simulate the footer again; the region's 'full' might have
|
||||||
// changed.
|
// changed.
|
||||||
self.simulate_footer(footer, &self.regions, engine, disambiguator)?
|
self.simulate_footer(footer, &self.regions, engine, disambiguator)?
|
||||||
@ -489,7 +490,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// Ensure footer rows have their own height available.
|
// Ensure footer rows have their own height available.
|
||||||
// Won't change much as we're creating an unbreakable row group
|
// Won't change much as we're creating an unbreakable row group
|
||||||
// anyway, so this is mostly for correctness.
|
// anyway, so this is mostly for correctness.
|
||||||
self.regions.size.y += self.footer_height;
|
self.regions.size.y += self.current.footer_height;
|
||||||
|
|
||||||
let footer_len = self.grid.rows.len() - footer.start;
|
let footer_len = self.grid.rows.len() - footer.start;
|
||||||
self.unbreakable_rows_left += footer_len;
|
self.unbreakable_rows_left += footer_len;
|
||||||
|
@ -263,7 +263,7 @@ impl GridLayouter<'_> {
|
|||||||
// due to orphan/widow prevention, which explains the usage of
|
// due to orphan/widow prevention, which explains the usage of
|
||||||
// 'header_height' (include non-repeating but pending headers) rather
|
// 'header_height' (include non-repeating but pending headers) rather
|
||||||
// than 'repeating_header_height'.
|
// than 'repeating_header_height'.
|
||||||
self.header_height + self.footer_height,
|
self.current.header_height + self.current.footer_height,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
self.finish_region(engine, false)?;
|
self.finish_region(engine, false)?;
|
||||||
@ -422,7 +422,9 @@ impl GridLayouter<'_> {
|
|||||||
let mapped_regions = self.regions.map(&mut custom_backlog, |size| {
|
let mapped_regions = self.regions.map(&mut custom_backlog, |size| {
|
||||||
Size::new(
|
Size::new(
|
||||||
size.x,
|
size.x,
|
||||||
size.y - self.repeating_header_height - self.footer_height,
|
size.y
|
||||||
|
- self.current.repeating_header_height
|
||||||
|
- self.current.footer_height,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -535,7 +537,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_repeating_header_rows]
|
[..self.current.current_repeating_header_rows]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|row| match row {
|
.map(|row| match row {
|
||||||
Row::Frame(frame, _, _) => frame.height(),
|
Row::Frame(frame, _, _) => frame.height(),
|
||||||
@ -543,7 +545,9 @@ impl GridLayouter<'_> {
|
|||||||
})
|
})
|
||||||
.sum();
|
.sum();
|
||||||
|
|
||||||
self.initial.y - initial_header_height - self.footer_height
|
self.current.initial.y
|
||||||
|
- initial_header_height
|
||||||
|
- self.current.footer_height
|
||||||
} else {
|
} else {
|
||||||
// When measuring unbreakable auto rows, infinite
|
// When measuring unbreakable auto rows, infinite
|
||||||
// height is available for content to expand.
|
// height is available for content to expand.
|
||||||
@ -559,7 +563,8 @@ impl GridLayouter<'_> {
|
|||||||
// Assume only repeating headers will survive starting at
|
// Assume only repeating headers will survive starting at
|
||||||
// the next region.
|
// the next region.
|
||||||
let backlog = self.regions.backlog.iter().map(|&size| {
|
let backlog = self.regions.backlog.iter().map(|&size| {
|
||||||
size - self.repeating_header_height - self.footer_height
|
size - self.current.repeating_header_height
|
||||||
|
- self.current.footer_height
|
||||||
});
|
});
|
||||||
|
|
||||||
heights_up_to_current_region.chain(backlog).collect::<Vec<_>>()
|
heights_up_to_current_region.chain(backlog).collect::<Vec<_>>()
|
||||||
@ -574,10 +579,10 @@ impl GridLayouter<'_> {
|
|||||||
height = *rowspan_height;
|
height = *rowspan_height;
|
||||||
backlog = None;
|
backlog = None;
|
||||||
full = rowspan_full;
|
full = rowspan_full;
|
||||||
last = self
|
last = self.regions.last.map(|size| {
|
||||||
.regions
|
size - self.current.repeating_header_height
|
||||||
.last
|
- self.current.footer_height
|
||||||
.map(|size| size - self.repeating_header_height - self.footer_height);
|
});
|
||||||
} else {
|
} else {
|
||||||
// The rowspan started in the current region, as its vector
|
// The rowspan started in the current region, as its vector
|
||||||
// of heights in regions is currently empty.
|
// of heights in regions is currently empty.
|
||||||
@ -782,7 +787,8 @@ impl GridLayouter<'_> {
|
|||||||
// Subtract the repeating header and footer height, since that's
|
// Subtract the repeating header and footer height, since that's
|
||||||
// the height we used when subtracting from the region backlog's
|
// the height we used when subtracting from the region backlog's
|
||||||
// heights while measuring cells.
|
// heights while measuring cells.
|
||||||
simulated_regions.size.y -= self.repeating_header_height + self.footer_height;
|
simulated_regions.size.y -=
|
||||||
|
self.current.repeating_header_height + self.current.footer_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(original_last_resolved_size) = last_resolved_size {
|
if let Some(original_last_resolved_size) = last_resolved_size {
|
||||||
@ -921,8 +927,8 @@ impl GridLayouter<'_> {
|
|||||||
// rowspan, since headers and footers are unbreakable, so
|
// rowspan, since headers and footers are unbreakable, so
|
||||||
// assuming the repeating header height and footer height
|
// assuming the repeating header height and footer height
|
||||||
// won't change is safe.
|
// won't change is safe.
|
||||||
self.repeating_header_height,
|
self.current.repeating_header_height,
|
||||||
self.footer_height,
|
self.current.footer_height,
|
||||||
);
|
);
|
||||||
|
|
||||||
let total_spanned_height = rowspan_simulator.simulate_rowspan_layout(
|
let total_spanned_height = rowspan_simulator.simulate_rowspan_layout(
|
||||||
@ -1006,7 +1012,7 @@ impl GridLayouter<'_> {
|
|||||||
extra_amount_to_grow -= simulated_regions.size.y.max(Abs::zero());
|
extra_amount_to_grow -= simulated_regions.size.y.max(Abs::zero());
|
||||||
simulated_regions.next();
|
simulated_regions.next();
|
||||||
simulated_regions.size.y -=
|
simulated_regions.size.y -=
|
||||||
self.repeating_header_height + self.footer_height;
|
self.current.repeating_header_height + self.current.footer_height;
|
||||||
disambiguator += 1;
|
disambiguator += 1;
|
||||||
}
|
}
|
||||||
simulated_regions.size.y -= extra_amount_to_grow;
|
simulated_regions.size.y -= extra_amount_to_grow;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user