Rename run to line and add some explanatory comments ✏

The name run was a relict of the time where a line consisted of a set of runs with same alignment. While these runs still exist conceptually, they are all stored flatly together in what was now renamed from `run`  to `line`.
This commit is contained in:
Laurenz 2021-03-09 17:25:25 +01:00
parent a0de9aad07
commit b2b8d37ce0
3 changed files with 72 additions and 46 deletions

View File

@ -16,9 +16,9 @@ impl Layout for NodeBackground {
for frame in layouted.frames_mut() { for frame in layouted.frames_mut() {
let element = Element::Geometry(Geometry { let element = Element::Geometry(Geometry {
shape: Shape::Rect(frame.size), 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 layouted

View File

@ -229,15 +229,6 @@ pub enum Element {
Geometry(Geometry), 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. /// A shape with some kind of fill.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Geometry { pub struct Geometry {
@ -258,8 +249,17 @@ pub enum Shape {
Rect(Size), 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. /// An image element.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
pub struct Image { pub struct Image {
/// The image resource. /// The image resource.
pub res: ResourceId, pub res: ResourceId,

View File

@ -51,9 +51,9 @@ struct ParLayouter<'a> {
finished: Vec<Frame>, finished: Vec<Frame>,
lines: Vec<(Length, Frame, Align)>, lines: Vec<(Length, Frame, Align)>,
lines_size: Gen<Length>, lines_size: Gen<Length>,
run: Vec<(Length, Frame, Align)>, line: Vec<(Length, Frame, Align)>,
run_size: Gen<Length>, line_size: Gen<Length>,
run_ruler: Align, line_ruler: Align,
} }
impl<'a> ParLayouter<'a> { impl<'a> ParLayouter<'a> {
@ -67,34 +67,54 @@ impl<'a> ParLayouter<'a> {
finished: vec![], finished: vec![],
lines: vec![], lines: vec![],
lines_size: Gen::ZERO, lines_size: Gen::ZERO,
run: vec![], line: vec![],
run_size: Gen::ZERO, line_size: Gen::ZERO,
run_ruler: Align::Start, line_ruler: Align::Start,
} }
} }
fn push_spacing(&mut self, amount: Length) { fn push_spacing(&mut self, amount: Length) {
let cross_max = self.areas.current.get(self.cross); 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) { fn push_frame(&mut self, frame: Frame, align: Align) {
if self.run_ruler > align { // When the alignment of the last pushed frame (stored in the "ruler")
self.finish_run(); // 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 fits = {
let mut usable = self.areas.current; 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) usable.fits(frame.size)
}; };
if !fits { 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) { while !self.areas.current.fits(frame.size) {
if self.areas.in_full_last() { 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; break;
} else { } else {
self.finish_area(); self.finish_area();
@ -103,36 +123,39 @@ impl<'a> ParLayouter<'a> {
} }
let size = frame.size.switch(self.dirs); let size = frame.size.switch(self.dirs);
self.run.push((self.run_size.cross, frame, align));
self.run_size.cross += size.cross; // A line can contain frames with different alignments. They exact
self.run_size.main = self.run_size.main.max(size.main); // positions are calculated later depending on the alignments.
self.run_ruler = align; 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_size = {
let full = self.areas.full.switch(self.dirs); let full = self.areas.full.switch(self.dirs);
Gen::new( Gen::new(
self.run_size.main, self.line_size.main,
self.par self.par
.cross_expansion .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()); 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); let child_cross_size = frame.size.get(self.cross);
// Position along the cross axis. // Position along the cross axis.
let cross = align.resolve(if self.dirs.cross.is_positive() { 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 before .. full_size.cross - after_with_self
} else { } else {
let before_with_self = before + child_cross_size; 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 full_size.cross - before_with_self .. after
}); });
@ -140,23 +163,25 @@ impl<'a> ParLayouter<'a> {
output.push_frame(pos, frame); output.push_frame(pos, frame);
} }
self.lines.push((self.lines_size.main, output, self.run_ruler)); // Update metrics of the whole paragraph.
self.lines.push((self.lines_size.main, output, self.line_ruler));
let main_offset = full_size.main + self.par.line_spacing; self.lines_size.main += full_size.main;
*self.areas.current.get_mut(self.main) -= main_offset; self.lines_size.main += self.par.line_spacing;
self.lines_size.main += main_offset;
self.lines_size.cross = self.lines_size.cross.max(full_size.cross); 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; // Reset metrics for the single line.
self.run_ruler = Align::Start; self.line_size = Gen::ZERO;
self.line_ruler = Align::Start;
} }
fn finish_area(&mut self) { fn finish_area(&mut self) {
let size = self.lines_size; let size = self.lines_size;
let mut output = Frame::new(size.switch(self.dirs).to_size()); let mut output = Frame::new(size.switch(self.dirs).to_size());
for (before, run, cross_align) in std::mem::take(&mut self.lines) { for (before, line, cross_align) in std::mem::take(&mut self.lines) {
let child_size = run.size.switch(self.dirs); let child_size = line.size.switch(self.dirs);
// Position along the main axis. // Position along the main axis.
let main = if self.dirs.main.is_positive() { 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(); 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.finished.push(output);
self.areas.next(); self.areas.next();
// Reset metrics for the whole paragraph.
self.lines_size = Gen::ZERO; self.lines_size = Gen::ZERO;
} }
fn finish(mut self) -> Vec<Frame> { fn finish(mut self) -> Vec<Frame> {
self.finish_run(); self.finish_line();
self.finish_area(); self.finish_area();
self.finished self.finished
} }