use super::rowspans::UnbreakableRowGroup;
use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::layout::{Abs, Axes, Frame, GridLayouter, Regions};
pub(super) struct Header {
pub(super) end: usize,
}
pub(super) struct Footer {
pub(super) start: usize,
}
pub(super) enum Repeatable<T> {
Repeated(T),
NotRepeated(T),
}
impl<T> Repeatable<T> {
pub(super) fn unwrap(&self) -> &T {
match self {
Self::Repeated(repeated) => repeated,
Self::NotRepeated(not_repeated) => not_repeated,
}
}
pub(super) fn as_repeated(&self) -> Option<&T> {
match self {
Self::Repeated(repeated) => Some(repeated),
Self::NotRepeated(_) => None,
}
}
}
impl<'a> GridLayouter<'a> {
pub(super) fn layout_header(
&mut self,
header: &Header,
engine: &mut Engine,
disambiguator: usize,
) -> SourceResult<()> {
let header_rows =
self.simulate_header(header, &self.regions, engine, disambiguator)?;
let mut skipped_region = false;
while self.unbreakable_rows_left == 0
&& !self.regions.size.y.fits(header_rows.height + self.footer_height)
&& self.regions.may_progress()
{
self.finish_region_internal(Frame::soft(Axes::splat(Abs::zero())), vec![]);
skipped_region = true;
}
self.header_height = Abs::zero();
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
if skipped_region {
self.footer_height = self
.simulate_footer(footer, &self.regions, engine, disambiguator)?
.height;
}
}
self.unbreakable_rows_left += header.end;
for y in 0..header.end {
self.layout_row(y, engine, disambiguator)?;
}
Ok(())
}
pub(super) fn simulate_header(
&self,
header: &Header,
regions: &Regions<'_>,
engine: &mut Engine,
disambiguator: usize,
) -> SourceResult<UnbreakableRowGroup> {
self.simulate_unbreakable_row_group(
0,
Some(header.end),
regions,
engine,
disambiguator,
)
}
pub(super) fn prepare_footer(
&mut self,
footer: &Footer,
engine: &mut Engine,
disambiguator: usize,
) -> SourceResult<()> {
let footer_height = self
.simulate_footer(footer, &self.regions, engine, disambiguator)?
.height;
let mut skipped_region = false;
while self.unbreakable_rows_left == 0
&& !self.regions.size.y.fits(footer_height)
&& self.regions.may_progress()
{
self.finish_region_internal(Frame::soft(Axes::splat(Abs::zero())), vec![]);
skipped_region = true;
}
self.footer_height = if skipped_region {
self.simulate_footer(footer, &self.regions, engine, disambiguator)?
.height
} else {
footer_height
};
Ok(())
}
pub(super) fn layout_footer(
&mut self,
footer: &Footer,
engine: &mut Engine,
disambiguator: usize,
) -> SourceResult<()> {
self.regions.size.y += self.footer_height;
let footer_len = self.grid.rows.len() - footer.start;
self.unbreakable_rows_left += footer_len;
for y in footer.start..self.grid.rows.len() {
self.layout_row(y, engine, disambiguator)?;
}
Ok(())
}
pub(super) fn simulate_footer(
&self,
footer: &Footer,
regions: &Regions<'_>,
engine: &mut Engine,
disambiguator: usize,
) -> SourceResult<UnbreakableRowGroup> {
self.simulate_unbreakable_row_group(
footer.start,
Some(self.grid.rows.len() - footer.start),
regions,
engine,
disambiguator,
)
}
}