Rename areas to regions

This commit is contained in:
Laurenz 2021-05-21 12:55:36 +02:00
parent 1cb6328d20
commit 6472c1e425
9 changed files with 83 additions and 78 deletions

View File

@ -19,8 +19,8 @@ pub enum BackgroundShape {
} }
impl Layout for BackgroundNode { impl Layout for BackgroundNode {
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Vec<Frame> { fn layout(&self, ctx: &mut LayoutContext, regions: &Regions) -> Vec<Frame> {
let mut frames = self.child.layout(ctx, areas); let mut frames = self.child.layout(ctx, regions);
for frame in &mut frames { for frame in &mut frames {
let (point, shape) = match self.shape { let (point, shape) = match self.shape {

View File

@ -12,16 +12,16 @@ pub struct FixedNode {
} }
impl Layout for FixedNode { impl Layout for FixedNode {
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Vec<Frame> { fn layout(&self, ctx: &mut LayoutContext, regions: &Regions) -> Vec<Frame> {
let Areas { current, base, .. } = areas; let Regions { current, base, .. } = regions;
let size = Size::new( let size = Size::new(
self.width.map_or(current.width, |w| w.resolve(base.width)), self.width.map_or(current.width, |w| w.resolve(base.width)),
self.height.map_or(current.height, |h| h.resolve(base.height)), self.height.map_or(current.height, |h| h.resolve(base.height)),
); );
let fixed = Spec::new(self.width.is_some(), self.height.is_some()); let fixed = Spec::new(self.width.is_some(), self.height.is_some());
let areas = Areas::once(size, fixed); let regions = Regions::one(size, fixed);
self.child.layout(ctx, &areas) self.child.layout(ctx, &regions)
} }
} }

View File

@ -58,8 +58,8 @@ impl PageRun {
// that axis. // that axis.
let Size { width, height } = self.size; let Size { width, height } = self.size;
let fixed = Spec::new(width.is_finite(), height.is_finite()); let fixed = Spec::new(width.is_finite(), height.is_finite());
let areas = Areas::repeat(self.size, fixed); let regions = Regions::repeat(self.size, fixed);
self.child.layout(ctx, &areas) self.child.layout(ctx, &regions)
} }
} }
@ -77,8 +77,8 @@ impl AnyNode {
} }
impl Layout for AnyNode { impl Layout for AnyNode {
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Vec<Frame> { fn layout(&self, ctx: &mut LayoutContext, regions: &Regions) -> Vec<Frame> {
self.0.layout(ctx, areas) self.0.layout(ctx, regions)
} }
} }
@ -129,8 +129,8 @@ where
/// Layout a node. /// Layout a node.
pub trait Layout { pub trait Layout {
/// Layout the node into the given areas. /// Layout the node into the given regions.
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Vec<Frame>; fn layout(&self, ctx: &mut LayoutContext, regions: &Regions) -> Vec<Frame>;
} }
/// The context for layouting. /// The context for layouting.
@ -139,21 +139,21 @@ pub struct LayoutContext<'a> {
pub env: &'a mut Env, pub env: &'a mut Env,
} }
/// A sequence of areas to layout into. /// A sequence of regions to layout into.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Areas { pub struct Regions {
/// The remaining size of the current area. /// The remaining size of the current region.
pub current: Size, pub current: Size,
/// The base size for relative sizing. /// The base size for relative sizing.
pub base: Size, pub base: Size,
/// A stack of followup areas. /// A stack of followup regions.
/// ///
/// Note that this is a stack and not a queue! The size of the next area is /// Note that this is a stack and not a queue! The size of the next region is
/// `backlog.last()`. /// `backlog.last()`.
pub backlog: Vec<Size>, pub backlog: Vec<Size>,
/// The final area that is repeated once the backlog is drained. /// The final region that is repeated once the backlog is drained.
pub last: Option<Size>, pub last: Option<Size>,
/// Whether layouting into these areas should produce frames of the exact /// Whether layouting into these regions should produce frames of the exact
/// size of `current` instead of shrinking to fit the content. /// size of `current` instead of shrinking to fit the content.
/// ///
/// This property is only handled by nodes that have the ability to control /// This property is only handled by nodes that have the ability to control
@ -161,9 +161,9 @@ pub struct Areas {
pub fixed: Spec<bool>, pub fixed: Spec<bool>,
} }
impl Areas { impl Regions {
/// Create a new area sequence of length one. /// Create a new region sequence with exactly one region.
pub fn once(size: Size, fixed: Spec<bool>) -> Self { pub fn one(size: Size, fixed: Spec<bool>) -> Self {
Self { Self {
current: size, current: size,
base: size, base: size,
@ -173,7 +173,7 @@ impl Areas {
} }
} }
/// Create a new sequence of same-size areas that repeats indefinitely. /// Create a new sequence of same-size regions that repeats indefinitely.
pub fn repeat(size: Size, fixed: Spec<bool>) -> Self { pub fn repeat(size: Size, fixed: Spec<bool>) -> Self {
Self { Self {
current: size, current: size,
@ -184,7 +184,7 @@ impl Areas {
} }
} }
/// Map the size of all areas. /// Map the size of all regions.
pub fn map<F>(&self, mut f: F) -> Self pub fn map<F>(&self, mut f: F) -> Self
where where
F: FnMut(Size) -> Size, F: FnMut(Size) -> Size,
@ -198,7 +198,7 @@ impl Areas {
} }
} }
/// Whether `current` is a fully sized (untouched) copy of the last area. /// Whether `current` is a fully sized (untouched) copy of the last region.
/// ///
/// If this is true, calling `next()` will have no effect. /// If this is true, calling `next()` will have no effect.
pub fn in_full_last(&self) -> bool { pub fn in_full_last(&self) -> bool {
@ -208,7 +208,7 @@ impl Areas {
}) })
} }
/// Advance to the next area if there is any. /// Advance to the next region if there is any.
pub fn next(&mut self) { pub fn next(&mut self) {
if let Some(size) = self.backlog.pop().or(self.last) { if let Some(size) = self.backlog.pop().or(self.last) {
self.current = size; self.current = size;

View File

@ -10,10 +10,10 @@ pub struct PadNode {
} }
impl Layout for PadNode { impl Layout for PadNode {
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Vec<Frame> { fn layout(&self, ctx: &mut LayoutContext, regions: &Regions) -> Vec<Frame> {
let areas = areas.map(|size| size - self.padding.resolve(size).size()); let regions = regions.map(|size| size - self.padding.resolve(size).size());
let mut frames = self.child.layout(ctx, &areas); let mut frames = self.child.layout(ctx, &regions);
for frame in &mut frames { for frame in &mut frames {
let padded = solve(self.padding, frame.size); let padded = solve(self.padding, frame.size);
let padding = self.padding.resolve(padded); let padding = self.padding.resolve(padded);

View File

@ -32,7 +32,7 @@ pub enum ParChild {
} }
impl Layout for ParNode { impl Layout for ParNode {
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Vec<Frame> { fn layout(&self, ctx: &mut LayoutContext, regions: &Regions) -> Vec<Frame> {
// Collect all text into one string used for BiDi analysis. // Collect all text into one string used for BiDi analysis.
let text = self.collect_text(); let text = self.collect_text();
@ -41,10 +41,10 @@ impl Layout for ParNode {
// Build a representation of the paragraph on which we can do // Build a representation of the paragraph on which we can do
// linebreaking without layouting each and every line from scratch. // linebreaking without layouting each and every line from scratch.
let layout = ParLayout::new(ctx, areas, self, bidi); let layout = ParLayout::new(ctx, regions, self, bidi);
// Find suitable linebreaks. // Find suitable linebreaks.
layout.build(ctx, areas.clone(), self) layout.build(ctx, regions.clone(), self)
} }
} }
@ -116,7 +116,7 @@ impl<'a> ParLayout<'a> {
/// Build a paragraph layout for the given node. /// Build a paragraph layout for the given node.
fn new( fn new(
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
areas: &Areas, regions: &Regions,
par: &'a ParNode, par: &'a ParNode,
bidi: BidiInfo<'a>, bidi: BidiInfo<'a>,
) -> Self { ) -> Self {
@ -141,7 +141,7 @@ impl<'a> ParLayout<'a> {
} }
} }
ParChild::Any(ref node, align) => { ParChild::Any(ref node, align) => {
let mut frames = node.layout(ctx, areas).into_iter(); let mut frames = node.layout(ctx, regions).into_iter();
let frame = frames.next().unwrap(); let frame = frames.next().unwrap();
assert!(frames.next().is_none()); assert!(frames.next().is_none());
items.push(ParItem::Frame(frame, align)); items.push(ParItem::Frame(frame, align));
@ -154,11 +154,16 @@ impl<'a> ParLayout<'a> {
} }
/// Find first-fit line breaks and build the paragraph. /// Find first-fit line breaks and build the paragraph.
fn build(self, ctx: &mut LayoutContext, areas: Areas, par: &ParNode) -> Vec<Frame> { fn build(
let mut stack = LineStack::new(par.line_spacing, areas); self,
ctx: &mut LayoutContext,
regions: Regions,
par: &ParNode,
) -> Vec<Frame> {
let mut stack = LineStack::new(par.line_spacing, regions);
// The current line attempt. // The current line attempt.
// Invariant: Always fits into `stack.areas.current`. // Invariant: Always fits into `stack.regions.current`.
let mut last = None; let mut last = None;
// The start of the line in `last`. // The start of the line in `last`.
@ -173,7 +178,7 @@ impl<'a> ParLayout<'a> {
// If the line doesn't fit anymore, we push the last fitting attempt // If the line doesn't fit anymore, we push the last fitting attempt
// into the stack and rebuild the line from its end. The resulting // into the stack and rebuild the line from its end. The resulting
// line cannot be broken up further. // line cannot be broken up further.
if !stack.areas.current.fits(line.size) { if !stack.regions.current.fits(line.size) {
if let Some((last_line, last_end)) = last.take() { if let Some((last_line, last_end)) = last.take() {
stack.push(last_line); stack.push(last_line);
start = last_end; start = last_end;
@ -181,17 +186,17 @@ impl<'a> ParLayout<'a> {
} }
} }
// If the line does not fit vertically, we start a new area. // If the line does not fit vertically, we start a new region.
while !stack.areas.current.height.fits(line.size.height) while !stack.regions.current.height.fits(line.size.height)
&& !stack.areas.in_full_last() && !stack.regions.in_full_last()
{ {
stack.finish_area(); stack.finish_region();
} }
// If the line does not fit horizontally or we have a mandatory // If the line does not fit horizontally or we have a mandatory
// line break (i.e. due to "\n"), we push the line into the // line break (i.e. due to "\n"), we push the line into the
// stack. // stack.
if mandatory || !stack.areas.current.width.fits(line.size.width) { if mandatory || !stack.regions.current.width.fits(line.size.width) {
stack.push(line); stack.push(line);
start = end; start = end;
last = None; last = None;
@ -266,20 +271,20 @@ impl ParItem<'_> {
} }
} }
/// A simple layouter that stacks lines into areas. /// A simple layouter that stacks lines into regions.
struct LineStack<'a> { struct LineStack<'a> {
line_spacing: Length, line_spacing: Length,
areas: Areas, regions: Regions,
finished: Vec<Frame>, finished: Vec<Frame>,
lines: Vec<LineLayout<'a>>, lines: Vec<LineLayout<'a>>,
size: Size, size: Size,
} }
impl<'a> LineStack<'a> { impl<'a> LineStack<'a> {
fn new(line_spacing: Length, areas: Areas) -> Self { fn new(line_spacing: Length, regions: Regions) -> Self {
Self { Self {
line_spacing, line_spacing,
areas, regions,
finished: vec![], finished: vec![],
lines: vec![], lines: vec![],
size: Size::ZERO, size: Size::ZERO,
@ -293,13 +298,13 @@ impl<'a> LineStack<'a> {
self.size.height += self.line_spacing; self.size.height += self.line_spacing;
} }
self.areas.current.height -= line.size.height + self.line_spacing; self.regions.current.height -= line.size.height + self.line_spacing;
self.lines.push(line); self.lines.push(line);
} }
fn finish_area(&mut self) { fn finish_region(&mut self) {
if self.areas.fixed.horizontal { if self.regions.fixed.horizontal {
self.size.width = self.areas.current.width; self.size.width = self.regions.current.width;
} }
let mut output = Frame::new(self.size, self.size.height); let mut output = Frame::new(self.size, self.size.height);
@ -320,12 +325,12 @@ impl<'a> LineStack<'a> {
} }
self.finished.push(output); self.finished.push(output);
self.areas.next(); self.regions.next();
self.size = Size::ZERO; self.size = Size::ZERO;
} }
fn finish(mut self) -> Vec<Frame> { fn finish(mut self) -> Vec<Frame> {
self.finish_area(); self.finish_region();
self.finished self.finished
} }
} }

View File

@ -26,19 +26,19 @@ pub enum StackChild {
} }
impl Layout for StackNode { impl Layout for StackNode {
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Vec<Frame> { fn layout(&self, ctx: &mut LayoutContext, regions: &Regions) -> Vec<Frame> {
let mut layouter = StackLayouter::new(self.dirs, self.aspect, areas.clone()); let mut layouter = StackLayouter::new(self.dirs, self.aspect, regions.clone());
for child in &self.children { for child in &self.children {
match *child { match *child {
StackChild::Spacing(amount) => layouter.push_spacing(amount), StackChild::Spacing(amount) => layouter.push_spacing(amount),
StackChild::Any(ref node, aligns) => { StackChild::Any(ref node, aligns) => {
let mut frames = node.layout(ctx, &layouter.areas).into_iter(); let mut frames = node.layout(ctx, &layouter.regions).into_iter();
if let Some(frame) = frames.next() { if let Some(frame) = frames.next() {
layouter.push_frame(frame, aligns); layouter.push_frame(frame, aligns);
} }
for frame in frames { for frame in frames {
layouter.finish_area(); layouter.finish_region();
layouter.push_frame(frame, aligns); layouter.push_frame(frame, aligns);
} }
} }
@ -58,7 +58,7 @@ struct StackLayouter {
dirs: Gen<Dir>, dirs: Gen<Dir>,
aspect: Option<f64>, aspect: Option<f64>,
main: SpecAxis, main: SpecAxis,
areas: Areas, regions: Regions,
finished: Vec<Frame>, finished: Vec<Frame>,
frames: Vec<(Length, Frame, Gen<Align>)>, frames: Vec<(Length, Frame, Gen<Align>)>,
full: Size, full: Size,
@ -67,9 +67,9 @@ struct StackLayouter {
} }
impl StackLayouter { impl StackLayouter {
fn new(dirs: Gen<Dir>, aspect: Option<f64>, mut areas: Areas) -> Self { fn new(dirs: Gen<Dir>, aspect: Option<f64>, mut regions: Regions) -> Self {
if let Some(aspect) = aspect { if let Some(aspect) = aspect {
areas.apply_aspect_ratio(aspect); regions.apply_aspect_ratio(aspect);
} }
Self { Self {
@ -78,15 +78,15 @@ impl StackLayouter {
main: dirs.main.axis(), main: dirs.main.axis(),
finished: vec![], finished: vec![],
frames: vec![], frames: vec![],
full: areas.current, full: regions.current,
size: Gen::ZERO, size: Gen::ZERO,
ruler: Align::Start, ruler: Align::Start,
areas, regions,
} }
} }
fn push_spacing(&mut self, amount: Length) { fn push_spacing(&mut self, amount: Length) {
let remaining = self.areas.current.get_mut(self.main); let remaining = self.regions.current.get_mut(self.main);
let capped = amount.min(*remaining); let capped = amount.min(*remaining);
*remaining -= capped; *remaining -= capped;
self.size.main += capped; self.size.main += capped;
@ -94,11 +94,11 @@ impl StackLayouter {
fn push_frame(&mut self, frame: Frame, aligns: Gen<Align>) { fn push_frame(&mut self, frame: Frame, aligns: Gen<Align>) {
if self.ruler > aligns.main { if self.ruler > aligns.main {
self.finish_area(); self.finish_region();
} }
while !self.areas.current.fits(frame.size) && !self.areas.in_full_last() { while !self.regions.current.fits(frame.size) && !self.regions.in_full_last() {
self.finish_area(); self.finish_region();
} }
let offset = self.size.main; let offset = self.size.main;
@ -106,12 +106,12 @@ impl StackLayouter {
self.size.main += size.main; self.size.main += size.main;
self.size.cross.set_max(size.cross); self.size.cross.set_max(size.cross);
self.ruler = aligns.main; self.ruler = aligns.main;
*self.areas.current.get_mut(self.main) -= size.main; *self.regions.current.get_mut(self.main) -= size.main;
self.frames.push((offset, frame, aligns)); self.frames.push((offset, frame, aligns));
} }
fn finish_area(&mut self) { fn finish_region(&mut self) {
let fixed = self.areas.fixed; let fixed = self.regions.fixed;
let used = self.size.switch(self.main).to_size(); let used = self.size.switch(self.main).to_size();
let mut size = Size::new( let mut size = Size::new(
@ -165,16 +165,16 @@ impl StackLayouter {
self.size = Gen::ZERO; self.size = Gen::ZERO;
self.ruler = Align::Start; self.ruler = Align::Start;
self.areas.next(); self.regions.next();
if let Some(aspect) = self.aspect { if let Some(aspect) = self.aspect {
self.areas.apply_aspect_ratio(aspect); self.regions.apply_aspect_ratio(aspect);
} }
self.finished.push(output); self.finished.push(output);
} }
fn finish(mut self) -> Vec<Frame> { fn finish(mut self) -> Vec<Frame> {
self.finish_area(); self.finish_region();
self.finished self.finished
} }
} }

View File

@ -2,7 +2,7 @@ use ::image::GenericImageView;
use super::*; use super::*;
use crate::env::ImageId; use crate::env::ImageId;
use crate::layout::{AnyNode, Areas, Element, Frame, Layout, LayoutContext}; use crate::layout::{AnyNode, Element, Frame, Layout, LayoutContext, Regions};
/// `image`: An image. /// `image`: An image.
/// ///
@ -45,8 +45,8 @@ struct ImageNode {
} }
impl Layout for ImageNode { impl Layout for ImageNode {
fn layout(&self, _: &mut LayoutContext, areas: &Areas) -> Vec<Frame> { fn layout(&self, _: &mut LayoutContext, regions: &Regions) -> Vec<Frame> {
let Areas { current, base, .. } = areas; let Regions { current, base, .. } = regions;
let width = self.width.map(|w| w.resolve(base.width)); let width = self.width.map(|w| w.resolve(base.width));
let height = self.height.map(|w| w.resolve(base.height)); let height = self.height.map(|w| w.resolve(base.height));
@ -66,7 +66,7 @@ impl Layout for ImageNode {
// TODO: Fix issue with line spacing. // TODO: Fix issue with line spacing.
Size::new(current.height * pixel_ratio, current.height) Size::new(current.height * pixel_ratio, current.height)
} else { } else {
// Totally unbounded area, we have to make up something. // Totally unbounded region, we have to make up something.
Size::new(Length::pt(pixel_width), Length::pt(pixel_height)) Size::new(Length::pt(pixel_width), Length::pt(pixel_height))
} }
} }

View File

@ -14,7 +14,7 @@ use crate::layout::PadNode;
/// - Bottom padding: `bottom`, of type `linear` relative to parent height. /// - Bottom padding: `bottom`, of type `linear` relative to parent height.
/// ///
/// # Return value /// # Return value
/// A template that sets the body into a padded area. /// A template that pads its region and sets the body into it.
pub fn pad(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { pub fn pad(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
let all = args.eat(ctx); let all = args.eat(ctx);
let left = args.eat_named(ctx, "left"); let left = args.eat_named(ctx, "left");

View File

@ -131,7 +131,7 @@ fn ellipse_impl(
body: TemplateValue, body: TemplateValue,
) -> Value { ) -> Value {
Value::template(name, move |ctx| { Value::template(name, move |ctx| {
// This padding ratio ensures that the rectangular padded area fits // This padding ratio ensures that the rectangular padded region fits
// perfectly into the ellipse. // perfectly into the ellipse.
const PAD: f64 = 0.5 - SQRT_2 / 4.0; const PAD: f64 = 0.5 - SQRT_2 / 4.0;