diff --git a/crates/typst-layout/src/grid/layouter.rs b/crates/typst-layout/src/grid/layouter.rs index 5b35ca8fe..0d86cbdfa 100644 --- a/crates/typst-layout/src/grid/layouter.rs +++ b/crates/typst-layout/src/grid/layouter.rs @@ -287,9 +287,9 @@ impl<'a> GridLayouter<'a> { while y < self.grid.rows.len() { if let Some(next_header) = self.upcoming_headers.get(consecutive_header_count) { - if next_header.range().contains(&y) { + if next_header.range.contains(&y) { self.place_new_headers(&mut consecutive_header_count, engine)?; - y = next_header.end; + y = next_header.range.end; // Skip header rows during normal layout. continue; diff --git a/crates/typst-layout/src/grid/repeated.rs b/crates/typst-layout/src/grid/repeated.rs index fc717b2ff..4f74210eb 100644 --- a/crates/typst-layout/src/grid/repeated.rs +++ b/crates/typst-layout/src/grid/repeated.rs @@ -39,7 +39,8 @@ impl<'a> GridLayouter<'a> { if new_upcoming_headers.first().is_some_and(|next_header| { consecutive_headers.last().is_none_or(|latest_header| { - !latest_header.short_lived && next_header.start == latest_header.end + !latest_header.short_lived + && next_header.range.start == latest_header.range.end }) && !next_header.short_lived }) { // More headers coming, so wait until we reach them. @@ -131,7 +132,7 @@ impl<'a> GridLayouter<'a> { as_short_lived: bool, ) -> SourceResult { let mut header_height = Abs::zero(); - for y in header.range() { + for y in header.range.clone() { header_height += self .layout_row_with_state( y, @@ -261,7 +262,7 @@ impl<'a> GridLayouter<'a> { self.unbreakable_rows_left += repeating_header_rows + pending_header_rows; self.current.last_repeated_header_end = - self.repeating_headers.last().map(|h| h.end).unwrap_or_default(); + self.repeating_headers.last().map(|h| h.range.end).unwrap_or_default(); // Reset the header height for this region. // It will be re-calculated when laying out each header row. @@ -453,8 +454,8 @@ impl<'a> GridLayouter<'a> { // assume that the amount of unbreakable rows following the first row // in the header will be precisely the rows in the header. self.simulate_unbreakable_row_group( - header.start, - Some(header.end - header.start), + header.range.start, + Some(header.range.end - header.range.start), regions, engine, disambiguator, @@ -569,5 +570,5 @@ impl<'a> GridLayouter<'a> { pub fn total_header_row_count<'h>( headers: impl IntoIterator, ) -> usize { - headers.into_iter().map(|h| h.end - h.start).sum() + headers.into_iter().map(|h| h.range.end - h.range.start).sum() } diff --git a/crates/typst-library/src/layout/grid/resolve.rs b/crates/typst-library/src/layout/grid/resolve.rs index db80604a0..8641c3659 100644 --- a/crates/typst-library/src/layout/grid/resolve.rs +++ b/crates/typst-library/src/layout/grid/resolve.rs @@ -428,10 +428,8 @@ pub struct Line { /// A repeatable grid header. Starts at the first row. #[derive(Debug)] pub struct Header { - /// The first row included in this header. - pub start: usize, - /// The index after the last row included in this header. - pub end: usize, + /// The range of rows included in this header. + pub range: Range, /// The header's level. /// /// Higher level headers repeat together with lower level headers. If a @@ -446,14 +444,6 @@ pub struct Header { pub short_lived: bool, } -impl Header { - /// The header's range of included rows. - #[inline] - pub fn range(&self) -> Range { - self.start..self.end - } -} - /// A repeatable grid footer. Stops at the last row. #[derive(Debug)] pub struct Footer { @@ -1594,13 +1584,11 @@ impl<'x> CellGridResolver<'_, '_, 'x> { match row_group.kind { RowGroupKind::Header => { let data = Header { - start: group_range.start, - - // 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 has fully expanded in the fixup loop // below. - end: group_range.end, + range: group_range, level: row_group.repeatable_level.get(), @@ -1613,13 +1601,13 @@ impl<'x> CellGridResolver<'_, '_, 'x> { // lived if they would have a higher or equal level, as // then they would immediately stop repeating during // layout. - let mut consecutive_header_start = data.start; + let mut consecutive_header_start = data.range.start; for conflicting_header in headers.iter_mut().rev().take_while(move |h| { - let conflicts = h.end == consecutive_header_start + let conflicts = h.range.end == consecutive_header_start && h.level >= data.level; - consecutive_header_start = h.start; + consecutive_header_start = h.range.start; conflicts }) { @@ -1841,9 +1829,9 @@ impl<'x> CellGridResolver<'_, '_, 'x> { let mut consecutive_header_start = footer.as_ref().map(|(_, _, f)| f.start).unwrap_or(row_amount); for header_at_the_end in headers.iter_mut().rev().take_while(move |h| { - let at_the_end = h.end == consecutive_header_start; + let at_the_end = h.range.end == consecutive_header_start; - consecutive_header_start = h.start; + consecutive_header_start = h.range.start; at_the_end }) { header_at_the_end.unwrap_mut().short_lived = true; @@ -1858,7 +1846,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> { // Index of first y is doubled, as each row before it // receives a gutter row below. - header.start *= 2; + header.range.start *= 2; // - 'header.end' is always 'last y + 1'. The header stops // before that row. @@ -1871,14 +1859,14 @@ impl<'x> CellGridResolver<'_, '_, 'x> { // to the index of the gutter row right below the header, // which is what we want (that gutter spacing should be // repeated across pages to maintain uniformity). - header.end *= 2; + header.range.end *= 2; // If the header occupies the entire grid, ensure we don't // include an extra gutter row when it doesn't exist, since // the last row of the header is at the very bottom, // therefore '2 * last y + 1' is not a valid index. let row_amount = (2 * row_amount).saturating_sub(1); - header.end = header.end.min(row_amount); + header.range.end = header.range.end.min(row_amount); } } @@ -1898,7 +1886,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> { // only the gutter above the footer is kept, ensuring the same // gutter row isn't laid out two times in a row. When laying // out the footer for real, the mechanism can be disabled. - let last_header_end = headers.last().map(|header| header.end); + let last_header_end = headers.last().map(|header| header.range.end); if has_gutter { // Convert the footer's start index to post-gutter coordinates. @@ -2122,7 +2110,7 @@ fn check_for_conflicting_cell_row( // conflict. if headers .iter() - .any(|header| cell_y < header.end && cell_y + rowspan > header.start) + .any(|header| cell_y < header.range.end && cell_y + rowspan > header.range.start) { bail!( "cell would conflict with header spanning the same position"; @@ -2341,14 +2329,14 @@ fn find_next_available_position( } } else if let Some(header) = headers .get(*next_header) - .filter(|header| resolved_index >= header.start * columns) + .filter(|header| resolved_index >= header.range.start * columns) { // Skip header (can't place a cell inside it from outside it). // No changes needed if we already passed this header (which // also triggers this branch) - in that case, we only update the // counter. - if resolved_index < header.end * columns { - resolved_index = header.end * columns; + if resolved_index < header.range.end * columns { + resolved_index = header.range.end * columns; if skip_rows { // Ensure the cell's chosen column is kept after the diff --git a/crates/typst-library/src/model/table.rs b/crates/typst-library/src/model/table.rs index 61021f8d0..14d40e749 100644 --- a/crates/typst-library/src/model/table.rs +++ b/crates/typst-library/src/model/table.rs @@ -306,8 +306,8 @@ fn show_cellgrid_html(grid: CellGrid, styles: StyleChain) -> Content { .headers .iter() .take_while(|hd| { - let is_consecutive = hd.start == consecutive_header_end; - consecutive_header_end = hd.end; + let is_consecutive = hd.range.start == consecutive_header_end; + consecutive_header_end = hd.range.end; is_consecutive }) @@ -315,7 +315,7 @@ fn show_cellgrid_html(grid: CellGrid, styles: StyleChain) -> Content { let (y_offset, header) = if first_mid_table_header > 0 { let removed_header_rows = - grid.headers.get(first_mid_table_header - 1).unwrap().end; + grid.headers.get(first_mid_table_header - 1).unwrap().range.end; let rows = rows.drain(..removed_header_rows); ( @@ -335,9 +335,9 @@ fn show_cellgrid_html(grid: CellGrid, styles: StyleChain) -> Content { Content::sequence(rows.into_iter().enumerate().map(|(relative_y, row)| { let y = relative_y + y_offset; if let Some(current_header) = - grid.headers.get(next_header).filter(|h| h.range().contains(&y)) + grid.headers.get(next_header).filter(|h| h.range.contains(&y)) { - if y + 1 == current_header.end { + if y + 1 == current_header.range.end { next_header += 1; }