begin refactoring layout_headers

- May have to include ALL headers when skipping a region...
- Approach too naive
This commit is contained in:
PgBiel 2025-04-04 00:58:49 -03:00
parent 6029e6f3bb
commit 0143d0775b

View File

@ -1,3 +1,4 @@
use std::ops::Deref;
use typst_library::diag::SourceResult; use typst_library::diag::SourceResult;
use typst_library::engine::Engine; use typst_library::engine::Engine;
@ -146,12 +147,26 @@ impl<'a> GridLayouter<'a> {
/// footers. /// footers.
pub fn layout_headers( pub fn layout_headers(
&mut self, &mut self,
headers: &[&Header], headers: impl Clone + IntoIterator<Item = &'a Header>,
include_repeating: bool,
engine: &mut Engine, engine: &mut Engine,
disambiguator: usize,
) -> SourceResult<()> { ) -> SourceResult<()> {
let header_height = // Generate different locations for content in headers across its
self.simulate_header_height(&self.regions, engine, disambiguator)?; // repetitions by assigning a unique number for each one.
let disambiguator = self.finished.len();
// At first, only consider the height of the given headers. However,
// for upcoming regions, we will have to consider repeating headers as
// well.
let mut header_height = self.simulate_header_height(
headers.clone(),
&self.regions,
engine,
disambiguator,
)?;
// 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; let mut skipped_region = false;
while self.unbreakable_rows_left == 0 while self.unbreakable_rows_left == 0
&& !self.regions.size.y.fits(header_height + self.footer_height) && !self.regions.size.y.fits(header_height + self.footer_height)
@ -161,26 +176,58 @@ impl<'a> GridLayouter<'a> {
// header and the footer. // header and the footer.
self.finish_region_internal(Frame::soft(Axes::splat(Abs::zero())), vec![]); self.finish_region_internal(Frame::soft(Axes::splat(Abs::zero())), vec![]);
skipped_region = true; skipped_region = true;
header_height = if include_repeating {
// Laying out pending headers, so we have to consider the
// combined height of already repeating headers as well.
self.simulate_header_height(
self.repeating_headers.iter().map(|h| *h).chain(headers.clone()),
&self.regions,
engine,
disambiguator,
)?
} else {
self.simulate_header_height(
headers.clone(),
&self.regions,
engine,
disambiguator,
)?
};
// Simulate the footer again; the region's 'full' might have
// changed.
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
self.footer_height = self
.simulate_footer(footer, &self.regions, engine, disambiguator)?
.height;
}
// Ensure we also take the footer into account for remaining space.
self.regions.size.y -= self.footer_height;
} }
// 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.header_height = Abs::zero();
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer { let trivial_vector = vec![];
if skipped_region { let repeating_header_prefix =
// Simulate the footer again; the region's 'full' might have if include_repeating { &self.repeating_headers } else { &trivial_vector };
// changed.
self.footer_height = self
.simulate_footer(footer, &self.regions, engine, disambiguator)?
.height;
}
}
// Group of headers is unbreakable. // Group of headers is unbreakable.
// Thus, no risk of 'finish_region' being recursively called from // Thus, no risk of 'finish_region' being recursively called from
// within 'layout_row'. // within 'layout_row'.
self.unbreakable_rows_left += total_header_row_count(headers); self.unbreakable_rows_left +=
total_header_row_count(repeating_header_prefix.iter().map(Deref::deref))
+ total_header_row_count(headers.clone());
let mut i = 0;
while let Some(header) = repeating_header_prefix.get(i) {
for y in header.range() {
self.layout_row(y, engine, disambiguator)?;
}
i += 1;
}
for header in headers { for header in headers {
for y in header.range() { for y in header.range() {
self.layout_row(y, engine, disambiguator)?; self.layout_row(y, engine, disambiguator)?;
@ -190,9 +237,9 @@ impl<'a> GridLayouter<'a> {
} }
/// Calculates the total expected height of several headers. /// Calculates the total expected height of several headers.
pub fn simulate_header_height( pub fn simulate_header_height<'h: 'a>(
&self, &self,
headers: &[&Header], headers: impl IntoIterator<Item = &'h Header>,
regions: &Regions<'_>, regions: &Regions<'_>,
engine: &mut Engine, engine: &mut Engine,
disambiguator: usize, disambiguator: usize,
@ -307,6 +354,8 @@ impl<'a> GridLayouter<'a> {
/// The total amount of rows in the given list of headers. /// The total amount of rows in the given list of headers.
#[inline] #[inline]
pub fn total_header_row_count(headers: &[&Header]) -> usize { pub fn total_header_row_count<'h>(
headers.iter().map(|h| h.end - h.start).sum() headers: impl IntoIterator<Item = &'h Header>,
) -> usize {
headers.into_iter().map(|h| h.end - h.start).sum()
} }