summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
Diffstat (limited to 'src/library')
-rw-r--r--src/library/align.rs5
-rw-r--r--src/library/columns.rs7
-rw-r--r--src/library/flow.rs22
-rw-r--r--src/library/grid.rs20
-rw-r--r--src/library/heading.rs29
-rw-r--r--src/library/image.rs3
-rw-r--r--src/library/link.rs2
-rw-r--r--src/library/list.rs11
-rw-r--r--src/library/mod.rs3
-rw-r--r--src/library/pad.rs3
-rw-r--r--src/library/page.rs43
-rw-r--r--src/library/par.rs24
-rw-r--r--src/library/placed.rs3
-rw-r--r--src/library/shape.rs7
-rw-r--r--src/library/sized.rs3
-rw-r--r--src/library/spacing.rs2
-rw-r--r--src/library/stack.rs12
-rw-r--r--src/library/text.rs31
-rw-r--r--src/library/transform.rs3
19 files changed, 132 insertions, 101 deletions
diff --git a/src/library/align.rs b/src/library/align.rs
index 5f21fa37..32735244 100644
--- a/src/library/align.rs
+++ b/src/library/align.rs
@@ -8,7 +8,7 @@ pub fn align(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let aligns: Spec<_> = args.find().unwrap_or_default();
let body: PackedNode = args.expect("body")?;
- let mut styles = Styles::new();
+ let mut styles = StyleMap::new();
if let Some(align) = aligns.x {
styles.set(ParNode::ALIGN, align);
}
@@ -50,13 +50,14 @@ impl Layout for AlignNode {
&self,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> {
// The child only needs to expand along an axis if there's no alignment.
let mut pod = regions.clone();
pod.expand &= self.aligns.map_is_none();
// Layout the child.
- let mut frames = self.child.layout(ctx, &pod);
+ let mut frames = self.child.layout(ctx, &pod, styles);
for ((current, base), Constrained { item: frame, cts }) in
regions.iter().zip(&mut frames)
diff --git a/src/library/columns.rs b/src/library/columns.rs
index f5d06e56..17ae6058 100644
--- a/src/library/columns.rs
+++ b/src/library/columns.rs
@@ -34,6 +34,7 @@ impl Layout for ColumnsNode {
&self,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> {
let columns = self.columns.get();
@@ -41,7 +42,7 @@ impl Layout for ColumnsNode {
// much sense. Note that this line assumes that no infinitely wide
// region will follow if the first region's width is finite.
if regions.current.x.is_infinite() {
- return self.child.layout(ctx, regions);
+ return self.child.layout(ctx, regions, styles);
}
// Gutter width for each region. (Can be different because the relative
@@ -81,9 +82,9 @@ impl Layout for ColumnsNode {
pod.backlog = sizes.into_iter();
let mut finished = vec![];
- let mut frames = self.child.layout(ctx, &pod).into_iter();
+ let mut frames = self.child.layout(ctx, &pod, styles).into_iter();
- let dir = ctx.styles.get(ParNode::DIR);
+ let dir = styles.get(ParNode::DIR);
let total_regions = (frames.len() as f32 / columns as f32).ceil() as usize;
// Stitch together the columns for each region.
diff --git a/src/library/flow.rs b/src/library/flow.rs
index 10d57022..8656efca 100644
--- a/src/library/flow.rs
+++ b/src/library/flow.rs
@@ -17,8 +17,9 @@ impl Layout for FlowNode {
&self,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> {
- FlowLayouter::new(self, regions.clone()).layout(ctx)
+ FlowLayouter::new(self, regions.clone(), styles).layout(ctx)
}
}
@@ -37,14 +38,14 @@ pub enum FlowChild {
/// An arbitrary node.
Node(PackedNode),
/// A paragraph/block break.
- Break(Styles),
+ Break(StyleMap),
/// 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<&Styles> {
+ pub fn styles(&self) -> Option<&StyleMap> {
match self {
Self::Spacing(node) => Some(&node.styles),
Self::Node(node) => Some(&node.styles),
@@ -54,7 +55,7 @@ impl FlowChild {
}
/// A mutable reference to the child's styles.
- pub fn styles_mut(&mut self) -> Option<&mut 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),
@@ -86,6 +87,8 @@ struct FlowLayouter<'a> {
children: &'a [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
@@ -115,7 +118,7 @@ enum FlowItem {
impl<'a> FlowLayouter<'a> {
/// Create a new flow layouter.
- fn new(flow: &'a FlowNode, mut regions: Regions) -> Self {
+ fn new(flow: &'a FlowNode, mut regions: Regions, styles: StyleChain<'a>) -> Self {
let expand = regions.expand;
let full = regions.current;
@@ -125,6 +128,7 @@ impl<'a> FlowLayouter<'a> {
Self {
children: &flow.0,
regions,
+ styles,
expand,
full,
used: Size::zero(),
@@ -149,7 +153,7 @@ impl<'a> FlowLayouter<'a> {
self.layout_node(ctx, node);
}
FlowChild::Break(styles) => {
- let chain = styles.chain(&ctx.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());
@@ -191,7 +195,7 @@ impl<'a> FlowLayouter<'a> {
// aligned later.
if let Some(placed) = node.downcast::<PlacedNode>() {
if placed.out_of_flow() {
- let frame = node.layout(ctx, &self.regions).remove(0);
+ let frame = node.layout(ctx, &self.regions, self.styles).remove(0);
self.items.push(FlowItem::Placed(frame.item));
return;
}
@@ -202,7 +206,7 @@ impl<'a> FlowLayouter<'a> {
// For non-expanding paragraphs it is crucial that we align the
// whole paragraph according to its internal alignment.
if node.is::<ParNode>() {
- node.styles.chain(&ctx.styles).get(ParNode::ALIGN)
+ node.styles.chain(&self.styles).get(ParNode::ALIGN)
} else {
Align::Left
},
@@ -212,7 +216,7 @@ impl<'a> FlowLayouter<'a> {
.unwrap_or(Align::Top),
);
- let frames = node.layout(ctx, &self.regions);
+ let frames = node.layout(ctx, &self.regions, self.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/grid.rs b/src/library/grid.rs
index cc636afc..ffadf9c2 100644
--- a/src/library/grid.rs
+++ b/src/library/grid.rs
@@ -35,9 +35,10 @@ impl Layout for GridNode {
&self,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> {
// Prepare grid layout by unifying content and gutter tracks.
- let mut layouter = GridLayouter::new(self, regions.clone());
+ let mut layouter = GridLayouter::new(self, regions.clone(), styles);
// Determine all column sizes.
layouter.measure_columns(ctx);
@@ -93,6 +94,8 @@ struct GridLayouter<'a> {
rows: Vec<TrackSizing>,
/// The regions to layout children into.
regions: Regions,
+ /// The inherited styles.
+ styles: StyleChain<'a>,
/// Resolved column sizes.
rcols: Vec<Length>,
/// Rows in the current region.
@@ -123,7 +126,7 @@ enum Row {
impl<'a> GridLayouter<'a> {
/// Prepare grid layout by unifying content and gutter tracks.
- fn new(grid: &'a GridNode, mut regions: Regions) -> Self {
+ fn new(grid: &'a GridNode, mut regions: Regions, styles: StyleChain<'a>) -> Self {
let mut cols = vec![];
let mut rows = vec![];
@@ -175,6 +178,7 @@ impl<'a> GridLayouter<'a> {
cols,
rows,
regions,
+ styles,
rcols,
lrows,
expand,
@@ -296,7 +300,7 @@ impl<'a> GridLayouter<'a> {
pod.base.y = v.resolve(self.regions.base.y);
}
- let frame = node.layout(ctx, &pod).remove(0).item;
+ let frame = node.layout(ctx, &pod, self.styles).remove(0).item;
resolved.set_max(frame.size.x);
}
}
@@ -387,8 +391,10 @@ impl<'a> GridLayouter<'a> {
pod.base.x = self.regions.base.x;
}
- let mut sizes =
- node.layout(ctx, &pod).into_iter().map(|frame| frame.item.size.y);
+ let mut sizes = node
+ .layout(ctx, &pod, self.styles)
+ .into_iter()
+ .map(|frame| frame.item.size.y);
// For each region, we want to know the maximum height any
// column requires.
@@ -479,7 +485,7 @@ impl<'a> GridLayouter<'a> {
.select(self.regions.base, size);
let pod = Regions::one(size, base, Spec::splat(true));
- let frame = node.layout(ctx, &pod).remove(0);
+ let frame = node.layout(ctx, &pod, self.styles).remove(0);
output.push_frame(pos, frame.item);
}
@@ -522,7 +528,7 @@ impl<'a> GridLayouter<'a> {
}
// Push the layouted frames into the individual output frames.
- let frames = node.layout(ctx, &pod);
+ let frames = node.layout(ctx, &pod, self.styles);
for (output, frame) in outputs.iter_mut().zip(frames) {
output.push_frame(pos, frame.item);
}
diff --git a/src/library/heading.rs b/src/library/heading.rs
index f2ed3194..111472f4 100644
--- a/src/library/heading.rs
+++ b/src/library/heading.rs
@@ -32,7 +32,7 @@ impl Construct for HeadingNode {
}
impl Set for HeadingNode {
- fn set(args: &mut Args, styles: &mut Styles) -> TypResult<()> {
+ fn set(args: &mut Args, styles: &mut StyleMap) -> TypResult<()> {
styles.set_opt(Self::FAMILY, args.named("family")?);
styles.set_opt(Self::FILL, args.named("fill")?);
Ok(())
@@ -44,23 +44,28 @@ impl Layout for HeadingNode {
&self,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> {
let upscale = (1.6 - 0.1 * self.level as f64).max(0.75);
- ctx.styles.set(TextNode::STRONG, true);
- ctx.styles.set(TextNode::SIZE, Relative::new(upscale).into());
- if let Smart::Custom(family) = ctx.styles.get_ref(Self::FAMILY) {
- let list = std::iter::once(family)
- .chain(ctx.styles.get_ref(TextNode::FAMILY_LIST))
- .cloned()
- .collect();
- ctx.styles.set(TextNode::FAMILY_LIST, list);
+ let mut local = StyleMap::new();
+ local.set(TextNode::STRONG, true);
+ local.set(TextNode::SIZE, Relative::new(upscale).into());
+
+ if let Smart::Custom(family) = styles.get_ref(Self::FAMILY) {
+ local.set(
+ TextNode::FAMILY_LIST,
+ std::iter::once(family)
+ .chain(styles.get_ref(TextNode::FAMILY_LIST))
+ .cloned()
+ .collect(),
+ );
}
- if let Smart::Custom(fill) = ctx.styles.get(Self::FILL) {
- ctx.styles.set(TextNode::FILL, fill);
+ if let Smart::Custom(fill) = styles.get(Self::FILL) {
+ local.set(TextNode::FILL, fill);
}
- self.child.layout(ctx, regions)
+ self.child.layout(ctx, regions, local.chain(&styles))
}
}
diff --git a/src/library/image.rs b/src/library/image.rs
index 4e5acdc6..2b91b2fc 100644
--- a/src/library/image.rs
+++ b/src/library/image.rs
@@ -42,6 +42,7 @@ impl Layout for ImageNode {
&self,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> {
let img = ctx.images.get(self.id);
let pxw = img.width() as f64;
@@ -89,7 +90,7 @@ impl Layout for ImageNode {
}
// Apply link if it exists.
- if let Some(url) = ctx.styles.get_ref(LinkNode::URL) {
+ if let Some(url) = styles.get_ref(LinkNode::URL) {
frame.link(url);
}
diff --git a/src/library/link.rs b/src/library/link.rs
index 0f341793..d1d7842d 100644
--- a/src/library/link.rs
+++ b/src/library/link.rs
@@ -15,7 +15,7 @@ pub fn link(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
});
Ok(Value::Node(
- body.styled(Styles::one(LinkNode::URL, Some(url))),
+ body.styled(StyleMap::with(LinkNode::URL, Some(url))),
))
}
diff --git a/src/library/list.rs b/src/library/list.rs
index 765cc22b..a9dfbec5 100644
--- a/src/library/list.rs
+++ b/src/library/list.rs
@@ -32,7 +32,7 @@ impl<L: Labelling> Construct for ListNode<L> {
}
impl<L: Labelling> Set for ListNode<L> {
- fn set(args: &mut Args, styles: &mut Styles) -> TypResult<()> {
+ fn set(args: &mut Args, styles: &mut StyleMap) -> TypResult<()> {
styles.set_opt(Self::LABEL_INDENT, args.named("label-indent")?);
styles.set_opt(Self::BODY_INDENT, args.named("body-indent")?);
Ok(())
@@ -44,10 +44,11 @@ impl<L: Labelling> Layout for ListNode<L> {
&self,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> {
- let em = ctx.styles.get(TextNode::SIZE).abs;
- let label_indent = ctx.styles.get(Self::LABEL_INDENT).resolve(em);
- let body_indent = ctx.styles.get(Self::BODY_INDENT).resolve(em);
+ let em = styles.get(TextNode::SIZE).abs;
+ let label_indent = styles.get(Self::LABEL_INDENT).resolve(em);
+ let body_indent = styles.get(Self::BODY_INDENT).resolve(em);
let columns = vec![
TrackSizing::Linear(label_indent.into()),
@@ -68,7 +69,7 @@ impl<L: Labelling> Layout for ListNode<L> {
gutter: Spec::default(),
children,
}
- .layout(ctx, regions)
+ .layout(ctx, regions, styles)
}
}
diff --git a/src/library/mod.rs b/src/library/mod.rs
index 0cdabcb0..9033b3a7 100644
--- a/src/library/mod.rs
+++ b/src/library/mod.rs
@@ -61,7 +61,8 @@ prelude! {
pub use crate::diag::{At, TypResult};
pub use crate::eval::{
- Args, Construct, EvalContext, Node, Property, Set, Smart, Styles, Value,
+ Args, Construct, EvalContext, Node, Property, Set, Smart, StyleChain, StyleMap,
+ Value,
};
pub use crate::frame::*;
pub use crate::geom::*;
diff --git a/src/library/pad.rs b/src/library/pad.rs
index 96da7a0a..e2969fd6 100644
--- a/src/library/pad.rs
+++ b/src/library/pad.rs
@@ -34,10 +34,11 @@ impl Layout for PadNode {
&self,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> {
// Layout child into padded regions.
let pod = regions.map(|size| shrink(size, self.padding));
- let mut frames = self.child.layout(ctx, &pod);
+ let mut frames = self.child.layout(ctx, &pod, styles);
for ((current, base), Constrained { item: frame, cts }) in
regions.iter().zip(&mut frames)
diff --git a/src/library/page.rs b/src/library/page.rs
index 520cdaef..69be2bb7 100644
--- a/src/library/page.rs
+++ b/src/library/page.rs
@@ -12,7 +12,7 @@ pub struct PageNode {
/// The node producing the content.
pub child: PackedNode,
/// The page's styles.
- pub styles: Styles,
+ pub styles: StyleMap,
}
#[properties]
@@ -44,14 +44,14 @@ impl PageNode {
impl Construct for PageNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
Ok(Node::Page(Self {
- styles: Styles::new(),
child: args.expect("body")?,
+ styles: StyleMap::new(),
}))
}
}
impl Set for PageNode {
- fn set(args: &mut Args, styles: &mut Styles) -> TypResult<()> {
+ fn set(args: &mut Args, styles: &mut StyleMap) -> TypResult<()> {
if let Some(paper) = args.named::<Paper>("paper")?.or_else(|| args.find()) {
styles.set(Self::CLASS, paper.class());
styles.set(Self::WIDTH, Smart::Custom(paper.width()));
@@ -85,41 +85,40 @@ impl Set for PageNode {
impl PageNode {
/// Style the node with styles from a style map.
- pub fn styled(mut self, styles: Styles) -> Self {
+ 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) -> Vec<Rc<Frame>> {
- let prev = ctx.styles.clone();
- ctx.styles = self.styles.chain(&ctx.styles);
+ 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 = ctx.styles.get(Self::WIDTH).unwrap_or(Length::inf());
- let height = ctx.styles.get(Self::HEIGHT).unwrap_or(Length::inf());
+ let width = styles.get(Self::WIDTH).unwrap_or(Length::inf());
+ let height = styles.get(Self::HEIGHT).unwrap_or(Length::inf());
let mut size = Size::new(width, height);
- if ctx.styles.get(Self::FLIPPED) {
+ if styles.get(Self::FLIPPED) {
std::mem::swap(&mut size.x, &mut size.y);
}
// Determine the margins.
- let class = ctx.styles.get(Self::CLASS);
+ let class = styles.get(Self::CLASS);
let default = class.default_margins();
let padding = Sides {
- left: ctx.styles.get(Self::LEFT).unwrap_or(default.left),
- right: ctx.styles.get(Self::RIGHT).unwrap_or(default.right),
- top: ctx.styles.get(Self::TOP).unwrap_or(default.top),
- bottom: ctx.styles.get(Self::BOTTOM).unwrap_or(default.bottom),
+ left: styles.get(Self::LEFT).unwrap_or(default.left),
+ right: styles.get(Self::RIGHT).unwrap_or(default.right),
+ top: styles.get(Self::TOP).unwrap_or(default.top),
+ bottom: styles.get(Self::BOTTOM).unwrap_or(default.bottom),
};
// Realize columns with columns node.
- let columns = ctx.styles.get(Self::COLUMNS);
+ let columns = styles.get(Self::COLUMNS);
let child = if columns.get() > 1 {
ColumnsNode {
columns,
- gutter: ctx.styles.get(Self::COLUMN_GUTTER),
+ gutter: styles.get(Self::COLUMN_GUTTER),
child: self.child.clone(),
}
.pack()
@@ -133,18 +132,20 @@ impl PageNode {
// Layout the child.
let expand = size.map(Length::is_finite);
let regions = Regions::repeat(size, size, expand);
- let mut frames: Vec<_> =
- child.layout(ctx, &regions).into_iter().map(|c| c.item).collect();
+ let mut frames: Vec<_> = child
+ .layout(ctx, &regions, styles)
+ .into_iter()
+ .map(|c| c.item)
+ .collect();
// Add background fill if requested.
- if let Some(fill) = ctx.styles.get(Self::FILL) {
+ if let Some(fill) = styles.get(Self::FILL) {
for frame in &mut frames {
let shape = Shape::filled(Geometry::Rect(frame.size), fill);
Rc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape));
}
}
- ctx.styles = prev;
frames
}
}
diff --git a/src/library/par.rs b/src/library/par.rs
index 2bedc98b..65a541f6 100644
--- a/src/library/par.rs
+++ b/src/library/par.rs
@@ -35,7 +35,7 @@ impl Construct for ParNode {
}
impl Set for ParNode {
- fn set(args: &mut Args, styles: &mut Styles) -> TypResult<()> {
+ fn set(args: &mut Args, styles: &mut StyleMap) -> TypResult<()> {
let spacing = args.named("spacing")?;
let leading = args.named("leading")?;
@@ -78,17 +78,18 @@ impl Layout for ParNode {
&self,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> {
// Collect all text into one string used for BiDi analysis.
let text = self.collect_text();
// Find out the BiDi embedding levels.
- let level = Level::from_dir(ctx.styles.get(Self::DIR));
+ let level = Level::from_dir(styles.get(Self::DIR));
let bidi = BidiInfo::new(&text, level);
// Prepare paragraph layout by building a representation on which we can
// do line breaking without layouting each and every line from scratch.
- let layouter = ParLayouter::new(self, ctx, regions, bidi);
+ let layouter = ParLayouter::new(self, ctx, regions, &styles, bidi);
// Find suitable linebreaks.
layouter.layout(ctx, regions.clone())
@@ -147,12 +148,12 @@ pub enum ParChild {
impl ParChild {
/// Create a text child.
- pub fn text(text: impl Into<EcoString>, styles: Styles) -> Self {
+ 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) -> &Styles {
+ pub fn styles(&self) -> &StyleMap {
match self {
Self::Spacing(node) => &node.styles,
Self::Text(node) => &node.styles,
@@ -161,7 +162,7 @@ impl ParChild {
}
/// A mutable reference to the child's styles.
- pub fn styles_mut(&mut self) -> &mut Styles {
+ pub fn styles_mut(&mut self) -> &mut StyleMap {
match self {
Self::Spacing(node) => &mut node.styles,
Self::Text(node) => &mut node.styles,
@@ -226,6 +227,7 @@ impl<'a> ParLayouter<'a> {
par: &'a ParNode,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: &'a StyleChain<'a>,
bidi: BidiInfo<'a>,
) -> Self {
let mut items = vec![];
@@ -253,7 +255,7 @@ impl<'a> ParLayouter<'a> {
cursor += group.len();
let subrange = start .. cursor;
let text = &bidi.text[subrange.clone()];
- let styles = node.styles.chain(&ctx.styles);
+ let styles = node.styles.chain(styles);
let shaped = shape(ctx.fonts, text, styles, level.dir());
items.push(ParItem::Text(shaped));
ranges.push(subrange);
@@ -262,16 +264,16 @@ impl<'a> ParLayouter<'a> {
ParChild::Node(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).remove(0);
+ let frame = node.layout(ctx, &pod, *styles).remove(0);
items.push(ParItem::Frame(Rc::take(frame.item)));
ranges.push(range);
}
}
}
- let em = ctx.styles.get(TextNode::SIZE).abs;
- let align = ctx.styles.get(ParNode::ALIGN);
- let leading = ctx.styles.get(ParNode::LEADING).resolve(em);
+ let em = styles.get(TextNode::SIZE).abs;
+ let align = styles.get(ParNode::ALIGN);
+ let leading = styles.get(ParNode::LEADING).resolve(em);
Self { align, leading, bidi, items, ranges }
}
diff --git a/src/library/placed.rs b/src/library/placed.rs
index 5d98edc4..8a4f46af 100644
--- a/src/library/placed.rs
+++ b/src/library/placed.rs
@@ -34,6 +34,7 @@ impl Layout for PlacedNode {
&self,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> {
let out_of_flow = self.out_of_flow();
@@ -45,7 +46,7 @@ impl Layout for PlacedNode {
Regions::one(regions.base, regions.base, expand)
};
- let mut frames = self.0.layout(ctx, &pod);
+ let mut frames = self.0.layout(ctx, &pod, styles);
let Constrained { item: frame, cts } = &mut frames[0];
// If expansion is off, zero all sizes so that we don't take up any
diff --git a/src/library/shape.rs b/src/library/shape.rs
index 15a857ef..76c03edb 100644
--- a/src/library/shape.rs
+++ b/src/library/shape.rs
@@ -106,11 +106,12 @@ impl Layout for ShapeNode {
&self,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> {
let mut frames;
if let Some(child) = &self.child {
let mut pod = Regions::one(regions.current, regions.base, regions.expand);
- frames = child.layout(ctx, &pod);
+ frames = child.layout(ctx, &pod, styles);
// Relayout with full expansion into square region to make sure
// the result is really a square or circle.
@@ -126,7 +127,7 @@ impl Layout for ShapeNode {
pod.current = Size::splat(length);
pod.expand = Spec::splat(true);
- frames = child.layout(ctx, &pod);
+ frames = child.layout(ctx, &pod, styles);
frames[0].cts = Constraints::tight(regions);
}
} else {
@@ -169,7 +170,7 @@ impl Layout for ShapeNode {
}
// Apply link if it exists.
- if let Some(url) = ctx.styles.get_ref(LinkNode::URL) {
+ if let Some(url) = styles.get_ref(LinkNode::URL) {
frame.link(url);
}
diff --git a/src/library/sized.rs b/src/library/sized.rs
index 81ca69c2..2400971a 100644
--- a/src/library/sized.rs
+++ b/src/library/sized.rs
@@ -30,6 +30,7 @@ impl Layout for SizedNode {
&self,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> {
let is_auto = self.sizing.map_is_none();
let is_rel = self.sizing.map(|s| s.map_or(false, Linear::is_relative));
@@ -51,7 +52,7 @@ impl Layout for SizedNode {
Regions::one(size, base, expand)
};
- let mut frames = self.child.layout(ctx, &pod);
+ let mut frames = self.child.layout(ctx, &pod, styles);
let Constrained { item: frame, cts } = &mut frames[0];
// Ensure frame size matches regions size if expansion is on.
diff --git a/src/library/spacing.rs b/src/library/spacing.rs
index e552828c..a5888485 100644
--- a/src/library/spacing.rs
+++ b/src/library/spacing.rs
@@ -24,7 +24,7 @@ pub struct SpacingNode {
/// The kind of spacing.
pub kind: SpacingKind,
/// The spacing's styles.
- pub styles: Styles,
+ pub styles: StyleMap,
}
impl Debug for SpacingNode {
diff --git a/src/library/stack.rs b/src/library/stack.rs
index d7748378..d36c2e15 100644
--- a/src/library/stack.rs
+++ b/src/library/stack.rs
@@ -28,8 +28,9 @@ impl Layout for StackNode {
&self,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> {
- StackLayouter::new(self, regions.clone()).layout(ctx)
+ StackLayouter::new(self, regions.clone(), styles).layout(ctx)
}
}
@@ -44,7 +45,7 @@ pub enum StackChild {
impl From<SpacingKind> for StackChild {
fn from(kind: SpacingKind) -> Self {
- Self::Spacing(SpacingNode { kind, styles: Styles::new() })
+ Self::Spacing(SpacingNode { kind, styles: StyleMap::new() })
}
}
@@ -79,6 +80,8 @@ struct StackLayouter<'a> {
spacing: Option<SpacingKind>,
/// The regions to layout children into.
regions: Regions,
+ /// The inherited styles.
+ styles: StyleChain<'a>,
/// Whether the stack should expand to fill the region.
expand: Spec<bool>,
/// The full size of `regions.current` that was available before we started
@@ -106,7 +109,7 @@ enum StackItem {
impl<'a> StackLayouter<'a> {
/// Create a new stack layouter.
- fn new(stack: &'a StackNode, mut regions: Regions) -> Self {
+ fn new(stack: &'a StackNode, mut regions: Regions, styles: StyleChain<'a>) -> Self {
let dir = stack.dir;
let axis = dir.axis();
let expand = regions.expand;
@@ -121,6 +124,7 @@ impl<'a> StackLayouter<'a> {
axis,
spacing: stack.spacing,
regions,
+ styles,
expand,
full,
used: Gen::zero(),
@@ -190,7 +194,7 @@ impl<'a> StackLayouter<'a> {
.and_then(|node| node.aligns.get(self.axis))
.unwrap_or(self.dir.start().into());
- let frames = node.layout(ctx, &self.regions);
+ let frames = node.layout(ctx, &self.regions, self.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/text.rs b/src/library/text.rs
index 26e949fc..5fa19cb9 100644
--- a/src/library/text.rs
+++ b/src/library/text.rs
@@ -23,7 +23,7 @@ pub struct TextNode {
/// The run's text.
pub text: EcoString,
/// The run's styles.
- pub styles: Styles,
+ pub styles: StyleMap,
}
#[properties]
@@ -108,7 +108,7 @@ impl Construct for TextNode {
}
impl Set for TextNode {
- fn set(args: &mut Args, styles: &mut Styles) -> TypResult<()> {
+ fn set(args: &mut Args, styles: &mut StyleMap) -> TypResult<()> {
let list = args.named("family")?.or_else(|| {
let families: Vec<_> = args.all().collect();
(!families.is_empty()).then(|| families)
@@ -412,7 +412,7 @@ fn line_impl(args: &mut Args, kind: LineKind) -> TypResult<Value> {
let body: Node = args.expect("body")?;
let deco = LineDecoration { kind, stroke, thickness, offset, extent };
Ok(Value::Node(
- body.styled(Styles::one(TextNode::LINES, vec![deco])),
+ body.styled(StyleMap::with(TextNode::LINES, vec![deco])),
))
}
@@ -449,7 +449,7 @@ pub enum LineKind {
pub fn shape<'a>(
fonts: &mut FontStore,
text: &'a str,
- styles: Styles,
+ styles: StyleChain<'a>,
dir: Dir,
) -> ShapedText<'a> {
let mut glyphs = vec![];
@@ -459,16 +459,16 @@ pub fn shape<'a>(
&mut glyphs,
0,
text,
- variant(&styles),
- families(&styles),
+ variant(styles),
+ families(styles),
None,
dir,
- &tags(&styles),
+ &tags(styles),
);
}
track(&mut glyphs, styles.get(TextNode::TRACKING));
- let (size, baseline) = measure(fonts, &glyphs, &styles);
+ let (size, baseline) = measure(fonts, &glyphs, styles);
ShapedText {
text,
@@ -627,7 +627,7 @@ fn track(glyphs: &mut [ShapedGlyph], tracking: Em) {
fn measure(
fonts: &mut FontStore,
glyphs: &[ShapedGlyph],
- styles: &Styles,
+ styles: StyleChain,
) -> (Size, Length) {
let mut width = Length::zero();
let mut top = Length::zero();
@@ -667,7 +667,7 @@ fn measure(
}
/// Resolve the font variant with `STRONG` and `EMPH` factored in.
-fn variant(styles: &Styles) -> FontVariant {
+fn variant(styles: StyleChain) -> FontVariant {
let mut variant = FontVariant::new(
styles.get(TextNode::STYLE),
styles.get(TextNode::WEIGHT),
@@ -690,7 +690,7 @@ fn variant(styles: &Styles) -> FontVariant {
}
/// Resolve a prioritized iterator over the font families.
-fn families(styles: &Styles) -> impl Iterator<Item = &str> + Clone {
+fn families(styles: StyleChain) -> impl Iterator<Item = &str> + Clone {
let head = if styles.get(TextNode::MONOSPACE) {
styles.get_ref(TextNode::MONOSPACE_LIST).as_slice()
} else {
@@ -719,7 +719,7 @@ fn families(styles: &Styles) -> impl Iterator<Item = &str> + Clone {
}
/// Collect the tags of the OpenType features to apply.
-fn tags(styles: &Styles) -> Vec<Feature> {
+fn tags(styles: StyleChain) -> Vec<Feature> {
let mut tags = vec![];
let mut feat = |tag, value| {
tags.push(Feature::new(Tag::from_bytes(tag), value, ..));
@@ -803,8 +803,7 @@ pub struct ShapedText<'a> {
/// The text direction.
pub dir: Dir,
/// The text's style properties.
- // TODO(style): Go back to reference.
- pub styles: Styles,
+ pub styles: StyleChain<'a>,
/// The font size.
pub size: Size,
/// The baseline from the top of the frame.
@@ -858,7 +857,7 @@ impl<'a> ShapedText<'a> {
frame.push(pos, Element::Text(text));
// Apply line decorations.
- for line in self.styles.get_ref(TextNode::LINES) {
+ for line in self.styles.get_cloned(TextNode::LINES) {
let face = fonts.get(face_id);
let metrics = match line.kind {
LineKind::Underline => face.underline,
@@ -905,7 +904,7 @@ impl<'a> ShapedText<'a> {
text_range: Range<usize>,
) -> ShapedText<'a> {
if let Some(glyphs) = self.slice_safe_to_break(text_range.clone()) {
- let (size, baseline) = measure(fonts, glyphs, &self.styles);
+ let (size, baseline) = measure(fonts, glyphs, self.styles);
Self {
text: &self.text[text_range],
dir: self.dir,
diff --git a/src/library/transform.rs b/src/library/transform.rs
index 03f0a84c..7392b89f 100644
--- a/src/library/transform.rs
+++ b/src/library/transform.rs
@@ -53,8 +53,9 @@ impl Layout for TransformNode {
&self,
ctx: &mut LayoutContext,
regions: &Regions,
+ styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> {
- let mut frames = self.child.layout(ctx, regions);
+ let mut frames = self.child.layout(ctx, regions, styles);
for Constrained { item: frame, .. } in &mut frames {
let Spec { x, y } = self.origin.zip(frame.size).map(|(o, s)| o.resolve(s));