change Repeatable to struct

This commit is contained in:
PgBiel 2025-06-10 02:31:53 -03:00
parent 9139baf263
commit 75a4cfb2e4
4 changed files with 54 additions and 59 deletions

View File

@ -274,7 +274,8 @@ impl<'a> GridLayouter<'a> {
pub fn layout(mut self, engine: &mut Engine) -> SourceResult<Fragment> {
self.measure_columns(engine)?;
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
if let Some(footer) = self.grid.footer.as_ref().and_then(Repeatable::as_repeated)
{
// Ensure rows in the first region will be aware of the possible
// presence of the footer.
self.prepare_footer(footer, engine, 0)?;
@ -296,7 +297,9 @@ impl<'a> GridLayouter<'a> {
}
}
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
if let Some(footer) =
self.grid.footer.as_ref().and_then(Repeatable::as_repeated)
{
if y >= footer.start {
if y == footer.start {
self.layout_footer(footer, engine, self.finished.len())?;
@ -1564,14 +1567,15 @@ impl<'a> GridLayouter<'a> {
// TODO(subfooters): explicitly check for short-lived footers.
// TODO(subfooters): widow prevention for non-repeated footers with a
// similar mechanism / when implementing multiple footers.
let footer_would_be_widow =
matches!(self.grid.footer, Some(Repeatable::Repeated(_)))
&& self.current.lrows.is_empty()
&& self.current.could_progress_at_top;
let footer_would_be_widow = matches!(&self.grid.footer, Some(footer) if footer.repeated)
&& self.current.lrows.is_empty()
&& self.current.could_progress_at_top;
let mut laid_out_footer_start = None;
if !footer_would_be_widow {
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
if let Some(footer) =
self.grid.footer.as_ref().and_then(Repeatable::as_repeated)
{
// Don't layout the footer if it would be alone with the header
// in the page (hence the widow check), and don't layout it
// twice (check below).
@ -1735,7 +1739,9 @@ impl<'a> GridLayouter<'a> {
self.current.repeating_header_heights.clear();
let disambiguator = self.finished.len();
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
if let Some(footer) =
self.grid.footer.as_ref().and_then(Repeatable::as_repeated)
{
self.prepare_footer(footer, engine, disambiguator)?;
}

View File

@ -170,7 +170,7 @@ impl<'a> GridLayouter<'a> {
}
for header in self.pending_headers {
if let Repeatable::Repeated(header) = header {
if header.repeated {
// Vector remains sorted by increasing levels:
// - 'pending_headers' themselves are sorted, since we only
// push non-mutually-conflicting headers at a time.
@ -238,8 +238,8 @@ impl<'a> GridLayouter<'a> {
self.current.initial_after_repeats = self.regions.size.y;
}
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
if skipped_region {
if let Some(footer) = &self.grid.footer {
if footer.repeated && skipped_region {
// Simulate the footer again; the region's 'full' might have
// changed.
self.regions.size.y += self.current.footer_height;
@ -321,13 +321,13 @@ impl<'a> GridLayouter<'a> {
let mut has_non_repeated_pending_header = false;
for header in self.pending_headers {
if matches!(header, Repeatable::NotRepeated(_)) {
if !header.repeated {
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(_)) {
if header.repeated {
self.current.repeating_header_height += header_height;
self.current.repeating_header_heights.push(header_height);
}
@ -410,7 +410,7 @@ impl<'a> GridLayouter<'a> {
// it is guaranteed this header won't appear in a future
// region, so multi-page rows and cells can effectively ignore
// this header.
if !short_lived && matches!(header, Repeatable::Repeated(_)) {
if !short_lived && header.repeated {
self.current.repeating_header_height += header_height;
self.current.repeating_header_heights.push(header_height);
if at_top {
@ -519,11 +519,7 @@ impl<'a> GridLayouter<'a> {
// anyway, so this is mostly for correctness.
self.regions.size.y += self.current.footer_height;
let repeats = self
.grid
.footer
.as_ref()
.is_some_and(|f| matches!(f, Repeatable::Repeated(_)));
let repeats = self.grid.footer.as_ref().is_some_and(|f| f.repeated);
let footer_len = self.grid.rows.len() - footer.start;
self.unbreakable_rows_left += footer_len;

View File

@ -238,8 +238,8 @@ impl GridLayouter<'_> {
// current row is dynamic and depends on the amount of upcoming
// unbreakable cells (with or without a rowspan setting).
let mut amount_unbreakable_rows = None;
if let Some(Repeatable::NotRepeated(footer)) = &self.grid.footer {
if current_row >= footer.start {
if let Some(footer) = &self.grid.footer {
if !footer.repeated && current_row >= footer.start {
// Non-repeated footer, so keep it unbreakable.
//
// TODO(subfooters): This will become unnecessary
@ -400,7 +400,7 @@ impl GridLayouter<'_> {
if breakable
&& (!self.repeating_headers.is_empty()
|| !self.pending_headers.is_empty()
|| matches!(self.grid.footer, Some(Repeatable::Repeated(_))))
|| matches!(&self.grid.footer, Some(footer) if footer.repeated))
{
// Subtract header and footer height from all upcoming regions
// when measuring the cell, including the last repeated region.
@ -1176,14 +1176,15 @@ impl<'a> RowspanSimulator<'a> {
(None, Abs::zero())
};
let footer_height =
if let Some(Repeatable::Repeated(footer)) = &layouter.grid.footer {
layouter
.simulate_footer(footer, &self.regions, engine, disambiguator)?
.height
} else {
Abs::zero()
};
let footer_height = if let Some(footer) =
layouter.grid.footer.as_ref().and_then(Repeatable::as_repeated)
{
layouter
.simulate_footer(footer, &self.regions, engine, disambiguator)?
.height
} else {
Abs::zero()
};
let mut skipped_region = false;
@ -1211,7 +1212,9 @@ impl<'a> RowspanSimulator<'a> {
};
}
if let Some(Repeatable::Repeated(footer)) = &layouter.grid.footer {
if let Some(footer) =
layouter.grid.footer.as_ref().and_then(Repeatable::as_repeated)
{
self.footer_height = if skipped_region {
// Simulate footers again, at the new region, as
// the full region height may change.

View File

@ -465,23 +465,23 @@ impl Footer {
}
}
/// A possibly repeatable grid child.
/// A possibly repeatable grid child (header or footer).
///
/// It still exists even when not repeatable, but must not have additional
/// considerations by grid layout, other than for consistency (such as making
/// a certain group of rows unbreakable).
pub enum Repeatable<T> {
/// The user asked this grid child to repeat.
Repeated(T),
/// The user asked this grid child to not repeat.
NotRepeated(T),
pub struct Repeatable<T> {
inner: T,
/// Whether the user requested the child to repeat.
pub repeated: bool,
}
impl<T> Deref for Repeatable<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.unwrap()
&self.inner
}
}
@ -490,28 +490,23 @@ impl<T> Repeatable<T> {
/// it repeats.
#[inline]
pub fn unwrap(&self) -> &T {
match self {
Self::Repeated(repeated) => repeated,
Self::NotRepeated(not_repeated) => not_repeated,
}
&self.inner
}
/// Gets the value inside this repeatable, regardless of whether
/// it repeats (mutably).
#[inline]
pub fn unwrap_mut(&mut self) -> &mut T {
match self {
Self::Repeated(repeated) => repeated,
Self::NotRepeated(not_repeated) => not_repeated,
}
&mut self.inner
}
/// Returns `Some` if the value is repeated, `None` otherwise.
#[inline]
pub fn as_repeated(&self) -> Option<&T> {
match self {
Self::Repeated(repeated) => Some(repeated),
Self::NotRepeated(_) => None,
if self.repeated {
Some(&self.inner)
} else {
None
}
}
}
@ -906,7 +901,7 @@ impl<'a> CellGrid<'a> {
#[inline]
pub fn has_repeated_headers(&self) -> bool {
self.headers.iter().any(|h| matches!(h, Repeatable::Repeated(_)))
self.headers.iter().any(|h| h.repeated)
}
}
@ -1614,11 +1609,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
conflicting_header.unwrap_mut().short_lived = true;
}
headers.push(if row_group.repeat {
Repeatable::Repeated(data)
} else {
Repeatable::NotRepeated(data)
});
headers.push(Repeatable { inner: data, repeated: row_group.repeat });
}
RowGroupKind::Footer => {
@ -1920,10 +1911,9 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
// footers.
// TODO(subfooters): Switch this to marking the last N
// consecutive footers as short lived.
if repeat_footer && at_least_one_cell {
Repeatable::Repeated(footer)
} else {
Repeatable::NotRepeated(footer)
Repeatable {
inner: footer,
repeated: repeat_footer && at_least_one_cell,
}
});