Move grid cell locator creation to GridLayouter (#6746)

This commit is contained in:
Tobias Schmitz 2025-08-13 14:09:56 +02:00 committed by GitHub
parent a7c8fd6872
commit 343a57b50d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 111 additions and 122 deletions

View File

@ -5,7 +5,7 @@ use typst_library::diag::{At, bail, warning};
use typst_library::foundations::{ use typst_library::foundations::{
Content, NativeElement, NativeRuleMap, ShowFn, Smart, StyleChain, Target, Content, NativeElement, NativeRuleMap, ShowFn, Smart, StyleChain, Target,
}; };
use typst_library::introspection::{Counter, Locator}; use typst_library::introspection::Counter;
use typst_library::layout::resolve::{Cell, CellGrid, Entry, table_to_cellgrid}; use typst_library::layout::resolve::{Cell, CellGrid, Entry, table_to_cellgrid};
use typst_library::layout::{BlockBody, BlockElem, BoxElem, OuterVAlignment, Sizing}; use typst_library::layout::{BlockBody, BlockElem, BoxElem, OuterVAlignment, Sizing};
use typst_library::model::{ use typst_library::model::{
@ -278,9 +278,7 @@ const REF_RULE: ShowFn<RefElem> = |elem, engine, styles| elem.realize(engine, st
const CITE_GROUP_RULE: ShowFn<CiteGroup> = |elem, engine, _| elem.realize(engine); const CITE_GROUP_RULE: ShowFn<CiteGroup> = |elem, engine, _| elem.realize(engine);
const TABLE_RULE: ShowFn<TableElem> = |elem, engine, styles| { const TABLE_RULE: ShowFn<TableElem> = |elem, engine, styles| {
// The locator is not used by HTML export, so we can just fabricate one. Ok(show_cellgrid(table_to_cellgrid(elem, engine, styles)?, styles))
let locator = Locator::root();
Ok(show_cellgrid(table_to_cellgrid(elem, engine, locator, styles)?, styles))
}; };
fn show_cellgrid(grid: CellGrid, styles: StyleChain) -> Content { fn show_cellgrid(grid: CellGrid, styles: StyleChain) -> Content {

View File

@ -1,11 +1,14 @@
use std::fmt::Debug; use std::fmt::Debug;
use rustc_hash::FxHashMap;
use typst_library::diag::{SourceResult, bail}; use typst_library::diag::{SourceResult, bail};
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{Resolve, StyleChain}; use typst_library::foundations::{Resolve, StyleChain};
use typst_library::introspection::Locator;
use typst_library::layout::grid::resolve::{ use typst_library::layout::grid::resolve::{
Cell, CellGrid, Header, LinePosition, Repeatable, Cell, CellGrid, Header, LinePosition, Repeatable,
}; };
use typst_library::layout::resolve::Entry;
use typst_library::layout::{ use typst_library::layout::{
Abs, Axes, Dir, Fr, Fragment, Frame, FrameItem, Length, Point, Region, Regions, Rel, Abs, Axes, Dir, Fr, Fragment, Frame, FrameItem, Length, Point, Region, Regions, Rel,
Size, Sizing, Size, Sizing,
@ -23,9 +26,11 @@ use super::{
/// Performs grid layout. /// Performs grid layout.
pub struct GridLayouter<'a> { pub struct GridLayouter<'a> {
/// The grid of cells. /// The grid of cells.
pub(super) grid: &'a CellGrid<'a>, pub(super) grid: &'a CellGrid,
/// The regions to layout children into. /// The regions to layout children into.
pub(super) regions: Regions<'a>, pub(super) regions: Regions<'a>,
/// The locators for the each cell in the cell grid.
pub(super) cell_locators: FxHashMap<Axes<usize>, Locator<'a>>,
/// The inherited styles. /// The inherited styles.
pub(super) styles: StyleChain<'a>, pub(super) styles: StyleChain<'a>,
/// Resolved column sizes. /// Resolved column sizes.
@ -228,8 +233,9 @@ impl<'a> GridLayouter<'a> {
/// ///
/// This prepares grid layout by unifying content and gutter tracks. /// This prepares grid layout by unifying content and gutter tracks.
pub fn new( pub fn new(
grid: &'a CellGrid<'a>, grid: &'a CellGrid,
regions: Regions<'a>, regions: Regions<'a>,
locator: Locator<'a>,
styles: StyleChain<'a>, styles: StyleChain<'a>,
span: Span, span: Span,
) -> Self { ) -> Self {
@ -238,9 +244,22 @@ impl<'a> GridLayouter<'a> {
let mut regions = regions; let mut regions = regions;
regions.expand = Axes::new(true, false); regions.expand = Axes::new(true, false);
// Prepare the locators for each cell in the cell grid.
let mut locator = locator.split();
let mut cell_locators = FxHashMap::default();
for y in 0..grid.rows.len() {
for x in 0..grid.cols.len() {
let Some(Entry::Cell(cell)) = grid.entry(x, y) else {
continue;
};
cell_locators.insert(Axes::new(x, y), locator.next(&cell.body.span()));
}
}
Self { Self {
grid, grid,
regions, regions,
cell_locators,
styles, styles,
rcols: vec![Abs::zero(); grid.cols.len()], rcols: vec![Abs::zero(); grid.cols.len()],
width: Abs::zero(), width: Abs::zero(),
@ -270,6 +289,22 @@ impl<'a> GridLayouter<'a> {
} }
} }
/// Create a [`Locator`] for use in [`layout_cell`].
pub(super) fn cell_locator(
&self,
pos: Axes<usize>,
disambiguator: usize,
) -> Locator<'a> {
let mut cell_locator = self.cell_locators[&pos].relayout();
// The disambiguator is used for repeated cells, e.g. in repeated headers.
if disambiguator > 0 {
cell_locator = cell_locator.split().next_inner(disambiguator as u128);
}
cell_locator
}
/// Determines the columns sizes and then layouts the grid row-by-row. /// Determines the columns sizes and then layouts the grid row-by-row.
pub fn layout(mut self, engine: &mut Engine) -> SourceResult<Fragment> { pub fn layout(mut self, engine: &mut Engine) -> SourceResult<Fragment> {
self.measure_columns(engine)?; self.measure_columns(engine)?;
@ -1037,8 +1072,9 @@ impl<'a> GridLayouter<'a> {
let size = Size::new(available, height); let size = Size::new(available, height);
let pod = Region::new(size, Axes::splat(false)); let pod = Region::new(size, Axes::splat(false));
let frame = let locator = self.cell_locator(parent, 0);
layout_cell(cell, engine, 0, self.styles, pod.into())?.into_frame(); let frame = layout_cell(cell, engine, locator, self.styles, pod.into())?
.into_frame();
resolved.set_max(frame.width() - already_covered_width); resolved.set_max(frame.width() - already_covered_width);
} }
@ -1276,8 +1312,9 @@ impl<'a> GridLayouter<'a> {
pod pod
}; };
let locator = self.cell_locator(parent, disambiguator);
let frames = let frames =
layout_cell(cell, engine, disambiguator, self.styles, pod)?.into_frames(); layout_cell(cell, engine, locator, self.styles, pod)?.into_frames();
// Skip the first region if one cell in it is empty. Then, // Skip the first region if one cell in it is empty. Then,
// remeasure. // remeasure.
@ -1434,8 +1471,8 @@ impl<'a> GridLayouter<'a> {
// rows. // rows.
pod.full = self.regions.full; pod.full = self.regions.full;
} }
let frame = let locator = self.cell_locator(Axes::new(x, y), disambiguator);
layout_cell(cell, engine, disambiguator, self.styles, pod)? let frame = layout_cell(cell, engine, locator, self.styles, pod)?
.into_frame(); .into_frame();
let mut pos = offset; let mut pos = offset;
if self.is_rtl { if self.is_rtl {
@ -1483,8 +1520,8 @@ impl<'a> GridLayouter<'a> {
pod.size.x = width; pod.size.x = width;
// Push the layouted frames into the individual output frames. // Push the layouted frames into the individual output frames.
let fragment = let locator = self.cell_locator(Axes::new(x, y), disambiguator);
layout_cell(cell, engine, disambiguator, self.styles, pod)?; let fragment = layout_cell(cell, engine, locator, self.styles, pod)?;
for (output, frame) in outputs.iter_mut().zip(fragment) { for (output, frame) in outputs.iter_mut().zip(fragment) {
let mut pos = offset; let mut pos = offset;
if self.is_rtl { if self.is_rtl {

View File

@ -560,17 +560,15 @@ pub fn hline_stroke_at_column(
mod test { mod test {
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use typst_library::foundations::Content; use typst_library::foundations::Content;
use typst_library::introspection::Locator;
use typst_library::layout::grid::resolve::{Cell, Entry, LinePosition}; use typst_library::layout::grid::resolve::{Cell, Entry, LinePosition};
use typst_library::layout::{Axes, Sides, Sizing}; use typst_library::layout::{Axes, Sides, Sizing};
use typst_utils::NonZeroExt; use typst_utils::NonZeroExt;
use super::*; use super::*;
fn sample_cell() -> Cell<'static> { fn sample_cell() -> Cell {
Cell { Cell {
body: Content::default(), body: Content::default(),
locator: Locator::root(),
fill: None, fill: None,
colspan: NonZeroUsize::ONE, colspan: NonZeroUsize::ONE,
rowspan: NonZeroUsize::ONE, rowspan: NonZeroUsize::ONE,
@ -580,10 +578,9 @@ mod test {
} }
} }
fn cell_with_colspan_rowspan(colspan: usize, rowspan: usize) -> Cell<'static> { fn cell_with_colspan_rowspan(colspan: usize, rowspan: usize) -> Cell {
Cell { Cell {
body: Content::default(), body: Content::default(),
locator: Locator::root(),
fill: None, fill: None,
colspan: NonZeroUsize::try_from(colspan).unwrap(), colspan: NonZeroUsize::try_from(colspan).unwrap(),
rowspan: NonZeroUsize::try_from(rowspan).unwrap(), rowspan: NonZeroUsize::try_from(rowspan).unwrap(),
@ -593,7 +590,7 @@ mod test {
} }
} }
fn sample_grid_for_vlines(gutters: bool) -> CellGrid<'static> { fn sample_grid_for_vlines(gutters: bool) -> CellGrid {
const COLS: usize = 4; const COLS: usize = 4;
const ROWS: usize = 6; const ROWS: usize = 6;
let entries = vec![ let entries = vec![
@ -1116,7 +1113,7 @@ mod test {
} }
} }
fn sample_grid_for_hlines(gutters: bool) -> CellGrid<'static> { fn sample_grid_for_hlines(gutters: bool) -> CellGrid {
const COLS: usize = 4; const COLS: usize = 4;
const ROWS: usize = 9; const ROWS: usize = 9;
let entries = vec![ let entries = vec![

View File

@ -28,14 +28,10 @@ use self::rowspans::{Rowspan, UnbreakableRowGroup};
pub fn layout_cell( pub fn layout_cell(
cell: &Cell, cell: &Cell,
engine: &mut Engine, engine: &mut Engine,
disambiguator: usize, locator: Locator,
styles: StyleChain, styles: StyleChain,
regions: Regions, regions: Regions,
) -> SourceResult<Fragment> { ) -> SourceResult<Fragment> {
let mut locator = cell.locator.relayout();
if disambiguator > 0 {
locator = locator.split().next_inner(disambiguator as u128);
}
crate::layout_fragment(engine, &cell.body, locator, styles, regions) crate::layout_fragment(engine, &cell.body, locator, styles, regions)
} }
@ -48,8 +44,8 @@ pub fn layout_grid(
styles: StyleChain, styles: StyleChain,
regions: Regions, regions: Regions,
) -> SourceResult<Fragment> { ) -> SourceResult<Fragment> {
let grid = grid_to_cellgrid(elem, engine, locator, styles)?; let grid = grid_to_cellgrid(elem, engine, styles)?;
GridLayouter::new(&grid, regions, styles, elem.span()).layout(engine) GridLayouter::new(&grid, regions, locator, styles, elem.span()).layout(engine)
} }
/// Layout the table. /// Layout the table.
@ -61,6 +57,6 @@ pub fn layout_table(
styles: StyleChain, styles: StyleChain,
regions: Regions, regions: Regions,
) -> SourceResult<Fragment> { ) -> SourceResult<Fragment> {
let grid = table_to_cellgrid(elem, engine, locator, styles)?; let grid = table_to_cellgrid(elem, engine, styles)?;
GridLayouter::new(&grid, regions, styles, elem.span()).layout(engine) GridLayouter::new(&grid, regions, locator, styles, elem.span()).layout(engine)
} }

View File

@ -145,7 +145,8 @@ impl GridLayouter<'_> {
} }
// Push the layouted frames directly into the finished frames. // Push the layouted frames directly into the finished frames.
let fragment = layout_cell(cell, engine, disambiguator, self.styles, pod)?; let locator = self.cell_locator(Axes::new(x, y), disambiguator);
let fragment = layout_cell(cell, engine, locator, self.styles, pod)?;
let (current_region, current_header_row_height) = current_region_data.unzip(); let (current_region, current_header_row_height) = current_region_data.unzip();
// Clever trick to process finished header rows: // Clever trick to process finished header rows:

View File

@ -36,8 +36,6 @@ pub fn layout_list(
.aligned(HAlignment::Start + VAlignment::Top); .aligned(HAlignment::Start + VAlignment::Top);
let mut cells = vec![]; let mut cells = vec![];
let mut locator = locator.split();
for item in &elem.children { for item in &elem.children {
// Text in wide lists shall always turn into paragraphs. // Text in wide lists shall always turn into paragraphs.
let mut body = item.body.clone(); let mut body = item.body.clone();
@ -45,13 +43,10 @@ pub fn layout_list(
body += ParbreakElem::shared(); body += ParbreakElem::shared();
} }
cells.push(Cell::new(Content::empty(), locator.next(&()))); cells.push(Cell::new(Content::empty()));
cells.push(Cell::new(marker.clone(), locator.next(&marker.span()))); cells.push(Cell::new(marker.clone()));
cells.push(Cell::new(Content::empty(), locator.next(&()))); cells.push(Cell::new(Content::empty()));
cells.push(Cell::new( cells.push(Cell::new(body.set(ListElem::depth, Depth(1))));
body.set(ListElem::depth, Depth(1)),
locator.next(&item.body.span()),
));
} }
let grid = CellGrid::new( let grid = CellGrid::new(
@ -64,7 +59,7 @@ pub fn layout_list(
Axes::with_y(&[gutter.into()]), Axes::with_y(&[gutter.into()]),
cells, cells,
); );
let layouter = GridLayouter::new(&grid, regions, styles, elem.span()); let layouter = GridLayouter::new(&grid, regions, locator, styles, elem.span());
layouter.layout(engine) layouter.layout(engine)
} }
@ -88,7 +83,6 @@ pub fn layout_enum(
}); });
let mut cells = vec![]; let mut cells = vec![];
let mut locator = locator.split();
let mut number = elem let mut number = elem
.start .start
.get(styles) .get(styles)
@ -131,13 +125,10 @@ pub fn layout_enum(
body += ParbreakElem::shared(); body += ParbreakElem::shared();
} }
cells.push(Cell::new(Content::empty(), locator.next(&()))); cells.push(Cell::new(Content::empty()));
cells.push(Cell::new(resolved, locator.next(&()))); cells.push(Cell::new(resolved));
cells.push(Cell::new(Content::empty(), locator.next(&()))); cells.push(Cell::new(Content::empty()));
cells.push(Cell::new( cells.push(Cell::new(body.set(EnumElem::parents, smallvec![number])));
body.set(EnumElem::parents, smallvec![number]),
locator.next(&item.body.span()),
));
number = number =
if reversed { number.saturating_sub(1) } else { number.saturating_add(1) }; if reversed { number.saturating_sub(1) } else { number.saturating_add(1) };
} }
@ -152,7 +143,7 @@ pub fn layout_enum(
Axes::with_y(&[gutter.into()]), Axes::with_y(&[gutter.into()]),
cells, cells,
); );
let layouter = GridLayouter::new(&grid, regions, styles, elem.span()); let layouter = GridLayouter::new(&grid, regions, locator, styles, elem.span());
layouter.layout(engine) layouter.layout(engine)
} }

View File

@ -9,7 +9,6 @@ use typst_library::diag::{
}; };
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{Content, Fold, Packed, Smart, StyleChain}; use typst_library::foundations::{Content, Fold, Packed, Smart, StyleChain};
use typst_library::introspection::Locator;
use typst_library::layout::{ use typst_library::layout::{
Abs, Alignment, Axes, Celled, GridCell, GridChild, GridElem, GridItem, Length, Abs, Alignment, Axes, Celled, GridCell, GridChild, GridElem, GridItem, Length,
OuterHAlignment, OuterVAlignment, Rel, ResolvedCelled, Sides, Sizing, OuterHAlignment, OuterVAlignment, Rel, ResolvedCelled, Sides, Sizing,
@ -21,16 +20,13 @@ use typst_library::visualize::{Paint, Stroke};
use typst_syntax::Span; use typst_syntax::Span;
use typst_utils::{NonZeroExt, SmallBitSet}; use typst_utils::{NonZeroExt, SmallBitSet};
use crate::introspection::SplitLocator;
/// Convert a grid to a cell grid. /// Convert a grid to a cell grid.
#[typst_macros::time(span = elem.span())] #[typst_macros::time(span = elem.span())]
pub fn grid_to_cellgrid<'a>( pub fn grid_to_cellgrid(
elem: &Packed<GridElem>, elem: &Packed<GridElem>,
engine: &mut Engine, engine: &mut Engine,
locator: Locator<'a>,
styles: StyleChain, styles: StyleChain,
) -> SourceResult<CellGrid<'a>> { ) -> SourceResult<CellGrid> {
let inset = elem.inset.get_cloned(styles); let inset = elem.inset.get_cloned(styles);
let align = elem.align.get_ref(styles); let align = elem.align.get_ref(styles);
let columns = elem.columns.get_ref(styles); let columns = elem.columns.get_ref(styles);
@ -64,7 +60,6 @@ pub fn grid_to_cellgrid<'a>(
resolve_cellgrid( resolve_cellgrid(
tracks, tracks,
gutter, gutter,
locator,
children, children,
fill, fill,
align, align,
@ -79,12 +74,11 @@ pub fn grid_to_cellgrid<'a>(
/// Convert a table to a cell grid. /// Convert a table to a cell grid.
#[typst_macros::time(span = elem.span())] #[typst_macros::time(span = elem.span())]
pub fn table_to_cellgrid<'a>( pub fn table_to_cellgrid(
elem: &Packed<TableElem>, elem: &Packed<TableElem>,
engine: &mut Engine, engine: &mut Engine,
locator: Locator<'a>,
styles: StyleChain, styles: StyleChain,
) -> SourceResult<CellGrid<'a>> { ) -> SourceResult<CellGrid> {
let inset = elem.inset.get_cloned(styles); let inset = elem.inset.get_cloned(styles);
let align = elem.align.get_ref(styles); let align = elem.align.get_ref(styles);
let columns = elem.columns.get_ref(styles); let columns = elem.columns.get_ref(styles);
@ -118,7 +112,6 @@ pub fn table_to_cellgrid<'a>(
resolve_cellgrid( resolve_cellgrid(
tracks, tracks,
gutter, gutter,
locator,
children, children,
fill, fill,
align, align,
@ -206,7 +199,7 @@ fn table_item_to_resolvable(
} }
impl ResolvableCell for Packed<TableCell> { impl ResolvableCell for Packed<TableCell> {
fn resolve_cell<'a>( fn resolve_cell(
mut self, mut self,
x: usize, x: usize,
y: usize, y: usize,
@ -215,9 +208,8 @@ impl ResolvableCell for Packed<TableCell> {
inset: Sides<Option<Rel<Length>>>, inset: Sides<Option<Rel<Length>>>,
stroke: Sides<Option<Option<Arc<Stroke<Abs>>>>>, stroke: Sides<Option<Option<Arc<Stroke<Abs>>>>>,
breakable: bool, breakable: bool,
locator: Locator<'a>,
styles: StyleChain, styles: StyleChain,
) -> Cell<'a> { ) -> Cell {
let cell = &mut *self; let cell = &mut *self;
let colspan = cell.colspan.get(styles); let colspan = cell.colspan.get(styles);
let rowspan = cell.rowspan.get(styles); let rowspan = cell.rowspan.get(styles);
@ -269,7 +261,6 @@ impl ResolvableCell for Packed<TableCell> {
cell.breakable.set(Smart::Custom(breakable)); cell.breakable.set(Smart::Custom(breakable));
Cell { Cell {
body: self.pack(), body: self.pack(),
locator,
fill, fill,
colspan, colspan,
rowspan, rowspan,
@ -301,7 +292,7 @@ impl ResolvableCell for Packed<TableCell> {
} }
impl ResolvableCell for Packed<GridCell> { impl ResolvableCell for Packed<GridCell> {
fn resolve_cell<'a>( fn resolve_cell(
mut self, mut self,
x: usize, x: usize,
y: usize, y: usize,
@ -310,9 +301,8 @@ impl ResolvableCell for Packed<GridCell> {
inset: Sides<Option<Rel<Length>>>, inset: Sides<Option<Rel<Length>>>,
stroke: Sides<Option<Option<Arc<Stroke<Abs>>>>>, stroke: Sides<Option<Option<Arc<Stroke<Abs>>>>>,
breakable: bool, breakable: bool,
locator: Locator<'a>,
styles: StyleChain, styles: StyleChain,
) -> Cell<'a> { ) -> Cell {
let cell = &mut *self; let cell = &mut *self;
let colspan = cell.colspan.get(styles); let colspan = cell.colspan.get(styles);
let rowspan = cell.rowspan.get(styles); let rowspan = cell.rowspan.get(styles);
@ -364,7 +354,6 @@ impl ResolvableCell for Packed<GridCell> {
cell.breakable.set(Smart::Custom(breakable)); cell.breakable.set(Smart::Custom(breakable));
Cell { Cell {
body: self.pack(), body: self.pack(),
locator,
fill, fill,
colspan, colspan,
rowspan, rowspan,
@ -507,7 +496,7 @@ pub trait ResolvableCell {
/// the `breakable` field. /// the `breakable` field.
/// Returns a final Cell. /// Returns a final Cell.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn resolve_cell<'a>( fn resolve_cell(
self, self,
x: usize, x: usize,
y: usize, y: usize,
@ -516,9 +505,8 @@ pub trait ResolvableCell {
inset: Sides<Option<Rel<Length>>>, inset: Sides<Option<Rel<Length>>>,
stroke: Sides<Option<Option<Arc<Stroke<Abs>>>>>, stroke: Sides<Option<Option<Arc<Stroke<Abs>>>>>,
breakable: bool, breakable: bool,
locator: Locator<'a>,
styles: StyleChain, styles: StyleChain,
) -> Cell<'a>; ) -> Cell;
/// Returns this cell's column override. /// Returns this cell's column override.
fn x(&self, styles: StyleChain) -> Smart<usize>; fn x(&self, styles: StyleChain) -> Smart<usize>;
@ -570,11 +558,9 @@ pub enum ResolvableGridItem<T: ResolvableCell> {
} }
/// Represents a cell in CellGrid, to be laid out by GridLayouter. /// Represents a cell in CellGrid, to be laid out by GridLayouter.
pub struct Cell<'a> { pub struct Cell {
/// The cell's body. /// The cell's body.
pub body: Content, pub body: Content,
/// The cell's locator.
pub locator: Locator<'a>,
/// The cell's fill. /// The cell's fill.
pub fill: Option<Paint>, pub fill: Option<Paint>,
/// The amount of columns spanned by the cell. /// The amount of columns spanned by the cell.
@ -600,12 +586,11 @@ pub struct Cell<'a> {
pub breakable: bool, pub breakable: bool,
} }
impl<'a> Cell<'a> { impl Cell {
/// Create a simple cell given its body and its locator. /// Create a simple cell given its body.
pub fn new(body: Content, locator: Locator<'a>) -> Self { pub fn new(body: Content) -> Self {
Self { Self {
body, body,
locator,
fill: None, fill: None,
colspan: NonZeroUsize::ONE, colspan: NonZeroUsize::ONE,
rowspan: NonZeroUsize::ONE, rowspan: NonZeroUsize::ONE,
@ -629,9 +614,9 @@ pub enum LinePosition {
} }
/// A grid entry. /// A grid entry.
pub enum Entry<'a> { pub enum Entry {
/// An entry which holds a cell. /// An entry which holds a cell.
Cell(Cell<'a>), Cell(Cell),
/// An entry which is merged with another cell. /// An entry which is merged with another cell.
Merged { Merged {
/// The index of the cell this entry is merged with. /// The index of the cell this entry is merged with.
@ -639,9 +624,9 @@ pub enum Entry<'a> {
}, },
} }
impl<'a> Entry<'a> { impl Entry {
/// Obtains the cell inside this entry, if this is not a merged cell. /// Obtains the cell inside this entry, if this is not a merged cell.
pub fn as_cell(&self) -> Option<&Cell<'a>> { pub fn as_cell(&self) -> Option<&Cell> {
match self { match self {
Self::Cell(cell) => Some(cell), Self::Cell(cell) => Some(cell),
Self::Merged { .. } => None, Self::Merged { .. } => None,
@ -657,9 +642,9 @@ pub enum ResolvableGridChild<T: ResolvableCell, I> {
} }
/// A grid of cells, including the columns, rows, and cell data. /// A grid of cells, including the columns, rows, and cell data.
pub struct CellGrid<'a> { pub struct CellGrid {
/// The grid cells. /// The grid cells.
pub entries: Vec<Entry<'a>>, pub entries: Vec<Entry>,
/// The column tracks including gutter tracks. /// The column tracks including gutter tracks.
pub cols: Vec<Sizing>, pub cols: Vec<Sizing>,
/// The row tracks including gutter tracks. /// The row tracks including gutter tracks.
@ -680,12 +665,12 @@ pub struct CellGrid<'a> {
pub has_gutter: bool, pub has_gutter: bool,
} }
impl<'a> CellGrid<'a> { impl CellGrid {
/// Generates the cell grid, given the tracks and cells. /// Generates the cell grid, given the tracks and cells.
pub fn new( pub fn new(
tracks: Axes<&[Sizing]>, tracks: Axes<&[Sizing]>,
gutter: Axes<&[Sizing]>, gutter: Axes<&[Sizing]>,
cells: impl IntoIterator<Item = Cell<'a>>, cells: impl IntoIterator<Item = Cell>,
) -> Self { ) -> Self {
let entries = cells.into_iter().map(Entry::Cell).collect(); let entries = cells.into_iter().map(Entry::Cell).collect();
Self::new_internal(tracks, gutter, vec![], vec![], vec![], None, entries) Self::new_internal(tracks, gutter, vec![], vec![], vec![], None, entries)
@ -699,7 +684,7 @@ impl<'a> CellGrid<'a> {
hlines: Vec<Vec<Line>>, hlines: Vec<Vec<Line>>,
headers: Vec<Repeatable<Header>>, headers: Vec<Repeatable<Header>>,
footer: Option<Repeatable<Footer>>, footer: Option<Repeatable<Footer>>,
entries: Vec<Entry<'a>>, entries: Vec<Entry>,
) -> Self { ) -> Self {
let mut cols = vec![]; let mut cols = vec![];
let mut rows = vec![]; let mut rows = vec![];
@ -761,7 +746,7 @@ impl<'a> CellGrid<'a> {
/// ///
/// Returns `None` if it's a gutter cell. /// Returns `None` if it's a gutter cell.
#[track_caller] #[track_caller]
pub fn entry(&self, x: usize, y: usize) -> Option<&Entry<'a>> { pub fn entry(&self, x: usize, y: usize) -> Option<&Entry> {
assert!(x < self.cols.len()); assert!(x < self.cols.len());
assert!(y < self.rows.len()); assert!(y < self.rows.len());
@ -783,7 +768,7 @@ impl<'a> CellGrid<'a> {
/// ///
/// Returns `None` if it's a gutter cell or merged position. /// Returns `None` if it's a gutter cell or merged position.
#[track_caller] #[track_caller]
pub fn cell(&self, x: usize, y: usize) -> Option<&Cell<'a>> { pub fn cell(&self, x: usize, y: usize) -> Option<&Cell> {
self.entry(x, y).and_then(Entry::as_cell) self.entry(x, y).and_then(Entry::as_cell)
} }
@ -892,10 +877,9 @@ impl<'a> CellGrid<'a> {
/// must implement Default in order to fill positions in the grid which /// must implement Default in order to fill positions in the grid which
/// weren't explicitly specified by the user with empty cells. /// weren't explicitly specified by the user with empty cells.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn resolve_cellgrid<'a, 'x, T, C, I>( pub fn resolve_cellgrid<'a, T, C, I>(
tracks: Axes<&'a [Sizing]>, tracks: Axes<&'a [Sizing]>,
gutter: Axes<&'a [Sizing]>, gutter: Axes<&'a [Sizing]>,
locator: Locator<'x>,
children: C, children: C,
fill: &'a Celled<Option<Paint>>, fill: &'a Celled<Option<Paint>>,
align: &'a Celled<Smart<Alignment>>, align: &'a Celled<Smart<Alignment>>,
@ -904,7 +888,7 @@ pub fn resolve_cellgrid<'a, 'x, T, C, I>(
engine: &'a mut Engine, engine: &'a mut Engine,
styles: StyleChain<'a>, styles: StyleChain<'a>,
span: Span, span: Span,
) -> SourceResult<CellGrid<'x>> ) -> SourceResult<CellGrid>
where where
T: ResolvableCell + Default, T: ResolvableCell + Default,
I: Iterator<Item = ResolvableGridItem<T>>, I: Iterator<Item = ResolvableGridItem<T>>,
@ -914,7 +898,6 @@ where
CellGridResolver { CellGridResolver {
tracks, tracks,
gutter, gutter,
locator: locator.split(),
fill, fill,
align, align,
inset, inset,
@ -926,10 +909,9 @@ where
.resolve(children) .resolve(children)
} }
struct CellGridResolver<'a, 'b, 'x> { struct CellGridResolver<'a, 'b> {
tracks: Axes<&'a [Sizing]>, tracks: Axes<&'a [Sizing]>,
gutter: Axes<&'a [Sizing]>, gutter: Axes<&'a [Sizing]>,
locator: SplitLocator<'x>,
fill: &'a Celled<Option<Paint>>, fill: &'a Celled<Option<Paint>>,
align: &'a Celled<Smart<Alignment>>, align: &'a Celled<Smart<Alignment>>,
inset: &'a Celled<Sides<Option<Rel<Length>>>>, inset: &'a Celled<Sides<Option<Rel<Length>>>>,
@ -996,8 +978,8 @@ struct RowGroupData {
top_hlines_end: Option<usize>, top_hlines_end: Option<usize>,
} }
impl<'x> CellGridResolver<'_, '_, 'x> { impl CellGridResolver<'_, '_> {
fn resolve<T, C, I>(mut self, children: C) -> SourceResult<CellGrid<'x>> fn resolve<T, C, I>(mut self, children: C) -> SourceResult<CellGrid>
where where
T: ResolvableCell + Default, T: ResolvableCell + Default,
I: Iterator<Item = ResolvableGridItem<T>>, I: Iterator<Item = ResolvableGridItem<T>>,
@ -1138,7 +1120,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
footer: &mut Option<(usize, Span, Footer)>, footer: &mut Option<(usize, Span, Footer)>,
repeat_footer: &mut bool, repeat_footer: &mut bool,
auto_index: &mut usize, auto_index: &mut usize,
resolved_cells: &mut Vec<Option<Entry<'x>>>, resolved_cells: &mut Vec<Option<Entry>>,
at_least_one_cell: &mut bool, at_least_one_cell: &mut bool,
child: ResolvableGridChild<T, I>, child: ResolvableGridChild<T, I>,
) -> SourceResult<()> ) -> SourceResult<()>
@ -1441,7 +1423,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
// Let's resolve the cell so it can determine its own fields // Let's resolve the cell so it can determine its own fields
// based on its final position. // based on its final position.
let cell = self.resolve_cell(cell, x, y, rowspan, cell_span)?; let cell = self.resolve_cell(cell, x, y, rowspan)?;
if largest_index >= resolved_cells.len() { if largest_index >= resolved_cells.len() {
// Ensure the length of the vector of resolved cells is // Ensure the length of the vector of resolved cells is
@ -1538,14 +1520,9 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
// and footers without having to loop through them each time. // and footers without having to loop through them each time.
// Cells themselves, unfortunately, still have to. // Cells themselves, unfortunately, still have to.
assert!(resolved_cells[*local_auto_index].is_none()); assert!(resolved_cells[*local_auto_index].is_none());
resolved_cells[*local_auto_index] = resolved_cells[*local_auto_index] = Some(Entry::Cell(
Some(Entry::Cell(self.resolve_cell( self.resolve_cell(T::default(), 0, first_available_row, 1)?,
T::default(), ));
0,
first_available_row,
1,
Span::detached(),
)?));
group_start..group_end group_start..group_end
} }
@ -1635,9 +1612,9 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
/// can be affected by show rules and grid-wide styling. /// can be affected by show rules and grid-wide styling.
fn fixup_cells<T>( fn fixup_cells<T>(
&mut self, &mut self,
resolved_cells: Vec<Option<Entry<'x>>>, resolved_cells: Vec<Option<Entry>>,
columns: usize, columns: usize,
) -> SourceResult<Vec<Entry<'x>>> ) -> SourceResult<Vec<Entry>>
where where
T: ResolvableCell + Default, T: ResolvableCell + Default,
{ {
@ -1657,13 +1634,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
let x = i % columns; let x = i % columns;
let y = i / columns; let y = i / columns;
Ok(Entry::Cell(self.resolve_cell( Ok(Entry::Cell(self.resolve_cell(T::default(), x, y, 1)?))
T::default(),
x,
y,
1,
Span::detached(),
)?))
} }
}) })
.collect::<SourceResult<Vec<Entry>>>() .collect::<SourceResult<Vec<Entry>>>()
@ -1915,8 +1886,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
x: usize, x: usize,
y: usize, y: usize,
rowspan: usize, rowspan: usize,
cell_span: Span, ) -> SourceResult<Cell>
) -> SourceResult<Cell<'x>>
where where
T: ResolvableCell + Default, T: ResolvableCell + Default,
{ {
@ -1950,7 +1920,6 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
self.inset.resolve(self.engine, self.styles, x, y)?, self.inset.resolve(self.engine, self.styles, x, y)?,
self.stroke.resolve(self.engine, self.styles, x, y)?, self.stroke.resolve(self.engine, self.styles, x, y)?,
breakable, breakable,
self.locator.next(&cell_span),
self.styles, self.styles,
)) ))
} }
@ -1962,7 +1931,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
/// returned. Otherwise, the new `start..end` range of rows in the row group is /// returned. Otherwise, the new `start..end` range of rows in the row group is
/// returned. /// returned.
fn expand_row_group( fn expand_row_group(
resolved_cells: &[Option<Entry<'_>>], resolved_cells: &[Option<Entry>],
group_range: Option<&Range<usize>>, group_range: Option<&Range<usize>>,
group_kind: RowGroupKind, group_kind: RowGroupKind,
first_available_row: usize, first_available_row: usize,
@ -2280,7 +2249,7 @@ fn resolve_cell_position(
fn find_next_available_position( fn find_next_available_position(
header_rows: &SmallBitSet, header_rows: &SmallBitSet,
footer: Option<&(usize, Span, Footer)>, footer: Option<&(usize, Span, Footer)>,
resolved_cells: &[Option<Entry<'_>>], resolved_cells: &[Option<Entry>],
columns: usize, columns: usize,
initial_index: usize, initial_index: usize,
skip_rows: bool, skip_rows: bool,