diff options
Diffstat (limited to 'src/layout')
| -rw-r--r-- | src/layout/elements.rs | 83 | ||||
| -rw-r--r-- | src/layout/line.rs | 35 | ||||
| -rw-r--r-- | src/layout/mod.rs | 51 | ||||
| -rw-r--r-- | src/layout/primitive.rs | 10 | ||||
| -rw-r--r-- | src/layout/stack.rs | 45 | ||||
| -rw-r--r-- | src/layout/tree.rs | 5 |
6 files changed, 69 insertions, 160 deletions
diff --git a/src/layout/elements.rs b/src/layout/elements.rs deleted file mode 100644 index b5f83bfe..00000000 --- a/src/layout/elements.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! Basic building blocks of layouts. - -use std::fmt::{self, Debug, Formatter}; - -use fontdock::FaceId; -use ttf_parser::GlyphId; - -use crate::geom::Point; - -/// A collection of absolutely positioned layout elements. -#[derive(Debug, Default, Clone, PartialEq)] -pub struct LayoutElements(pub Vec<(Point, LayoutElement)>); - -impl LayoutElements { - /// Create an new empty collection. - pub fn new() -> Self { - Self(vec![]) - } - - /// Add an element at a position. - pub fn push(&mut self, pos: Point, element: LayoutElement) { - self.0.push((pos, element)); - } - - /// Add all elements of another collection, placing them relative to the - /// given position. - pub fn push_elements(&mut self, pos: Point, more: Self) { - for (subpos, element) in more.0 { - self.0.push((pos + subpos.to_vec2(), element)); - } - } -} - -/// A layout element, the basic building block layouts are composed of. -#[derive(Debug, Clone, PartialEq)] -pub enum LayoutElement { - Text(Shaped), -} - -/// A shaped run of text. -#[derive(Clone, PartialEq)] -pub struct Shaped { - /// The shaped text. - pub text: String, - /// The font face the text was shaped with. - pub face: FaceId, - /// The shaped glyphs. - pub glyphs: Vec<GlyphId>, - /// The horizontal offsets of the glyphs. This is indexed parallel to `glyphs`. - /// Vertical offets are not yet supported. - pub offsets: Vec<f64>, - /// The font size. - pub size: f64, -} - -impl 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![], - offsets: vec![], - size, - } - } - - /// Encode the glyph ids into a big-endian byte buffer. - 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 - } -} - -impl Debug for Shaped { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "Shaped({})", self.text) - } -} diff --git a/src/layout/line.rs b/src/layout/line.rs index c190c152..9de8348c 100644 --- a/src/layout/line.rs +++ b/src/layout/line.rs @@ -22,7 +22,7 @@ pub struct LineLayouter { #[derive(Debug, Clone)] pub struct LineContext { /// The spaces to layout into. - pub spaces: LayoutSpaces, + pub spaces: Vec<LayoutSpace>, /// The initial layouting system, which can be updated through `set_sys`. pub sys: LayoutSystem, /// The alignment of the _resulting_ layout. This does not effect the line @@ -132,15 +132,6 @@ impl LineLayouter { self.run.last_spacing = LastSpacing::None; } - /// Add multiple layouts. - /// - /// 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 line. /// /// This specifies how much more would fit before a line break would be @@ -201,7 +192,7 @@ impl LineLayouter { /// If `replace_empty` is true, the current space is replaced if there 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) { + pub fn set_spaces(&mut self, spaces: Vec<LayoutSpace>, replace_empty: bool) { self.stack.set_spaces(spaces, replace_empty && self.line_is_empty()); } @@ -212,7 +203,7 @@ impl LineLayouter { /// 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 { + pub fn remaining(&self) -> Vec<LayoutSpace> { let mut spaces = self.stack.remaining(); *spaces[0].size.secondary_mut(self.ctx.sys) -= self.run.size.height; spaces @@ -224,7 +215,7 @@ impl LineLayouter { } /// Finish everything up and return the final collection of boxes. - pub fn finish(mut self) -> MultiLayout { + pub fn finish(mut self) -> Vec<BoxLayout> { self.finish_line_if_not_empty(); self.stack.finish() } @@ -239,27 +230,25 @@ impl LineLayouter { /// Finish the active line and start a new one. pub fn finish_line(&mut self) { - let mut elements = LayoutElements::new(); + let mut layout = BoxLayout::new( + self.run.size.specialized(self.ctx.sys), + self.run.align.unwrap_or_default(), + ); let layouts = std::mem::take(&mut self.run.layouts); - for (offset, layout) in layouts { + for (offset, child) in layouts { let x = match self.ctx.sys.primary.is_positive() { true => offset, - false => self.run.size.width - offset - layout.size.primary(self.ctx.sys), + false => self.run.size.width - offset - child.size.primary(self.ctx.sys), }; let pos = Point::new(x, 0.0); - elements.push_elements(pos, layout.elements); + layout.push_layout(pos, child); } - self.stack.add(BoxLayout { - size: self.run.size.specialized(self.ctx.sys), - align: self.run.align.unwrap_or(LayoutAlign::START), - elements, - }); + self.stack.add(layout); self.run = LineRun::new(); - self.stack.add_spacing(self.ctx.line_spacing, SpacingKind::LINE); } diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 1ee862e3..75d7b96b 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1,13 +1,11 @@ -//! Layouting of syntax trees into box layouts. +//! Layouting of syntax trees. pub mod primitive; -mod elements; mod line; mod stack; mod tree; -pub use elements::*; pub use line::*; pub use primitive::*; pub use stack::*; @@ -17,6 +15,7 @@ use crate::geom::{Insets, Point, Rect, RectExt, Sides, Size, SizeExt}; use crate::eval::{PageState, State, TextState}; use crate::font::SharedFontLoader; +use crate::shaping::Shaped; use crate::syntax::SynTree; use crate::{Feedback, Pass}; @@ -25,7 +24,7 @@ pub async fn layout( tree: &SynTree, state: State, loader: SharedFontLoader, -) -> Pass<MultiLayout> { +) -> Pass<Vec<BoxLayout>> { let space = LayoutSpace { size: state.page.size, insets: state.page.insets(), @@ -51,9 +50,6 @@ pub async fn layout( Pass::new(layouts, ctx.f) } -/// A collection of layouts. -pub type MultiLayout = Vec<BoxLayout>; - /// A finished box with content at fixed positions. #[derive(Debug, Clone, PartialEq)] pub struct BoxLayout { @@ -62,7 +58,34 @@ pub struct BoxLayout { /// How to align this box in a parent container. pub align: LayoutAlign, /// The elements composing this layout. - pub elements: LayoutElements, + pub elements: Vec<(Point, LayoutElement)>, +} + +impl BoxLayout { + /// Create an new empty collection. + pub fn new(size: Size, align: LayoutAlign) -> Self { + Self { size, align, elements: vec![] } + } + + /// Add an element at a position. + pub fn push(&mut self, pos: Point, element: LayoutElement) { + self.elements.push((pos, element)); + } + + /// Add all elements of another collection, placing them relative to the + /// given position. + pub fn push_layout(&mut self, pos: Point, more: Self) { + for (subpos, element) in more.elements { + self.push(pos + subpos.to_vec2(), element); + } + } +} + +/// A layout element, the basic building block layouts are composed of. +#[derive(Debug, Clone, PartialEq)] +pub enum LayoutElement { + /// Shaped text. + Text(Shaped), } /// The context for layouting. @@ -86,15 +109,12 @@ pub struct LayoutConstraints { /// The unpadded size of this container (the base 100% for relative sizes). pub base: Size, /// The spaces to layout into. - pub spaces: LayoutSpaces, + pub spaces: Vec<LayoutSpace>, /// Whether to spill over into copies of the last space or finish layouting /// when the last space is used up. pub repeat: bool, } -/// A collection of layout spaces. -pub type LayoutSpaces = Vec<LayoutSpace>; - /// The space into which content is laid out. #[derive(Debug, Copy, Clone, PartialEq)] pub struct LayoutSpace { @@ -129,9 +149,6 @@ impl LayoutSpace { } } -/// A sequence of layouting commands. -pub type Commands = Vec<Command>; - /// Commands executable by the layouting engine. #[derive(Debug, Clone, PartialEq)] pub enum Command { @@ -146,10 +163,6 @@ pub enum Command { /// Add a finished layout. Add(BoxLayout), - /// Add multiple layouts, one after another. This is equivalent to multiple - /// `Add` commands. - AddMultiple(MultiLayout), - /// 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), diff --git a/src/layout/primitive.rs b/src/layout/primitive.rs index cdbe63c2..d13110e3 100644 --- a/src/layout/primitive.rs +++ b/src/layout/primitive.rs @@ -17,12 +17,10 @@ impl Default for LayoutSystem { /// Specifies where to align a layout in a parent container. pub type LayoutAlign = Gen2<GenAlign>; -impl LayoutAlign { - /// The layout alignment that has both components set to `Start`. - pub const START: Self = Self { - primary: GenAlign::Start, - secondary: GenAlign::Start, - }; +impl Default for LayoutAlign { + fn default() -> Self { + Self::new(GenAlign::Start, GenAlign::Start) + } } /// Whether to expand a layout to an area's full size or shrink it to fit its content. diff --git a/src/layout/stack.rs b/src/layout/stack.rs index a68fbac0..e69dc071 100644 --- a/src/layout/stack.rs +++ b/src/layout/stack.rs @@ -24,7 +24,7 @@ use super::*; /// Performs the stack layouting. pub struct StackLayouter { ctx: StackContext, - layouts: MultiLayout, + layouts: Vec<BoxLayout>, /// The in-progress space. space: Space, } @@ -33,7 +33,7 @@ pub struct StackLayouter { #[derive(Debug, Clone)] pub struct StackContext { /// The spaces to layout into. - pub spaces: LayoutSpaces, + pub spaces: Vec<LayoutSpace>, /// The initial layouting system, which can be updated through `set_sys`. pub sys: LayoutSystem, /// The alignment of the _resulting_ layout. This does not effect the line @@ -75,7 +75,7 @@ impl StackLayouter { let space = ctx.spaces[0]; Self { ctx, - layouts: MultiLayout::new(), + layouts: vec![], space: Space::new(0, true, space.usable()), } } @@ -110,15 +110,6 @@ impl StackLayouter { self.space.last_spacing = LastSpacing::None; } - /// Add multiple layouts to the stack. - /// - /// 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 spacing to the stack. pub fn add_spacing(&mut self, mut spacing: f64, kind: SpacingKind) { match kind { @@ -129,11 +120,13 @@ impl StackLayouter { let size = Size::new(0.0, spacing); self.update_metrics(size); - self.space.layouts.push((self.ctx.sys, BoxLayout { - size: size.specialized(self.ctx.sys), - align: LayoutAlign::START, - elements: LayoutElements::new(), - })); + self.space.layouts.push(( + self.ctx.sys, + BoxLayout::new( + size.specialized(self.ctx.sys), + LayoutAlign::default(), + ), + )); self.space.last_spacing = LastSpacing::Hard; } @@ -208,7 +201,7 @@ impl StackLayouter { /// If `replace_empty` is true, the current space is replaced if there 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) { + pub fn set_spaces(&mut self, spaces: Vec<LayoutSpace>, replace_empty: bool) { if replace_empty && self.space_is_empty() { self.ctx.spaces = spaces; self.start_space(0, self.space.hard); @@ -233,7 +226,7 @@ impl StackLayouter { /// The remaining inner spaces. If something is laid out into these spaces, /// it will fit into this stack. - pub fn remaining(&self) -> LayoutSpaces { + pub fn remaining(&self) -> Vec<LayoutSpace> { let size = self.usable(); let mut spaces = vec