mirror of
https://github.com/typst/typst
synced 2025-05-20 12:05:27 +08:00
Pass Vt
through grid layouter explicitly
This commit is contained in:
parent
c5cdbaeaf8
commit
6c542ea1a4
@ -256,7 +256,6 @@ impl Layout for EnumElem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let layouter = GridLayouter::new(
|
let layouter = GridLayouter::new(
|
||||||
vt,
|
|
||||||
Axes::with_x(&[
|
Axes::with_x(&[
|
||||||
Sizing::Rel(indent.into()),
|
Sizing::Rel(indent.into()),
|
||||||
Sizing::Auto,
|
Sizing::Auto,
|
||||||
@ -269,7 +268,7 @@ impl Layout for EnumElem {
|
|||||||
styles,
|
styles,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(layouter.layout()?.fragment)
|
Ok(layouter.layout(vt)?.fragment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ pub struct GridElem {
|
|||||||
#[parse(args.named("row-gutter")?.or_else(|| gutter.clone()))]
|
#[parse(args.named("row-gutter")?.or_else(|| gutter.clone()))]
|
||||||
pub row_gutter: TrackSizings,
|
pub row_gutter: TrackSizings,
|
||||||
|
|
||||||
/// The contents of the table cells.
|
/// The contents of the grid cells.
|
||||||
///
|
///
|
||||||
/// The cells are populated in row-major order.
|
/// The cells are populated in row-major order.
|
||||||
#[variadic]
|
#[variadic]
|
||||||
@ -112,7 +112,6 @@ impl Layout for GridElem {
|
|||||||
// Prepare grid layout by unifying content and gutter tracks.
|
// Prepare grid layout by unifying content and gutter tracks.
|
||||||
let cells = self.children();
|
let cells = self.children();
|
||||||
let layouter = GridLayouter::new(
|
let layouter = GridLayouter::new(
|
||||||
vt,
|
|
||||||
Axes::new(&self.columns(styles).0, &self.rows(styles).0),
|
Axes::new(&self.columns(styles).0, &self.rows(styles).0),
|
||||||
Axes::new(&self.column_gutter(styles).0, &self.row_gutter(styles).0),
|
Axes::new(&self.column_gutter(styles).0, &self.row_gutter(styles).0),
|
||||||
&cells,
|
&cells,
|
||||||
@ -121,7 +120,7 @@ impl Layout for GridElem {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Measure the columns and layout the grid row-by-row.
|
// Measure the columns and layout the grid row-by-row.
|
||||||
Ok(layouter.layout()?.fragment)
|
Ok(layouter.layout(vt)?.fragment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,9 +137,7 @@ cast! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Performs grid layout.
|
/// Performs grid layout.
|
||||||
pub struct GridLayouter<'a, 'v> {
|
pub struct GridLayouter<'a> {
|
||||||
/// The core context.
|
|
||||||
vt: &'a mut Vt<'v>,
|
|
||||||
/// The grid cells.
|
/// The grid cells.
|
||||||
cells: &'a [Content],
|
cells: &'a [Content],
|
||||||
/// Whether this is an RTL grid.
|
/// Whether this is an RTL grid.
|
||||||
@ -198,12 +195,11 @@ enum Row {
|
|||||||
Fr(Fr, usize),
|
Fr(Fr, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'v> GridLayouter<'a, 'v> {
|
impl<'a> GridLayouter<'a> {
|
||||||
/// Create a new grid layouter.
|
/// Create a new grid layouter.
|
||||||
///
|
///
|
||||||
/// 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(
|
||||||
vt: &'a mut Vt<'v>,
|
|
||||||
tracks: Axes<&[Sizing]>,
|
tracks: Axes<&[Sizing]>,
|
||||||
gutter: Axes<&[Sizing]>,
|
gutter: Axes<&[Sizing]>,
|
||||||
cells: &'a [Content],
|
cells: &'a [Content],
|
||||||
@ -260,51 +256,47 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
cols.reverse();
|
cols.reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
let rcols = vec![Abs::zero(); cols.len()];
|
|
||||||
let lrows = vec![];
|
|
||||||
|
|
||||||
// We use these regions for auto row measurement. Since at that moment,
|
// We use these regions for auto row measurement. Since at that moment,
|
||||||
// columns are already sized, we can enable horizontal expansion.
|
// columns are already sized, we can enable horizontal expansion.
|
||||||
let mut regions = regions;
|
let mut regions = regions;
|
||||||
regions.expand = Axes::new(true, false);
|
regions.expand = Axes::new(true, false);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
vt,
|
|
||||||
cells,
|
cells,
|
||||||
is_rtl,
|
is_rtl,
|
||||||
has_gutter,
|
has_gutter,
|
||||||
cols,
|
|
||||||
rows,
|
rows,
|
||||||
regions,
|
regions,
|
||||||
styles,
|
styles,
|
||||||
rcols,
|
rcols: vec![Abs::zero(); cols.len()],
|
||||||
|
cols,
|
||||||
width: Abs::zero(),
|
width: Abs::zero(),
|
||||||
rrows: vec![],
|
rrows: vec![],
|
||||||
lrows,
|
lrows: vec![],
|
||||||
initial: regions.size,
|
initial: regions.size,
|
||||||
finished: vec![],
|
finished: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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) -> SourceResult<GridLayout> {
|
pub fn layout(mut self, vt: &mut Vt) -> SourceResult<GridLayout> {
|
||||||
self.measure_columns()?;
|
self.measure_columns(vt)?;
|
||||||
|
|
||||||
for y in 0..self.rows.len() {
|
for y in 0..self.rows.len() {
|
||||||
// Skip to next region if current one is full, but only for content
|
// Skip to next region if current one is full, but only for content
|
||||||
// rows, not for gutter rows.
|
// rows, not for gutter rows.
|
||||||
if self.regions.is_full() && (!self.has_gutter || y % 2 == 0) {
|
if self.regions.is_full() && (!self.has_gutter || y % 2 == 0) {
|
||||||
self.finish_region()?;
|
self.finish_region(vt)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.rows[y] {
|
match self.rows[y] {
|
||||||
Sizing::Auto => self.layout_auto_row(y)?,
|
Sizing::Auto => self.layout_auto_row(vt, y)?,
|
||||||
Sizing::Rel(v) => self.layout_relative_row(v, y)?,
|
Sizing::Rel(v) => self.layout_relative_row(vt, v, y)?,
|
||||||
Sizing::Fr(v) => self.lrows.push(Row::Fr(v, y)),
|
Sizing::Fr(v) => self.lrows.push(Row::Fr(v, y)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.finish_region()?;
|
self.finish_region(vt)?;
|
||||||
|
|
||||||
Ok(GridLayout {
|
Ok(GridLayout {
|
||||||
fragment: Fragment::frames(self.finished),
|
fragment: Fragment::frames(self.finished),
|
||||||
@ -315,7 +307,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
|
|
||||||
/// Determine all column sizes.
|
/// Determine all column sizes.
|
||||||
#[tracing::instrument(name = "GridLayouter::measure_columns", skip_all)]
|
#[tracing::instrument(name = "GridLayouter::measure_columns", skip_all)]
|
||||||
fn measure_columns(&mut self) -> SourceResult<()> {
|
fn measure_columns(&mut self, vt: &mut Vt) -> SourceResult<()> {
|
||||||
// Sum of sizes of resolved relative tracks.
|
// Sum of sizes of resolved relative tracks.
|
||||||
let mut rel = Abs::zero();
|
let mut rel = Abs::zero();
|
||||||
|
|
||||||
@ -341,7 +333,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
let available = self.regions.size.x - rel;
|
let available = self.regions.size.x - rel;
|
||||||
if available >= Abs::zero() {
|
if available >= Abs::zero() {
|
||||||
// Determine size of auto columns.
|
// Determine size of auto columns.
|
||||||
let (auto, count) = self.measure_auto_columns(available)?;
|
let (auto, count) = self.measure_auto_columns(vt, available)?;
|
||||||
|
|
||||||
// If there is remaining space, distribute it to fractional columns,
|
// If there is remaining space, distribute it to fractional columns,
|
||||||
// otherwise shrink auto columns.
|
// otherwise shrink auto columns.
|
||||||
@ -360,7 +352,11 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Measure the size that is available to auto columns.
|
/// Measure the size that is available to auto columns.
|
||||||
fn measure_auto_columns(&mut self, available: Abs) -> SourceResult<(Abs, usize)> {
|
fn measure_auto_columns(
|
||||||
|
&mut self,
|
||||||
|
vt: &mut Vt,
|
||||||
|
available: Abs,
|
||||||
|
) -> SourceResult<(Abs, usize)> {
|
||||||
let mut auto = Abs::zero();
|
let mut auto = Abs::zero();
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
|
|
||||||
@ -385,7 +381,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
|
|
||||||
let size = Size::new(available, height);
|
let size = Size::new(available, height);
|
||||||
let pod = Regions::one(size, Axes::splat(false));
|
let pod = Regions::one(size, Axes::splat(false));
|
||||||
let frame = cell.measure(self.vt, self.styles, pod)?.into_frame();
|
let frame = cell.measure(vt, self.styles, pod)?.into_frame();
|
||||||
resolved.set_max(frame.width());
|
resolved.set_max(frame.width());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -446,14 +442,14 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
|
|
||||||
/// Layout a row with automatic height. Such a row may break across multiple
|
/// Layout a row with automatic height. Such a row may break across multiple
|
||||||
/// regions.
|
/// regions.
|
||||||
fn layout_auto_row(&mut self, y: usize) -> SourceResult<()> {
|
fn layout_auto_row(&mut self, vt: &mut Vt, y: usize) -> SourceResult<()> {
|
||||||
// Determine the size for each region of the row. If the first region
|
// Determine the size for each region of the row. If the first region
|
||||||
// ends up empty for some column, skip the region and remeasure.
|
// ends up empty for some column, skip the region and remeasure.
|
||||||
let mut resolved = match self.measure_auto_row(y, true)? {
|
let mut resolved = match self.measure_auto_row(vt, y, true)? {
|
||||||
Some(resolved) => resolved,
|
Some(resolved) => resolved,
|
||||||
None => {
|
None => {
|
||||||
self.finish_region()?;
|
self.finish_region(vt)?;
|
||||||
self.measure_auto_row(y, false)?.unwrap()
|
self.measure_auto_row(vt, y, false)?.unwrap()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -464,7 +460,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
|
|
||||||
// Layout into a single region.
|
// Layout into a single region.
|
||||||
if let &[first] = resolved.as_slice() {
|
if let &[first] = resolved.as_slice() {
|
||||||
let frame = self.layout_single_row(first, y)?;
|
let frame = self.layout_single_row(vt, first, y)?;
|
||||||
self.push_row(frame, y);
|
self.push_row(frame, y);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -482,12 +478,12 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Layout into multiple regions.
|
// Layout into multiple regions.
|
||||||
let fragment = self.layout_multi_row(&resolved, y)?;
|
let fragment = self.layout_multi_row(vt, &resolved, y)?;
|
||||||
let len = fragment.len();
|
let len = fragment.len();
|
||||||
for (i, frame) in fragment.into_iter().enumerate() {
|
for (i, frame) in fragment.into_iter().enumerate() {
|
||||||
self.push_row(frame, y);
|
self.push_row(frame, y);
|
||||||
if i + 1 < len {
|
if i + 1 < len {
|
||||||
self.finish_region()?;
|
self.finish_region(vt)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,6 +494,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
/// if `can_skip` is false.
|
/// if `can_skip` is false.
|
||||||
fn measure_auto_row(
|
fn measure_auto_row(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
vt: &mut Vt,
|
||||||
y: usize,
|
y: usize,
|
||||||
can_skip: bool,
|
can_skip: bool,
|
||||||
) -> SourceResult<Option<Vec<Abs>>> {
|
) -> SourceResult<Option<Vec<Abs>>> {
|
||||||
@ -508,7 +505,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
let mut pod = self.regions;
|
let mut pod = self.regions;
|
||||||
pod.size.x = rcol;
|
pod.size.x = rcol;
|
||||||
|
|
||||||
let frames = cell.measure(self.vt, self.styles, pod)?.into_frames();
|
let frames = cell.measure(vt, 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.
|
||||||
@ -537,14 +534,19 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
|
|
||||||
/// Layout a row with relative height. Such a row cannot break across
|
/// Layout a row with relative height. Such a row cannot break across
|
||||||
/// multiple regions, but it may force a region break.
|
/// multiple regions, but it may force a region break.
|
||||||
fn layout_relative_row(&mut self, v: Rel<Length>, y: usize) -> SourceResult<()> {
|
fn layout_relative_row(
|
||||||
|
&mut self,
|
||||||
|
vt: &mut Vt,
|
||||||
|
v: Rel<Length>,
|
||||||
|
y: usize,
|
||||||
|
) -> SourceResult<()> {
|
||||||
let resolved = v.resolve(self.styles).relative_to(self.regions.base().y);
|
let resolved = v.resolve(self.styles).relative_to(self.regions.base().y);
|
||||||
let frame = self.layout_single_row(resolved, y)?;
|
let frame = self.layout_single_row(vt, resolved, y)?;
|
||||||
|
|
||||||
// Skip to fitting region.
|
// Skip to fitting region.
|
||||||
let height = frame.height();
|
let height = frame.height();
|
||||||
while !self.regions.size.y.fits(height) && !self.regions.in_last() {
|
while !self.regions.size.y.fits(height) && !self.regions.in_last() {
|
||||||
self.finish_region()?;
|
self.finish_region(vt)?;
|
||||||
|
|
||||||
// Don't skip multiple regions for gutter and don't push a row.
|
// Don't skip multiple regions for gutter and don't push a row.
|
||||||
if self.has_gutter && y % 2 == 1 {
|
if self.has_gutter && y % 2 == 1 {
|
||||||
@ -558,7 +560,12 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Layout a row with fixed height and return its frame.
|
/// Layout a row with fixed height and return its frame.
|
||||||
fn layout_single_row(&mut self, height: Abs, y: usize) -> SourceResult<Frame> {
|
fn layout_single_row(
|
||||||
|
&mut self,
|
||||||
|
vt: &mut Vt,
|
||||||
|
height: Abs,
|
||||||
|
y: usize,
|
||||||
|
) -> SourceResult<Frame> {
|
||||||
let mut output = Frame::new(Size::new(self.width, height));
|
let mut output = Frame::new(Size::new(self.width, height));
|
||||||
let mut pos = Point::zero();
|
let mut pos = Point::zero();
|
||||||
|
|
||||||
@ -569,7 +576,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
if self.rows[y] == Sizing::Auto {
|
if self.rows[y] == Sizing::Auto {
|
||||||
pod.full = self.regions.full;
|
pod.full = self.regions.full;
|
||||||
}
|
}
|
||||||
let frame = cell.layout(self.vt, self.styles, pod)?.into_frame();
|
let frame = cell.layout(vt, self.styles, pod)?.into_frame();
|
||||||
output.push_frame(pos, frame);
|
output.push_frame(pos, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -580,7 +587,12 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Layout a row spanning multiple regions.
|
/// Layout a row spanning multiple regions.
|
||||||
fn layout_multi_row(&mut self, heights: &[Abs], y: usize) -> SourceResult<Fragment> {
|
fn layout_multi_row(
|
||||||
|
&mut self,
|
||||||
|
vt: &mut Vt,
|
||||||
|
heights: &[Abs],
|
||||||
|
y: usize,
|
||||||
|
) -> SourceResult<Fragment> {
|
||||||
// Prepare frames.
|
// Prepare frames.
|
||||||
let mut outputs: Vec<_> = heights
|
let mut outputs: Vec<_> = heights
|
||||||
.iter()
|
.iter()
|
||||||
@ -600,7 +612,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
pod.size.x = rcol;
|
pod.size.x = rcol;
|
||||||
|
|
||||||
// Push the layouted frames into the individual output frames.
|
// Push the layouted frames into the individual output frames.
|
||||||
let fragment = cell.layout(self.vt, self.styles, pod)?;
|
let fragment = cell.layout(vt, self.styles, pod)?;
|
||||||
for (output, frame) in outputs.iter_mut().zip(fragment) {
|
for (output, frame) in outputs.iter_mut().zip(fragment) {
|
||||||
output.push_frame(pos, frame);
|
output.push_frame(pos, frame);
|
||||||
}
|
}
|
||||||
@ -619,7 +631,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finish rows for one region.
|
/// Finish rows for one region.
|
||||||
fn finish_region(&mut self) -> SourceResult<()> {
|
fn finish_region(&mut self, vt: &mut Vt) -> SourceResult<()> {
|
||||||
// Determine the height of existing rows in the region.
|
// Determine the height of existing rows in the region.
|
||||||
let mut used = Abs::zero();
|
let mut used = Abs::zero();
|
||||||
let mut fr = Fr::zero();
|
let mut fr = Fr::zero();
|
||||||
@ -649,7 +661,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
Row::Fr(v, y) => {
|
Row::Fr(v, y) => {
|
||||||
let remaining = self.regions.full - used;
|
let remaining = self.regions.full - used;
|
||||||
let height = v.share(fr, remaining);
|
let height = v.share(fr, remaining);
|
||||||
(self.layout_single_row(height, y)?, y)
|
(self.layout_single_row(vt, height, y)?, y)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -151,7 +151,6 @@ impl Layout for ListElem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let layouter = GridLayouter::new(
|
let layouter = GridLayouter::new(
|
||||||
vt,
|
|
||||||
Axes::with_x(&[
|
Axes::with_x(&[
|
||||||
Sizing::Rel(indent.into()),
|
Sizing::Rel(indent.into()),
|
||||||
Sizing::Auto,
|
Sizing::Auto,
|
||||||
@ -164,7 +163,7 @@ impl Layout for ListElem {
|
|||||||
styles,
|
styles,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(layouter.layout()?.fragment)
|
Ok(layouter.layout(vt)?.fragment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +162,6 @@ impl Layout for TableElem {
|
|||||||
|
|
||||||
// Prepare grid layout by unifying content and gutter tracks.
|
// Prepare grid layout by unifying content and gutter tracks.
|
||||||
let layouter = GridLayouter::new(
|
let layouter = GridLayouter::new(
|
||||||
vt,
|
|
||||||
tracks.as_deref(),
|
tracks.as_deref(),
|
||||||
gutter.as_deref(),
|
gutter.as_deref(),
|
||||||
&cells,
|
&cells,
|
||||||
@ -171,7 +170,7 @@ impl Layout for TableElem {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Measure the columns and layout the grid row-by-row.
|
// Measure the columns and layout the grid row-by-row.
|
||||||
let mut layout = layouter.layout()?;
|
let mut layout = layouter.layout(vt)?;
|
||||||
|
|
||||||
// Add lines and backgrounds.
|
// Add lines and backgrounds.
|
||||||
for (frame, rows) in layout.fragment.iter_mut().zip(&layout.rows) {
|
for (frame, rows) in layout.fragment.iter_mut().zip(&layout.rows) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user