diff --git a/src/library/flow.rs b/src/library/flow.rs index f422a62b0..cc53d5207 100644 --- a/src/library/flow.rs +++ b/src/library/flow.rs @@ -48,15 +48,6 @@ pub struct FlowNode { pub children: Vec, } -/// A child of a flow node. -#[derive(Hash)] -pub enum FlowChild { - /// Vertical spacing between other children. - Spacing(Spacing), - /// Any block node and how to align it in the flow. - Node(BlockNode, Align), -} - impl BlockLevel for FlowNode { fn layout( &self, @@ -67,6 +58,15 @@ impl BlockLevel for FlowNode { } } +/// A child of a flow node. +#[derive(Hash)] +pub enum FlowChild { + /// Vertical spacing between other children. + Spacing(Spacing), + /// Any block node and how to align it in the flow. + Node(BlockNode, Align), +} + impl Debug for FlowChild { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { @@ -79,7 +79,7 @@ impl Debug for FlowChild { /// Performs flow layout. struct FlowLayouter<'a> { /// The flow node to layout. - flow: &'a FlowNode, + children: &'a [FlowChild], /// Whether the flow should expand to fill the region. expand: Spec, /// The region to layout into. @@ -115,7 +115,7 @@ impl<'a> FlowLayouter<'a> { regions.expand.y = false; Self { - flow, + children: &flow.children, expand, full: regions.current, regions, @@ -128,7 +128,7 @@ impl<'a> FlowLayouter<'a> { /// Layout all children. fn layout(mut self, ctx: &mut LayoutContext) -> Vec>> { - for child in &self.flow.children { + for child in self.children { match *child { FlowChild::Spacing(Spacing::Linear(v)) => { self.layout_absolute(v); @@ -150,10 +150,9 @@ impl<'a> FlowLayouter<'a> { /// Layout absolute spacing. fn layout_absolute(&mut self, amount: Linear) { // Resolve the linear, limiting it to the remaining available space. - let remaining = &mut self.regions.current.h; let resolved = amount.resolve(self.full.h); - let limited = resolved.min(*remaining); - *remaining -= limited; + let limited = resolved.min(self.regions.current.h); + self.regions.current.h -= limited; self.used.h += limited; self.items.push(FlowItem::Absolute(resolved)); } @@ -163,15 +162,12 @@ impl<'a> FlowLayouter<'a> { let frames = node.layout(ctx, &self.regions); let len = frames.len(); for (i, frame) in frames.into_iter().enumerate() { - // Grow our size. + // Grow our size, shrink the region and save the frame for later. let size = frame.item.size; self.used.h += size.h; self.used.w.set_max(size.w); - - // Remember the frame and shrink available space in the region for the - // following children. - self.items.push(FlowItem::Frame(frame.item, align)); self.regions.current.h -= size.h; + self.items.push(FlowItem::Frame(frame.item, align)); if i + 1 < len { self.finish_region(); @@ -181,21 +177,17 @@ impl<'a> FlowLayouter<'a> { /// Finish the frame for one region. fn finish_region(&mut self) { - // Determine the size that remains for fractional spacing. - let remaining = self.full.h - self.used.h; - // Determine the size of the flow in this region dependening on whether // the region expands. - let mut size = Size::new( + let size = Size::new( if self.expand.x { self.full.w } else { self.used.w }, - if self.expand.y { self.full.h } else { self.used.h }, + if self.expand.y || (!self.fr.is_zero() && self.full.h.is_finite()) { + self.full.h + } else { + self.used.h + }, ); - // Expand fully if there are fr spacings. - if !self.fr.is_zero() && self.full.h.is_finite() { - size.h = self.full.h; - } - let mut output = Frame::new(size, size.h); let mut before = Length::zero(); let mut ruler = Align::Start; @@ -207,6 +199,7 @@ impl<'a> FlowLayouter<'a> { FlowItem::Absolute(v) => before += v, FlowItem::Fractional(v) => { let ratio = v / self.fr; + let remaining = self.full.h - self.used.h; if remaining.is_finite() && ratio.is_finite() { before += ratio * remaining; } @@ -215,18 +208,17 @@ impl<'a> FlowLayouter<'a> { ruler = ruler.max(align); // Align vertically. - let y = - ruler.resolve(Dir::TTB, before .. before + size.h - self.used.h); + let range = before .. before + size.h - self.used.h; + let y = ruler.resolve(Dir::TTB, range); + before += frame.size.h; - let pos = Point::new(Length::zero(), y); + // The baseline of the flow is that of the first frame. if first { - // The baseline of the flow is that of the first frame. - output.baseline = pos.y + frame.baseline; + output.baseline = y + frame.baseline; first = false; } - before += frame.size.h; - output.push_frame(pos, frame); + output.push_frame(Point::new(Length::zero(), y), frame); } } } @@ -236,6 +228,7 @@ impl<'a> FlowLayouter<'a> { cts.exact = self.full.to_spec().map(Some); cts.base = self.regions.base.to_spec().map(Some); + // Advance to the next region. self.regions.next(); self.full = self.regions.current; self.used = Size::zero(); diff --git a/src/library/grid.rs b/src/library/grid.rs index c69762fd4..bafd639ca 100644 --- a/src/library/grid.rs +++ b/src/library/grid.rs @@ -91,14 +91,14 @@ impl BlockLevel for GridNode { /// Performs grid layout. struct GridLayouter<'a> { - /// The original expand state of the target region. + /// The children of the grid. + children: &'a [BlockNode], + /// Whether the grid should expand to fill the region. expand: Spec, /// The column tracks including gutter tracks. cols: Vec, /// The row tracks including gutter tracks. rows: Vec, - /// The children of the grid. - children: &'a [BlockNode], /// The regions to layout into. regions: Regions, /// Resolved column sizes. @@ -173,17 +173,17 @@ impl<'a> GridLayouter<'a> { Self { children: &grid.children, - cts: Constraints::new(expand), - full: regions.current.h, expand, rcols: vec![Length::zero(); cols.len()], - lrows: vec![], - used: Size::zero(), - fr: Fractional::zero(), - finished: vec![], cols, rows, + full: regions.current.h, regions, + used: Size::zero(), + fr: Fractional::zero(), + lrows: vec![], + cts: Constraints::new(expand), + finished: vec![], } } @@ -544,9 +544,6 @@ impl<'a> GridLayouter<'a> { /// Finish rows for one region. fn finish_region(&mut self, ctx: &mut LayoutContext) { - // Determine the size that remains for fractional rows. - let remaining = self.full - self.used.h; - // Determine the size of the grid in this region, expanding fully if // there are fr rows. let mut size = self.used; @@ -567,6 +564,7 @@ impl<'a> GridLayouter<'a> { Row::Frame(frame) => frame, Row::Fr(v, y) => { let ratio = v / self.fr; + let remaining = self.full - self.used.h; if remaining.is_finite() && ratio.is_finite() { let resolved = ratio * remaining; self.layout_single_row(ctx, resolved, y) diff --git a/src/library/par.rs b/src/library/par.rs index eeb46dd84..c781a32de 100644 --- a/src/library/par.rs +++ b/src/library/par.rs @@ -74,21 +74,6 @@ pub struct ParNode { pub children: Vec, } -/// A child of a paragraph node. -#[derive(Hash)] -pub enum ParChild { - /// Spacing between other nodes. - Spacing(Spacing), - /// A run of text and how to align it in its line. - Text(EcoString, Align, Rc), - /// Any child node and how to align it in its line. - Node(InlineNode, Align), - /// A decoration that applies until a matching `Undecorate`. - Decorate(Decoration), - /// The end of a decoration. - Undecorate, -} - impl BlockLevel for ParNode { fn layout( &self, @@ -144,6 +129,21 @@ impl ParNode { } } +/// A child of a paragraph node. +#[derive(Hash)] +pub enum ParChild { + /// Spacing between other nodes. + Spacing(Spacing), + /// A run of text and how to align it in its line. + Text(EcoString, Align, Rc), + /// Any child node and how to align it in its line. + Node(InlineNode, Align), + /// A decoration that applies until a matching `Undecorate`. + Decorate(Decoration), + /// The end of a decoration. + Undecorate, +} + impl Debug for ParChild { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { @@ -156,8 +156,6 @@ impl Debug for ParChild { } } -type Range = std::ops::Range; - /// A paragraph representation in which children are already layouted and text /// is separated into shapable runs. struct ParLayouter<'a> { @@ -175,6 +173,9 @@ struct ParLayouter<'a> { decos: Vec<(Range, &'a Decoration)>, } +/// Range of a substring of text. +type Range = std::ops::Range; + /// A prepared item in a paragraph layout. enum ParItem<'a> { /// Absolute spacing between other items. diff --git a/src/library/stack.rs b/src/library/stack.rs index 78ae506df..6b327f579 100644 --- a/src/library/stack.rs +++ b/src/library/stack.rs @@ -60,15 +60,6 @@ pub struct StackNode { pub children: Vec, } -/// A child of a stack node. -#[derive(Hash)] -pub enum StackChild { - /// Spacing between other nodes. - Spacing(Spacing), - /// Any block node and how to align it in the stack. - Node(BlockNode, Align), -} - impl BlockLevel for StackNode { fn layout( &self, @@ -79,6 +70,15 @@ impl BlockLevel for StackNode { } } +/// A child of a stack node. +#[derive(Hash)] +pub enum StackChild { + /// Spacing between other nodes. + Spacing(Spacing), + /// Any block node and how to align it in the stack. + Node(BlockNode, Align), +} + impl Debug for StackChild { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { @@ -179,15 +179,12 @@ impl<'a> StackLayouter<'a> { let frames = node.layout(ctx, &self.regions); let len = frames.len(); for (i, frame) in frames.into_iter().enumerate() { - // Grow our size. + // Grow our size, shrink the region and save the frame for later. let size = frame.item.size.to_gen(self.axis); self.used.block += size.block; self.used.inline.set_max(size.inline); - - // Remember the frame and shrink available space in the region for the - // following children. - self.items.push(StackItem::Frame(frame.item, align)); *self.regions.current.get_mut(self.axis) -= size.block; + self.items.push(StackItem::Frame(frame.item, align)); if i + 1 < len { self.finish_region(); @@ -197,9 +194,6 @@ impl<'a> StackLayouter<'a> { /// Finish the frame for one region. fn finish_region(&mut self) { - // Determine the size that remains for fractional spacing. - let remaining = self.full.get(self.axis) - self.used.block; - // Determine the size of the stack in this region dependening on whether // the region expands. let used = self.used.to_size(self.axis); @@ -217,7 +211,6 @@ impl<'a> StackLayouter<'a> { let mut output = Frame::new(size, size.h); let mut before = Length::zero(); let mut ruler = Align::Start; - let mut first = true; // Place all frames. for item in self.items.drain(..) { @@ -225,6 +218,7 @@ impl<'a> StackLayouter<'a> { StackItem::Absolute(v) => before += v, StackItem::Fractional(v) => { let ratio = v / self.fr; + let remaining = self.full.get(self.axis) - self.used.block; if remaining.is_finite() && ratio.is_finite() { before += ratio * remaining; } @@ -248,15 +242,10 @@ impl<'a> StackLayouter<'a> { }, ); - let pos = Gen::new(Length::zero(), block).to_point(self.axis); - if first { - // The baseline of the stack is that of the first frame. - output.baseline = pos.y + frame.baseline; - first = false; - } - - output.push_frame(pos, frame); before += child.block; + + let pos = Gen::new(Length::zero(), block).to_point(self.axis); + output.push_frame(pos, frame); } } } @@ -266,6 +255,7 @@ impl<'a> StackLayouter<'a> { cts.exact = self.full.to_spec().map(Some); cts.base = self.regions.base.to_spec().map(Some); + // Advance to the next region. self.regions.next(); self.full = self.regions.current; self.used = Gen::zero();