summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
Diffstat (limited to 'src/library')
-rw-r--r--src/library/flow.rs105
-rw-r--r--src/library/mod.rs2
-rw-r--r--src/library/page.rs41
-rw-r--r--src/library/par.rs46
-rw-r--r--src/library/spacing.rs18
-rw-r--r--src/library/stack.rs26
-rw-r--r--src/library/text.rs12
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)
}
}