From cce5fe739a0d476b6d54ae7cd9385a2313eb639e Mon Sep 17 00:00:00 2001 From: PgBiel <9021226+PgBiel@users.noreply.github.com> Date: Mon, 3 Mar 2025 19:59:41 -0300 Subject: [PATCH 01/28] multiple footers --- crates/typst-library/src/layout/grid/resolve.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/typst-library/src/layout/grid/resolve.rs b/crates/typst-library/src/layout/grid/resolve.rs index baf6b7383..42df8953b 100644 --- a/crates/typst-library/src/layout/grid/resolve.rs +++ b/crates/typst-library/src/layout/grid/resolve.rs @@ -678,8 +678,8 @@ pub struct CellGrid<'a> { pub hlines: Vec>, /// The repeatable headers of this grid. pub headers: Vec>, - /// The repeatable footer of this grid. - pub footer: Option>, + /// The repeatable footers of this grid. + pub footers: Vec>, /// Whether this grid has gutters. pub has_gutter: bool, } @@ -756,7 +756,7 @@ impl<'a> CellGrid<'a> { vlines, hlines, headers, - footer, + footers: footer.into_iter().collect(), has_gutter, } } @@ -895,6 +895,11 @@ impl<'a> CellGrid<'a> { pub fn has_repeated_headers(&self) -> bool { self.headers.iter().any(|h| h.repeated) } + + #[inline] + pub fn has_repeated_footers(&self) -> bool { + self.footers.iter().any(|f| f.repeated) + } } /// Resolves and positions all cells in the grid before creating it. From 5292c5b198aaf39f6666fd9164d7fa2e1653b495 Mon Sep 17 00:00:00 2001 From: PgBiel <9021226+PgBiel@users.noreply.github.com> Date: Fri, 16 May 2025 20:01:17 -0300 Subject: [PATCH 02/28] update html code for multiple footers todo: test --- crates/typst-library/src/model/table.rs | 33 ++++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/crates/typst-library/src/model/table.rs b/crates/typst-library/src/model/table.rs index dcc77b0dc..367d3e66f 100644 --- a/crates/typst-library/src/model/table.rs +++ b/crates/typst-library/src/model/table.rs @@ -292,12 +292,33 @@ fn show_cellgrid_html(grid: CellGrid, styles: StyleChain) -> Content { elem(tag::tr, Content::sequence(row)) }; - // TODO(subfooters): similarly to headers, take consecutive footers from - // the end for 'tfoot'. - let footer = grid.footer.map(|ft| { - let rows = rows.drain(ft.start..); - elem(tag::tfoot, Content::sequence(rows.map(|row| tr(tag::td, row)))) - }); + // Store all consecutive headers at the start in 'tfoot'. All remaining + // headers are just normal rows across the table body. (There doesn't + // appear to be an equivalent of 'th' for footers in HTML.) + // TODO: test + let footer = { + let mut consecutive_footer_start = grid.footers.len(); + let footers_at_end = grid + .footers + .iter() + .rev() + .take_while(|ft| { + let is_consecutive = ft.end == consecutive_footer_start; + consecutive_footer_start = ft.start; + + is_consecutive + }) + .count(); + + if footers_at_end > 0 { + let last_mid_table_footer = grid.footers.len() - footers_at_end; + let rows = rows.drain(last_mid_table_footer..); + + Some(elem(tag::tfoot, Content::sequence(rows.map(|row| tr(tag::td, row))))) + } else { + None + } + }; // Store all consecutive headers at the start in 'thead'. All remaining // headers are just 'th' rows across the table body. From 0a27b5055180461fd27688d8c8653f8e10378fc1 Mon Sep 17 00:00:00 2001 From: PgBiel <9021226+PgBiel@users.noreply.github.com> Date: Sun, 30 Mar 2025 23:46:13 -0300 Subject: [PATCH 03/28] footer pre sorting --- .../typst-library/src/layout/grid/resolve.rs | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/crates/typst-library/src/layout/grid/resolve.rs b/crates/typst-library/src/layout/grid/resolve.rs index 42df8953b..acb588e95 100644 --- a/crates/typst-library/src/layout/grid/resolve.rs +++ b/crates/typst-library/src/layout/grid/resolve.rs @@ -680,6 +680,10 @@ pub struct CellGrid<'a> { pub headers: Vec>, /// The repeatable footers of this grid. pub footers: Vec>, + /// Footers sorted by order of when they start repeating, or should + /// otherwise be laid out for the first time (even if only once, for + /// non-repeating footers). + pub sorted_footers: Vec>, /// Whether this grid has gutters. pub has_gutter: bool, } @@ -749,6 +753,9 @@ impl<'a> CellGrid<'a> { rows.pop(); } + let footers: Vec> = footer.into_iter().collect(); + let sorted_footers = simulate_footer_repetition(&footers); + Self { cols, rows, @@ -2394,3 +2401,50 @@ fn skip_auto_index_through_fully_merged_rows( } } } + +/// Generates a vector where all footers are sorted ahead of time by the points +/// at which they start repeating. When a new footer is about to be laid out, +/// conflicting footers which come before it in this vector must stop +/// repeating. +fn simulate_footer_repetition( + footers: &[Repeatable