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), Float(b)) => Relative(a / b),
(Relative(a), Relative(b)) => Float(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), Int(b)) => Fractional(a / b as f64),
(Fractional(a), Float(b)) => Fractional(a / b), (Fractional(a), Float(b)) => Fractional(a / b),
(Fractional(a), Fractional(b)) => Float(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), (a, b) => mismatch!("cannot divide {} by {}", a, b),
}) })
} }

View File

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

View File

@ -1,3 +1,5 @@
use std::fmt::{self, Debug, Formatter};
use super::*; use super::*;
/// A node that stacks its children. /// A node that stacks its children.
@ -14,7 +16,6 @@ pub struct StackNode {
} }
/// A child of a stack node. /// A child of a stack node.
#[derive(Debug)]
#[cfg_attr(feature = "layout-cache", derive(Hash))] #[cfg_attr(feature = "layout-cache", derive(Hash))]
pub enum StackChild { pub enum StackChild {
/// Spacing between other nodes. /// 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. /// Performs stack layout.
struct StackLayouter<'a> { struct StackLayouter<'a> {
/// The stack node to layout. /// 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(); let children: Vec<Template> = args.all().collect();
Ok(Value::Template(Template::from_block(move |state| { 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); let mut dirs = Gen::new(None, dir).unwrap_or(state.dirs);
// If the directions become aligned, fix up the inline direction since // 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; 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 } 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| { 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 // If the directions become aligned, try to fix up the direction which
// is not user-defined. // is not user-defined.
let mut dirs = Gen::new(column_dir, row_dir).unwrap_or(state.dirs); 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 { GridNode {
dirs, dirs,
tracks: tracks.clone(), 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. // Test stack layouts.
--- ---
#let rect(width, fill) = rect(width: width, height: 1cm, fill: fill) // Test stacks with different directions.
#stack( #let widths = (
rect(2cm, rgb("2a631a")), 30pt, 20pt, 40pt, 15pt,
rect(3cm, forest), 30pt, 50%, 20pt, 100%,
rect(1cm, conifer),
) )
#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. // Test overflowing stack.
#page(width: 50pt, height: 30pt, margins: 0pt)
#let rect(width, fill) = rect(width: 1cm, height: 0.4cm, fill: fill) #box(stack(
#box(height: 0.5cm, stack( rect(width: 40pt, height: 20pt, fill: conifer),
rect(3cm, forest), rect(width: 30pt, height: 13pt, fill: forest),
rect(1cm, conifer),
)) ))