diff --git a/crates/typst-html/src/rules.rs b/crates/typst-html/src/rules.rs
index c30e8bd5f..a024d384e 100644
--- a/crates/typst-html/src/rules.rs
+++ b/crates/typst-html/src/rules.rs
@@ -5,7 +5,7 @@ use typst_library::diag::{At, bail, warning};
use typst_library::foundations::{
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::{BlockBody, BlockElem, BoxElem, OuterVAlignment, Sizing};
use typst_library::model::{
@@ -278,9 +278,7 @@ const REF_RULE: ShowFn = |elem, engine, styles| elem.realize(engine, st
const CITE_GROUP_RULE: ShowFn = |elem, engine, _| elem.realize(engine);
const TABLE_RULE: ShowFn = |elem, engine, styles| {
- // The locator is not used by HTML export, so we can just fabricate one.
- let locator = Locator::root();
- Ok(show_cellgrid(table_to_cellgrid(elem, engine, locator, styles)?, styles))
+ Ok(show_cellgrid(table_to_cellgrid(elem, engine, styles)?, styles))
};
fn show_cellgrid(grid: CellGrid, styles: StyleChain) -> Content {
diff --git a/crates/typst-layout/src/grid/layouter.rs b/crates/typst-layout/src/grid/layouter.rs
index 2e8cc9e55..fb48a4f33 100644
--- a/crates/typst-layout/src/grid/layouter.rs
+++ b/crates/typst-layout/src/grid/layouter.rs
@@ -1,11 +1,14 @@
use std::fmt::Debug;
+use rustc_hash::FxHashMap;
use typst_library::diag::{SourceResult, bail};
use typst_library::engine::Engine;
use typst_library::foundations::{Resolve, StyleChain};
+use typst_library::introspection::Locator;
use typst_library::layout::grid::resolve::{
Cell, CellGrid, Header, LinePosition, Repeatable,
};
+use typst_library::layout::resolve::Entry;
use typst_library::layout::{
Abs, Axes, Dir, Fr, Fragment, Frame, FrameItem, Length, Point, Region, Regions, Rel,
Size, Sizing,
@@ -23,9 +26,11 @@ use super::{
/// Performs grid layout.
pub struct GridLayouter<'a> {
/// The grid of cells.
- pub(super) grid: &'a CellGrid<'a>,
+ pub(super) grid: &'a CellGrid,
/// The regions to layout children into.
pub(super) regions: Regions<'a>,
+ /// The locators for the each cell in the cell grid.
+ pub(super) cell_locators: FxHashMap, Locator<'a>>,
/// The inherited styles.
pub(super) styles: StyleChain<'a>,
/// Resolved column sizes.
@@ -228,8 +233,9 @@ impl<'a> GridLayouter<'a> {
///
/// This prepares grid layout by unifying content and gutter tracks.
pub fn new(
- grid: &'a CellGrid<'a>,
+ grid: &'a CellGrid,
regions: Regions<'a>,
+ locator: Locator<'a>,
styles: StyleChain<'a>,
span: Span,
) -> Self {
@@ -238,9 +244,22 @@ impl<'a> GridLayouter<'a> {
let mut regions = regions;
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 {
grid,
regions,
+ cell_locators,
styles,
rcols: vec![Abs::zero(); grid.cols.len()],
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,
+ 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.
pub fn layout(mut self, engine: &mut Engine) -> SourceResult {
self.measure_columns(engine)?;
@@ -1037,8 +1072,9 @@ impl<'a> GridLayouter<'a> {
let size = Size::new(available, height);
let pod = Region::new(size, Axes::splat(false));
- let frame =
- layout_cell(cell, engine, 0, self.styles, pod.into())?.into_frame();
+ let locator = self.cell_locator(parent, 0);
+ let frame = layout_cell(cell, engine, locator, self.styles, pod.into())?
+ .into_frame();
resolved.set_max(frame.width() - already_covered_width);
}
@@ -1276,8 +1312,9 @@ impl<'a> GridLayouter<'a> {
pod
};
+ let locator = self.cell_locator(parent, disambiguator);
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,
// remeasure.
@@ -1434,9 +1471,9 @@ impl<'a> GridLayouter<'a> {
// rows.
pod.full = self.regions.full;
}
- let frame =
- layout_cell(cell, engine, disambiguator, self.styles, pod)?
- .into_frame();
+ let locator = self.cell_locator(Axes::new(x, y), disambiguator);
+ let frame = layout_cell(cell, engine, locator, self.styles, pod)?
+ .into_frame();
let mut pos = offset;
if self.is_rtl {
// In RTL cells expand to the left, thus the position
@@ -1483,8 +1520,8 @@ impl<'a> GridLayouter<'a> {
pod.size.x = width;
// Push the layouted frames into the individual output 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)?;
for (output, frame) in outputs.iter_mut().zip(fragment) {
let mut pos = offset;
if self.is_rtl {
diff --git a/crates/typst-layout/src/grid/lines.rs b/crates/typst-layout/src/grid/lines.rs
index 1c93fdb4d..f792ffb1f 100644
--- a/crates/typst-layout/src/grid/lines.rs
+++ b/crates/typst-layout/src/grid/lines.rs
@@ -560,17 +560,15 @@ pub fn hline_stroke_at_column(
mod test {
use std::num::NonZeroUsize;
use typst_library::foundations::Content;
- use typst_library::introspection::Locator;
use typst_library::layout::grid::resolve::{Cell, Entry, LinePosition};
use typst_library::layout::{Axes, Sides, Sizing};
use typst_utils::NonZeroExt;
use super::*;
- fn sample_cell() -> Cell<'static> {
+ fn sample_cell() -> Cell {
Cell {
body: Content::default(),
- locator: Locator::root(),
fill: None,
colspan: 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 {
body: Content::default(),
- locator: Locator::root(),
fill: None,
colspan: NonZeroUsize::try_from(colspan).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 ROWS: usize = 6;
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 ROWS: usize = 9;
let entries = vec![
diff --git a/crates/typst-layout/src/grid/mod.rs b/crates/typst-layout/src/grid/mod.rs
index 2f78e090d..45fba260d 100644
--- a/crates/typst-layout/src/grid/mod.rs
+++ b/crates/typst-layout/src/grid/mod.rs
@@ -28,14 +28,10 @@ use self::rowspans::{Rowspan, UnbreakableRowGroup};
pub fn layout_cell(
cell: &Cell,
engine: &mut Engine,
- disambiguator: usize,
+ locator: Locator,
styles: StyleChain,
regions: Regions,
) -> SourceResult {
- 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)
}
@@ -48,8 +44,8 @@ pub fn layout_grid(
styles: StyleChain,
regions: Regions,
) -> SourceResult {
- let grid = grid_to_cellgrid(elem, engine, locator, styles)?;
- GridLayouter::new(&grid, regions, styles, elem.span()).layout(engine)
+ let grid = grid_to_cellgrid(elem, engine, styles)?;
+ GridLayouter::new(&grid, regions, locator, styles, elem.span()).layout(engine)
}
/// Layout the table.
@@ -61,6 +57,6 @@ pub fn layout_table(
styles: StyleChain,
regions: Regions,
) -> SourceResult {
- let grid = table_to_cellgrid(elem, engine, locator, styles)?;
- GridLayouter::new(&grid, regions, styles, elem.span()).layout(engine)
+ let grid = table_to_cellgrid(elem, engine, styles)?;
+ GridLayouter::new(&grid, regions, locator, styles, elem.span()).layout(engine)
}
diff --git a/crates/typst-layout/src/grid/rowspans.rs b/crates/typst-layout/src/grid/rowspans.rs
index 66da9bd85..1faa31550 100644
--- a/crates/typst-layout/src/grid/rowspans.rs
+++ b/crates/typst-layout/src/grid/rowspans.rs
@@ -145,7 +145,8 @@ impl GridLayouter<'_> {
}
// 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();
// Clever trick to process finished header rows:
diff --git a/crates/typst-layout/src/lists.rs b/crates/typst-layout/src/lists.rs
index 3a3ea8227..b116836cb 100644
--- a/crates/typst-layout/src/lists.rs
+++ b/crates/typst-layout/src/lists.rs
@@ -36,8 +36,6 @@ pub fn layout_list(
.aligned(HAlignment::Start + VAlignment::Top);
let mut cells = vec![];
- let mut locator = locator.split();
-
for item in &elem.children {
// Text in wide lists shall always turn into paragraphs.
let mut body = item.body.clone();
@@ -45,13 +43,10 @@ pub fn layout_list(
body += ParbreakElem::shared();
}
- cells.push(Cell::new(Content::empty(), locator.next(&())));
- cells.push(Cell::new(marker.clone(), locator.next(&marker.span())));
- cells.push(Cell::new(Content::empty(), locator.next(&())));
- cells.push(Cell::new(
- body.set(ListElem::depth, Depth(1)),
- locator.next(&item.body.span()),
- ));
+ cells.push(Cell::new(Content::empty()));
+ cells.push(Cell::new(marker.clone()));
+ cells.push(Cell::new(Content::empty()));
+ cells.push(Cell::new(body.set(ListElem::depth, Depth(1))));
}
let grid = CellGrid::new(
@@ -64,7 +59,7 @@ pub fn layout_list(
Axes::with_y(&[gutter.into()]),
cells,
);
- let layouter = GridLayouter::new(&grid, regions, styles, elem.span());
+ let layouter = GridLayouter::new(&grid, regions, locator, styles, elem.span());
layouter.layout(engine)
}
@@ -88,7 +83,6 @@ pub fn layout_enum(
});
let mut cells = vec![];
- let mut locator = locator.split();
let mut number = elem
.start
.get(styles)
@@ -131,13 +125,10 @@ pub fn layout_enum(
body += ParbreakElem::shared();
}
- cells.push(Cell::new(Content::empty(), locator.next(&())));
- cells.push(Cell::new(resolved, locator.next(&())));
- cells.push(Cell::new(Content::empty(), locator.next(&())));
- cells.push(Cell::new(
- body.set(EnumElem::parents, smallvec![number]),
- locator.next(&item.body.span()),
- ));
+ cells.push(Cell::new(Content::empty()));
+ cells.push(Cell::new(resolved));
+ cells.push(Cell::new(Content::empty()));
+ cells.push(Cell::new(body.set(EnumElem::parents, smallvec![number])));
number =
if reversed { number.saturating_sub(1) } else { number.saturating_add(1) };
}
@@ -152,7 +143,7 @@ pub fn layout_enum(
Axes::with_y(&[gutter.into()]),
cells,
);
- let layouter = GridLayouter::new(&grid, regions, styles, elem.span());
+ let layouter = GridLayouter::new(&grid, regions, locator, styles, elem.span());
layouter.layout(engine)
}
diff --git a/crates/typst-library/src/layout/grid/resolve.rs b/crates/typst-library/src/layout/grid/resolve.rs
index e8c52d2fb..6a2472897 100644
--- a/crates/typst-library/src/layout/grid/resolve.rs
+++ b/crates/typst-library/src/layout/grid/resolve.rs
@@ -9,7 +9,6 @@ use typst_library::diag::{
};
use typst_library::engine::Engine;
use typst_library::foundations::{Content, Fold, Packed, Smart, StyleChain};
-use typst_library::introspection::Locator;
use typst_library::layout::{
Abs, Alignment, Axes, Celled, GridCell, GridChild, GridElem, GridItem, Length,
OuterHAlignment, OuterVAlignment, Rel, ResolvedCelled, Sides, Sizing,
@@ -21,16 +20,13 @@ use typst_library::visualize::{Paint, Stroke};
use typst_syntax::Span;
use typst_utils::{NonZeroExt, SmallBitSet};
-use crate::introspection::SplitLocator;
-
/// Convert a grid to a cell grid.
#[typst_macros::time(span = elem.span())]
-pub fn grid_to_cellgrid<'a>(
+pub fn grid_to_cellgrid(
elem: &Packed,
engine: &mut Engine,
- locator: Locator<'a>,
styles: StyleChain,
-) -> SourceResult> {
+) -> SourceResult {
let inset = elem.inset.get_cloned(styles);
let align = elem.align.get_ref(styles);
let columns = elem.columns.get_ref(styles);
@@ -64,7 +60,6 @@ pub fn grid_to_cellgrid<'a>(
resolve_cellgrid(
tracks,
gutter,
- locator,
children,
fill,
align,
@@ -79,12 +74,11 @@ pub fn grid_to_cellgrid<'a>(
/// Convert a table to a cell grid.
#[typst_macros::time(span = elem.span())]
-pub fn table_to_cellgrid<'a>(
+pub fn table_to_cellgrid(
elem: &Packed,
engine: &mut Engine,
- locator: Locator<'a>,
styles: StyleChain,
-) -> SourceResult> {
+) -> SourceResult {
let inset = elem.inset.get_cloned(styles);
let align = elem.align.get_ref(styles);
let columns = elem.columns.get_ref(styles);
@@ -118,7 +112,6 @@ pub fn table_to_cellgrid<'a>(
resolve_cellgrid(
tracks,
gutter,
- locator,
children,
fill,
align,
@@ -206,7 +199,7 @@ fn table_item_to_resolvable(
}
impl ResolvableCell for Packed {
- fn resolve_cell<'a>(
+ fn resolve_cell(
mut self,
x: usize,
y: usize,
@@ -215,9 +208,8 @@ impl ResolvableCell for Packed {
inset: Sides