mirror of
https://github.com/typst/typst
synced 2025-05-13 12:36:23 +08:00
Fix grid sizing
This commit is contained in:
parent
cc9b52ddd4
commit
b9c0fd87d3
@ -70,9 +70,9 @@ struct FlowLayouter<'a> {
|
|||||||
regions: Regions<'a>,
|
regions: Regions<'a>,
|
||||||
/// Whether the flow should expand to fill the region.
|
/// Whether the flow should expand to fill the region.
|
||||||
expand: Axes<bool>,
|
expand: Axes<bool>,
|
||||||
/// The full size of `regions.size` that was available before we started
|
/// The intial size of `regions.size` that was available before we started
|
||||||
/// subtracting.
|
/// subtracting.
|
||||||
full: Size,
|
initial: Size,
|
||||||
/// Whether the last block was a paragraph.
|
/// Whether the last block was a paragraph.
|
||||||
last_was_par: bool,
|
last_was_par: bool,
|
||||||
/// Spacing and layouted blocks.
|
/// Spacing and layouted blocks.
|
||||||
@ -98,7 +98,6 @@ impl<'a> FlowLayouter<'a> {
|
|||||||
/// Create a new flow layouter.
|
/// Create a new flow layouter.
|
||||||
fn new(mut regions: Regions<'a>) -> Self {
|
fn new(mut regions: Regions<'a>) -> Self {
|
||||||
let expand = regions.expand;
|
let expand = regions.expand;
|
||||||
let full = regions.size;
|
|
||||||
|
|
||||||
// Disable vertical expansion for children.
|
// Disable vertical expansion for children.
|
||||||
regions.expand.y = false;
|
regions.expand.y = false;
|
||||||
@ -106,7 +105,7 @@ impl<'a> FlowLayouter<'a> {
|
|||||||
Self {
|
Self {
|
||||||
regions,
|
regions,
|
||||||
expand,
|
expand,
|
||||||
full,
|
initial: regions.size,
|
||||||
last_was_par: false,
|
last_was_par: false,
|
||||||
items: vec![],
|
items: vec![],
|
||||||
finished: vec![],
|
finished: vec![],
|
||||||
@ -117,7 +116,7 @@ impl<'a> FlowLayouter<'a> {
|
|||||||
fn layout_spacing(&mut self, node: VNode, styles: StyleChain) {
|
fn layout_spacing(&mut self, node: VNode, styles: StyleChain) {
|
||||||
self.layout_item(match node.amount {
|
self.layout_item(match node.amount {
|
||||||
Spacing::Rel(v) => FlowItem::Absolute(
|
Spacing::Rel(v) => FlowItem::Absolute(
|
||||||
v.resolve(styles).relative_to(self.full.y),
|
v.resolve(styles).relative_to(self.initial.y),
|
||||||
node.weakness > 0,
|
node.weakness > 0,
|
||||||
),
|
),
|
||||||
Spacing::Fr(v) => FlowItem::Fractional(v),
|
Spacing::Fr(v) => FlowItem::Fractional(v),
|
||||||
@ -256,10 +255,10 @@ impl<'a> FlowLayouter<'a> {
|
|||||||
let mut fr = Fr::zero();
|
let mut fr = Fr::zero();
|
||||||
let mut used = Size::zero();
|
let mut used = Size::zero();
|
||||||
for item in &self.items {
|
for item in &self.items {
|
||||||
match *item {
|
match item {
|
||||||
FlowItem::Absolute(v, _) => used.y += v,
|
FlowItem::Absolute(v, _) => used.y += *v,
|
||||||
FlowItem::Fractional(v) => fr += v,
|
FlowItem::Fractional(v) => fr += *v,
|
||||||
FlowItem::Frame(ref frame, ..) => {
|
FlowItem::Frame(frame, ..) => {
|
||||||
let size = frame.size();
|
let size = frame.size();
|
||||||
used.y += size.y;
|
used.y += size.y;
|
||||||
used.x.set_max(size.x);
|
used.x.set_max(size.x);
|
||||||
@ -269,14 +268,10 @@ impl<'a> FlowLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine the size of the flow in this region depending on whether
|
// Determine the size of the flow in this region depending on whether
|
||||||
// the region expands.
|
// the region expands. Also account for fractional spacing.
|
||||||
let mut size = self.expand.select(self.full, used).min(self.full);
|
let mut size = self.expand.select(self.initial, used).min(self.initial);
|
||||||
|
if fr.get() > 0.0 && self.initial.y.is_finite() {
|
||||||
// Account for fractional spacing in the size calculation.
|
size.y = self.initial.y;
|
||||||
let remaining = self.full.y - used.y;
|
|
||||||
if fr.get() > 0.0 && self.full.y.is_finite() {
|
|
||||||
used.y = self.full.y;
|
|
||||||
size.y = self.full.y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output = Frame::new(size);
|
let mut output = Frame::new(size);
|
||||||
@ -290,6 +285,7 @@ impl<'a> FlowLayouter<'a> {
|
|||||||
offset += v;
|
offset += v;
|
||||||
}
|
}
|
||||||
FlowItem::Fractional(v) => {
|
FlowItem::Fractional(v) => {
|
||||||
|
let remaining = self.initial.y - used.y;
|
||||||
offset += v.share(fr, remaining);
|
offset += v.share(fr, remaining);
|
||||||
}
|
}
|
||||||
FlowItem::Frame(frame, aligns, _) => {
|
FlowItem::Frame(frame, aligns, _) => {
|
||||||
@ -309,7 +305,7 @@ impl<'a> FlowLayouter<'a> {
|
|||||||
// Advance to the next region.
|
// Advance to the next region.
|
||||||
self.finished.push(output);
|
self.finished.push(output);
|
||||||
self.regions.next();
|
self.regions.next();
|
||||||
self.full = self.regions.size;
|
self.initial = self.regions.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish layouting and return the resulting fragment.
|
/// Finish layouting and return the resulting fragment.
|
||||||
|
@ -184,15 +184,14 @@ pub struct GridLayouter<'a, 'v> {
|
|||||||
styles: StyleChain<'a>,
|
styles: StyleChain<'a>,
|
||||||
/// Resolved column sizes.
|
/// Resolved column sizes.
|
||||||
rcols: Vec<Abs>,
|
rcols: Vec<Abs>,
|
||||||
|
/// The sum of `rcols`.
|
||||||
|
width: Abs,
|
||||||
/// Resolve row sizes, by region.
|
/// Resolve row sizes, by region.
|
||||||
rrows: Vec<Vec<RowPiece>>,
|
rrows: Vec<Vec<RowPiece>>,
|
||||||
/// Rows in the current region.
|
/// Rows in the current region.
|
||||||
lrows: Vec<Row>,
|
lrows: Vec<Row>,
|
||||||
/// The used-up size of the current region. The horizontal size is
|
/// The initial size of the current region before we started subtracting.
|
||||||
/// determined once after columns are resolved and not touched again.
|
initial: Size,
|
||||||
used: Size,
|
|
||||||
/// The sum of fractions in the current region.
|
|
||||||
fr: Fr,
|
|
||||||
/// Frames for finished regions.
|
/// Frames for finished regions.
|
||||||
finished: Vec<Frame>,
|
finished: Vec<Frame>,
|
||||||
}
|
}
|
||||||
@ -306,10 +305,10 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
regions,
|
regions,
|
||||||
styles,
|
styles,
|
||||||
rcols,
|
rcols,
|
||||||
|
width: Abs::zero(),
|
||||||
rrows: vec![],
|
rrows: vec![],
|
||||||
lrows,
|
lrows,
|
||||||
used: Size::zero(),
|
initial: regions.size,
|
||||||
fr: Fr::zero(),
|
|
||||||
finished: vec![],
|
finished: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -328,10 +327,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
match self.rows[y] {
|
match self.rows[y] {
|
||||||
Sizing::Auto => self.layout_auto_row(y)?,
|
Sizing::Auto => self.layout_auto_row(y)?,
|
||||||
Sizing::Rel(v) => self.layout_relative_row(v, y)?,
|
Sizing::Rel(v) => self.layout_relative_row(v, y)?,
|
||||||
Sizing::Fr(v) => {
|
Sizing::Fr(v) => self.lrows.push(Row::Fr(v, y)),
|
||||||
self.lrows.push(Row::Fr(v, y));
|
|
||||||
self.fr += v;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,7 +380,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sum up the resolved column sizes once here.
|
// Sum up the resolved column sizes once here.
|
||||||
self.used.x = self.rcols.iter().sum();
|
self.width = self.rcols.iter().sum();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -523,13 +519,16 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
resolved.remove(0);
|
resolved.remove(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expand all but the last region if the space is not
|
// Expand all but the last region.
|
||||||
// eaten up by any fr rows.
|
// Skip the first region if the space is eaten up by an fr row.
|
||||||
if self.fr.is_zero() {
|
let len = resolved.len();
|
||||||
let len = resolved.len();
|
for (region, target) in self
|
||||||
for (region, target) in self.regions.iter().zip(&mut resolved[..len - 1]) {
|
.regions
|
||||||
target.set_max(region.y);
|
.iter()
|
||||||
}
|
.zip(&mut resolved[..len - 1])
|
||||||
|
.skip(self.lrows.iter().any(|row| matches!(row, Row::Fr(..))) as usize)
|
||||||
|
{
|
||||||
|
target.set_max(region.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layout into multiple regions.
|
// Layout into multiple regions.
|
||||||
@ -569,7 +568,7 @@ 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, height: Abs, y: usize) -> SourceResult<Frame> {
|
||||||
let mut output = Frame::new(Size::new(self.used.x, height));
|
let mut output = Frame::new(Size::new(self.width, height));
|
||||||
let mut pos = Point::zero();
|
let mut pos = Point::zero();
|
||||||
|
|
||||||
for (x, &rcol) in self.rcols.iter().enumerate() {
|
for (x, &rcol) in self.rcols.iter().enumerate() {
|
||||||
@ -594,11 +593,11 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
// Prepare frames.
|
// Prepare frames.
|
||||||
let mut outputs: Vec<_> = heights
|
let mut outputs: Vec<_> = heights
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&h| Frame::new(Size::new(self.used.x, h)))
|
.map(|&h| Frame::new(Size::new(self.width, h)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Prepare regions.
|
// Prepare regions.
|
||||||
let size = Size::new(self.used.x, heights[0]);
|
let size = Size::new(self.width, heights[0]);
|
||||||
let mut pod = Regions::one(size, Axes::splat(true));
|
let mut pod = Regions::one(size, Axes::splat(true));
|
||||||
pod.full = self.regions.full;
|
pod.full = self.regions.full;
|
||||||
pod.backlog = &heights[1..];
|
pod.backlog = &heights[1..];
|
||||||
@ -625,17 +624,26 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
/// Push a row frame into the current region.
|
/// Push a row frame into the current region.
|
||||||
fn push_row(&mut self, frame: Frame, y: usize) {
|
fn push_row(&mut self, frame: Frame, y: usize) {
|
||||||
self.regions.size.y -= frame.height();
|
self.regions.size.y -= frame.height();
|
||||||
self.used.y += frame.height();
|
|
||||||
self.lrows.push(Row::Frame(frame, y));
|
self.lrows.push(Row::Frame(frame, y));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish rows for one region.
|
/// Finish rows for one region.
|
||||||
fn finish_region(&mut self) -> SourceResult<()> {
|
fn finish_region(&mut self) -> SourceResult<()> {
|
||||||
|
// Determine the height of existing rows in the region.
|
||||||
|
let mut used = Abs::zero();
|
||||||
|
let mut fr = Fr::zero();
|
||||||
|
for row in &self.lrows {
|
||||||
|
match row {
|
||||||
|
Row::Frame(frame, _) => used += frame.height(),
|
||||||
|
Row::Fr(v, _) => fr += *v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Determine the size of the grid in this region, expanding fully if
|
// Determine the size of the grid in this region, expanding fully if
|
||||||
// there are fr rows.
|
// there are fr rows.
|
||||||
let mut size = self.used;
|
let mut size = Size::new(self.width, used).min(self.initial);
|
||||||
if self.fr.get() > 0.0 && self.regions.full.is_finite() {
|
if fr.get() > 0.0 && self.initial.y.is_finite() {
|
||||||
size.y = self.regions.full;
|
size.y = self.initial.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The frame for the region.
|
// The frame for the region.
|
||||||
@ -648,8 +656,8 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
let (frame, y) = match row {
|
let (frame, y) = match row {
|
||||||
Row::Frame(frame, y) => (frame, y),
|
Row::Frame(frame, y) => (frame, y),
|
||||||
Row::Fr(v, y) => {
|
Row::Fr(v, y) => {
|
||||||
let remaining = self.regions.full - self.used.y;
|
let remaining = self.regions.full - used;
|
||||||
let height = v.share(self.fr, remaining);
|
let height = v.share(fr, remaining);
|
||||||
(self.layout_single_row(height, y)?, y)
|
(self.layout_single_row(height, y)?, y)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -661,10 +669,9 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.finished.push(output);
|
self.finished.push(output);
|
||||||
self.regions.next();
|
|
||||||
self.rrows.push(rrows);
|
self.rrows.push(rrows);
|
||||||
self.used.y = Abs::zero();
|
self.regions.next();
|
||||||
self.fr = Fr::zero();
|
self.initial = self.regions.size;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -129,8 +129,8 @@ struct StackLayouter<'a> {
|
|||||||
styles: StyleChain<'a>,
|
styles: StyleChain<'a>,
|
||||||
/// Whether the stack itself should expand to fill the region.
|
/// Whether the stack itself should expand to fill the region.
|
||||||
expand: Axes<bool>,
|
expand: Axes<bool>,
|
||||||
/// The full size of the current region that was available at the start.
|
/// The initial size of the current region before we started subtracting.
|
||||||
full: Size,
|
initial: Size,
|
||||||
/// The generic size used by the frames for the current region.
|
/// The generic size used by the frames for the current region.
|
||||||
used: Gen<Abs>,
|
used: Gen<Abs>,
|
||||||
/// The sum of fractions in the current region.
|
/// The sum of fractions in the current region.
|
||||||
@ -154,13 +154,11 @@ enum StackItem {
|
|||||||
|
|
||||||
impl<'a> StackLayouter<'a> {
|
impl<'a> StackLayouter<'a> {
|
||||||
/// Create a new stack layouter.
|
/// Create a new stack layouter.
|
||||||
fn new(dir: Dir, regions: Regions<'a>, styles: StyleChain<'a>) -> Self {
|
fn new(dir: Dir, mut regions: Regions<'a>, styles: StyleChain<'a>) -> Self {
|
||||||
let axis = dir.axis();
|
let axis = dir.axis();
|
||||||
let expand = regions.expand;
|
let expand = regions.expand;
|
||||||
let full = regions.size;
|
|
||||||
|
|
||||||
// Disable expansion along the block axis for children.
|
// Disable expansion along the block axis for children.
|
||||||
let mut regions = regions.clone();
|
|
||||||
regions.expand.set(axis, false);
|
regions.expand.set(axis, false);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -169,7 +167,7 @@ impl<'a> StackLayouter<'a> {
|
|||||||
regions,
|
regions,
|
||||||
styles,
|
styles,
|
||||||
expand,
|
expand,
|
||||||
full,
|
initial: regions.size,
|
||||||
used: Gen::zero(),
|
used: Gen::zero(),
|
||||||
fr: Fr::zero(),
|
fr: Fr::zero(),
|
||||||
items: vec![],
|
items: vec![],
|
||||||
@ -251,11 +249,13 @@ impl<'a> StackLayouter<'a> {
|
|||||||
fn finish_region(&mut self) {
|
fn finish_region(&mut self) {
|
||||||
// Determine the size of the stack in this region dependening on whether
|
// Determine the size of the stack in this region dependening on whether
|
||||||
// the region expands.
|
// the region expands.
|
||||||
let used = self.used.to_axes(self.axis);
|
let mut size = self
|
||||||
let mut size = self.expand.select(self.full, used);
|
.expand
|
||||||
|
.select(self.initial, self.used.to_axes(self.axis))
|
||||||
|
.min(self.initial);
|
||||||
|
|
||||||
// Expand fully if there are fr spacings.
|
// Expand fully if there are fr spacings.
|
||||||
let full = self.full.get(self.axis);
|
let full = self.initial.get(self.axis);
|
||||||
let remaining = full - self.used.main;
|
let remaining = full - self.used.main;
|
||||||
if self.fr.get() > 0.0 && full.is_finite() {
|
if self.fr.get() > 0.0 && full.is_finite() {
|
||||||
self.used.main = full;
|
self.used.main = full;
|
||||||
@ -303,7 +303,7 @@ impl<'a> StackLayouter<'a> {
|
|||||||
|
|
||||||
// Advance to the next region.
|
// Advance to the next region.
|
||||||
self.regions.next();
|
self.regions.next();
|
||||||
self.full = self.regions.size;
|
self.initial = self.regions.size;
|
||||||
self.used = Gen::zero();
|
self.used = Gen::zero();
|
||||||
self.fr = Fr::zero();
|
self.fr = Fr::zero();
|
||||||
self.finished.push(output);
|
self.finished.push(output);
|
||||||
|
@ -34,7 +34,7 @@ impl Fr {
|
|||||||
pub fn share(self, total: Self, remaining: Abs) -> Abs {
|
pub fn share(self, total: Self, remaining: Abs) -> Abs {
|
||||||
let ratio = self / total;
|
let ratio = self / total;
|
||||||
if ratio.is_finite() && remaining.is_finite() {
|
if ratio.is_finite() && remaining.is_finite() {
|
||||||
ratio * remaining
|
(ratio * remaining).max(Abs::zero())
|
||||||
} else {
|
} else {
|
||||||
Abs::zero()
|
Abs::zero()
|
||||||
}
|
}
|
||||||
|
BIN
tests/ref/bugs/grid-3.png
Normal file
BIN
tests/ref/bugs/grid-3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
8
tests/typ/bugs/grid-3.typ
Normal file
8
tests/typ/bugs/grid-3.typ
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Ensure that the list does not jump to the third page.
|
||||||
|
|
||||||
|
---
|
||||||
|
#set page(height: 70pt)
|
||||||
|
#v(40pt)
|
||||||
|
The following:
|
||||||
|
+ A
|
||||||
|
+ B
|
Loading…
x
Reference in New Issue
Block a user