Fix panic due to bad alignments in stack function

This commit is contained in:
Laurenz 2021-09-27 13:40:56 +02:00
parent ff37a2893d
commit e10b3d838a
6 changed files with 57 additions and 25 deletions

View File

@ -181,13 +181,13 @@ pub fn div(lhs: Value, rhs: Value) -> StrResult<Value> {
(Relative(a), Float(b)) => Relative(a / b),
(Relative(a), Relative(b)) => Float(a / b),
(Linear(a), Int(b)) => Linear(a / b as f64),
(Linear(a), Float(b)) => Linear(a / b),
(Fractional(a), Int(b)) => Fractional(a / b as f64),
(Fractional(a), Float(b)) => Fractional(a / b),
(Fractional(a), Fractional(b)) => Float(a / b),
(Linear(a), Int(b)) => Linear(a / b as f64),
(Linear(a), Float(b)) => Linear(a / b),
(a, b) => mismatch!("cannot divide {} by {}", a, b),
})
}

View File

@ -96,9 +96,9 @@ impl From<ParNode> for LayoutNode {
impl Debug for ParChild {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
ParChild::Spacing(v) => write!(f, "Spacing({:?})", v),
ParChild::Text(text, ..) => write!(f, "Text({:?})", text),
ParChild::Any(node, ..) => f.debug_tuple("Any").field(node).finish(),
Self::Spacing(v) => write!(f, "Spacing({:?})", v),
Self::Text(text, ..) => write!(f, "Text({:?})", text),
Self::Any(node, ..) => node.fmt(f),
}
}
}

View File

@ -1,3 +1,5 @@
use std::fmt::{self, Debug, Formatter};
use super::*;
/// A node that stacks its children.
@ -14,7 +16,6 @@ pub struct StackNode {
}
/// A child of a stack node.
#[derive(Debug)]
#[cfg_attr(feature = "layout-cache", derive(Hash))]
pub enum StackChild {
/// Spacing between other nodes.
@ -39,6 +40,15 @@ impl From<StackNode> for LayoutNode {
}
}
impl Debug for StackChild {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Spacing(v) => write!(f, "Spacing({:?})", v),
Self::Any(node, _) => node.fmt(f),
}
}
}
/// Performs stack layout.
struct StackLayouter<'a> {
/// The stack node to layout.

View File

@ -192,11 +192,6 @@ pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let children: Vec<Template> = args.all().collect();
Ok(Value::Template(Template::from_block(move |state| {
let children = children
.iter()
.map(|child| StackChild::Any(child.to_stack(state).into(), state.aligns))
.collect();
let mut dirs = Gen::new(None, dir).unwrap_or(state.dirs);
// If the directions become aligned, fix up the inline direction since
@ -205,6 +200,19 @@ pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
dirs.inline = state.dirs.block;
}
// Use the current alignments for all children, but take care to apply
// them to the correct axes (by swapping them if the stack axes are
// different from the state axes).
let mut aligns = state.aligns;
if dirs.block.axis() == state.dirs.inline.axis() {
aligns = Gen::new(aligns.block, aligns.inline);
}
let children = children
.iter()
.map(|child| StackChild::Any(child.to_stack(state).into(), aligns))
.collect();
StackNode { dirs, children }
})))
}
@ -233,9 +241,6 @@ pub fn grid(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
);
Ok(Value::Template(Template::from_block(move |state| {
let children =
children.iter().map(|child| child.to_stack(&state).into()).collect();
// If the directions become aligned, try to fix up the direction which
// is not user-defined.
let mut dirs = Gen::new(column_dir, row_dir).unwrap_or(state.dirs);
@ -253,6 +258,9 @@ pub fn grid(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
};
}
let children =
children.iter().map(|child| child.to_stack(&state).into()).collect();
GridNode {
dirs,
tracks: tracks.clone(),

Binary file not shown.

Before

Width:  |  Height:  |  Size: 325 B

After

Width:  |  Height:  |  Size: 318 B

View File

@ -1,18 +1,32 @@
// Test stack layouts.
---
#let rect(width, fill) = rect(width: width, height: 1cm, fill: fill)
#stack(
rect(2cm, rgb("2a631a")),
rect(3cm, forest),
rect(1cm, conifer),
// Test stacks with different directions.
#let widths = (
30pt, 20pt, 40pt, 15pt,
30pt, 50%, 20pt, 100%,
)
#let shaded = {
let v = 0
let next() = { v += 0.1; rgb(v, v, v) }
w => rect(width: w, height: 10pt, fill: next())
}
#let items = for w in widths { (shaded(w),) }
#align(right)
#page(width: 50pt, margins: 0pt)
#stack(dir: btt, ..items)
#pagebreak()
// Currently stack works like flexbox apparently.
#stack(dir: ltr, ..items)
---
// Test overflowing stack.
#let rect(width, fill) = rect(width: 1cm, height: 0.4cm, fill: fill)
#box(height: 0.5cm, stack(
rect(3cm, forest),
rect(1cm, conifer),
#page(width: 50pt, height: 30pt, margins: 0pt)
#box(stack(
rect(width: 40pt, height: 20pt, fill: conifer),
rect(width: 30pt, height: 13pt, fill: forest),
))