diff --git a/crates/typst-layout/src/grid/layouter.rs b/crates/typst-layout/src/grid/layouter.rs index d5aca0586..31e17894d 100644 --- a/crates/typst-layout/src/grid/layouter.rs +++ b/crates/typst-layout/src/grid/layouter.rs @@ -320,11 +320,11 @@ impl<'a> GridLayouter<'a> { if let [next_footer, other_footers @ ..] = self.upcoming_footers { // TODO(subfooters): effective range (consider gutter before // if it was removed) - if next_footer.range().contains(&y) { + if next_footer.range.contains(&y) { self.upcoming_footers = other_footers; self.place_new_footer(engine, next_footer)?; self.flush_orphans(); - y = next_footer.end; + y = next_footer.range.end; continue; } @@ -1719,8 +1719,7 @@ impl<'a> GridLayouter<'a> { // // TODO(subfooters): use effective range // (what about the gutter?). - !footer.range().contains(&y) - || footer.range().contains(&rowspan.y) + !footer.range.contains(&y) || footer.range.contains(&rowspan.y) })) && (rowspan.y + rowspan.rowspan < y + 1 || rowspan.y + rowspan.rowspan == y + 1 && is_last) diff --git a/crates/typst-layout/src/grid/lines.rs b/crates/typst-layout/src/grid/lines.rs index 0ea113ac1..b75c7177f 100644 --- a/crates/typst-layout/src/grid/lines.rs +++ b/crates/typst-layout/src/grid/lines.rs @@ -521,9 +521,9 @@ pub fn hline_stroke_at_column( // Ensure the row below us is a repeated footer. // FIXME: Make this check more robust when footers at arbitrary // positions are added. - footer.end == grid.rows.len() - && local_top_y.unwrap_or(0) + 1 < footer.start - && y >= footer.start + footer.range.end == grid.rows.len() + && local_top_y.unwrap_or(0) + 1 < footer.range.start + && y >= footer.range.start }); let (prioritized_cell_stroke, deprioritized_cell_stroke) = diff --git a/crates/typst-layout/src/grid/repeated.rs b/crates/typst-layout/src/grid/repeated.rs index 4fdbd8e62..c1fbe7e00 100644 --- a/crates/typst-layout/src/grid/repeated.rs +++ b/crates/typst-layout/src/grid/repeated.rs @@ -493,7 +493,7 @@ impl<'a> GridLayouter<'a> { // Placing a non-short-lived repeating footer, so it must be // the latest one in the repeating footers vector. let latest_repeating_footer = self.repeating_footers.pop().unwrap(); - assert_eq!(latest_repeating_footer.start, footer.start); + assert_eq!(latest_repeating_footer.range.start, footer.range.start); let expected_footer_height = self.current.repeating_footer_heights.pop().unwrap(); @@ -660,12 +660,12 @@ impl<'a> GridLayouter<'a> { engine: &mut Engine, disambiguator: usize, ) -> SourceResult<()> { - let footer_len = footer.end - footer.start; + let footer_len = footer.range.end - footer.range.start; self.unbreakable_rows_left += footer_len; // TODO(subfooters): also consider omitted gutter before the footer // when there is a header right before it taking it. - for y in footer.start..self.grid.rows.len() { + for y in footer.range.start..self.grid.rows.len() { self.layout_row_with_state( y, engine, @@ -694,8 +694,8 @@ impl<'a> GridLayouter<'a> { // assume that the amount of unbreakable rows following the first row // in the footer will be precisely the rows in the footer. self.simulate_unbreakable_row_group( - footer.start, - Some(footer.end - footer.start), + footer.range.start, + Some(footer.range.end - footer.range.start), regions, engine, disambiguator, diff --git a/crates/typst-library/src/layout/grid/resolve.rs b/crates/typst-library/src/layout/grid/resolve.rs index 9738ed73d..fc1d13564 100644 --- a/crates/typst-library/src/layout/grid/resolve.rs +++ b/crates/typst-library/src/layout/grid/resolve.rs @@ -447,24 +447,14 @@ pub struct Header { /// A repeatable grid footer. Stops at the last row. #[derive(Debug, Clone)] pub struct Footer { - /// The first row included in this footer. - pub start: usize, - /// The index after the last row included in this footer. - pub end: usize, + /// The range of rows included in this footer. + pub range: Range, /// The footer's level. /// /// Used similarly to header level. pub level: u32, } -impl Footer { - /// The footer's range of included rows. - #[inline] - pub fn range(&self) -> Range { - self.start..self.end - } -} - /// A possibly repeatable grid child (header or footer). /// /// It still exists even when not repeatable, but must not have additional @@ -1621,14 +1611,13 @@ impl<'x> CellGridResolver<'_, '_, 'x> { // Only check if the footer is at the end later, once we know // the final amount of rows. let data = Footer { - // Later on, we have to correct this number in case there + // Later on, we have to correct this range in case there // is gutter, but only once all cells have been analyzed // and the header's and footer's exact boundaries are // known. That is because the gutter row immediately // before the footer might not be included as part of // the footer if it is contained within the header. - start: group_range.start, - end: group_range.end, + range: group_range, level: row_group.repeatable_level.get(), }; @@ -1818,11 +1807,11 @@ impl<'x> CellGridResolver<'_, '_, 'x> { // TODO: interleaved headers and footers? let mut first_end_footer = row_amount; for end_footer in footers.iter().rev() { - if end_footer.end != first_end_footer { + if end_footer.range.end != first_end_footer { break; } - first_end_footer = end_footer.start; + first_end_footer = end_footer.range.start; } let mut consecutive_header_start = first_end_footer; @@ -1879,14 +1868,14 @@ impl<'x> CellGridResolver<'_, '_, 'x> { let last_header_end = headers.last().map(|header| header.range.end); // Convert the footer's start index to post-gutter coordinates. - footer.start *= 2; + footer.range.start *= 2; // TODO: this probably has to change // Include the gutter right before the footer, unless there is // none, or the gutter is already included in the header (no // rows between the header and the footer). - if last_header_end != Some(footer.start) { - footer.start = footer.start.saturating_sub(1); + if last_header_end != Some(footer.range.start) { + footer.range.start = footer.range.start.saturating_sub(1); } // Adapt footer end but DO NOT include the gutter below it, @@ -1899,7 +1888,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> { // // It also keeps us within the total amount of rows, so we // don't need to '.min()' later. - footer.end = (2 * footer.end).saturating_sub(1); + footer.range.end = (2 * footer.range.end).saturating_sub(1); if !at_least_one_cell { // TODO: short-lived (and remove this?) @@ -2101,7 +2090,7 @@ fn check_for_conflicting_cell_row( if footers .iter() - .any(|footer| cell_y < footer.end && cell_y + rowspan > footer.start) + .any(|footer| cell_y < footer.range.end && cell_y + rowspan > footer.range.start) { bail!( "cell would conflict with footer spanning the same position"; @@ -2335,11 +2324,11 @@ fn find_next_available_position( *next_header += 1; } else if let Some(footer) = footers .get(*next_footer) - .filter(|footer| resolved_index >= footer.start * columns) + .filter(|footer| resolved_index >= footer.range.start * columns) { // Skip footer, for the same reason. - if resolved_index < footer.end * columns { - resolved_index = footer.end * columns; + if resolved_index < footer.range.end * columns { + resolved_index = footer.range.end * columns; if skip_rows { resolved_index += initial_index % columns; diff --git a/crates/typst-library/src/model/table.rs b/crates/typst-library/src/model/table.rs index 917953981..0b905bd5f 100644 --- a/crates/typst-library/src/model/table.rs +++ b/crates/typst-library/src/model/table.rs @@ -303,8 +303,8 @@ fn show_cellgrid_html(grid: CellGrid, styles: StyleChain) -> Content { .iter() .rev() .take_while(|ft| { - let is_consecutive = ft.end == consecutive_footer_start; - consecutive_footer_start = ft.start; + let is_consecutive = ft.range.end == consecutive_footer_start; + consecutive_footer_start = ft.range.start; is_consecutive }) @@ -313,7 +313,7 @@ fn show_cellgrid_html(grid: CellGrid, styles: StyleChain) -> Content { if footers_at_end > 0 { let last_mid_table_footer = grid.footers.len() - footers_at_end; let removed_footer_rows = - grid.footers.get(last_mid_table_footer).unwrap().start; + grid.footers.get(last_mid_table_footer).unwrap().range.start; let rows = rows.drain(removed_footer_rows..); Some(elem(tag::tfoot, Content::sequence(rows.map(|row| tr(tag::td, row)))))