mirror of
https://github.com/typst/typst
synced 2025-06-15 16:46:24 +08:00
use header.range field
a bit verbose at times but seems potentially more consistent
This commit is contained in:
parent
88c9dea3fa
commit
b997450a4b
@ -287,9 +287,9 @@ impl<'a> GridLayouter<'a> {
|
|||||||
while y < self.grid.rows.len() {
|
while y < self.grid.rows.len() {
|
||||||
if let Some(next_header) = self.upcoming_headers.get(consecutive_header_count)
|
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)?;
|
self.place_new_headers(&mut consecutive_header_count, engine)?;
|
||||||
y = next_header.end;
|
y = next_header.range.end;
|
||||||
|
|
||||||
// Skip header rows during normal layout.
|
// Skip header rows during normal layout.
|
||||||
continue;
|
continue;
|
||||||
|
@ -39,7 +39,8 @@ impl<'a> GridLayouter<'a> {
|
|||||||
|
|
||||||
if new_upcoming_headers.first().is_some_and(|next_header| {
|
if new_upcoming_headers.first().is_some_and(|next_header| {
|
||||||
consecutive_headers.last().is_none_or(|latest_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
|
}) && !next_header.short_lived
|
||||||
}) {
|
}) {
|
||||||
// More headers coming, so wait until we reach them.
|
// More headers coming, so wait until we reach them.
|
||||||
@ -131,7 +132,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
as_short_lived: bool,
|
as_short_lived: bool,
|
||||||
) -> SourceResult<Abs> {
|
) -> SourceResult<Abs> {
|
||||||
let mut header_height = Abs::zero();
|
let mut header_height = Abs::zero();
|
||||||
for y in header.range() {
|
for y in header.range.clone() {
|
||||||
header_height += self
|
header_height += self
|
||||||
.layout_row_with_state(
|
.layout_row_with_state(
|
||||||
y,
|
y,
|
||||||
@ -261,7 +262,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
self.unbreakable_rows_left += repeating_header_rows + pending_header_rows;
|
self.unbreakable_rows_left += repeating_header_rows + pending_header_rows;
|
||||||
|
|
||||||
self.current.last_repeated_header_end =
|
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.
|
// 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.
|
||||||
@ -453,8 +454,8 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// assume that the amount of unbreakable rows following the first row
|
// assume that the amount of unbreakable rows following the first row
|
||||||
// in the header will be precisely the rows in the header.
|
// in the header will be precisely the rows in the header.
|
||||||
self.simulate_unbreakable_row_group(
|
self.simulate_unbreakable_row_group(
|
||||||
header.start,
|
header.range.start,
|
||||||
Some(header.end - header.start),
|
Some(header.range.end - header.range.start),
|
||||||
regions,
|
regions,
|
||||||
engine,
|
engine,
|
||||||
disambiguator,
|
disambiguator,
|
||||||
@ -569,5 +570,5 @@ impl<'a> GridLayouter<'a> {
|
|||||||
pub fn total_header_row_count<'h>(
|
pub fn total_header_row_count<'h>(
|
||||||
headers: impl IntoIterator<Item = &'h Header>,
|
headers: impl IntoIterator<Item = &'h Header>,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
headers.into_iter().map(|h| h.end - h.start).sum()
|
headers.into_iter().map(|h| h.range.end - h.range.start).sum()
|
||||||
}
|
}
|
||||||
|
@ -428,10 +428,8 @@ pub struct Line {
|
|||||||
/// A repeatable grid header. Starts at the first row.
|
/// A repeatable grid header. Starts at the first row.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Header {
|
pub struct Header {
|
||||||
/// The first row included in this header.
|
/// The range of rows included in this header.
|
||||||
pub start: usize,
|
pub range: Range<usize>,
|
||||||
/// The index after the last row included in this header.
|
|
||||||
pub end: usize,
|
|
||||||
/// The header's level.
|
/// The header's level.
|
||||||
///
|
///
|
||||||
/// Higher level headers repeat together with lower level headers. If a
|
/// Higher level headers repeat together with lower level headers. If a
|
||||||
@ -446,14 +444,6 @@ pub struct Header {
|
|||||||
pub short_lived: bool,
|
pub short_lived: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Header {
|
|
||||||
/// The header's range of included rows.
|
|
||||||
#[inline]
|
|
||||||
pub fn range(&self) -> Range<usize> {
|
|
||||||
self.start..self.end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A repeatable grid footer. Stops at the last row.
|
/// A repeatable grid footer. Stops at the last row.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Footer {
|
pub struct Footer {
|
||||||
@ -1594,13 +1584,11 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
|||||||
match row_group.kind {
|
match row_group.kind {
|
||||||
RowGroupKind::Header => {
|
RowGroupKind::Header => {
|
||||||
let data = Header {
|
let data = Header {
|
||||||
start: group_range.start,
|
// Later on, we have to correct this range in case there
|
||||||
|
|
||||||
// Later on, we have to correct this number in case there
|
|
||||||
// is gutter. But only once all cells have been analyzed
|
// is gutter. But only once all cells have been analyzed
|
||||||
// and the header has fully expanded in the fixup loop
|
// and the header has fully expanded in the fixup loop
|
||||||
// below.
|
// below.
|
||||||
end: group_range.end,
|
range: group_range,
|
||||||
|
|
||||||
level: row_group.repeatable_level.get(),
|
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
|
// lived if they would have a higher or equal level, as
|
||||||
// then they would immediately stop repeating during
|
// then they would immediately stop repeating during
|
||||||
// layout.
|
// layout.
|
||||||
let mut consecutive_header_start = data.start;
|
let mut consecutive_header_start = data.range.start;
|
||||||
for conflicting_header in
|
for conflicting_header in
|
||||||
headers.iter_mut().rev().take_while(move |h| {
|
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;
|
&& h.level >= data.level;
|
||||||
|
|
||||||
consecutive_header_start = h.start;
|
consecutive_header_start = h.range.start;
|
||||||
conflicts
|
conflicts
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
@ -1841,9 +1829,9 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
|||||||
let mut consecutive_header_start =
|
let mut consecutive_header_start =
|
||||||
footer.as_ref().map(|(_, _, f)| f.start).unwrap_or(row_amount);
|
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| {
|
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
|
at_the_end
|
||||||
}) {
|
}) {
|
||||||
header_at_the_end.unwrap_mut().short_lived = true;
|
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
|
// Index of first y is doubled, as each row before it
|
||||||
// receives a gutter row below.
|
// receives a gutter row below.
|
||||||
header.start *= 2;
|
header.range.start *= 2;
|
||||||
|
|
||||||
// - 'header.end' is always 'last y + 1'. The header stops
|
// - 'header.end' is always 'last y + 1'. The header stops
|
||||||
// before that row.
|
// before that row.
|
||||||
@ -1871,14 +1859,14 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
|||||||
// to the index of the gutter row right below the header,
|
// to the index of the gutter row right below the header,
|
||||||
// which is what we want (that gutter spacing should be
|
// which is what we want (that gutter spacing should be
|
||||||
// repeated across pages to maintain uniformity).
|
// repeated across pages to maintain uniformity).
|
||||||
header.end *= 2;
|
header.range.end *= 2;
|
||||||
|
|
||||||
// If the header occupies the entire grid, ensure we don't
|
// If the header occupies the entire grid, ensure we don't
|
||||||
// include an extra gutter row when it doesn't exist, since
|
// include an extra gutter row when it doesn't exist, since
|
||||||
// the last row of the header is at the very bottom,
|
// the last row of the header is at the very bottom,
|
||||||
// therefore '2 * last y + 1' is not a valid index.
|
// therefore '2 * last y + 1' is not a valid index.
|
||||||
let row_amount = (2 * row_amount).saturating_sub(1);
|
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
|
// only the gutter above the footer is kept, ensuring the same
|
||||||
// gutter row isn't laid out two times in a row. When laying
|
// gutter row isn't laid out two times in a row. When laying
|
||||||
// out the footer for real, the mechanism can be disabled.
|
// 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 {
|
if has_gutter {
|
||||||
// Convert the footer's start index to post-gutter coordinates.
|
// Convert the footer's start index to post-gutter coordinates.
|
||||||
@ -2122,7 +2110,7 @@ fn check_for_conflicting_cell_row(
|
|||||||
// conflict.
|
// conflict.
|
||||||
if headers
|
if headers
|
||||||
.iter()
|
.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!(
|
bail!(
|
||||||
"cell would conflict with header spanning the same position";
|
"cell would conflict with header spanning the same position";
|
||||||
@ -2341,14 +2329,14 @@ fn find_next_available_position(
|
|||||||
}
|
}
|
||||||
} else if let Some(header) = headers
|
} else if let Some(header) = headers
|
||||||
.get(*next_header)
|
.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).
|
// Skip header (can't place a cell inside it from outside it).
|
||||||
// No changes needed if we already passed this header (which
|
// No changes needed if we already passed this header (which
|
||||||
// also triggers this branch) - in that case, we only update the
|
// also triggers this branch) - in that case, we only update the
|
||||||
// counter.
|
// counter.
|
||||||
if resolved_index < header.end * columns {
|
if resolved_index < header.range.end * columns {
|
||||||
resolved_index = header.end * columns;
|
resolved_index = header.range.end * columns;
|
||||||
|
|
||||||
if skip_rows {
|
if skip_rows {
|
||||||
// Ensure the cell's chosen column is kept after the
|
// Ensure the cell's chosen column is kept after the
|
||||||
|
@ -306,8 +306,8 @@ fn show_cellgrid_html(grid: CellGrid, styles: StyleChain) -> Content {
|
|||||||
.headers
|
.headers
|
||||||
.iter()
|
.iter()
|
||||||
.take_while(|hd| {
|
.take_while(|hd| {
|
||||||
let is_consecutive = hd.start == consecutive_header_end;
|
let is_consecutive = hd.range.start == consecutive_header_end;
|
||||||
consecutive_header_end = hd.end;
|
consecutive_header_end = hd.range.end;
|
||||||
|
|
||||||
is_consecutive
|
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 (y_offset, header) = if first_mid_table_header > 0 {
|
||||||
let removed_header_rows =
|
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);
|
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)| {
|
Content::sequence(rows.into_iter().enumerate().map(|(relative_y, row)| {
|
||||||
let y = relative_y + y_offset;
|
let y = relative_y + y_offset;
|
||||||
if let Some(current_header) =
|
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;
|
next_header += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user