summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/func/mod.rs8
-rw-r--r--src/layout/flex.rs87
-rw-r--r--src/layout/mod.rs11
-rw-r--r--src/layout/stacked.rs64
-rw-r--r--src/layout/tree.rs72
-rw-r--r--src/lib.rs2
6 files changed, 114 insertions, 130 deletions
diff --git a/src/func/mod.rs b/src/func/mod.rs
index e921966a..f59c1ec0 100644
--- a/src/func/mod.rs
+++ b/src/func/mod.rs
@@ -93,9 +93,11 @@ pub enum Command<'a> {
Add(Layout),
AddMultiple(MultiLayout),
- BreakFlex,
- FinishFlex,
- BreakStack,
+ FinishRun,
+ FinishBox,
+ FinishLayout,
+
+ BreakParagraph,
SetStyle(TextStyle),
SetAxes(LayoutAxes),
diff --git a/src/layout/flex.rs b/src/layout/flex.rs
index 01086c32..dfe38bba 100644
--- a/src/layout/flex.rs
+++ b/src/layout/flex.rs
@@ -20,8 +20,8 @@ use super::*;
#[derive(Debug, Clone)]
pub struct FlexLayouter {
ctx: FlexContext,
- units: Vec<FlexUnit>,
stack: StackLayouter,
+ units: Vec<FlexUnit>,
usable: Size,
run: FlexRun,
@@ -35,6 +35,7 @@ pub struct FlexLayouter {
pub struct FlexContext {
pub spaces: LayoutSpaces,
pub axes: LayoutAxes,
+ pub shrink_to_fit: bool,
/// The spacing between two lines of boxes.
pub flex_spacing: Size,
}
@@ -63,6 +64,7 @@ impl FlexLayouter {
let stack = StackLayouter::new(StackContext {
spaces: ctx.spaces,
axes: ctx.axes,
+ shrink_to_fit: ctx.shrink_to_fit,
});
FlexLayouter {
@@ -88,14 +90,20 @@ impl FlexLayouter {
}
}
+ /// Add a forced run break.
+ pub fn add_run_break(&mut self) {
+ self.units.push(FlexUnit::Break);
+ }
+
/// Add a space box which can be replaced by a run break.
- pub fn add_space(&mut self, space: Size) {
+ pub fn add_primary_space(&mut self, space: Size) {
self.units.push(FlexUnit::Space(space));
}
- /// Add a forced run break.
- pub fn add_break(&mut self) {
- self.units.push(FlexUnit::Break);
+ pub fn add_secondary_space(&mut self, space: Size) -> LayoutResult<()> {
+ self.finish_box()?;
+ self.stack.add_space(space);
+ Ok(())
}
/// Update the axes in use by this flex layouter.
@@ -109,6 +117,21 @@ impl FlexLayouter {
/// with borrowed layouters. The state of the layouter is not reset.
/// Therefore, it should not be further used after calling `finish`.
pub fn finish(&mut self) -> LayoutResult<MultiLayout> {
+ self.finish_box()?;
+ Ok(self.stack.finish())
+ }
+
+ pub fn finish_layout(&mut self, hard: bool) -> LayoutResult<()> {
+ self.finish_box()?;
+ self.stack.finish_layout(hard);
+ Ok(())
+ }
+
+ pub fn finish_box(&mut self) -> LayoutResult<()> {
+ if self.box_is_empty() {
+ return Ok(());
+ }
+
// Move the units out of the layout because otherwise, we run into
// ownership problems.
let units = std::mem::replace(&mut self.units, vec![]);
@@ -131,7 +154,28 @@ impl FlexLayouter {
// Finish the last flex run.
self.finish_run()?;
- Ok(self.stack.finish())
+ Ok(())
+ }
+
+ /// Finish the current flex run.
+ fn finish_run(&mut self) -> LayoutResult<()> {
+ let mut actions = LayoutActionList::new();
+ for (x, layout) in self.run.content.drain(..) {
+ let position = self.ctx.axes.specialize(Size2D::with_x(x));
+ actions.add_layout(position, layout);
+ }
+
+ self.run.size.y += self.ctx.flex_spacing;
+
+ self.stack.add(Layout {
+ dimensions: self.ctx.axes.specialize(self.run.size),
+ actions: actions.into_vec(),
+ debug_render: false,
+ })?;
+
+ self.run.size = Size2D::zero();
+
+ Ok(())
}
/// Layout a content box into the current flex run or start a new run if
@@ -150,7 +194,7 @@ impl FlexLayouter {
Err(LayoutError::NotEnoughSpace("cannot fix box into flex run"))?;
}
- self.stack.add_break(true);
+ self.stack.finish_layout(true);
self.usable = self.stack.usable().x;
}
@@ -174,34 +218,19 @@ impl FlexLayouter {
// TODO
}
- /// Finish the current flex run.
- fn finish_run(&mut self) -> LayoutResult<()> {
- let mut actions = LayoutActionList::new();
- for (x, layout) in self.run.content.drain(..) {
- let position = self.ctx.axes.specialize(Size2D::with_x(x));
- actions.add_layout(position, layout);
- }
-
- self.run.size.y += self.ctx.flex_spacing;
-
- self.stack.add(Layout {
- dimensions: self.ctx.axes.specialize(self.run.size),
- actions: actions.into_vec(),
- debug_render: false,
- })?;
-
- self.run.size = Size2D::zero();
-
- Ok(())
- }
-
/// This layouter's context.
pub fn ctx(&self) -> FlexContext {
self.ctx
}
+ pub fn remaining(&self) -> LayoutResult<LayoutSpaces> {
+ let mut future = self.clone();
+ future.finish_box()?;
+ Ok(future.stack.remaining())
+ }
+
/// Whether this layouter contains any items.
- pub fn is_empty(&self) -> bool {
+ pub fn box_is_empty(&self) -> bool {
self.units.is_empty()
}
}
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 442747b5..9bb91956 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -150,6 +150,10 @@ pub struct LayoutContext<'a, 'p> {
/// The axes to flow on.
pub axes: LayoutAxes,
+
+ /// Whether to shrink the spaces to fit the content or to keep
+ /// the original dimensions.
+ pub shrink_to_fit: bool,
}
/// A possibly stack-allocated vector of layout spaces.
@@ -163,10 +167,6 @@ pub struct LayoutSpace {
/// Padding that should be respected on each side.
pub padding: SizeBox,
-
- /// Whether to shrink the space to fit the content or to keep
- /// the original dimensions.
- pub shrink_to_fit: bool,
}
impl LayoutSpace {
@@ -182,11 +182,10 @@ impl LayoutSpace {
}
/// A layout space without padding and dimensions reduced by the padding.
- pub fn usable_space(&self, shrink_to_fit: bool) -> LayoutSpace {
+ pub fn usable_space(&self) -> LayoutSpace {
LayoutSpace {
dimensions: self.usable(),
padding: SizeBox::zero(),
- shrink_to_fit,
}
}
}
diff --git a/src/layout/stacked.rs b/src/layout/stacked.rs
index d80ebf7a..764b8325 100644
--- a/src/layout/stacked.rs
+++ b/src/layout/stacked.rs
@@ -27,6 +27,7 @@ pub struct StackLayouter {
pub struct StackContext {
pub spaces: LayoutSpaces,
pub axes: LayoutAxes,
+ pub shrink_to_fit: bool,
}
impl StackLayouter {
@@ -61,7 +62,7 @@ impl StackLayouter {
Err(LayoutError::NotEnoughSpace("cannot fit box into stack"))?;
}
- self.add_break(true);
+ self.finish_layout(true);
new_dimensions = merge_sizes(self.dimensions, size);
}
@@ -85,16 +86,20 @@ impl StackLayouter {
/// Add space after the last layout.
pub fn add_space(&mut self, space: Size) {
if self.dimensions.y + space > self.usable.y {
- self.add_break(false);
+ self.finish_layout(false);
} else {
self.dimensions.y += space;
}
}
- /// Finish the current layout and start a new one in a new space.
- pub fn add_break(&mut self, hard: bool) {
- self.finish_layout();
- self.start_new_space(hard);
+ /// Update the axes in use by this stack layouter.
+ pub fn set_axes(&self, axes: LayoutAxes) {
+ if axes != self.ctx.axes {
+ self.finish_boxes();
+ self.usable = self.remains();
+ self.dimensions = Size2D::zero();
+ self.ctx.axes = axes;
+ }
}
/// Finish the layouting.
@@ -103,19 +108,20 @@ impl StackLayouter {
/// Nevertheless, it should not be used further.
pub fn finish(&mut self) -> MultiLayout {
if self.hard || !self.boxes.is_empty() {
- self.finish_layout();
+ self.finish_layout(false);
}
std::mem::replace(&mut self.layouts, MultiLayout::new())
}
- fn finish_layout(&mut self) {
+ /// Finish the current layout and start a new one in a new space.
+ pub fn finish_layout(&mut self, hard: bool) {
self.finish_boxes();
let space = self.ctx.spaces[self.active_space];
let actions = std::mem::replace(&mut self.merged_actions, LayoutActionList::new());
self.layouts.add(Layout {
- dimensions: if space.shrink_to_fit {
+ dimensions: if self.ctx.shrink_to_fit {
self.merged_dimensions.padded(space.padding)
} else {
space.dimensions
@@ -123,6 +129,16 @@ impl StackLayouter {
actions: actions.into_vec(),
debug_render: true,
});
+
+ let next_space = self.next_space();
+ let space = self.ctx.spaces[next_space];
+
+ self.merged_dimensions = Size2D::zero();
+
+ self.usable = self.ctx.axes.generalize(space.usable());
+ self.dimensions = Size2D::zero();
+ self.active_space = next_space;
+ self.hard = hard;
}
/// Compose all cached boxes into a layout.
@@ -154,29 +170,6 @@ impl StackLayouter {
self.merged_dimensions = merge_sizes(self.merged_dimensions, dimensions);
}
- /// Set up layouting in the next space.
- fn start_new_space(&mut self, hard: bool) {
- let next_space = self.next_space();
- let space = self.ctx.spaces[next_space];
-
- self.merged_dimensions = Size2D::zero();
-
- self.usable = self.ctx.axes.generalize(space.usable());
- self.dimensions = Size2D::zero();
- self.active_space = next_space;
- self.hard = hard;
- }
-
- /// Update the axes in use by this stack layouter.
- pub fn set_axes(&self, axes: LayoutAxes) {
- if axes != self.ctx.axes {
- self.finish_boxes();
- self.usable = self.remains();
- self.dimensions = Size2D::zero();
- self.ctx.axes = axes;
- }
- }
-
/// This layouter's context.
pub fn ctx(&self) -> StackContext {
self.ctx
@@ -187,16 +180,15 @@ impl StackLayouter {
self.usable
}
- /// The remaining spaces for new layouts in the current space.
- pub fn remaining(&self, shrink_to_fit: bool) -> LayoutSpaces {
+ /// The remaining usable spaces for new layouts.
+ pub fn remaining(&self) -> LayoutSpaces {
let mut spaces = smallvec![LayoutSpace {
dimensions: self.ctx.axes.specialize(self.remains()),
padding: SizeBox::zero(),
- shrink_to_fit,
}];
for space in &self.ctx.spaces[self.next_space()..] {
- spaces.push(space.usable_space(shrink_to_fit));
+ spaces.push(space.usable_space());
}
spaces
diff --git a/src/layout/tree.rs b/src/layout/tree.rs
index 89e47c91..4742de23 100644
--- a/src/layout/tree.rs
+++ b/src/layout/tree.rs
@@ -10,7 +10,6 @@ pub fn layout_tree(tree: &SyntaxTree, ctx: LayoutContext) -> LayoutResult<MultiL
#[derive(Debug, Clone)]
struct TreeLayouter<'a, 'p> {
ctx: LayoutContext<'a, 'p>,
- stack: StackLayouter,
flex: FlexLayouter,
style: Cow<'a, TextStyle>,
}
@@ -20,14 +19,11 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
fn new(ctx: LayoutContext<'a, 'p>) -> TreeLayouter<'a, 'p> {
TreeLayouter {
ctx,
- stack: StackLayouter::new(StackContext {
- spaces: ctx.spaces,
- axes: ctx.axes,
- }),
flex: FlexLayouter::new(FlexContext {
flex_spacing: flex_spacing(&ctx.style),
- spaces: ctx.spaces.iter().map(|space| space.usable_space(true)).collect(),
+ spaces: ctx.spaces,
axes: ctx.axes,
+ shrink_to_fit: ctx.shrink_to_fit,
}),
style: Cow::Borrowed(ctx.style),
}
@@ -45,13 +41,14 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
}
Node::Space => {
- if !self.flex.is_empty() {
- self.flex.add_space(self.style.word_spacing * self.style.font_size);
+ if !self.flex.box_is_empty() {
+ let space = self.style.word_spacing * self.style.font_size;
+ self.flex.add_primary_space(space);
}
}
Node::Newline => {
- if !self.flex.is_empty() {
- self.finish_paragraph()?;
+ if !self.flex.box_is_empty() {
+ self.break_paragraph()?;
}
}
@@ -68,15 +65,9 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
/// Layout a function.
fn layout_func(&mut self, func: &FuncCall) -> LayoutResult<()> {
- // Finish the current flex layout on a copy to find out how
- // much space would be remaining if we finished.
- let mut lookahead = self.stack.clone();
- lookahead.add_multiple(self.flex.clone().finish()?)?;
- let spaces = lookahead.remaining(true);
-
let commands = func.body.val.layout(LayoutContext {
style: &self.style,
- spaces,
+ spaces: self.flex.remaining()?,
.. self.ctx
})?;
@@ -94,16 +85,15 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
Command::Add(layout) => self.flex.add(layout),
Command::AddMultiple(layouts) => self.flex.add_multiple(layouts),
- Command::BreakFlex => self.flex.add_break(),
- Command::FinishFlex => self.finish_paragraph()?,
- Command::BreakStack => self.finish_layout()?,
+ Command::FinishRun => self.flex.add_run_break(),
+ Command::FinishBox => self.flex.finish_box()?,
+ Command::FinishLayout => self.flex.finish_layout(true)?,
+
+ Command::BreakParagraph => self.break_paragraph()?,
Command::SetStyle(style) => *self.style.to_mut() = style,
Command::SetAxes(axes) => {
self.flex.set_axes(axes);
- if axes.secondary != self.ctx.axes.secondary {
- self.stack.set_axes(axes);
- }
self.ctx.axes = axes;
}
}
@@ -113,43 +103,15 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
/// Finish the layout.
fn finish(mut self) -> LayoutResult<MultiLayout> {
- self.finish_flex()?;
- Ok(self.stack.finish())
- }
-
- /// Finish the current stack layout with a hard break.
- fn finish_layout(&mut self) -> LayoutResult<()> {
- self.finish_flex()?;
- self.stack.add_break(true);
- self.start_new_flex();
- Ok(())
+ self.flex.finish()
}
/// Finish the current flex layout and add space after it.
- fn finish_paragraph(&mut self) -> LayoutResult<()> {
- self.finish_flex()?;
- self.stack.add_space(paragraph_spacing(&self.style));
- self.start_new_flex();
- Ok(())
- }
-
- /// Finish the current flex layout and add it the stack.
- fn finish_flex(&mut self) -> LayoutResult<()> {
- if !self.flex.is_empty() {
- let layouts = self.flex.finish()?;
- self.stack.add_multiple(layouts)?;
- }
+ fn break_paragraph(&mut self) -> LayoutResult<()> {
+ self.flex.finish_box()?;
+ self.flex.add_secondary_space(paragraph_spacing(&self.style))?;
Ok(())
}
-
- /// Start a new flex layout.
- fn start_new_flex(&mut self) {
- self.flex = FlexLayouter::new(FlexContext {
- flex_spacing: flex_spacing(&self.style),
- spaces: self.stack.remaining(true),
- axes: self.ctx.axes,
- });
- }
}
fn flex_spacing(style: &TextStyle) -> Size {
diff --git a/src/lib.rs b/src/lib.rs
index 43f35511..d2494166 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -102,12 +102,12 @@ impl<'p> Typesetter<'p> {
spaces: smallvec![LayoutSpace {
dimensions: self.page_style.dimensions,
padding: self.page_style.margins,
- shrink_to_fit: false,
}],
axes: LayoutAxes {
primary: AlignedAxis::new(Axis::LeftToRight, Alignment::Origin),
secondary: AlignedAxis::new(Axis::TopToBottom, Alignment::Origin),
},
+ shrink_to_fit: false,
},
)?)
}