summaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/elements.rs46
-rw-r--r--src/layout/line.rs122
-rw-r--r--src/layout/mod.rs106
-rw-r--r--src/layout/primitive.rs91
-rw-r--r--src/layout/stack.rs122
-rw-r--r--src/layout/text.rs41
-rw-r--r--src/layout/tree.rs100
7 files changed, 302 insertions, 326 deletions
diff --git a/src/layout/elements.rs b/src/layout/elements.rs
index 92b53ae8..b4a6b31c 100644
--- a/src/layout/elements.rs
+++ b/src/layout/elements.rs
@@ -1,19 +1,20 @@
-//! The elements layouts are composed of.
+//! Basic building blocks of layouts.
use std::fmt::{self, Debug, Formatter};
-use ttf_parser::GlyphId;
use fontdock::FaceId;
+use ttf_parser::GlyphId;
+
use crate::geom::Size;
-/// A sequence of positioned layout elements.
-#[derive(Debug, Clone, PartialEq)]
+/// A collection of absolutely positioned layout elements.
+#[derive(Debug, Default, Clone, PartialEq)]
pub struct LayoutElements(pub Vec<(Size, LayoutElement)>);
impl LayoutElements {
- /// Create an empty sequence.
+ /// Create an new empty collection.
pub fn new() -> Self {
- LayoutElements(vec![])
+ Self(vec![])
}
/// Add an element at a position.
@@ -21,7 +22,9 @@ impl LayoutElements {
self.0.push((pos, element));
}
- /// Add a sequence of elements offset by an `offset`.
+ /// Add all elements of another collection, offsetting each by the given
+ /// `offset`. This can be used to place a sublayout at a position in another
+ /// layout.
pub fn extend_offset(&mut self, offset: Size, more: Self) {
for (subpos, element) in more.0 {
self.0.push((subpos + offset, element));
@@ -29,16 +32,9 @@ impl LayoutElements {
}
}
-impl Default for LayoutElements {
- fn default() -> Self {
- Self::new()
- }
-}
-
-/// A layout element, which is the basic building block layouts are composed of.
+/// A layout element, the basic building block layouts are composed of.
#[derive(Debug, Clone, PartialEq)]
pub enum LayoutElement {
- /// Shaped text.
Text(Shaped),
}
@@ -48,14 +44,17 @@ pub struct Shaped {
pub text: String,
pub face: FaceId,
pub glyphs: Vec<GlyphId>,
+ /// The horizontal offsets of the glyphs with the same indices. Vertical
+ /// offets are not yet supported.
pub offsets: Vec<f64>,
+ /// The font size.
pub size: f64,
}
impl Shaped {
- /// Create an empty shape run.
- pub fn new(face: FaceId, size: f64) -> Shaped {
- Shaped {
+ /// Create a new shape run with empty `text`, `glyphs` and `offsets`.
+ pub fn new(face: FaceId, size: f64) -> Self {
+ Self {
text: String::new(),
face,
glyphs: vec![],
@@ -65,12 +64,11 @@ impl Shaped {
}
/// Encode the glyph ids into a big-endian byte buffer.
- pub fn encode_glyphs(&self) -> Vec<u8> {
- const BYTES_PER_GLYPH: usize = 2;
- let mut bytes = Vec::with_capacity(BYTES_PER_GLYPH * self.glyphs.len());
- for g in &self.glyphs {
- bytes.push((g.0 >> 8) as u8);
- bytes.push((g.0 & 0xff) as u8);
+ pub fn encode_glyphs_be(&self) -> Vec<u8> {
+ let mut bytes = Vec::with_capacity(2 * self.glyphs.len());
+ for &GlyphId(g) in &self.glyphs {
+ bytes.push((g >> 8) as u8);
+ bytes.push((g & 0xff) as u8);
}
bytes
}
diff --git a/src/layout/line.rs b/src/layout/line.rs
index 358d2ac9..069a4e56 100644
--- a/src/layout/line.rs
+++ b/src/layout/line.rs
@@ -1,70 +1,67 @@
-//! The line layouter arranges boxes into lines.
+//! Arranging boxes into lines.
//!
-//! Along the primary axis, the boxes are laid out next to each other while they
-//! fit into a line. When a line break is necessary, the line is finished and a
-//! new line is started offset on the secondary axis by the height of previous
-//! line and the extra line spacing.
+//! Along the primary axis, the boxes are laid out next to each other as long as
+//! they fit into a line. When necessary, a line break is inserted and the new
+//! line is offset along the secondary axis by the height of the previous line
+//! plus extra line spacing.
//!
-//! Internally, the line layouter uses a stack layouter to arrange the finished
-//! lines.
+//! Internally, the line layouter uses a stack layouter to stack the finished
+//! lines on top of each.
-use super::stack::{StackLayouter, StackContext};
+use super::stack::{StackContext, StackLayouter};
use super::*;
/// Performs the line layouting.
-#[derive(Debug)]
pub struct LineLayouter {
- /// The context for layouting.
ctx: LineContext,
- /// The underlying stack layouter.
stack: StackLayouter,
- /// The currently written line.
+ /// The in-progress line.
run: LineRun,
}
/// The context for line layouting.
#[derive(Debug, Clone)]
pub struct LineContext {
- /// The spaces to layout in.
+ /// The spaces to layout into.
pub spaces: LayoutSpaces,
- /// The initial layouting axes, which can be updated by the
- /// [`LineLayouter::set_axes`] method.
+ /// The initial layouting axes, which can be updated through `set_axes`.
pub axes: LayoutAxes,
- /// Which alignment to set on the resulting layout. This affects how it will
- /// be positioned in a parent box.
+ /// The alignment of the _resulting_ layout. This does not effect the line
+ /// layouting itself, but rather how the finished layout will be positioned
+ /// in a parent layout.
pub align: LayoutAlign,
- /// Whether to have repeated spaces or to use only the first and only once.
+ /// Whether to spill over into copies of the last space or finish layouting
+ /// when the last space is used up.
pub repeat: bool,
- /// The line spacing.
+ /// The spacing to be inserted between each pair of lines.
pub line_spacing: f64,
}
-/// A line run is a sequence of boxes with the same alignment that are arranged
-/// in a line. A real line can consist of multiple runs with different
-/// alignments.
-#[derive(Debug)]
+/// A sequence of boxes with the same alignment. A real line can consist of
+/// multiple runs with different alignments.
struct LineRun {
- /// The so-far accumulated layouts in the line.
+ /// The so-far accumulated items of the run.
layouts: Vec<(f64, BoxLayout)>,
- /// The width and maximal height of the line.
+ /// The summed width and maximal height of the run.
size: Size,
/// The alignment of all layouts in the line.
///
- /// When a new run is created the alignment is yet to be determined. Once a
- /// layout is added, it is decided which alignment the run has and all
- /// further elements of the run must have this alignment.
+ /// When a new run is created the alignment is yet to be determined and
+ /// `None` as such. Once a layout is added, its alignment decides the
+ /// alignment for the whole run.
align: Option<LayoutAlign>,
- /// If another line run with different alignment already took up some space
- /// of the line, this run has less space and how much is stored here.
+ /// The amount of space left by another run on the same line or `None` if
+ /// this is the only run so far.
usable: Option<f64>,
- /// A possibly cached soft spacing or spacing state.
+ /// The spacing state. This influences how new spacing is handled, e.g. hard
+ /// spacing may override soft spacing.
last_spacing: LastSpacing,
}
impl LineLayouter {
/// Create a new line layouter.
- pub fn new(ctx: LineContext) -> LineLayouter {
- LineLayouter {
+ pub fn new(ctx: LineContext) -> Self {
+ Self {
stack: StackLayouter::new(StackContext {
spaces: ctx.spaces.clone(),
axes: ctx.axes,
@@ -76,14 +73,14 @@ impl LineLayouter {
}
}
- /// Add a layout to the run.
+ /// Add a layout.
pub fn add(&mut self, layout: BoxLayout) {
let axes = self.ctx.axes;
if let Some(align) = self.run.align {
if layout.align.secondary != align.secondary {
// TODO: Issue warning for non-fitting alignment in
- // non-repeating context.
+ // non-repeating context.
let fitting = self.stack.is_fitting_alignment(layout.align);
if !fitting && self.ctx.repeat {
self.finish_space(true);
@@ -92,7 +89,6 @@ impl LineLayouter {
}
} else if layout.align.primary < align.primary {
self.finish_line();
-
} else if layout.align.primary > align.primary {
let mut rest_run = LineRun::new();
@@ -137,25 +133,24 @@ impl LineLayouter {
self.run.last_spacing = LastSpacing::None;
}
- /// Add multiple layouts to the run.
+ /// Add multiple layouts.
///
- /// This function simply calls `add` repeatedly for each layout.
+ /// This is equivalent to calling `add` repeatedly for each layout.
pub fn add_multiple(&mut self, layouts: MultiLayout) {
for layout in layouts {
self.add(layout);
}
}
- /// The remaining usable size of the run.
+ /// The remaining usable size of the line.
///
- /// This specifies how much more fits before a line break needs to be
- /// issued.
+ /// This specifies how much more would fit before a line break would be
+ /// needed.
fn usable(&self) -> Size {
- // The base is the usable space per stack layouter.
+ // The base is the usable space of the stack layouter.
let mut usable = self.stack.usable().generalized(self.ctx.axes);
- // If this is a alignment-continuing line, we override the primary
- // usable size.
+ // If there was another run already, override the stack's size.
if let Some(primary) = self.run.usable {
usable.x = primary;
}
@@ -164,18 +159,17 @@ impl LineLayouter {
usable
}
- /// Add spacing along the primary axis to the line.
+ /// Add spacing to the line.
pub fn add_primary_spacing(&mut self, mut spacing: f64, kind: SpacingKind) {
match kind {
- // A hard space is simply an empty box.
SpacingKind::Hard => {
spacing = spacing.min(self.usable().x);
self.run.size.x += spacing;
self.run.last_spacing = LastSpacing::Hard;
}
- // A soft space is cached if it is not consumed by a hard space or
- // previous soft space with higher level.
+ // A soft space is cached since it might be consumed by a hard
+ // spacing.
SpacingKind::Soft(level) => {
let consumes = match self.run.last_spacing {
LastSpacing::None => true,
@@ -190,23 +184,23 @@ impl LineLayouter {
}
}
- /// Finish the line and add secondary spacing to the underlying stack.
+ /// Finish the line and add spacing to the underlying stack.
pub fn add_secondary_spacing(&mut self, spacing: f64, kind: SpacingKind) {
self.finish_line_if_not_empty();
self.stack.add_spacing(spacing, kind)
}
- /// Update the layouting axes used by this layouter.
+ /// Update the layouting axes.
pub fn set_axes(&mut self, axes: LayoutAxes) {
self.finish_line_if_not_empty();
self.ctx.axes = axes;
self.stack.set_axes(axes)
}
- /// Update the layouting spaces to use.
+ /// Update the layouting spaces.
///
/// If `replace_empty` is true, the current space is replaced if there are
- /// no boxes laid into it yet. Otherwise, only the followup spaces are
+ /// no boxes laid out into it yet. Otherwise, the followup spaces are
/// replaced.
pub fn set_spaces(&mut self, spaces: LayoutSpaces, replace_empty: bool) {
self.stack.set_spaces(spaces, replace_empty && self.line_is_empty());
@@ -217,13 +211,11 @@ impl LineLayouter {
self.ctx.line_spacing = line_spacing;
}
- /// The remaining inner layout spaces. Inner means, that padding is already
- /// subtracted and the spaces are unexpanding. This can be used to signal
- /// a function how much space it has to layout itself.
+ /// The remaining inner spaces. If something is laid out into these spaces,
+ /// it will fit into this layouter's underlying stack.
pub fn remaining(&self) -> LayoutSpaces {
let mut spaces = self.stack.remaining();
- *spaces[0].size.secondary_mut(self.ctx.axes)
- -= self.run.size.y;
+ *spaces[0].size.secondary_mut(self.ctx.axes) -= self.run.size.y;
spaces
}
@@ -232,13 +224,13 @@ impl LineLayouter {
self.run.size == Size::ZERO && self.run.layouts.is_empty()
}
- /// Finish the last line and compute the final list of boxes.
+ /// Finish everything up and return the final collection of boxes.
pub fn finish(mut self) -> MultiLayout {
self.finish_line_if_not_empty();
self.stack.finish()
}
- /// Finish the currently active space and start a new one.
+ /// Finish the active space and start a new one.
///
/// At the top level, this is a page break.
pub fn finish_space(&mut self, hard: bool) {
@@ -246,7 +238,7 @@ impl LineLayouter {
self.stack.finish_space(hard)
}
- /// Finish the line and start a new one.
+ /// Finish the active line and start a new one.
pub fn finish_line(&mut self) {
let mut elements = LayoutElements::new();
@@ -265,9 +257,8 @@ impl LineLayouter {
self.stack.add(BoxLayout {
size: self.run.size.specialized(self.ctx.axes),
- align: self.run.align
- .unwrap_or(LayoutAlign::new(Start, Start)),
- elements
+ align: self.run.align.unwrap_or(LayoutAlign::new(Start, Start)),
+ elements
});
self.run = LineRun::new();
@@ -275,7 +266,6 @@ impl LineLayouter {
self.stack.add_spacing(self.ctx.line_spacing, SpacingKind::LINE);
}
- /// Finish the current line if it is not empty.
fn finish_line_if_not_empty(&mut self) {
if !self.line_is_empty() {
self.finish_line()
@@ -284,8 +274,8 @@ impl LineLayouter {
}
impl LineRun {
- fn new() -> LineRun {
- LineRun {
+ fn new() -> Self {
+ Self {
layouts: vec![],
size: Size::ZERO,
align: None,
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 143f1984..8a68a6a5 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -1,37 +1,37 @@
-//! Layouting types and engines.
-
-use async_trait::async_trait;
-
-use crate::Pass;
-use crate::font::SharedFontLoader;
-use crate::geom::{Size, Margins};
-use crate::style::{LayoutStyle, TextStyle, PageStyle};
-use crate::syntax::tree::SyntaxTree;
-
-use elements::LayoutElements;
-use tree::TreeLayouter;
-use prelude::*;
+//! Layouting of syntax trees into box layouts.
pub mod elements;
pub mod line;
pub mod primitive;
pub mod stack;
pub mod text;
-pub mod tree;
-
-pub use primitive::*;
+mod tree;
/// Basic types used across the layouting engine.
pub mod prelude {
- pub use super::layout;
pub use super::primitive::*;
+ pub use super::layout;
pub use Dir::*;
- pub use GenAxis::*;
- pub use SpecAxis::*;
pub use GenAlign::*;
+ pub use GenAxis::*;
pub use SpecAlign::*;
+ pub use SpecAxis::*;
}
+pub use primitive::*;
+pub use tree::layout_tree as layout;
+
+use async_trait::async_trait;
+
+use crate::font::SharedFontLoader;
+use crate::geom::{Margins, Size};
+use crate::style::{LayoutStyle, PageStyle, TextStyle};
+use crate::syntax::tree::SyntaxTree;
+use crate::Pass;
+
+use elements::LayoutElements;
+use prelude::*;
+
/// A collection of layouts.
pub type MultiLayout = Vec<BoxLayout>;
@@ -40,47 +40,41 @@ pub type MultiLayout = Vec<BoxLayout>;
pub struct BoxLayout {
/// The size of the box.
pub size: Size,
- /// How to align this layout in a parent container.
+ /// How to align this box in a parent container.
pub align: LayoutAlign,
/// The elements composing this layout.
pub elements: LayoutElements,
}
-/// Layouting of elements.
+/// Comamnd-based layout.
#[async_trait(?Send)]
pub trait Layout {
- /// Layout self into a sequence of layouting commands.
- async fn layout<'a>(&'a self, _: LayoutContext<'_>) -> Pass<Commands<'a>>;
-}
-
-/// Layout a syntax tree into a list of boxes.
-pub async fn layout(tree: &SyntaxTree, ctx: LayoutContext<'_>) -> Pass<MultiLayout> {
- let mut layouter = TreeLayouter::new(ctx);
- layouter.layout_tree(tree).await;
- layouter.finish()
+ /// Create a sequence of layouting commands to execute.
+ async fn layout<'a>(&'a self, ctx: LayoutContext<'_>) -> Pass<Commands<'a>>;
}
/// The context for layouting.
#[derive(Debug, Clone)]
pub struct LayoutContext<'a> {
- /// The font loader to retrieve fonts from when typesetting text
- /// using [`layout_text`].
+ /// The font loader to query fonts from when typesetting text.
pub loader: &'a SharedFontLoader,
/// The style for pages and text.
pub style: &'a LayoutStyle,
- /// The base unpadded size of this container (for relative sizing).
+ /// The unpadded size of this container (the base 100% for relative sizes).
pub base: Size,
- /// The spaces to layout in.
+ /// The spaces to layout into.
pub spaces: LayoutSpaces,
- /// Whether to have repeated spaces or to use only the first and only once.
+ /// Whether to spill over into copies of the last space or finish layouting
+ /// when the last space is used up.
pub repeat: bool,
- /// The initial axes along which content is laid out.
+ /// The axes along which content is laid out.
pub axes: LayoutAxes,
- /// The alignment of the finished layout.
+ /// The alignment of the _resulting_ layout. This does not effect the line
+ /// layouting itself, but rather how the finished layout will be positioned
+ /// in a parent layout.
pub align: LayoutAlign,
- /// Whether the layout that is to be created will be nested in a parent
- /// container.
- pub nested: bool,
+ /// Whether this layouting process is the root page-building process.
+ pub root: bool,
}
/// A collection of layout spaces.
@@ -89,17 +83,17 @@ pub type LayoutSpaces = Vec<LayoutSpace>;
/// The space into which content is laid out.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct LayoutSpace {
- /// The maximum size of the box to layout in.
+ /// The maximum size of the rectangle to layout into.
pub size: Size,
/// Padding that should be respected on each side.
pub padding: Margins,
/// Whether to expand the size of the resulting layout to the full size of
- /// this space or to shrink them to fit the content.
+ /// this space or to shrink it to fit the content.
pub expansion: LayoutExpansion,
}
impl LayoutSpace {
- /// The offset from the origin to the start of content, that is,
+ /// The offset from the origin to the start of content, i.e.
/// `(padding.left, padding.top)`.
pub fn start(&self) -> Size {
Size::new(self.padding.left, self.padding.top)
@@ -110,9 +104,10 @@ impl LayoutSpace {
self.size.unpadded(self.padding)
}
- /// A layout space without padding and size reduced by the padding.
- pub fn usable_space(&self) -> LayoutSpace {
- LayoutSpace {
+ /// The inner layout space with size reduced by the padding, zero padding of
+ /// its own and no layout expansion.
+ pub fn inner(&self) -> Self {
+ Self {
size: self.usable(),
padding: Margins::ZERO,
expansion: LayoutExpansion::new(false, false),
@@ -123,34 +118,33 @@ impl LayoutSpace {
/// A sequence of layouting commands.
pub type Commands<'a> = Vec<Command<'a>>;
-/// Commands issued to the layouting engine by trees.
+/// Commands executable by the layouting engine.
#[derive(Debug, Clone)]
pub enum Command<'a> {
/// Layout the given tree in the current context (i.e. not nested). The
/// content of the tree is not laid out into a separate box and then added,
- /// but simply laid out flat in the active layouting process.
+ /// but simply laid out flatly in the active layouting process.
///
/// This has the effect that the content fits nicely into the active line
/// layouting, enabling functions to e.g. change the style of some piece of
- /// text while keeping it integrated in the current paragraph.
+ /// text while keeping it part of the current paragraph.
LayoutSyntaxTree(&'a SyntaxTree),
- /// Add a already computed layout.
+ /// Add a finished layout.
Add(BoxLayout),
/// Add multiple layouts, one after another. This is equivalent to multiple
- /// [Add](Command::Add) commands.
+ /// `Add` commands.
AddMultiple(MultiLayout),
- /// Add spacing of given [kind](super::SpacingKind) along the primary or
- /// secondary axis. The spacing kind defines how the spacing interacts with
- /// surrounding spacing.
+ /// Add spacing of the given kind along the primary or secondary axis. The
+ /// kind defines how the spacing interacts with surrounding spacing.
AddSpacing(f64, SpacingKind, GenAxis),
/// Start a new line.
BreakLine,
/// Start a new paragraph.
BreakParagraph,
- /// Start a new page, which will exist in the finished layout even if it
+ /// Start a new page, which will be part of the finished layout even if it
/// stays empty (since the page break is a _hard_ space break).
BreakPage,
@@ -162,6 +156,6 @@ pub enum Command<'a> {
/// Update the alignment for future boxes added to this layouting process.
SetAlignment(LayoutAlign),
/// Update the layouting axes along which future boxes will be laid
- /// out. This finishes the current line.
+ /// out. This ends the current line.
SetAxes(LayoutAxes),
}
diff --git a/src/layout/primitive.rs b/src/layout/primitive.rs
index 2eb5669b..1d79f530 100644
--- a/src/layout/primitive.rs
+++ b/src/layout/primitive.rs
@@ -1,29 +1,27 @@
//! Layouting primitives.
use std::fmt::{self, Display, Formatter};
+
use super::prelude::*;
-/// Specifies along which axes content is laid out.
+/// Specifies the axes along content is laid out.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct LayoutAxes {
- /// The primary layouting direction.
pub primary: Dir,
- /// The secondary layouting direction.
pub secondary: Dir,
}
impl LayoutAxes {
- /// Create a new instance from the two values.
+ /// Create a new instance from the two directions.
///
/// # Panics
- /// This function panics if the axes are aligned, that is, they are
+ /// This function panics if the directions are aligned, i.e. if they are
/// on the same axis.
- pub fn new(primary: Dir, secondary: Dir) -> LayoutAxes {
+ pub fn new(primary: Dir, secondary: Dir) -> Self {
if primary.axis() == secondary.axis() {
- panic!("invalid aligned axes {} and {}", primary, secondary);
+ panic!("directions {} and {} are aligned", primary, secondary);
}
-
- LayoutAxes { primary, secondary }
+ Self { primary, secondary }
}
/// Return the direction of the specified generic axis.
@@ -46,9 +44,13 @@ impl LayoutAxes {
/// Directions along which content is laid out.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Dir {
- LTT,
+ /// Left to right.
+ LTR,
+ /// Right to left.
RTL,
+ /// Top to bottom.
TTB,
+ /// Bottom to top.
BTT,
}
@@ -56,34 +58,34 @@ impl Dir {
/// The specific axis this direction belongs to.
pub fn axis(self) -> SpecAxis {
match self {
- LTT | RTL => Horizontal,
+ LTR | RTL => Horizontal,
TTB | BTT => Vertical,
}
}
- /// Whether this axis points into the positive coordinate direction.
+ /// Whether this direction points into the positive coordinate direction.
///
- /// The positive axes are left-to-right and top-to-bottom.
+ /// The positive directions are left-to-right and top-to-bottom.
pub fn is_positive(self) -> bool {
match self {
- LTT | TTB => true,
+ LTR | TTB => true,
RTL | BTT => false,
}
}
/// The factor for this direction.
///
- /// - `1` if the direction is positive.
- /// - `-1` if the direction is negative.
+ /// - `1.0` if the direction is positive.
+ /// - `-1.0` if the direction is negative.
pub fn factor(self) -> f64 {
if self.is_positive() { 1.0 } else { -1.0 }
}
- /// The inverse axis.
- pub fn inv(self) -> Dir {
+ /// The inverse direction.
+ pub fn inv(self) -> Self {
match self {
- LTT => RTL,
- RTL => LTT,
+ LTR => RTL,
+ RTL => LTR,
TTB => BTT,
BTT => TTB,
}
@@ -93,7 +95,7 @@ impl Dir {
impl Display for Dir {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad(match self {
- LTT => "ltr",
+ LTR => "ltr",
RTL => "rtl",
TTB => "ttb",
BTT => "btt",
@@ -104,9 +106,9 @@ impl Display for Dir {
/// The two generic layouting axes.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum GenAxis {
- /// The primary axis along which words are laid out.
+ /// The primary layouting direction along which text and lines flow.
Primary,
- /// The secondary axis along which lines and paragraphs are laid out.
+ /// The secondary layouting direction along which paragraphs grow.
Secondary,
}
@@ -154,19 +156,17 @@ impl Display for SpecAxis {
/// Specifies where to align a layout in a parent container.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct LayoutAlign {
- /// The alignment along the primary axis.
pub primary: GenAlign,
- /// The alignment along the secondary axis.
pub secondary: GenAlign,
}
impl LayoutAlign {
- /// Create a new instance from the two values.
- pub fn new(primary: GenAlign, secondary: GenAlign) -> LayoutAlign {
- LayoutAlign { primary, secondary }
+ /// Create a new instance from the two alignments.
+ pub fn new(primary: GenAlign, secondary: GenAlign) -> Self {
+ Self { primary, secondary }
}
- /// Return the alignment of the specified generic axis.
+ /// Return the alignment for the specified generic axis.
pub fn get(self, axis: GenAxis) -> GenAlign {
match axis {
Primary => self.primary,
@@ -174,7 +174,7 @@ impl LayoutAlign {
}
}
- /// Borrow the alignment of the specified generic axis mutably.
+ /// Borrow the alignment for the specified generic axis mutably.
pub fn get_mut(&mut self, axis: GenAxis) -> &mut GenAlign {
match axis {
Primary => &mut self.primary,
@@ -183,7 +183,7 @@ impl LayoutAlign {
}
}
-/// Where to align content along a generic context.
+/// Where to align content along an axis in a generic context.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum GenAlign {
Start,
@@ -193,7 +193,7 @@ pub enum GenAlign {
impl GenAlign {
/// The inverse alignment.
- pub fn inv(self) -> GenAlign {
+ pub fn inv(self) -> Self {
match self {
Start => End,
Center => Center,
@@ -212,7 +212,7 @@ impl Display for GenAlign {
}
}
-/// Where to align content in a specific context.
+/// Where to align content along an axis in a specific context.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum SpecAlign {
Left,
@@ -225,7 +225,7 @@ pub enum SpecAlign {
impl SpecAlign {
/// The specific axis this alignment refers to.
///
- /// Returns `None` if this is center.
+ /// Returns `None` if this is `Center` since the axis is unknown.
pub fn axis(self) -> Option<SpecAxis> {
match self {
Self::Left => Some(Horizontal),
@@ -236,7 +236,7 @@ impl SpecAlign {
}
}
- /// Convert this to a generic alignment.
+ /// The generic version of this alignment in the given system of axes.
pub fn to_generic(self, axes: LayoutAxes) -> GenAlign {
let get = |spec: SpecAxis, align: GenAlign| {
let axis = spec.to_generic(axes);
@@ -277,8 +277,8 @@ pub struct LayoutExpansion {
impl LayoutExpansion {
/// Create a new instance from the two values.
- pub fn new(horizontal: bool, vertical: bool) -> LayoutExpansion {
- LayoutExpansion { horizontal, vertical }
+ pub fn new(horizontal: bool, vertical: bool) -> Self {
+ Self { horizontal, vertical }
}
/// Return the expansion value for the given specific axis.
@@ -298,8 +298,7 @@ impl LayoutExpansion {
}
}
-/// Defines how a given spacing interacts with (possibly existing) surrounding
-/// spacing.
+/// Defines how spacing interacts with surrounding spacing.
///
/// There are two options for interaction: Hard and soft spacing. Typically,
/// hard spacing is used when a fixed amount of space needs to be inserted no
@@ -317,31 +316,31 @@ pub enum SpacingKind {
impl SpacingKind {
/// The standard spacing kind used for paragraph spacing.
- pub const PARAGRAPH: SpacingKind = SpacingKind::Soft(1);
+ pub const PARAGRAPH: Self = Self::Soft(1);
/// The standard spacing kind used for line spacing.
- pub const LINE: SpacingKind = SpacingKind::Soft(2);
+ pub const LINE: Self = Self::Soft(2);
/// The standard spacing kind used for word spacing.
- pub const WORD: SpacingKind = SpacingKind::Soft(1);
+ pub const WORD: Self = Self::Soft(1);
}
/// The spacing kind of the most recently inserted item in a layouting process.
-/// This is not about the last _spacing item_, but the last _item_, which is why
-/// this can be `None`.
+///
+/// Since the last inserted item may not be spacing at all, this can be `None`.
#[derive(Debug, Copy, Clone, PartialEq)]
pub(crate) enum LastSpacing {
/// The last item was hard spacing.
Hard,
/// The last item was soft spacing with the given width and level.
Soft(f64, u32),
- /// The last item was not spacing.
+ /// The last item wasn't spacing.
None,
}
impl LastSpacing {
/// The width of the soft space if this is a soft space or zero otherwise.
- pub(crate) fn soft_or_zero(self) -> f64 {
+ pub fn soft_or_zero(self) -> f64 {
match self {
LastSpacing::Soft(space, _) => space,
_ => 0.0,
diff --git a/src/layout/stack.rs b/src/layout/stack.rs
index 28da74b7..62f2c976 100644
--- a/src/layout/stack.rs
+++ b/src/layout/stack.rs
@@ -1,11 +1,9 @@
-//! The stack layouter arranges boxes along the secondary layouting axis.
+//! Arranging boxes into a stack along the secondary axis.
//!
-//! Individual layouts can be aligned at origin / center / end on both axes and
-//! these alignments are with respect to the growable layout space and not the
-//! total possible size.
-//!
-//! This means that a later layout can have influence on the position of an
-//! earlier one. Consider, for example, the following code:
+//! Individual layouts can be aligned at `Start`, `Center` or `End` along both
+//! axes. These alignments are with respect to the size of the finished layout
+//! and not the total usable size. This means that a later layout can have
+//! influence on the position of an earlier one. Consider the following example.
//! ```typst
//! [align: right][A word.]
//! [align: left][A sentence with a couple more words.]
@@ -25,38 +23,35 @@ use crate::geom::Value4;
use super::*;
/// Performs the stack layouting.
-#[derive(Debug)]
pub struct StackLayouter {
- /// The context for layouting.
ctx: StackContext,
- /// The output layouts.
layouts: MultiLayout,
- /// The currently active layout space.
+ /// The in-progress space.
space: Space,
}
/// The context for stack layouting.
#[derive(Debug, Clone)]
pub struct StackContext {
- /// The spaces to layout in.
+ /// The spaces to layout into.
pub spaces: LayoutSpaces,
- /// The initial layouting axes, which can be updated by the
- /// [`StackLayouter::set_axes`] method.
+ /// The initial layouting axes, which can be updated through `set_axes`.
pub axes: LayoutAxes,
- /// Which alignment to set on the resulting layout. This affects how it will
- /// be positioned in a parent box.
+ /// The alignment of the _resulting_ layout. This does not effect the line
+ /// layouting itself, but rather how the finished layout will be positioned
+ /// in a parent layout.
pub align: LayoutAlign,
- /// Whether to have repeated spaces or to use only the first and only once.
+ /// Whether to spill over into copies of the last space or finish layouting
+ /// when the last space is used up.
pub repeat: bool,
}
/// A layout space composed of subspaces which can have different axes and
/// alignments.
-#[derive(Debug)]
struct Space {
- /// The index of this space in the list of spaces.
+ /// The index of this space in `ctx.spaces`.
index: usize,
- /// Whether to add the layout for this space even if it would be empty.
+ /// Whether to include a layout for this space even if it would be empty.
hard: bool,
/// The so-far accumulated layouts.
layouts: Vec<(LayoutAxes, BoxLayout)>,
@@ -66,18 +61,20 @@ struct Space {
usable: Size,
/// The specialized extra-needed size to affect the size at all.
extra: Size,
- /// The rulers of a space dictate which alignments for new boxes are still
- /// allowed and which require a new space to be started.
+ /// Dictate which alignments for new boxes are still allowed and which
+ /// require a new space to be started. For example, after an `End`-aligned
+ /// item, no `Start`-aligned one can follow.
rulers: Value4<GenAlign>,
- /// The last added spacing if the last added thing was spacing.
+ /// The spacing state. This influences how new spacing is handled, e.g. hard
+ /// spacing may override soft spacing.
last_spacing: LastSpacing,
}
impl StackLayouter {
/// Create a new stack layouter.
- pub fn new(ctx: StackContext) -> StackLayouter {
+ pub fn new(ctx: StackContext) -> Self {
let space = ctx.spaces[0];
- StackLayouter {
+ Self {
ctx,
layouts: MultiLayout::new(),
space: Space::new(0, true, space.usable()),
@@ -87,8 +84,8 @@ impl StackLayouter {
/// Add a layout to the stack.
pub fn add(&mut self, layout: BoxLayout) {
// If the alignment cannot be fitted in this space, finish it.
- // TODO: Issue warning for non-fitting alignment in
- // non-repeating context.
+ // TODO: Issue warning for non-fitting alignment in non-repeating
+ // context.
if !self.update_rulers(layout.align) && self.ctx.repeat {
self.finish_space(true);
}
@@ -116,14 +113,14 @@ impl StackLayouter {
/// Add multiple layouts to the stack.
///
- /// This function simply calls `add` repeatedly for each layout.
+ /// This is equivalent to calling `add` repeatedly for each layout.
pub fn add_multiple(&mut self, layouts: MultiLayout) {
for layout in layouts {
self.add(layout);
}
}
- /// Add secondary spacing to the stack.
+ /// Add spacing to the stack.
pub fn add_spacing(&mut self, mut spacing: f64, kind: SpacingKind) {
match kind {
// A hard space is simply an empty box.
@@ -133,11 +130,14 @@ impl StackLayouter {
let size = Size::with_y(spacing);
self.update_metrics(size);
- self.space.layouts.push((self.ctx.axes, BoxLayout {
- size: size.specialized(self.ctx.axes),
- align: LayoutAlign::new(Start, Start),
- elements: LayoutElements::new(),
- }));
+ self.space.layouts.push((
+ self.ctx.axes,
+ BoxLayout {
+ size: size.specialized(self.ctx.axes),
+ align: LayoutAlign::new(Start, Start),
+ elements: LayoutElements::new(),
+ }
+ ));
self.space.last_spacing = LastSpacing::Hard;
}
@@ -158,8 +158,6 @@ impl StackLayouter {
}
}
- /// Update the size metrics to reflect that a layout or spacing with the
- /// given generalized size has been added.
fn update_metrics(&mut self, added: Size) {
let axes = self.ctx.axes;
@@ -177,31 +175,29 @@ impl StackLayouter {
*self.space.usable.secondary_mut(axes) -= added.y;
}
- /// Update the rulers to account for the new layout. Returns true if a
- /// space break is necessary.
+ /// Returns true if a space break is necessary.
fn update_rulers(&mut self, align: LayoutAlign) -> bool {
let allowed = self.is_fitting_alignment(align);
if allowed {
- *self.space.rulers.get_mut(self.ctx.axes.secondary, Start)
- = align.secondary;
+ *self.space.rulers.get_mut(self.ctx.axes.secondary, Start) =
+ align.secondary;
}
allowed
}
- /// Whether a layout with the given alignment can still be layouted in the
- /// active space.
- pub fn is_fitting_alignment(&mut self, align: LayoutAlign) -> bool {
+ /// Whether a layout with the given alignment can still be layouted into the
+ /// active space or a space break is necessary.
+ pub(crate) fn is_fitting_alignment(&mut self, align: LayoutAlign) -> bool {
self.is_fitting_axis(self.ctx.axes.primary, align.primary)
&& self.is_fitting_axis(self.ctx.axes.secondary, align.secondary)
}
- /// Whether the given alignment is still allowed according to the rulers.
fn is_fitting_axis(&mut self, dir: Dir, align: GenAlign) -> bool {
align >= *self.space.rulers.get_mut(dir, Start)
- && align <= self.space.rulers.get_mut(dir, End).inv()
+ && align <= self.space.rulers.get_mut(dir, End).inv()
}
- /// Change the layouting axes used by this layouter.
+ /// Update the layouting axes.
pub fn set_axes(&mut self, axes: LayoutAxes) {
// Forget the spacing because it is not relevant anymore.
if axes.secondary != self.ctx.axes.secondary {
@@ -211,10 +207,10 @@ impl StackLayouter {
self.ctx.axes = axes;
}
- /// Change the layouting spaces to use.
+ /// Update the layouting spaces.
///
/// If `replace_empty` is true, the current space is replaced if there are
- /// no boxes laid into it yet. Otherwise, only the followup spaces are
+ /// no boxes laid out into it yet. Otherwise, the followup spaces are
/// replaced.
pub fn set_spaces(&mut self, spaces: LayoutSpaces, replace_empty: bool) {
if replace_empty && self.space_is_empty() {
@@ -234,13 +230,13 @@ impl StackLayouter {
if space.usable().fits(size) {
self.finish_space(true);
self.start_space(start + index, true);
- return;
+ break;
}
}
}
- /// The remaining unpadded, unexpanding spaces. If a function is laid out
- /// into these spaces, it will fit into this stack.
+ /// The remaining inner spaces. If something is laid out into these spaces,
+ /// it will fit into this stack.
pub fn remaining(&self) -> LayoutSpaces {
let size = self.usable();
@@ -251,7 +247,7 @@ impl StackLayouter {
}];
for space in &self.ctx.spaces[self.next_space()..] {
- spaces.push(space.usable_space());
+ spaces.push(space.inner());
}
spaces
@@ -264,17 +260,17 @@ impl StackLayouter {
.specialized(self.ctx.axes)
}
- /// Whether the current layout space (not subspace) is empty.
+ /// Whether the current layout space is empty.
pub fn space_is_empty(&self) -> bool {
self.space.size == Size::ZERO && self.space.layouts.is_empty()
}
- /// Whether the current layout space is the last is the followup list.
+ /// Whether the current layout space is the last in the followup list.
pub fn space_is_last(&self) -> bool {
self.space.index == self.ctx.spaces.len() - 1
}
- /// Compute the finished list of boxes.
+ /// Finish everything up and return the final collection of boxes.
pub fn finish(mut self) -> MultiLayout {
if self.space.hard || !self.space_is_empty() {
self.finish_space(false);
@@ -282,7 +278,7 @@ impl StackLayouter {
self.layouts
}
- /// Finish the current space and start a new one.
+ /// Finish active current space and start a new one.
pub fn finish_space(&mut self, hard: bool) {
let space = self.ctx.spaces[self.space.index];
@@ -322,8 +318,8 @@ impl StackLayouter {
// layout uses up space from the origin to the end. Thus, it reduces
// the usable space for following layouts at it's origin by its
// extent along the secondary axis.
- *bound.get_mut(axes.secondary, Start)
- += axes.secondary.factor() * layout.size.secondary(*axes);
+ *bound.get_mut(axes.secondary, Start) +=
+ axes.secondary.factor() * layout.size.secondary(*axes);
}
// ------------------------------------------------------------------ //
@@ -351,8 +347,8 @@ impl StackLayouter {
// We reduce the bounding box of this layout at it's end by the
// accumulated secondary extent of all layouts we have seen so far,
// which are the layouts after this one since we iterate reversed.
- *bound.get_mut(axes.secondary, End)
- -= axes.secondary.factor() * extent.y;
+ *bound.get_mut(axes.secondary, End) -=
+ axes.secondary.factor() * extent.y;
// Then, we add this layout's secondary extent to the accumulator.
let size = layout.size.generalized(*axes);
@@ -395,21 +391,19 @@ impl StackLayouter {
self.start_space(self.next_space(), hard)
}
- /// Start a new space with the given index.
fn start_space(&mut self, index: usize, hard: bool) {
let space = self.ctx.spaces[index];
self.space = Space::new(index, hard, space.usable());
}
- /// The index of the next space.
fn next_space(&self) -> usize {
(self.space.index + 1).min(self.ctx.spaces.len() - 1)
}
}
impl Space {
- fn new(index: usize, hard: bool, usable: Size) -> Space {
- Space {
+ fn new(index: usize, hard: bool, usable: Size) -> Self {
+ Self {
index,
hard,
layouts: vec![],
diff --git a/src/layout/text.rs b/src/layout/text.rs
index 5c18cd32..b95110b7 100644
--- a/src/layout/text.rs
+++ b/src/layout/text.rs
@@ -1,17 +1,23 @@
-//! The text layouter layouts continous pieces of text into boxes.
+//! Layouting of continous pieces of text into boxes.
//!
//! The layouter picks the most suitable font for each individual character.
//! When the primary layouting axis horizontally inversed, the word is spelled
//! backwards. Vertical word layout is not yet supported.
-use ttf_parser::GlyphId;
use fontdock::{FaceId, FaceQuery, FontStyle};
+use ttf_parser::GlyphId;
+
use crate::font::SharedFontLoader;
use crate::geom::Size;
use crate::style::TextStyle;
use super::elements::{LayoutElement, Shaped};
use super::*;
+/// Layouts text into a box.
+pub async fn layout_text(text: &str, ctx: TextContext<'_>) -> BoxLayout {
+ TextLayouter::new(text, ctx).layout().await
+}
+
/// Performs the text layouting.
#[derive(Debug)]
struct TextLayouter<'a> {
@@ -26,28 +32,24 @@ struct TextLayouter<'a> {
/// The context for text layouting.
#[derive(Debug, Copy, Clone)]
pub struct TextContext<'a> {
- /// The font loader to retrieve fonts from when typesetting text
- /// using [`layout_text`].
+ /// The font loader to retrieve fonts from when typesetting text with
+ /// `layout_text`.
pub loader: &'a SharedFontLoader,
/// The style for text: Font selection with classes, weights and variants,
/// font sizes, spacing and so on.
pub style: &'a TextStyle,
- /// The axes along which the word is laid out. For now, only
- /// primary-horizontal layouting is supported.
- pub axes: LayoutAxes,
- /// The alignment of the finished layout.
+ /// The direction into which the word is laid out. For now, only horizontal
+ /// directions are supported.
+ pub dir: Dir,
+ /// The alignment of the _resulting_ layout. This does not effect the line
+ /// layouting itself, but rather how the finished layout will be positioned
+ /// in a parent layout.
pub align: LayoutAlign,
}
-/// Layouts text into a box.
-pub async fn layout_text(text: &str, ctx: TextContext<'_>) -> BoxLayout {
- TextLayouter::new(text, ctx).layout().await
-}
-
impl<'a> TextLayouter<'a> {
- /// Create a new text layouter.
- fn new(text: &'a str, ctx: TextContext<'a>) -> TextLayouter<'a> {
- TextLayouter {
+ fn new(text: &'a str, ctx: TextContext<'a>) -> Self {
+ Self {
ctx,
text,
shaped: Shaped::new(FaceId::MAX, ctx.style.font_size()),
@@ -57,10 +59,9 @@ impl<'a> TextLayouter<'a> {
}
}
- /// Do the layouting.
async fn layout(mut self) -> BoxLayout {
// If the primary axis is negative, we layout the characters reversed.
- if self.ctx.axes.primary.is_positive() {
+ if self.ctx.dir.is_positive() {
for c in self.text.chars() {
self.layout_char(c).await;
}
@@ -83,7 +84,6 @@ impl<'a> TextLayouter<'a> {
}
}
- /// Layout an individual character.
async fn layout_char(&mut self, c: char) {
let (index, glyph, char_width) = match self.select_font(c).await {
Some(selected) => selected,
@@ -115,11 +115,8 @@ impl<'a> TextLayouter<'a> {
self.width += char_width;
}
- /// Select the best font for a character and return its index along with
- /// the width of the char in the font.
async fn select_font(&mut self, c: char) -> Option<(FaceId, GlyphId, f64)> {
let mut loader = self.ctx.loader.borrow_mut();
-
let mut variant = self.ctx.style.variant;
if self.ctx.style.bolder {
diff --git a/src/layout/tree.rs b/src/layout/tree.rs
index 44c59211..d20fc666 100644
--- a/src/layout/tree.rs
+++ b/src/layout/tree.rs
@@ -1,19 +1,26 @@
-//! The tree layouter layouts trees (i.e.
-//! [syntax trees](crate::syntax::SyntaxTree) and [functions](crate::func))
-//! by executing commands issued by the trees.
+//! Layouting of syntax trees.
-use crate::{Pass, Feedback, DynFuture};
use crate::style::LayoutStyle;
use crate::syntax::decoration::Decoration;
-use crate::syntax::tree::{SyntaxTree, SyntaxNode, DynamicNode};
use crate::syntax::span::{Span, Spanned};
-use super::line::{LineLayouter, LineContext};
+use crate::syntax::tree::{DynamicNode, SyntaxNode, SyntaxTree};
+use crate::{DynFuture, Feedback, Pass};
+use super::line::{LineContext, LineLayouter};
use super::text::{layout_text, TextContext};
use super::*;
+/// Layout a syntax tree into a collection of boxes.
+pub async fn layout_tree(
+ tree: &SyntaxTree,
+ ctx: LayoutContext<'_>,
+) -> Pass<MultiLayout> {
+ let mut layouter = TreeLayouter::new(ctx);
+ layouter.layout_tree(tree).await;
+ layouter.finish()
+}
+
/// Performs the tree layouting.
-#[derive(Debug)]
-pub struct TreeLayouter<'a> {
+struct TreeLayouter<'a> {
ctx: LayoutContext<'a>,
layouter: LineLayouter,
style: LayoutStyle,
@@ -21,9 +28,8 @@ pub struct TreeLayouter<'a> {
}
impl<'a> TreeLayouter<'a> {
- /// Create a new tree layouter.
- pub fn new(ctx: LayoutContext<'a>) -> TreeLayouter<'a> {
- TreeLayouter {
+ fn new(ctx: LayoutContext<'a>) -> Self {
+ Self {
layouter: LineLayouter::new(LineContext {
spaces: ctx.spaces.clone(),
axes: ctx.axes,
@@ -37,15 +43,17 @@ impl<'a> TreeLayouter<'a> {
}
}
- /// Layout a syntax tree by directly processing the nodes instead of using
- /// the command based architecture.
- pub async fn layout_tree(&mut self, tree: &SyntaxTree) {
+ async fn layout_tree(&mut self, tree: &SyntaxTree) {
for node in tree {
self.layout_node(node).await;
}
}
- pub async fn layout_node(&mut self, node: &Spanned<SyntaxNode>) {
+ fn finish(self) -> Pass<MultiLayout> {
+ Pass::new(self.layouter.finish(), self.feedback)
+ }
+
+ async fn layout_node(&mut self, node: &Spanned<SyntaxNode>) {
let decorate = |this: &mut TreeLayouter, deco| {
this.feedback.decorations.push(Spanned::new(deco, node.span));
};
@@ -80,7 +88,10 @@ impl<'a> TreeLayouter<'a> {
SyntaxNode::Raw(lines) => {
// TODO: Make this more efficient.
let fallback = self.style.text.fallback.clone();
- self.style.text.fallback.list_mut().insert(0, "monospace".to_string());
+ self.style.text.fallback
+ .list_mut()
+ .insert(0, "monospace".to_string());
+
self.style.text.fallback.flatten();
// Layout the first line.
@@ -104,17 +115,15 @@ impl<'a> TreeLayouter<'a> {
}
}
- /// Layout a node into this layouting process.
- pub async fn layout_dyn(&mut self, dynamic: Spanned<&dyn DynamicNode>) {
- // Execute the tree's layout function which generates the commands.
+ async fn layout_dyn(&mut self, dynamic: Spanned<&dyn DynamicNode>) {
+ // Execute the tree's command-generating layout function.
let layouted = dynamic.v.layout(LayoutContext {
style: &self.style,
spaces: self.layouter.remaining(),
- nested: true,
- .. self.ctx
+ root: true,
+ ..self.ctx
}).await;
- // Add the errors generated by the tree to the error list.
self.feedback.extend_offset(layouted.feedback, dynamic.span.start);
for command in layouted.output {
@@ -122,13 +131,6 @@ impl<'a> TreeLayouter<'a> {
}
}
- /// Compute the finished list of boxes.
- pub fn finish(self) -> Pass<MultiLayout> {
- Pass::new(self.layouter.finish(), self.feedback)
- }
-
- /// Execute a command issued by a tree. When the command is errorful, the
- /// given span is stored with the error.
fn execute_command<'r>(
&'r mut self,
command: Command<'r>,
@@ -149,13 +151,13 @@ impl<'a> TreeLayouter<'a> {
BreakLine => self.layouter.finish_line(),
BreakParagraph => self.layout_paragraph(),
BreakPage => {
- if self.ctx.nested {
+ if self.ctx.root {
+ self.layouter.finish_space(true)
+ } else {
error!(
@self.feedback, tree_span,
- "page break cannot be issued from nested context",
+ "page break cannot only be issued from root context",
);
- } else {
- self.layouter.finish_space(true)
}
}
@@ -164,12 +166,7 @@ impl<'a> TreeLayouter<'a> {
self.style.text = style;
}
SetPageStyle(style) => {
- if self.ctx.nested {
- error!(
- @self.feedback, tree_span,
- "page style cannot be changed from nested context",
- );
- } else {
+ if self.ctx.root {
self.style.page = style;
// The line layouter has no idea of page styles and thus we
@@ -184,6 +181,11 @@ impl<'a> TreeLayouter<'a> {
expansion: LayoutExpansion::new(true, true),
}
], true);
+ } else {
+ error!(
+ @self.feedback, tree_span,
+ "page style cannot only be changed from root context",
+ );
}
}
@@ -195,17 +197,20 @@ impl<'a> TreeLayouter<'a> {
}
}) }
- /// Layout a continous piece of text and add it to the line layouter.
async fn layout_text(&mut self, text: &str) {
- self.layouter.add(layout_text(text, TextContext {
- loader: &self.ctx.loader,
- style: &self.style.text,
- axes: self.ctx.axes,
- align: self.ctx.align,
- }).await)
+ self.layouter.add(
+ layout_text(
+ text,
+ TextContext {
+ loader: &self.ctx.loader,
+ style: &self.style.text,
+ dir: self.ctx.axes.primary,
+ align: self.ctx.align,
+ }
+ ).await
+ );
}
- /// Add the spacing for a syntactic space node.
fn layout_space(&mut self) {
self.layouter.add_primary_spacing(
self.style.text.word_spacing(),
@@ -213,7 +218,6 @@ impl<'a> TreeLayouter<'a> {
);
}
- /// Finish the paragraph and add paragraph spacing.
fn layout_paragraph(&mut self) {
self.layouter.add_secondary_spacing(
self.style.text.paragraph_spacing(),