diff options
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/flow.rs | 105 | ||||
| -rw-r--r-- | src/library/mod.rs | 2 | ||||
| -rw-r--r-- | src/library/page.rs | 41 | ||||
| -rw-r--r-- | src/library/par.rs | 46 | ||||
| -rw-r--r-- | src/library/spacing.rs | 18 | ||||
| -rw-r--r-- | src/library/stack.rs | 26 | ||||
| -rw-r--r-- | src/library/text.rs | 12 |
7 files changed, 80 insertions, 170 deletions
diff --git a/src/library/flow.rs b/src/library/flow.rs index 8656efca..f274c9b6 100644 --- a/src/library/flow.rs +++ b/src/library/flow.rs @@ -3,14 +3,14 @@ use std::fmt::{self, Debug, Formatter}; use super::prelude::*; -use super::{AlignNode, ParNode, PlacedNode, SpacingKind, SpacingNode, TextNode}; +use super::{AlignNode, ParNode, PlacedNode, SpacingKind, TextNode}; /// A vertical flow of content consisting of paragraphs and other layout nodes. /// /// This node is reponsible for layouting both the top-level content flow and /// the contents of boxes. #[derive(Hash)] -pub struct FlowNode(pub Vec<FlowChild>); +pub struct FlowNode(pub Vec<Styled<FlowChild>>); impl Layout for FlowNode { fn layout( @@ -19,7 +19,7 @@ impl Layout for FlowNode { regions: &Regions, styles: StyleChain, ) -> Vec<Constrained<Rc<Frame>>> { - FlowLayouter::new(self, regions.clone(), styles).layout(ctx) + FlowLayouter::new(self, regions.clone()).layout(ctx, styles) } } @@ -33,50 +33,23 @@ impl Debug for FlowNode { /// A child of a flow node. #[derive(Hash)] pub enum FlowChild { - /// Vertical spacing between other children. - Spacing(SpacingNode), - /// An arbitrary node. - Node(PackedNode), /// A paragraph/block break. - Break(StyleMap), + Break, /// Skip the rest of the region and move to the next. Skip, -} - -impl FlowChild { - /// A reference to the child's styles. - pub fn styles(&self) -> Option<&StyleMap> { - match self { - Self::Spacing(node) => Some(&node.styles), - Self::Node(node) => Some(&node.styles), - Self::Break(styles) => Some(styles), - Self::Skip => None, - } - } - - /// A mutable reference to the child's styles. - pub fn styles_mut(&mut self) -> Option<&mut StyleMap> { - match self { - Self::Spacing(node) => Some(&mut node.styles), - Self::Node(node) => Some(&mut node.styles), - Self::Break(styles) => Some(styles), - Self::Skip => None, - } - } + /// Vertical spacing between other children. + Spacing(SpacingKind), + /// An arbitrary node. + Node(PackedNode), } impl Debug for FlowChild { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { + Self::Break => f.pad("Break"), + Self::Skip => f.pad("Skip"), Self::Spacing(node) => node.fmt(f), Self::Node(node) => node.fmt(f), - Self::Break(styles) => { - if f.alternate() { - styles.fmt(f)?; - } - write!(f, "Break") - } - Self::Skip => f.pad("Skip"), } } } @@ -84,11 +57,9 @@ impl Debug for FlowChild { /// Performs flow layout. struct FlowLayouter<'a> { /// The flow node to layout. - children: &'a [FlowChild], + children: &'a [Styled<FlowChild>], /// The regions to layout children into. regions: Regions, - /// The inherited styles. - styles: StyleChain<'a>, /// Whether the flow should expand to fill the region. expand: Spec<bool>, /// The full size of `regions.current` that was available before we started @@ -118,7 +89,7 @@ enum FlowItem { impl<'a> FlowLayouter<'a> { /// Create a new flow layouter. - fn new(flow: &'a FlowNode, mut regions: Regions, styles: StyleChain<'a>) -> Self { + fn new(flow: &'a FlowNode, mut regions: Regions) -> Self { let expand = regions.expand; let full = regions.current; @@ -128,7 +99,6 @@ impl<'a> FlowLayouter<'a> { Self { children: &flow.0, regions, - styles, expand, full, used: Size::zero(), @@ -139,27 +109,31 @@ impl<'a> FlowLayouter<'a> { } /// Layout all children. - fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> { - for child in self.children { - match child { - FlowChild::Spacing(node) => { - self.layout_spacing(node.kind); + fn layout( + mut self, + ctx: &mut LayoutContext, + styles: StyleChain, + ) -> Vec<Constrained<Rc<Frame>>> { + for styled in self.children { + let styles = styled.map.chain(&styles); + match styled.item { + FlowChild::Break => { + let em = styles.get(TextNode::SIZE).abs; + let amount = styles.get(ParNode::SPACING).resolve(em); + self.layout_absolute(amount.into()); + } + FlowChild::Skip => { + self.finish_region(); } - FlowChild::Node(node) => { + FlowChild::Spacing(kind) => { + self.layout_spacing(kind); + } + FlowChild::Node(ref node) => { if self.regions.is_full() { self.finish_region(); } - self.layout_node(ctx, node); - } - FlowChild::Break(styles) => { - let chain = styles.chain(&self.styles); - let em = chain.get(TextNode::SIZE).abs; - let amount = chain.get(ParNode::SPACING).resolve(em); - self.layout_absolute(amount.into()); - } - FlowChild::Skip => { - self.finish_region(); + self.layout_node(ctx, node, styles); } } } @@ -190,12 +164,17 @@ impl<'a> FlowLayouter<'a> { } /// Layout a node. - fn layout_node(&mut self, ctx: &mut LayoutContext, node: &PackedNode) { + fn layout_node( + &mut self, + ctx: &mut LayoutContext, + node: &PackedNode, + styles: StyleChain, + ) { // Placed nodes that are out of flow produce placed items which aren't // aligned later. if let Some(placed) = node.downcast::<PlacedNode>() { if placed.out_of_flow() { - let frame = node.layout(ctx, &self.regions, self.styles).remove(0); + let frame = node.layout(ctx, &self.regions, styles).remove(0); self.items.push(FlowItem::Placed(frame.item)); return; } @@ -204,9 +183,9 @@ impl<'a> FlowLayouter<'a> { // How to align the node. let aligns = Spec::new( // For non-expanding paragraphs it is crucial that we align the - // whole paragraph according to its internal alignment. + // whole paragraph as it is itself aligned. if node.is::<ParNode>() { - node.styles.chain(&self.styles).get(ParNode::ALIGN) + styles.get(ParNode::ALIGN) } else { Align::Left }, @@ -216,7 +195,7 @@ impl<'a> FlowLayouter<'a> { .unwrap_or(Align::Top), ); - let frames = node.layout(ctx, &self.regions, self.styles); + let frames = node.layout(ctx, &self.regions, styles); let len = frames.len(); for (i, frame) in frames.into_iter().enumerate() { // Grow our size, shrink the region and save the frame for later. diff --git a/src/library/mod.rs b/src/library/mod.rs index 9033b3a7..89f4ab9d 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -62,7 +62,7 @@ prelude! { pub use crate::diag::{At, TypResult}; pub use crate::eval::{ Args, Construct, EvalContext, Node, Property, Set, Smart, StyleChain, StyleMap, - Value, + Styled, Value, }; pub use crate::frame::*; pub use crate::geom::*; diff --git a/src/library/page.rs b/src/library/page.rs index fa9345f5..a6d489ba 100644 --- a/src/library/page.rs +++ b/src/library/page.rs @@ -8,12 +8,7 @@ use super::{ColumnsNode, PadNode}; /// Layouts its child onto one or multiple pages. #[derive(Clone, PartialEq, Hash)] -pub struct PageNode { - /// The node producing the content. - pub child: PackedNode, - /// The page's styles. - pub styles: StyleMap, -} +pub struct PageNode(pub PackedNode); #[properties] impl PageNode { @@ -43,10 +38,7 @@ impl PageNode { impl Construct for PageNode { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { - Ok(Node::Page(Self { - child: args.expect("body")?, - styles: StyleMap::new(), - })) + Ok(Node::Page(Self(args.expect("body")?))) } } @@ -84,16 +76,8 @@ impl Set for PageNode { } impl PageNode { - /// Style the node with styles from a style map. - pub fn styled(mut self, styles: StyleMap) -> Self { - self.styles.apply(&styles); - self - } - /// Layout the page run into a sequence of frames, one per page. pub fn layout(&self, ctx: &mut LayoutContext, styles: StyleChain) -> Vec<Rc<Frame>> { - let styles = self.styles.chain(&styles); - // When one of the lengths is infinite the page fits its content along // that axis. let width = styles.get(Self::WIDTH).unwrap_or(Length::inf()); @@ -113,21 +97,21 @@ impl PageNode { bottom: styles.get(Self::BOTTOM).unwrap_or(default.bottom), }; + let mut child = self.0.clone(); + // Realize columns with columns node. let columns = styles.get(Self::COLUMNS); - let child = if columns.get() > 1 { - ColumnsNode { + if columns.get() > 1 { + child = ColumnsNode { columns, gutter: styles.get(Self::COLUMN_GUTTER), - child: self.child.clone(), + child: self.0.clone(), } - .pack() - } else { - self.child.clone() - }; + .pack(); + } // Realize margins with padding node. - let child = PadNode { child, padding }.pack(); + child = PadNode { child, padding }.pack(); // Layout the child. let expand = size.map(Length::is_finite); @@ -152,11 +136,8 @@ impl PageNode { impl Debug for PageNode { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - if f.alternate() { - self.styles.fmt(f)?; - } f.write_str("Page(")?; - self.child.fmt(f)?; + self.0.fmt(f)?; f.write_str(")") } } diff --git a/src/library/par.rs b/src/library/par.rs index 65a541f6..87ad2ebe 100644 --- a/src/library/par.rs +++ b/src/library/par.rs @@ -8,12 +8,12 @@ use unicode_bidi::{BidiInfo, Level}; use xi_unicode::LineBreakIterator; use super::prelude::*; -use super::{shape, ShapedText, SpacingKind, SpacingNode, TextNode}; +use super::{shape, ShapedText, SpacingKind, TextNode}; use crate::util::{EcoString, RangeExt, RcExt, SliceExt}; /// A node that arranges its children into a paragraph. #[derive(Hash)] -pub struct ParNode(pub Vec<ParChild>); +pub struct ParNode(pub Vec<Styled<ParChild>>); #[properties] impl ParNode { @@ -120,9 +120,9 @@ impl ParNode { /// The string representation of each child. fn strings(&self) -> impl Iterator<Item = &str> { - self.0.iter().map(|child| match child { + self.0.iter().map(|styled| match &styled.item { ParChild::Spacing(_) => " ", - ParChild::Text(ref node) => &node.text, + ParChild::Text(node) => &node.0, ParChild::Node(_) => "\u{FFFC}", }) } @@ -139,7 +139,7 @@ impl Debug for ParNode { #[derive(Hash)] pub enum ParChild { /// Spacing between other nodes. - Spacing(SpacingNode), + Spacing(SpacingKind), /// A run of text and how to align it in its line. Text(TextNode), /// Any child node and how to align it in its line. @@ -148,26 +148,8 @@ pub enum ParChild { impl ParChild { /// Create a text child. - pub fn text(text: impl Into<EcoString>, styles: StyleMap) -> Self { - Self::Text(TextNode { text: text.into(), styles }) - } - - /// A reference to the child's styles. - pub fn styles(&self) -> &StyleMap { - match self { - Self::Spacing(node) => &node.styles, - Self::Text(node) => &node.styles, - Self::Node(node) => &node.styles, - } - } - - /// A mutable reference to the child's styles. - pub fn styles_mut(&mut self) -> &mut StyleMap { - match self { - Self::Spacing(node) => &mut node.styles, - Self::Text(node) => &mut node.styles, - Self::Node(node) => &mut node.styles, - } + pub fn text(text: impl Into<EcoString>) -> Self { + Self::Text(TextNode(text.into())) } } @@ -234,9 +216,10 @@ impl<'a> ParLayouter<'a> { let mut ranges = vec![]; // Layout the children and collect them into items. - for (range, child) in par.ranges().zip(&par.0) { - match child { - ParChild::Spacing(node) => match node.kind { + for (range, styled) in par.ranges().zip(&par.0) { + let styles = styled.map.chain(styles); + match styled.item { + ParChild::Spacing(kind) => match kind { SpacingKind::Linear(v) => { let resolved = v.resolve(regions.current.x); items.push(ParItem::Absolute(resolved)); @@ -247,7 +230,7 @@ impl<'a> ParLayouter<'a> { ranges.push(range); } }, - ParChild::Text(node) => { + ParChild::Text(_) => { // TODO: Also split by language and script. let mut cursor = range.start; for (level, group) in bidi.levels[range].group_by_key(|&lvl| lvl) { @@ -255,16 +238,15 @@ impl<'a> ParLayouter<'a> { cursor += group.len(); let subrange = start .. cursor; let text = &bidi.text[subrange.clone()]; - let styles = node.styles.chain(styles); let shaped = shape(ctx.fonts, text, styles, level.dir()); items.push(ParItem::Text(shaped)); ranges.push(subrange); } } - ParChild::Node(node) => { + ParChild::Node(ref node) => { let size = Size::new(regions.current.x, regions.base.y); let pod = Regions::one(size, regions.base, Spec::splat(false)); - let frame = node.layout(ctx, &pod, *styles).remove(0); + let frame = node.layout(ctx, &pod, styles).remove(0); items.push(ParItem::Frame(Rc::take(frame.item))); ranges.push(range); } diff --git a/src/library/spacing.rs b/src/library/spacing.rs index a5888485..1b1403e9 100644 --- a/src/library/spacing.rs +++ b/src/library/spacing.rs @@ -18,24 +18,6 @@ pub fn v(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { ))) } -/// Explicit spacing in a flow or paragraph. -#[derive(Hash)] -pub struct SpacingNode { - /// The kind of spacing. - pub kind: SpacingKind, - /// The spacing's styles. - pub styles: StyleMap, -} - -impl Debug for SpacingNode { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - if f.alternate() { - self.styles.fmt(f)?; - } - write!(f, "{:?}", self.kind) - } -} - /// Kinds of spacing. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum SpacingKind { diff --git a/src/library/stack.rs b/src/library/stack.rs index d36c2e15..f4f7a3cf 100644 --- a/src/library/stack.rs +++ b/src/library/stack.rs @@ -1,7 +1,7 @@ //! Side-by-side layout of nodes along an axis. use super::prelude::*; -use super::{AlignNode, SpacingKind, SpacingNode}; +use super::{AlignNode, SpacingKind}; /// `stack`: Stack children along an axis. pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { @@ -38,17 +38,11 @@ impl Layout for StackNode { #[derive(Hash)] pub enum StackChild { /// Spacing between other nodes. - Spacing(SpacingNode), + Spacing(SpacingKind), /// An arbitrary node. Node(PackedNode), } -impl From<SpacingKind> for StackChild { - fn from(kind: SpacingKind) -> Self { - Self::Spacing(SpacingNode { kind, styles: StyleMap::new() }) - } -} - impl Debug for StackChild { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { @@ -61,10 +55,10 @@ impl Debug for StackChild { castable! { StackChild, Expected: "linear, fractional or template", - Value::Length(v) => SpacingKind::Linear(v.into()).into(), - Value::Relative(v) => SpacingKind::Linear(v.into()).into(), - Value::Linear(v) => SpacingKind::Linear(v).into(), - Value::Fractional(v) => SpacingKind::Fractional(v).into(), + Value::Length(v) => Self::Spacing(SpacingKind::Linear(v.into())), + Value::Relative(v) => Self::Spacing(SpacingKind::Linear(v.into())), + Value::Linear(v) => Self::Spacing(SpacingKind::Linear(v)), + Value::Fractional(v) => Self::Spacing(SpacingKind::Fractional(v)), Value::Node(v) => Self::Node(v.into_block()), } @@ -140,12 +134,12 @@ impl<'a> StackLayouter<'a> { let mut deferred = None; for child in self.children { - match child { - StackChild::Spacing(node) => { - self.layout_spacing(node.kind); + match *child { + StackChild::Spacing(kind) => { + self.layout_spacing(kind); deferred = None; } - StackChild::Node(node) => { + StackChild::Node(ref node) => { if let Some(kind) = deferred { self.layout_spacing(kind); } diff --git a/src/library/text.rs b/src/library/text.rs index 486cb77f..ab5c15c3 100644 --- a/src/library/text.rs +++ b/src/library/text.rs @@ -18,12 +18,7 @@ use crate::util::{EcoString, SliceExt}; /// A single run of text with the same style. #[derive(Hash)] -pub struct TextNode { - /// The run's text. - pub text: EcoString, - /// The run's styles. - pub styles: StyleMap, -} +pub struct TextNode(pub EcoString); #[properties] impl TextNode { @@ -154,10 +149,7 @@ impl Set for TextNode { impl Debug for TextNode { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - if f.alternate() { - self.styles.fmt(f)?; - } - write!(f, "Text({:?})", self.text) + write!(f, "Text({:?})", self.0) } } |
