diff --git a/src/layout/background.rs b/src/layout/background.rs index 6b605d7f5..b331ba3c2 100644 --- a/src/layout/background.rs +++ b/src/layout/background.rs @@ -16,9 +16,9 @@ impl Layout for NodeBackground { for frame in layouted.frames_mut() { let element = Element::Geometry(Geometry { shape: Shape::Rect(frame.size), - fill: self.fill.clone(), + fill: self.fill, }); - frame.elements.insert(0, (Point::ZERO, element)) + frame.elements.insert(0, (Point::ZERO, element)); } layouted diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 1974b5783..622b0363a 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -229,15 +229,6 @@ pub enum Element { Geometry(Geometry), } -/// The kind of graphic fill to be applied to a [`Shape`]. -#[derive(Debug, Clone, PartialEq)] -pub enum Fill { - /// The fill is a color. - Color(Color), - /// The fill is an image. - Image(Image), -} - /// A shape with some kind of fill. #[derive(Debug, Clone, PartialEq)] pub struct Geometry { @@ -258,8 +249,17 @@ pub enum Shape { Rect(Size), } +/// The kind of graphic fill to be applied to a [`Shape`]. +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum Fill { + /// The fill is a color. + Color(Color), + /// The fill is an image. + Image(Image), +} + /// An image element. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] pub struct Image { /// The image resource. pub res: ResourceId, diff --git a/src/layout/par.rs b/src/layout/par.rs index 3f971e126..7d876fc17 100644 --- a/src/layout/par.rs +++ b/src/layout/par.rs @@ -51,9 +51,9 @@ struct ParLayouter<'a> { finished: Vec, lines: Vec<(Length, Frame, Align)>, lines_size: Gen, - run: Vec<(Length, Frame, Align)>, - run_size: Gen, - run_ruler: Align, + line: Vec<(Length, Frame, Align)>, + line_size: Gen, + line_ruler: Align, } impl<'a> ParLayouter<'a> { @@ -67,34 +67,54 @@ impl<'a> ParLayouter<'a> { finished: vec![], lines: vec![], lines_size: Gen::ZERO, - run: vec![], - run_size: Gen::ZERO, - run_ruler: Align::Start, + line: vec![], + line_size: Gen::ZERO, + line_ruler: Align::Start, } } fn push_spacing(&mut self, amount: Length) { let cross_max = self.areas.current.get(self.cross); - self.run_size.cross = (self.run_size.cross + amount).min(cross_max); + self.line_size.cross = (self.line_size.cross + amount).min(cross_max); } fn push_frame(&mut self, frame: Frame, align: Align) { - if self.run_ruler > align { - self.finish_run(); + // When the alignment of the last pushed frame (stored in the "ruler") + // is further to the end than the new `frame`, we need a line break. + // + // For example + // ``` + // #align(right)[First] #align(center)[Second] + // ``` + // would be laid out as: + // +----------------------------+ + // | First | + // | Second | + // +----------------------------+ + if self.line_ruler > align { + self.finish_line(); } + // Find out whether the area still has enough space for this frame. + // Space occupied by previous lines is already removed from + // `areas.current`, but the cross-extent of the current line needs to be + // subtracted to make sure the frame fits. let fits = { let mut usable = self.areas.current; - *usable.get_mut(self.cross) -= self.run_size.cross; + *usable.get_mut(self.cross) -= self.line_size.cross; usable.fits(frame.size) }; if !fits { - self.finish_run(); + self.finish_line(); + // Here, we can directly check whether the frame fits into + // `areas.current` since we just called `finish_line`. while !self.areas.current.fits(frame.size) { if self.areas.in_full_last() { - // TODO: Diagnose once the necessary spans exist. + // The frame fits nowhere. + // TODO: Should this be placed into the first area or the last? + // TODO: Produce diagnostic once the necessary spans exist. break; } else { self.finish_area(); @@ -103,36 +123,39 @@ impl<'a> ParLayouter<'a> { } let size = frame.size.switch(self.dirs); - self.run.push((self.run_size.cross, frame, align)); - self.run_size.cross += size.cross; - self.run_size.main = self.run_size.main.max(size.main); - self.run_ruler = align; + // A line can contain frames with different alignments. They exact + // positions are calculated later depending on the alignments. + self.line.push((self.line_size.cross, frame, align)); + + self.line_size.cross += size.cross; + self.line_size.main = self.line_size.main.max(size.main); + self.line_ruler = align; } - fn finish_run(&mut self) { + fn finish_line(&mut self) { let full_size = { let full = self.areas.full.switch(self.dirs); Gen::new( - self.run_size.main, + self.line_size.main, self.par .cross_expansion - .resolve(self.run_size.cross.min(full.cross), full.cross), + .resolve(self.line_size.cross.min(full.cross), full.cross), ) }; let mut output = Frame::new(full_size.switch(self.dirs).to_size()); - for (before, frame, align) in std::mem::take(&mut self.run) { + for (before, frame, align) in std::mem::take(&mut self.line) { let child_cross_size = frame.size.get(self.cross); // Position along the cross axis. let cross = align.resolve(if self.dirs.cross.is_positive() { - let after_with_self = self.run_size.cross - before; + let after_with_self = self.line_size.cross - before; before .. full_size.cross - after_with_self } else { let before_with_self = before + child_cross_size; - let after = self.run_size.cross - (before + child_cross_size); + let after = self.line_size.cross - (before + child_cross_size); full_size.cross - before_with_self .. after }); @@ -140,23 +163,25 @@ impl<'a> ParLayouter<'a> { output.push_frame(pos, frame); } - self.lines.push((self.lines_size.main, output, self.run_ruler)); - - let main_offset = full_size.main + self.par.line_spacing; - *self.areas.current.get_mut(self.main) -= main_offset; - self.lines_size.main += main_offset; + // Update metrics of the whole paragraph. + self.lines.push((self.lines_size.main, output, self.line_ruler)); + self.lines_size.main += full_size.main; + self.lines_size.main += self.par.line_spacing; self.lines_size.cross = self.lines_size.cross.max(full_size.cross); + *self.areas.current.get_mut(self.main) -= full_size.main; + *self.areas.current.get_mut(self.main) -= self.par.line_spacing; - self.run_size = Gen::ZERO; - self.run_ruler = Align::Start; + // Reset metrics for the single line. + self.line_size = Gen::ZERO; + self.line_ruler = Align::Start; } fn finish_area(&mut self) { let size = self.lines_size; let mut output = Frame::new(size.switch(self.dirs).to_size()); - for (before, run, cross_align) in std::mem::take(&mut self.lines) { - let child_size = run.size.switch(self.dirs); + for (before, line, cross_align) in std::mem::take(&mut self.lines) { + let child_size = line.size.switch(self.dirs); // Position along the main axis. let main = if self.dirs.main.is_positive() { @@ -173,17 +198,18 @@ impl<'a> ParLayouter<'a> { }); let pos = Gen::new(main, cross).switch(self.dirs).to_point(); - output.push_frame(pos, run); + output.push_frame(pos, line); } self.finished.push(output); - self.areas.next(); + + // Reset metrics for the whole paragraph. self.lines_size = Gen::ZERO; } fn finish(mut self) -> Vec { - self.finish_run(); + self.finish_line(); self.finish_area(); self.finished }