summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-10-28 16:43:38 +0200
committerLaurenz <laurmaedje@gmail.com>2022-10-28 16:43:38 +0200
commit95e9134a3c7d7a14d8c8928413fdffc665671895 (patch)
tree822b5f6c2d23aba33cfe4d199405e493e37c3d70 /src/library
parent66030ae5d73d85a0463562230b87f8ec7554c746 (diff)
Refactor `geom` module
Diffstat (limited to 'src/library')
-rw-r--r--src/library/graphics/image.rs4
-rw-r--r--src/library/graphics/line.rs17
-rw-r--r--src/library/graphics/shape.rs29
-rw-r--r--src/library/layout/align.rs10
-rw-r--r--src/library/layout/columns.rs8
-rw-r--r--src/library/layout/container.rs2
-rw-r--r--src/library/layout/flow.rs18
-rw-r--r--src/library/layout/grid.rs77
-rw-r--r--src/library/layout/pad.rs6
-rw-r--r--src/library/layout/page.rs25
-rw-r--r--src/library/layout/place.rs6
-rw-r--r--src/library/layout/spacing.rs16
-rw-r--r--src/library/layout/stack.rs65
-rw-r--r--src/library/layout/transform.rs8
-rw-r--r--src/library/math/mod.rs19
-rw-r--r--src/library/mod.rs12
-rw-r--r--src/library/prelude.rs9
-rw-r--r--src/library/structure/list.rs8
-rw-r--r--src/library/structure/table.rs10
-rw-r--r--src/library/text/deco.rs24
-rw-r--r--src/library/text/link.rs6
-rw-r--r--src/library/text/mod.rs24
-rw-r--r--src/library/text/par.rs66
-rw-r--r--src/library/text/shaping.rs18
-rw-r--r--src/library/text/shift.rs2
25 files changed, 254 insertions, 235 deletions
diff --git a/src/library/graphics/image.rs b/src/library/graphics/image.rs
index 7523471d..343b4788 100644
--- a/src/library/graphics/image.rs
+++ b/src/library/graphics/image.rs
@@ -33,7 +33,7 @@ impl ImageNode {
let height = args.named("height")?;
Ok(Content::inline(
- ImageNode(image).pack().sized(Spec::new(width, height)),
+ ImageNode(image).pack().sized(Axes::new(width, height)),
))
}
}
@@ -62,7 +62,7 @@ impl Layout for ImageNode {
} else if first.y.is_finite() {
Size::new(first.x.min(first.y * px_ratio), first.y)
} else {
- Size::new(Length::pt(pxw), Length::pt(pxh))
+ Size::new(Abs::pt(pxw), Abs::pt(pxh))
};
// Compute the actual size of the fitted image.
diff --git a/src/library/graphics/line.rs b/src/library/graphics/line.rs
index 192f8350..78878014 100644
--- a/src/library/graphics/line.rs
+++ b/src/library/graphics/line.rs
@@ -4,9 +4,9 @@ use crate::library::prelude::*;
#[derive(Debug, Hash)]
pub struct LineNode {
/// Where the line starts.
- origin: Spec<Relative<RawLength>>,
+ origin: Axes<Rel<Length>>,
/// The offset from the `origin` where the line ends.
- delta: Spec<Relative<RawLength>>,
+ delta: Axes<Rel<Length>>,
}
#[node]
@@ -18,18 +18,17 @@ impl LineNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
let origin = args.named("origin")?.unwrap_or_default();
- let delta = match args.named::<Spec<Relative<RawLength>>>("to")? {
+ let delta = match args.named::<Axes<Rel<Length>>>("to")? {
Some(to) => to.zip(origin).map(|(to, from)| to - from),
None => {
- let length = args
- .named::<Relative<RawLength>>("length")?
- .unwrap_or(Length::cm(1.0).into());
+ let length =
+ args.named::<Rel<Length>>("length")?.unwrap_or(Abs::cm(1.0).into());
let angle = args.named::<Angle>("angle")?.unwrap_or_default();
let x = angle.cos() * length;
let y = angle.sin() * length;
- Spec::new(x, y)
+ Axes::new(x, y)
}
};
@@ -69,12 +68,12 @@ impl Layout for LineNode {
}
castable! {
- Spec<Relative<RawLength>>,
+ Axes<Rel<Length>>,
Expected: "array of two relative lengths",
Value::Array(array) => {
let mut iter = array.into_iter();
match (iter.next(), iter.next(), iter.next()) {
- (Some(a), Some(b), None) => Spec::new(a.cast()?, b.cast()?),
+ (Some(a), Some(b), None) => Axes::new(a.cast()?, b.cast()?),
_ => Err("point array must contain exactly two entries")?,
}
},
diff --git a/src/library/graphics/shape.rs b/src/library/graphics/shape.rs
index eea02568..7a742109 100644
--- a/src/library/graphics/shape.rs
+++ b/src/library/graphics/shape.rs
@@ -29,20 +29,19 @@ impl<const S: ShapeKind> ShapeNode<S> {
/// How much to pad the shape's content.
#[property(resolve, fold)]
- pub const INSET: Sides<Option<Relative<RawLength>>> = Sides::splat(Relative::zero());
+ pub const INSET: Sides<Option<Rel<Length>>> = Sides::splat(Rel::zero());
/// How much to extend the shape's dimensions beyond the allocated space.
#[property(resolve, fold)]
- pub const OUTSET: Sides<Option<Relative<RawLength>>> = Sides::splat(Relative::zero());
+ pub const OUTSET: Sides<Option<Rel<Length>>> = Sides::splat(Rel::zero());
/// How much to round the shape's corners.
#[property(skip, resolve, fold)]
- pub const RADIUS: Corners<Option<Relative<RawLength>>> =
- Corners::splat(Relative::zero());
+ pub const RADIUS: Corners<Option<Rel<Length>>> = Corners::splat(Rel::zero());
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
let size = match S {
- SQUARE => args.named::<RawLength>("size")?.map(Relative::from),
- CIRCLE => args.named::<RawLength>("radius")?.map(|r| 2.0 * Relative::from(r)),
+ SQUARE => args.named::<Length>("size")?.map(Rel::from),
+ CIRCLE => args.named::<Length>("radius")?.map(|r| 2.0 * Rel::from(r)),
_ => None,
};
@@ -57,7 +56,7 @@ impl<const S: ShapeKind> ShapeNode<S> {
};
Ok(Content::inline(
- Self(args.eat()?).pack().sized(Spec::new(width, height)),
+ Self(args.eat()?).pack().sized(Axes::new(width, height)),
))
}
@@ -90,7 +89,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
}
// Pad the child.
- let child = child.clone().padded(inset.map(|side| side.map(RawLength::from)));
+ let child = child.clone().padded(inset.map(|side| side.map(Length::from)));
let mut pod = Regions::one(regions.first, regions.base, regions.expand);
frames = child.layout(world, &pod, styles)?;
@@ -112,14 +111,13 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
};
pod.first = Size::splat(length);
- pod.expand = Spec::splat(true);
+ pod.expand = Axes::splat(true);
frames = child.layout(world, &pod, styles)?;
}
} else {
// The default size that a shape takes on if it has no child and
// enough space.
- let mut size =
- Size::new(Length::pt(45.0), Length::pt(30.0)).min(regions.first);
+ let mut size = Size::new(Abs::pt(45.0), Abs::pt(30.0)).min(regions.first);
if is_quadratic(S) {
let length = if regions.expand.x || regions.expand.y {
@@ -159,16 +157,11 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
if fill.is_some() || stroke.iter().any(Option::is_some) {
if is_round(S) {
- let shape = Shape {
- geometry: Geometry::Ellipse(size),
- fill,
- stroke: stroke.left,
- };
+ let shape = ellipse(size, fill, stroke.left);
frame.prepend(pos, Element::Shape(shape));
} else {
frame.prepend_multiple(
- RoundedRect::new(size, radius)
- .shapes(fill, stroke)
+ rounded_rect(size, radius, fill, stroke)
.into_iter()
.map(|x| (pos, Element::Shape(x))),
)
diff --git a/src/library/layout/align.rs b/src/library/layout/align.rs
index 705d555b..95f5c01f 100644
--- a/src/library/layout/align.rs
+++ b/src/library/layout/align.rs
@@ -5,7 +5,7 @@ use crate::library::text::{HorizontalAlign, ParNode};
#[derive(Debug, Hash)]
pub struct AlignNode {
/// How to align the node horizontally and vertically.
- pub aligns: Spec<Option<RawAlign>>,
+ pub aligns: Axes<Option<RawAlign>>,
/// The node to be aligned.
pub child: LayoutNode,
}
@@ -13,11 +13,11 @@ pub struct AlignNode {
#[node]
impl AlignNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
- let aligns: Spec<Option<RawAlign>> = args.find()?.unwrap_or_default();
+ let aligns: Axes<Option<RawAlign>> = args.find()?.unwrap_or_default();
let body: Content = args.expect("body")?;
Ok(match (body, aligns) {
(Content::Block(node), _) => Content::Block(node.aligned(aligns)),
- (other, Spec { x: Some(x), y: None }) => {
+ (other, Axes { x: Some(x), y: None }) => {
other.styled(ParNode::ALIGN, HorizontalAlign(x))
}
(other, _) => Content::Block(other.pack().aligned(aligns)),
@@ -34,7 +34,7 @@ impl Layout for AlignNode {
) -> SourceResult<Vec<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();
+ pod.expand &= self.aligns.as_ref().map(Option::is_none);
// Align paragraphs inside the child.
let mut passed = StyleMap::new();
@@ -51,7 +51,7 @@ impl Layout for AlignNode {
let aligns = self
.aligns
.map(|align| align.resolve(styles))
- .unwrap_or(Spec::new(Align::Left, Align::Top));
+ .unwrap_or(Axes::new(Align::Left, Align::Top));
frame.resize(target, aligns);
}
diff --git a/src/library/layout/columns.rs b/src/library/layout/columns.rs
index 8ae4394e..3ba3598c 100644
--- a/src/library/layout/columns.rs
+++ b/src/library/layout/columns.rs
@@ -15,7 +15,7 @@ pub struct ColumnsNode {
impl ColumnsNode {
/// The size of the gutter space between each column.
#[property(resolve)]
- pub const GUTTER: Relative<RawLength> = Ratio::new(0.04).into();
+ pub const GUTTER: Rel<Length> = Ratio::new(0.04).into();
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Content::block(Self {
@@ -53,7 +53,7 @@ impl Layout for ColumnsNode {
.skip(1)
.collect(),
last: regions.last,
- expand: Spec::new(true, regions.expand.y),
+ expand: Axes::new(true, regions.expand.y),
};
// Layout the children.
@@ -69,9 +69,9 @@ impl Layout for ColumnsNode {
// Otherwise its the maximum column height for the frame. In that
// case, the frame is first created with zero height and then
// resized.
- let height = if regions.expand.y { region.y } else { Length::zero() };
+ let height = if regions.expand.y { region.y } else { Abs::zero() };
let mut output = Frame::new(Size::new(regions.first.x, height));
- let mut cursor = Length::zero();
+ let mut cursor = Abs::zero();
for _ in 0 .. columns {
let frame = match frames.next() {
diff --git a/src/library/layout/container.rs b/src/library/layout/container.rs
index 23556a2e..9b1f8f56 100644
--- a/src/library/layout/container.rs
+++ b/src/library/layout/container.rs
@@ -9,7 +9,7 @@ impl BoxNode {
let width = args.named("width")?;
let height = args.named("height")?;
let body: LayoutNode = args.eat()?.unwrap_or_default();
- Ok(Content::inline(body.sized(Spec::new(width, height))))
+ Ok(Content::inline(body.sized(Axes::new(width, height))))
}
}
diff --git a/src/library/layout/flow.rs b/src/library/layout/flow.rs
index 7cb52910..1f0a2b4a 100644
--- a/src/library/layout/flow.rs
+++ b/src/library/layout/flow.rs
@@ -81,14 +81,14 @@ pub struct FlowLayouter {
/// The regions to layout children into.
regions: Regions,
/// Whether the flow should expand to fill the region.
- expand: Spec<bool>,
+ expand: Axes<bool>,
/// The full size of `regions.size` that was available before we started
/// subtracting.
full: Size,
/// The size used by the frames for the current region.
used: Size,
/// The sum of fractions in the current region.
- fr: Fraction,
+ fr: Fr,
/// Spacing and layouted nodes.
items: Vec<FlowItem>,
/// Finished frames for previous regions.
@@ -98,11 +98,11 @@ pub struct FlowLayouter {
/// A prepared item in a flow layout.
enum FlowItem {
/// Absolute spacing between other items.
- Absolute(Length),
+ Absolute(Abs),
/// Fractional spacing between other items.
- Fractional(Fraction),
+ Fractional(Fr),
/// A frame for a layouted child node and how to align it.
- Frame(Frame, Spec<Align>),
+ Frame(Frame, Axes<Align>),
/// An absolutely placed frame.
Placed(Frame),
}
@@ -122,7 +122,7 @@ impl FlowLayouter {
expand,
full,
used: Size::zero(),
- fr: Fraction::zero(),
+ fr: Fr::zero(),
items: vec![],
finished: vec![],
}
@@ -169,7 +169,7 @@ impl FlowLayouter {
}
// How to align the node.
- let aligns = Spec::new(
+ let aligns = Axes::new(
// For non-expanding paragraphs it is crucial that we align the
// whole paragraph as it is itself aligned.
styles.get(ParNode::ALIGN),
@@ -215,7 +215,7 @@ impl FlowLayouter {
}
let mut output = Frame::new(size);
- let mut offset = Length::zero();
+ let mut offset = Abs::zero();
let mut ruler = Align::Top;
// Place all frames.
@@ -245,7 +245,7 @@ impl FlowLayouter {
self.regions.next();
self.full = self.regions.first;
self.used = Size::zero();
- self.fr = Fraction::zero();
+ self.fr = Fr::zero();
self.finished.push(output);
}
diff --git a/src/library/layout/grid.rs b/src/library/layout/grid.rs
index 2c246df9..a1098c6d 100644
--- a/src/library/layout/grid.rs
+++ b/src/library/layout/grid.rs
@@ -4,9 +4,9 @@ use crate::library::prelude::*;
#[derive(Debug, Hash)]
pub struct GridNode {
/// Defines sizing for content rows and columns.
- pub tracks: Spec<Vec<TrackSizing>>,
+ pub tracks: Axes<Vec<TrackSizing>>,
/// Defines sizing of gutter rows and columns between content.
- pub gutter: Spec<Vec<TrackSizing>>,
+ pub gutter: Axes<Vec<TrackSizing>>,
/// The nodes to be arranged in a grid.
pub cells: Vec<LayoutNode>,
}
@@ -20,8 +20,8 @@ impl GridNode {
let column_gutter = args.named("column-gutter")?;
let row_gutter = args.named("row-gutter")?;
Ok(Content::block(Self {
- tracks: Spec::new(columns, rows),
- gutter: Spec::new(
+ tracks: Axes::new(columns, rows),
+ gutter: Axes::new(
column_gutter.unwrap_or_else(|| base_gutter.clone()),
row_gutter.unwrap_or(base_gutter),
),
@@ -59,10 +59,10 @@ pub enum TrackSizing {
Auto,
/// A track size specified in absolute terms and relative to the parent's
/// size.
- Relative(Relative<RawLength>),
+ Relative(Rel<Length>),
/// A track size specified as a fraction of the remaining free space in the
/// parent.
- Fractional(Fraction),
+ Fractional(Fr),
}
castable! {
@@ -105,16 +105,16 @@ pub struct GridLayouter<'a> {
/// The inherited styles.
styles: StyleChain<'a>,
/// Resolved column sizes.
- rcols: Vec<Length>,
+ rcols: Vec<Abs>,
/// Rows in the current region.
lrows: Vec<Row>,
/// The full height of the current region.
- full: Length,
+ full: Abs,
/// The used-up size of the current region. The horizontal size is
/// determined once after columns are resolved and not touched again.
used: Size,
/// The sum of fractions in the current region.
- fr: Fraction,
+ fr: Fr,
/// Frames for finished regions.
finished: Vec<Frame>,
}
@@ -125,7 +125,7 @@ enum Row {
/// Finished row frame of auto or relative row.
Frame(Frame),
/// Fractional row with y index.
- Fr(Fraction, usize),
+ Fr(Fr, usize),
}
impl<'a> GridLayouter<'a> {
@@ -134,8 +134,8 @@ impl<'a> GridLayouter<'a> {
/// This prepares grid layout by unifying content and gutter tracks.
pub fn new(
world: Tracked<'a, dyn World>,
- tracks: Spec<&[TrackSizing]>,
- gutter: Spec<&[TrackSizing]>,
+ tracks: Axes<&[TrackSizing]>,
+ gutter: Axes<&[TrackSizing]>,
cells: &'a [LayoutNode],
regions: &Regions,
styles: StyleChain<'a>,
@@ -156,7 +156,7 @@ impl<'a> GridLayouter<'a> {
};
let auto = TrackSizing::Auto;
- let zero = TrackSizing::Relative(Relative::zero());
+ let zero = TrackSizing::Relative(Rel::zero());
let get_or = |tracks: &[_], idx, default| {
tracks.get(idx).or(tracks.last()).copied().unwrap_or(default)
};
@@ -178,13 +178,13 @@ impl<'a> GridLayouter<'a> {
rows.pop();
let full = regions.first.y;
- let rcols = vec![Length::zero(); cols.len()];
+ let rcols = vec![Abs::zero(); cols.len()];
let lrows = vec![];
// We use the regions for auto row measurement. Since at that moment,
// columns are already sized, we can enable horizontal expansion.
let mut regions = regions.clone();
- regions.expand = Spec::new(true, false);
+ regions.expand = Axes::new(true, false);
Self {
world,
@@ -197,7 +197,7 @@ impl<'a> GridLayouter<'a> {
lrows,
full,
used: Size::zero(),
- fr: Fraction::zero(),
+ fr: Fr::zero(),
finished: vec![],
}
}
@@ -230,10 +230,10 @@ impl<'a> GridLayouter<'a> {
/// Determine all column sizes.
fn measure_columns(&mut self) -> SourceResult<()> {
// Sum of sizes of resolved relative tracks.
- let mut rel = Length::zero();
+ let mut rel = Abs::zero();
// Sum of fractions of all fractional tracks.
- let mut fr = Fraction::zero();
+ let mut fr = Fr::zero();
// Resolve the size of all relative columns and compute the sum of all
// fractional tracks.
@@ -252,14 +252,14 @@ impl<'a> GridLayouter<'a> {
// Size that is not used by fixed-size columns.
let available = self.regions.first.x - rel;
- if available >= Length::zero() {
+ if available >= Abs::zero() {
// Determine size of auto columns.
let (auto, count) = self.measure_auto_columns(available)?;
// If there is remaining space, distribute it to fractional columns,
// otherwise shrink auto columns.
let remaining = available - auto;
- if remaining >= Length::zero() {
+ if remaining >= Abs::zero() {
if !fr.is_zero() {
self.grow_fractional_columns(remaining, fr);
}
@@ -275,11 +275,8 @@ impl<'a> GridLayouter<'a> {
}
/// Measure the size that is available to auto columns.
- fn measure_auto_columns(
- &mut self,
- available: Length,
- ) -> SourceResult<(Length, usize)> {
- let mut auto = Length::zero();
+ fn measure_auto_columns(&mut self, available: Abs) -> SourceResult<(Abs, usize)> {
+ let mut auto = Abs::zero();
let mut count = 0;
// Determine size of auto columns by laying out all cells in those
@@ -289,12 +286,12 @@ impl<'a> GridLayouter<'a> {
continue;
}
- let mut resolved = Length::zero();
+ let mut resolved = Abs::zero();
for y in 0 .. self.rows.len() {
if let Some(node) = self.cell(x, y) {
let size = Size::new(available, self.regions.base.y);
let mut pod =
- Regions::one(size, self.regions.base, Spec::splat(false));
+ Regions::one(size, self.regions.base, Axes::splat(false));
// For relative rows, we can already resolve the correct
// base, for auto it's already correct and for fr we could
@@ -318,7 +315,7 @@ impl<'a> GridLayouter<'a> {
}
/// Distribute remaining space to fractional columns.
- fn grow_fractional_columns(&mut self, remaining: Length, fr: Fraction) {
+ fn grow_fractional_columns(&mut self, remaining: Abs, fr: Fr) {
for (&col, rcol) in self.cols.iter().zip(&mut self.rcols) {
if let TrackSizing::Fractional(v) = col {
*rcol = v.share(fr, remaining);
@@ -327,7 +324,7 @@ impl<'a> GridLayouter<'a> {
}
/// Redistribute space to auto columns so that each gets a fair share.
- fn shrink_auto_columns(&mut self, available: Length, count: usize) {
+ fn shrink_auto_columns(&mut self, available: Abs, count: usize) {
// The fair share each auto column may have.
let fair = available / count as f64;
@@ -359,7 +356,7 @@ impl<'a> GridLayouter<'a> {
/// Layout a row with automatic height. Such a row may break across multiple
/// regions.
fn layout_auto_row(&mut self, y: usize) -> SourceResult<()> {
- let mut resolved: Vec<Length> = vec![];
+ let mut resolved: Vec<Abs> = vec![];
// Determine the size for each region of the row.
for (x, &rcol) in self.rcols.iter().enumerate() {
@@ -426,11 +423,7 @@ impl<'a> GridLayouter<'a> {
/// Layout a row with relative height. Such a row cannot break across
/// multiple regions, but it may force a region break.
- fn layout_relative_row(
- &mut self,
- v: Relative<RawLength>,
- y: usize,
- ) -> SourceResult<()> {
+ fn layout_relative_row(&mut self, v: Rel<Length>, y: usize) -> SourceResult<()> {
let resolved = v.resolve(self.styles).relative_to(self.regions.base.y);
let frame = self.layout_single_row(resolved, y)?;
@@ -451,7 +444,7 @@ impl<'a> GridLayouter<'a> {
}
/// Layout a row with fixed height and return its frame.
- fn layout_single_row(&mut self, height: Length, y: usize) -> SourceResult<Frame> {
+ fn layout_single_row(&mut self, height: Abs, y: usize) -> SourceResult<Frame> {
let mut output = Frame::new(Size::new(self.used.x, height));
let mut pos = Point::zero();
@@ -462,11 +455,11 @@ impl<'a> GridLayouter<'a> {
// Set the base to the region's base for auto rows and to the
// size for relative and fractional rows.
- let base = Spec::new(self.cols[x], self.rows[y])
+ let base = Axes::new(self.cols[x], self.rows[y])
.map(|s| s == TrackSizing::Auto)
.select(self.regions.base, size);
- let pod = Regions::one(size, base, Spec::splat(true));
+ let pod = Regions::one(size, base, Axes::splat(true));
let frame = node.layout(self.world, &pod, self.styles)?.remove(0);
match frame.role() {
Some(Role::ListLabel | Role::ListItemBody) => {
@@ -488,7 +481,7 @@ impl<'a> GridLayouter<'a> {
/// Layout a row spanning multiple regions.
fn layout_multi_row(
&mut self,
- heights: &[Length],
+ heights: &[Abs],
y: usize,
) -> SourceResult<Vec<Frame>> {
// Prepare frames.
@@ -499,7 +492,7 @@ impl<'a> GridLayouter<'a> {
// Prepare regions.
let size = Size::new(self.used.x, heights[0]);
- let mut pod = Regions::one(size, self.regions.base, Spec::splat(true));
+ let mut pod = Regions::one(size, self.regions.base, Axes::splat(true));
pod.backlog = heights[1 ..].to_vec();
// Layout the row.
@@ -573,8 +566,8 @@ impl<'a> GridLayouter<'a> {
self.finished.push(output);
self.regions.next();
self.full = self.regions.first.y;
- self.used.y = Length::zero();
- self.fr = Fraction::zero();
+ self.used.y = Abs::zero();
+ self.fr = Fr::zero();
Ok(())
}
diff --git a/src/library/layout/pad.rs b/src/library/layout/pad.rs
index 06c3672f..b0238d40 100644
--- a/src/library/layout/pad.rs
+++ b/src/library/layout/pad.rs
@@ -4,7 +4,7 @@ use crate::library::prelude::*;
#[derive(Debug, Hash)]
pub struct PadNode {
/// The amount of padding.
- pub padding: Sides<Relative<RawLength>>,
+ pub padding: Sides<Rel<Length>>,
/// The child node whose sides to pad.
pub child: LayoutNode,
}
@@ -54,7 +54,7 @@ impl Layout for PadNode {
}
/// Shrink a size by padding relative to the size itself.
-fn shrink(size: Size, padding: Sides<Relative<Length>>) -> Size {
+fn shrink(size: Size, padding: Sides<Rel<Abs>>) -> Size {
size - padding.relative_to(size).sum_by_axis()
}
@@ -77,7 +77,7 @@ fn shrink(size: Size, padding: Sides<Relative<Length>>) -> Size {
/// <=> w - p.rel * w - p.abs = s
/// <=> (1 - p.rel) * w = s + p.abs
/// <=> w = (s + p.abs) / (1 - p.rel)
-fn grow(size: Size, padding: Sides<Relative<Length>>) -> Size {
+fn grow(size: Size, padding: Sides<Rel<Abs>>) -> Size {
size.zip(padding.sum_by_axis())
.map(|(s, p)| (s + p.abs).safe_div(1.0 - p.rel.get()))
}
diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs
index 7d13163d..2e5cf2f9 100644
--- a/src/library/layout/page.rs
+++ b/src/library/layout/page.rs
@@ -11,17 +11,16 @@ pub struct PageNode(pub LayoutNode);
impl PageNode {
/// The unflipped width of the page.
#[property(resolve)]
- pub const WIDTH: Smart<RawLength> = Smart::Custom(Paper::A4.width().into());
+ pub const WIDTH: Smart<Length> = Smart::Custom(Paper::A4.width().into());
/// The unflipped height of the page.
#[property(resolve)]
- pub const HEIGHT: Smart<RawLength> = Smart::Custom(Paper::A4.height().into());
+ pub const HEIGHT: Smart<Length> = Smart::Custom(Paper::A4.height().into());
/// Whether the page is flipped into landscape orientation.
pub const FLIPPED: bool = false;
/// The page's margins.
#[property(fold)]
- pub const MARGINS: Sides<Option<Smart<Relative<RawLength>>>> =
- Sides::splat(Smart::Auto);
+ pub const MARGINS: Sides<Option<Smart<Rel<Length>>>> = Sides::splat(Smart::Auto);
/// How many columns the page has.
pub const COLUMNS: NonZeroUsize = NonZeroUsize::new(1).unwrap();
@@ -63,8 +62,8 @@ impl PageNode {
) -> SourceResult<Vec<Frame>> {
// 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());
- let height = styles.get(Self::HEIGHT).unwrap_or(Length::inf());
+ let width = styles.get(Self::WIDTH).unwrap_or(Abs::inf());
+ let height = styles.get(Self::HEIGHT).unwrap_or(Abs::inf());
let mut size = Size::new(width, height);
if styles.get(Self::FLIPPED) {
std::mem::swap(&mut size.x, &mut size.y);
@@ -76,7 +75,7 @@ impl PageNode {
}
// Determine the margins.
- let default = Relative::from(0.1190 * min);
+ let default = Rel::from(0.1190 * min);
let padding = styles.get(Self::MARGINS).map(|side| side.unwrap_or(default));
let mut child = self.0.clone();
@@ -96,7 +95,7 @@ impl PageNode {
}
// Layout the child.
- let regions = Regions::repeat(size, size, size.map(Length::is_finite));
+ let regions = Regions::repeat(size, size, size.map(Abs::is_finite));
let mut frames = child.layout(world, &regions, styles)?;
let header = styles.get(Self::HEADER);
@@ -127,7 +126,7 @@ impl PageNode {
(Role::Background, background, Point::zero(), size),
] {
if let Some(content) = marginal.resolve(world, page)? {
- let pod = Regions::one(area, area, Spec::splat(true));
+ let pod = Regions::one(area, area, Axes::splat(true));
let mut sub = content.layout(world, &pod, styles)?.remove(0);
sub.apply_role(role);
@@ -224,13 +223,13 @@ pub struct Paper {
impl Paper {
/// The width of the paper.
- pub fn width(self) -> Length {
- Length::mm(self.width)
+ pub fn width(self) -> Abs {
+ Abs::mm(self.width)
}
/// The height of the paper.
- pub fn height(self) -> Length {
- Length::mm(self.height)
+ pub fn height(self) -> Abs {
+ Abs::mm(self.height)
}
}
diff --git a/src/library/layout/place.rs b/src/library/layout/place.rs
index 01da62e5..8b68c087 100644
--- a/src/library/layout/place.rs
+++ b/src/library/layout/place.rs
@@ -8,12 +8,12 @@ pub struct PlaceNode(pub LayoutNode);
#[node]
impl PlaceNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
- let aligns = args.find()?.unwrap_or(Spec::with_x(Some(RawAlign::Start)));
+ let aligns = args.find()?.unwrap_or(Axes::with_x(Some(RawAlign::Start)));
let dx = args.named("dx")?.unwrap_or_default();
let dy = args.named("dy")?.unwrap_or_default();
let body: LayoutNode = args.expect("body")?;
Ok(Content::block(Self(
- body.moved(Spec::new(dx, dy)).aligned(aligns),
+ body.moved(Axes::new(dx, dy)).aligned(aligns),
)))
}
}
@@ -30,7 +30,7 @@ impl Layout for PlaceNode {
// The pod is the base area of the region because for absolute
// placement we don't really care about the already used area.
let pod = {
- let finite = regions.base.map(Length::is_finite);
+ let finite = regions.base.map(Abs::is_finite);
let expand = finite & (regions.expand | out_of_flow);
Regions::one(regions.base, regions.base, expand)
};
diff --git a/src/library/layout/spacing.rs b/src/library/layout/spacing.rs
index 0c5cbb92..28e52d73 100644
--- a/src/library/layout/spacing.rs
+++ b/src/library/layout/spacing.rs
@@ -31,10 +31,10 @@ impl VNode {
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Spacing {
/// Spacing specified in absolute terms and relative to the parent's size.
- Relative(Relative<RawLength>),
+ Relative(Rel<Length>),
/// Spacing specified as a fraction of the remaining free space in the
/// parent.
- Fractional(Fraction),
+ Fractional(Fr),
}
impl Spacing {
@@ -44,9 +44,9 @@ impl Spacing {
}
}
-impl From<Length> for Spacing {
- fn from(length: Length) -> Self {
- Self::Relative(length.into())
+impl From<Abs> for Spacing {
+ fn from(abs: Abs) -> Self {
+ Self::Relative(abs.into())
}
}
@@ -71,12 +71,12 @@ castable! {
/// Spacing around and between block-level nodes, relative to paragraph spacing.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub struct BlockSpacing(Relative<RawLength>);
+pub struct BlockSpacing(Rel<Length>);
-castable!(BlockSpacing: Relative<RawLength>);
+castable!(BlockSpacing: Rel<Length>);
impl Resolve for BlockSpacing {
- type Output = Length;
+ type Output = Abs;
fn resolve(self, styles: StyleChain) -> Self::Output {
let whole = styles.get(ParNode::SPACING);
diff --git a/src/library/layout/stack.rs b/src/library/layout/stack.rs
index b9a26642..b9663dd6 100644
--- a/src/library/layout/stack.rs
+++ b/src/library/layout/stack.rs
@@ -90,19 +90,19 @@ pub struct StackLayouter<'a> {
/// The stacking direction.
dir: Dir,
/// The axis of the stacking direction.
- axis: SpecAxis,
+ axis: Axis,
/// The regions to layout children into.
regions: Regions,
/// The inherited styles.
styles: StyleChain<'a>,
/// Whether the stack itself should expand to fill the region.
- expand: Spec<bool>,
+ expand: Axes<bool>,
/// The full size of the current region that was available at the start.
full: Size,
/// The generic size used by the frames for the current region.
- used: Gen<Length>,
+ used: Gen<Abs>,
/// The sum of fractions in the current region.
- fr: Fraction,
+ fr: Fr,
/// Already layouted items whose exact positions are not yet known due to
/// fractional spacing.
items: Vec<StackItem>,
@@ -113,9 +113,9 @@ pub struct StackLayouter<'a> {
/// A prepared item in a stack layout.
enum StackItem {
/// Absolute spacing between other items.
- Absolute(Length),
+ Absolute(Abs),
/// Fractional spacing between other items.
- Fractional(Fraction),
+ Fractional(Fr),
/// A frame for a layouted child node.
Frame(Frame, Align),
}
@@ -139,7 +139,7 @@ impl<'a> StackLayouter<'a> {
expand,
full,
used: Gen::zero(),
- fr: Fraction::zero(),
+ fr: Fr::zero(),
items: vec![],
finished: vec![],
}
@@ -200,7 +200,12 @@ impl<'a> StackLayouter<'a> {
frame.apply_role(Role::GenericBlock);
// Grow our size, shrink the region and save the frame for later.
- let size = frame.size().to_gen(self.axis);
+ let size = frame.size();
+ let size = match self.axis {
+ Axis::X => Gen::new(size.y, size.x),
+ Axis::Y => Gen::new(size.x, size.y),
+ };
+
self.used.main += size.main;
self.used.cross.set_max(size.cross);
*self.regions.first.get_mut(self.axis) -= size.main;
@@ -218,7 +223,7 @@ impl<'a> StackLayouter<'a> {
pub fn finish_region(&mut self) {
// Determine the size of the stack in this region dependening on whether
// the region expands.
- let used = self.used.to_spec(self.axis);
+ let used = self.used.to_axes(self.axis);
let mut size = self.expand.select(self.full, used);
// Expand fully if there are fr spacings.
@@ -230,7 +235,7 @@ impl<'a> StackLayouter<'a> {
}
let mut output = Frame::new(size);
- let mut cursor = Length::zero();
+ let mut cursor = Abs::zero();
let mut ruler: Align = self.dir.start().into();
// Place all frames.
@@ -255,7 +260,7 @@ impl<'a> StackLayouter<'a> {
self.used.main - child - cursor
};
- let pos = Gen::new(Length::zero(), block).to_point(self.axis);
+ let pos = Gen::new(Abs::zero(), block).to_point(self.axis);
cursor += child;
output.push_frame(pos, frame);
}
@@ -266,7 +271,7 @@ impl<'a> StackLayouter<'a> {
self.regions.next();
self.full = self.regions.first;
self.used = Gen::zero();
- self.fr = Fraction::zero();
+ self.fr = Fr::zero();
self.finished.push(output);
}
@@ -276,3 +281,39 @@ impl<'a> StackLayouter<'a> {
self.finished
}
}
+
+/// A container with a main and cross component.
+#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
+pub struct Gen<T> {
+ /// The main component.
+ pub cross: T,
+ /// The cross component.
+ pub main: T,
+}
+
+impl<T> Gen<T> {
+ /// Create a new instance from the two components.
+ pub const fn new(cross: T, main: T) -> Self {
+ Self { cross, main }
+ }
+
+ /// Convert to the specific representation, given the current main axis.
+ pub fn to_axes(self, main: Axis) -> Axes<T> {
+ match main {
+ Axis::X => Axes::new(self.main, self.cross),
+ Axis::Y => Axes::new(self.cross, self.main),
+ }
+ }
+}
+
+impl Gen<Abs> {
+ /// The zero value.
+ pub fn zero() -> Self {
+ Self { cross: Abs::zero(), main: Abs::zero() }
+ }
+
+ /// Convert to a point.
+ pub fn to_point(self, main: Axis) -> Point {
+ self.to_axes(main).to_point()
+ }
+}
diff --git a/src/library/layout/transform.rs b/src/library/layout/transform.rs
index b110f343..ff42744a 100644
--- a/src/library/layout/transform.rs
+++ b/src/library/layout/transform.rs
@@ -5,7 +5,7 @@ use crate::library::prelude::*;
#[derive(Debug, Hash)]
pub struct MoveNode {
/// The offset by which to move the node.
- pub delta: Spec<Relative<RawLength>>,
+ pub delta: Axes<Rel<Length>>,
/// The node whose contents should be moved.
pub child: LayoutNode,
}
@@ -16,7 +16,7 @@ impl MoveNode {
let dx = args.named("dx")?.unwrap_or_default();
let dy = args.named("dy")?.unwrap_or_default();
Ok(Content::inline(Self {
- delta: Spec::new(dx, dy),
+ delta: Axes::new(dx, dy),
child: args.expect("body")?,
}))
}
@@ -60,7 +60,7 @@ pub type ScaleNode = TransformNode<SCALE>;
impl<const T: TransformKind> TransformNode<T> {
/// The origin of the transformation.
#[property(resolve)]
- pub const ORIGIN: Spec<Option<RawAlign>> = Spec::default();
+ pub const ORIGIN: Axes<Option<RawAlign>> = Axes::default();
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
let transform = match T {
@@ -94,7 +94,7 @@ impl<const T: TransformKind> Layout for TransformNode<T> {
let mut frames = self.child.layout(world, regions, styles)?;
for frame in &mut frames {
- let Spec { x, y } = origin.zip(frame.size()).map(|(o, s)| o.position(s));
+ let Axes { x, y } = origin.zip(frame.size()).map(|(o, s)| o.position(s));
let transform = Transform::translate(x, y)
.pre_concat(self.transform)
.pre_concat(Transform::translate(-x, -y));
diff --git a/src/library/math/mod.rs b/src/library/math/mod.rs
index 7d0fecb4..df00cb71 100644
--- a/src/library/math/mod.rs
+++ b/src/library/math/mod.rs
@@ -92,7 +92,7 @@ impl Show for MathNode {
Ok(if self.display() {
Content::block(
LayoutNode::new(self.clone())
- .aligned(Spec::with_x(Some(Align::Center.into()))),
+ .aligned(Axes::with_x(Some(Align::Center.into()))),
)
} else {
Content::inline(self.clone())
@@ -171,9 +171,9 @@ fn layout_tex(
// Determine the metrics.
let (x0, y0, x1, y1) = renderer.size(&layout);
- let width = Length::pt(x1 - x0);
- let mut top = Length::pt(y1);
- let mut bottom = Length::pt(-y0);
+ let width = Abs::pt(x1 - x0);
+ let mut top = Abs::pt(y1);
+ let mut bottom = Abs::pt(-y0);
if style != Style::Display {
let metrics = font.metrics();
top = styles.get(TextNode::TOP_EDGE).resolve(styles, metrics);
@@ -204,7 +204,7 @@ fn layout_tex(
/// A ReX rendering backend that renders into a frame.
struct FrameBackend {
frame: Frame,
- baseline: Length,
+ baseline: Abs,
font: Font,
fill: Paint,
lang: Lang,
@@ -222,7 +222,7 @@ impl FrameBackend {
/// Convert a cursor to a point.
fn transform(&self, cursor: Cursor) -> Point {
- Point::new(Length::pt(cursor.x), self.baseline + Length::pt(cursor.y))
+ Point::new(Abs::pt(cursor.x), self.baseline + Abs::pt(cursor.y))
}
}
@@ -232,7 +232,7 @@ impl Backend for FrameBackend {
self.transform(pos),
Element::Text(Text {
font: self.font.clone(),
- size: Length::pt(scale),
+ size: Abs::pt(scale),
fill: self.fill(),
lang: self.lang,
glyphs: vec![Glyph {
@@ -249,10 +249,7 @@ impl Backend for FrameBackend {
self.frame.push(
self.transform(pos),
Element::Shape(Shape {
- geometry: Geometry::Rect(Size::new(
- Length::pt(width),
- Length::pt(height),
- )),
+ geometry: Geometry::Rect(Size::new(Abs::pt(width), Abs::pt(height))),
fill: Some(self.fill()),
stroke: None,
}),
diff --git a/src/library/mod.rs b/src/library/mod.rs
index 1691c8c7..b5a0e8eb 100644
--- a/src/library/mod.rs
+++ b/src/library/mod.rs
@@ -218,17 +218,17 @@ impl StyleMapExt for StyleMap {
/// Additional methods for layout nodes.
pub trait LayoutNodeExt {
/// Set alignments for this node.
- fn aligned(self, aligns: Spec<Option<RawAlign>>) -> Self;
+ fn aligned(self, aligns: Axes<Option<RawAlign>>) -> Self;
/// Pad this node at the sides.
- fn padded(self, padding: Sides<Relative<RawLength>>) -> Self;
+ fn padded(self, padding: Sides<Rel<Length>>) -> Self;
/// Transform this node's contents without affecting layout.
- fn moved(self, delta: Spec<Relative<RawLength>>) -> Self;
+ fn moved(self, delta: Axes<Rel<Length>>) -> Self;
}
impl LayoutNodeExt for LayoutNode {
- fn aligned(self, aligns: Spec<Option<RawAlign>>) -> Self {
+ fn aligned(self, aligns: Axes<Option<RawAlign>>) -> Self {
if aligns.any(Option::is_some) {
layout::AlignNode { aligns, child: self }.pack()
} else {
@@ -236,7 +236,7 @@ impl LayoutNodeExt for LayoutNode {
}
}
- fn padded(self, padding: Sides<Relative<RawLength>>) -> Self {
+ fn padded(self, padding: Sides<Rel<Length>>) -> Self {
if !padding.left.is_zero()
|| !padding.top.is_zero()
|| !padding.right.is_zero()
@@ -248,7 +248,7 @@ impl LayoutNodeExt for LayoutNode {
}
}
- fn moved(self, delta: Spec<Relative<RawLength>>) -> Self {
+ fn moved(self, delta: Axes<Rel<Length>>) -> Self {
if delta.any(|r| !r.is_zero()) {
layout::MoveNode { delta, child: self }.pack()
} else {
diff --git a/src/library/prelude.rs b/src/library/prelude.rs
index 1d98e2a9..c5a6bc8e 100644
--- a/src/library/prelude.rs
+++ b/src/library/prelude.rs
@@ -16,12 +16,9 @@ pub use crate::diag::{
pub use crate::frame::*;
pub use crate::geom::*;
pub use crate::model::{
- Arg, Args, Array, Cast, Dict, Dynamic, Func, Node, RawAlign, RawLength, RawStroke,
- Scope, Smart, Str, Value, Vm,
-};
-pub use crate::model::{
- Content, Fold, Key, Layout, LayoutNode, Regions, Resolve, Selector, Show, ShowNode,
- StyleChain, StyleMap, StyleVec,
+ Arg, Args, Array, Cast, Content, Dict, Dynamic, Fold, Func, Key, Layout, LayoutNode,
+ Node, RawAlign, RawStroke, Regions, Resolve, Scope, Selector, Show, ShowNode, Smart,
+ Str, StyleChain, StyleMap, StyleVec, Value, Vm,
};
pub use crate::syntax::{Span, Spanned};
pub use crate::util::EcoString;
diff --git a/src/library/structure/list.rs b/src/library/structure/list.rs
index 9d78238d..4ccdbc54 100644
--- a/src/library/structure/list.rs
+++ b/src/library/structure/list.rs
@@ -29,10 +29,10 @@ impl<const L: ListKind> ListNode<L> {
pub const LABEL: Label = Label::Default;
/// The indentation of each item's label.
#[property(resolve)]
- pub const INDENT: RawLength = RawLength::zero();
+ pub const INDENT: Length = Length::zero();
/// The space between the label and the body of each item.
#[property(resolve)]
- pub const BODY_INDENT: RawLength = Em::new(match L {
+ pub const BODY_INDENT: Length = Em::new(match L {
LIST | ENUM => 0.5,
DESC | _ => 1.0,
})
@@ -159,13 +159,13 @@ impl<const L: ListKind> Show for ListNode<L> {
}
Ok(Content::block(GridNode {
- tracks: Spec::with_x(vec![
+ tracks: Axes::with_x(vec![
TrackSizing::Relative(indent.into()),
TrackSizing::Auto,
TrackSizing::Relative(body_indent.into()),
TrackSizing::Auto,
]),
- gutter: Spec::with_y(vec![TrackSizing::Relative(gutter.into())]),
+ gutter: Axes::with_y(vec![TrackSizing::Relative(gutter.into())]),
cells,
}))
}
diff --git a/src/library/structure/table.rs b/src/library/structure/table.rs
index 9f89cd2b..7994f196 100644
--- a/src/library/structure/table.rs
+++ b/src/library/structure/table.rs
@@ -5,9 +5,9 @@ use crate::library::prelude::*;
#[derive(Debug, Hash)]
pub struct TableNode {
/// Defines sizing for content rows and columns.
- pub tracks: Spec<Vec<TrackSizing>>,
+ pub tracks: Axes<Vec<TrackSizing>>,
/// Defines sizing of gutter rows and columns between content.
- pub gutter: Spec<Vec<TrackSizing>>,
+ pub gutter: Axes<Vec<TrackSizing>>,
/// The nodes to be arranged in the table.
pub cells: Vec<Content>,
}
@@ -21,7 +21,7 @@ impl TableNode {
#[property(resolve, fold)]
pub const STROKE: Option<RawStroke> = Some(RawStroke::default());
/// How much to pad the cells's content.
- pub const PADDING: Relative<RawLength> = Length::pt(5.0).into();
+ pub const PADDING: Rel<Length> = Abs::pt(5.0).into();
/// The spacing above the table.
#[property(resolve, shorthand(around))]
@@ -37,8 +37,8 @@ impl TableNode {
let column_gutter = args.named("column-gutter")?;
let row_gutter = args.named("row-gutter")?;
Ok(Content::show(Self {
- tracks: Spec::new(columns, rows),
- gutter: Spec::new(
+ tracks: Axes::new(columns, rows),
+ gutter: Axes::new(
column_gutter.unwrap_or_else(|| base_gutter.clone()),
row_gutter.unwrap_or(base_gutter),
),
diff --git a/src/library/text/deco.rs b/src/library/text/deco.rs
index 1242488b..6a4905c8 100644
--- a/src/library/text/deco.rs
+++ b/src/library/text/deco.rs
@@ -26,10 +26,10 @@ impl<const L: DecoLine> DecoNode<L> {
/// Position of the line relative to the baseline, read from the font tables
/// if `auto`.
#[property(resolve)]
- pub const OFFSET: Smart<RawLength> = Smart::Auto;
+ pub const OFFSET: Smart<Length> = Smart::Auto;
/// Amount that the line will be longer or shorter than its associated text.
#[property(resolve)]
- pub const EXTENT: RawLength = RawLength::zero();
+ pub const EXTENT: Length = Length::zero();
/// Whether the line skips sections in which it would collide
/// with the glyphs. Does not apply to strikethrough.
pub const EVADE: bool = true;
@@ -69,9 +69,9 @@ impl<const L: DecoLine> Show for DecoNode<L> {
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Decoration {
pub line: DecoLine,
- pub stroke: RawStroke<Length>,
- pub offset: Smart<Length>,
- pub extent: Length,
+ pub stroke: RawStroke<Abs>,
+ pub offset: Smart<Abs>,
+ pub extent: Abs,
pub evade: bool,
}
@@ -92,9 +92,9 @@ pub fn decorate(
frame: &mut Frame,
deco: &Decoration,
text: &Text,
- shift: Length,
+ shift: Abs,
pos: Point,
- width: Length,
+ width: Abs,
) {
let font_metrics = text.font.metrics();
let metrics = match deco.line {
@@ -116,9 +116,9 @@ pub fn decorate(
let mut start = pos.x - deco.extent;
let end = pos.x + (width + 2.0 * deco.extent);
- let mut push_segment = |from: Length, to: Length| {
+ let mut push_segment = |from: Abs, to: Abs| {
let origin = Point::new(from, pos.y + offset);
- let target = Point::new(to - from, Length::zero());
+ let target = Point::new(to - from, Abs::zero());
if target.x >= min_width || !evade {
let shape = Geometry::Line(target).stroked(stroke);
@@ -161,7 +161,7 @@ pub fn decorate(
intersections.extend(
path.segments()
.flat_map(|seg| seg.intersect_line(line))
- .map(|is| Length::raw(line.eval(is.line_t).x)),
+ .map(|is| Abs::raw(line.eval(is.line_t).x)),
);
}
}
@@ -196,12 +196,12 @@ pub fn decorate(
struct BezPathBuilder {
path: BezPath,
units_per_em: f64,
- font_size: Length,
+ font_size: Abs,
x_offset: f64,
}
impl BezPathBuilder {
- fn new(units_per_em: f64, font_size: Length, x_offset: f64) -> Self {
+ fn new(units_per_em: f64, font_size: Abs, x_offset: f64) -> Self {
Self {
path: BezPath::new(),
units_per_em,
diff --git a/src/library/text/link.rs b/src/library/text/link.rs
index 78ae4d23..7c4a95ed 100644
--- a/src/library/text/link.rs
+++ b/src/library/text/link.rs
@@ -43,9 +43,9 @@ castable! {
Value::Str(string) => Self::Url(string.into()),
Value::Dict(dict) => {
let page = dict.get("page")?.clone().cast()?;
- let x: RawLength = dict.get("x")?.clone().cast()?;
- let y: RawLength = dict.get("y")?.clone().cast()?;
- Self::Internal(Location { page, pos: Point::new(x.length, y.length) })
+ let x: Length = dict.get("x")?.clone().cast()?;
+ let y: Length = dict.get("y")?.clone().cast()?;
+ Self::Internal(Location { page, pos: Point::new(x.abs, y.abs) })
},
}
diff --git a/src/library/text/mod.rs b/src/library/text/mod.rs
index 299357de..2d302b9a 100644
--- a/src/library/text/mod.rs
+++ b/src/library/text/mod.rs
@@ -48,19 +48,19 @@ impl TextNode {
/// The size of the glyphs.
#[property(shorthand, fold)]
- pub const SIZE: TextSize = Length::pt(11.0);
+ pub const SIZE: TextSize = Abs::pt(11.0);
/// The glyph fill color.
#[property(shorthand)]
pub const FILL: Paint = Color::BLACK.into();
/// The amount of space that should be added between characters.
#[property(resolve)]
- pub const TRACKING: RawLength = RawLength::zero();
+ pub const TRACKING: Length = Length::zero();
/// The width of spaces relative to the font's space width.
#[property(resolve)]
- pub const SPACING: Relative<RawLength> = Relative::one();
+ pub const SPACING: Rel<Length> = Rel::one();
/// The offset of the baseline.
#[property(resolve)]
- pub const BASELINE: RawLength = RawLength::zero();
+ pub const BASELINE: Length = Length::zero();
/// Whether certain glyphs can hang over into the margin.
pub const OVERHANG: bool = true;
/// The top end of the text bounding box.
@@ -243,17 +243,17 @@ castable! {
/// The size of text.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub struct TextSize(pub RawLength);
+pub struct TextSize(pub Length);
impl Fold for TextSize {
- type Output = Length;
+ type Output = Abs;
fn fold(self, outer: Self::Output) -> Self::Output {
- self.0.em.at(outer) + self.0.length
+ self.0.em.at(outer) + self.0.abs
}
}
-castable!(TextSize: RawLength);
+castable!(TextSize: Length);
/// Specifies the bottom or top edge of text.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
@@ -261,12 +261,12 @@ pub enum TextEdge {
/// An edge specified using one of the well-known font metrics.
Metric(VerticalFontMetric),
/// An edge specified as a length.
- Length(RawLength),
+ Length(Length),
}
impl TextEdge {
/// Resolve the value of the text edge given a font's metrics.
- pub fn resolve(self, styles: StyleChain, metrics: &FontMetrics) -> Length {
+ pub fn resolve(self, styles: StyleChain, metrics: &FontMetrics) -> Abs {
match self {
Self::Metric(metric) => metrics.vertical(metric).resolve(styles),
Self::Length(length) => length.resolve(styles),
@@ -310,8 +310,8 @@ castable! {
HorizontalDir,
Expected: "direction",
@dir: Dir => match dir.axis() {
- SpecAxis::Horizontal => Self(*dir),
- SpecAxis::Vertical => Err("must be horizontal")?,
+ Axis::X => Self(*dir),
+ Axis::Y => Err("must be horizontal")?,
},
}
diff --git a/src/library/text/par.rs b/src/library/text/par.rs
index 859a7c87..477bf97f 100644
--- a/src/library/text/par.rs
+++ b/src/library/text/par.rs
@@ -30,13 +30,13 @@ pub enum ParChild {
impl ParNode {
/// The spacing between lines.
#[property(resolve)]
- pub const LEADING: RawLength = Em::new(0.65).into();
+ pub const LEADING: Length = Em::new(0.65).into();
/// The extra spacing between paragraphs.
#[property(resolve)]
- pub const SPACING: RawLength = Em::new(1.2).into();
+ pub const SPACING: Length = Em::new(1.2).into();
/// The indent the first line of a consecutive paragraph should have.
#[property(resolve)]
- pub const INDENT: RawLength = RawLength::zero();
+ pub const INDENT: Length = Length::zero();
/// Whether to allow paragraph spacing when there is paragraph indent.
pub const SPACING_AND_INDENT: bool = false;
@@ -119,8 +119,8 @@ castable! {
HorizontalAlign,
Expected: "alignment",
@align: RawAlign => match align.axis() {
- SpecAxis::Horizontal => Self(*align),
- SpecAxis::Vertical => Err("must be horizontal")?,
+ Axis::X => Self(*align),
+ Axis::Y => Err("must be horizontal")?,
},
}
@@ -212,7 +212,7 @@ struct Preparation<'a> {
/// The text language if it's the same for all children.
lang: Option<Lang>,
/// The resolved leading between lines.
- leading: Length,
+ leading: Abs,
/// The paragraph's resolved alignment.
align: Align,
/// Whether to justify the paragraph.
@@ -292,9 +292,9 @@ enum Item<'a> {
/// A shaped text run with consistent style and direction.
Text(ShapedText<'a>),
/// Absolute spacing between other items.
- Absolute(Length),
+ Absolute(Abs),
/// Fractional spacing between other items.
- Fractional(Fraction),
+ Fractional(Fr),
/// A layouted child node.
Frame(Frame),
/// A repeating node that fills the remaining space.
@@ -320,12 +320,12 @@ impl<'a> Item<'a> {
}
/// The natural layouted width of the item.
- fn width(&self) -> Length {
+ fn width(&self) -> Abs {
match self {
Self::Text(shaped) => shaped.width,
Self::Absolute(v) => *v,
Self::Frame(frame) => frame.width(),
- Self::Fractional(_) | Self::Repeat(_, _) => Length::zero(),
+ Self::Fractional(_) | Self::Repeat(_, _) => Abs::zero(),
}
}
}
@@ -354,7 +354,7 @@ struct Line<'a> {
/// there is only one text item, this takes precedence over `first`.
last: Option<Item<'a>>,
/// The width of the line.
- width: Length,
+ width: Abs,
/// Whether the line should be justified.
justify: bool,
/// Whether the line ends with a hyphen or dash, either naturally or through
@@ -402,8 +402,8 @@ impl<'a> Line<'a> {
}
/// How much of the line is stretchable spaces.
- fn stretch(&self) -> Length {
- let mut stretch = Length::zero();
+ fn stretch(&self) -> Abs {
+ let mut stretch = Abs::zero();
for shaped in self.items().filter_map(Item::text) {
stretch += shaped.stretch();
}
@@ -411,11 +411,11 @@ impl<'a> Line<'a> {
}
/// The sum of fractions in the line.
- fn fr(&self) -> Fraction {
+ fn fr(&self) -> Fr {
self.items()
.filter_map(|item| match item {
Item::Fractional(fr) => Some(*fr),
- Item::Repeat(_, _) => Some(Fraction::one()),
+ Item::Repeat(_, _) => Some(Fr::one()),
_ => None,
})
.sum()
@@ -533,7 +533,7 @@ fn prepare<'a>(
items.push(Item::Repeat(repeat, styles));
} else {
let size = Size::new(regions.first.x, regions.base.y);
- let pod = Regions::one(size, regions.base, Spec::splat(false));
+ let pod = Regions::one(size, regions.base, Axes::splat(false));
let mut frame = node.layout(world, &pod, styles)?.remove(0);
frame.translate(Point::with_y(styles.get(TextNode::BASELINE)));
frame.apply_role(Role::GenericInline);
@@ -628,7 +628,7 @@ fn shared_get<'a, K: Key<'a>>(
fn linebreak<'a>(
p: &'a Preparation<'a>,
world: Tracked<dyn World>,
- width: Length,
+ width: Abs,
) -> Vec<Line<'a>> {
match p.styles.get(ParNode::LINEBREAKS) {
Linebreaks::Simple => linebreak_simple(p, world, width),
@@ -642,7 +642,7 @@ fn linebreak<'a>(
fn linebreak_simple<'a>(
p: &'a Preparation<'a>,
world: Tracked<dyn World>,
- width: Length,
+ width: Abs,
) -> Vec<Line<'a>> {
let mut lines = vec![];
let mut start = 0;
@@ -702,7 +702,7 @@ fn linebreak_simple<'a>(
fn linebreak_optimized<'a>(
p: &'a Preparation<'a>,
world: Tracked<dyn World>,
- width: Length,
+ width: Abs,
) -> Vec<Line<'a>> {
/// The cost of a line or paragraph layout.
type Cost = f64;
@@ -930,7 +930,7 @@ fn line<'a>(
first: None,
inner: &[],
last: None,
- width: Length::zero(),
+ width: Abs::zero(),
justify,
dash: false,
};
@@ -938,7 +938,7 @@ fn line<'a>(
// Slice out the relevant items.
let (expanded, mut inner) = p.slice(range.clone());
- let mut width = Length::zero();
+ let mut width = Abs::zero();
// Reshape the last item if it's split in half or hyphenated.
let mut last = None;
@@ -1075,10 +1075,10 @@ fn commit(
world: Tracked<dyn World>,
line: &Line,
regions: &Regions,
- width: Length,
+ width: Abs,
) -> SourceResult<Frame> {
let mut remaining = width - line.width;
- let mut offset = Length::zero();
+ let mut offset = Abs::zero();
// Reorder the line from logical to visual order.
let reordered = reorder(line);
@@ -1112,22 +1112,22 @@ fn commit(
// Determine how much to justify each space.
let fr = line.fr();
- let mut justification = Length::zero();
- if remaining < Length::zero() || (line.justify && fr.is_zero()) {
+ let mut justification = Abs::zero();
+ if remaining < Abs::zero() || (line.justify && fr.is_zero()) {
let justifiables = line.justifiables();
if justifiables > 0 {
justification = remaining / justifiables as f64;
- remaining = Length::zero();
+ remaining = Abs::zero();
}
}
- let mut top = Length::zero();
- let mut bottom = Length::zero();
+ let mut top = Abs::zero();
+ let mut bottom = Abs::zero();
// Build the frames and determine the height and baseline.
let mut frames = vec![];
for item in reordered {
- let mut push = |offset: &mut Length, frame: Frame| {
+ let mut push = |offset: &mut Abs, frame: Frame| {
let width = frame.width();
top.set_max(frame.baseline());
bottom.set_max(frame.size().y - frame.baseline());
@@ -1151,9 +1151,9 @@ fn commit(
}
Item::Repeat(node, styles) => {
let before = offset;
- let fill = Fraction::one().share(fr, remaining);
+ let fill = Fr::one().share(fr, remaining);
let size = Size::new(fill, regions.base.y);
- let pod = Regions::one(size, regions.base, Spec::new(false, false));
+ let pod = Regions::one(size, regions.base, Axes::new(false, false));
let frame = node.layout(world, &pod, *styles)?.remove(0);
let width = frame.width();
let count = (fill / width).floor();
@@ -1162,7 +1162,7 @@ fn commit(
if count == 1.0 {
offset += p.align.position(remaining);
}
- if width > Length::zero() {
+ if width > Abs::zero() {
for _ in 0 .. (count as usize).min(1000) {
push(&mut offset, frame.clone());
offset += apart;
@@ -1175,7 +1175,7 @@ fn commit(
// Remaining space is distributed now.
if !fr.is_zero() {
- remaining = Length::zero();
+ remaining = Abs::zero();
}
let size = Size::new(width, top + bottom);
diff --git a/src/library/text/shaping.rs b/src/library/text/shaping.rs
index 487b9090..9ac3db1c 100644
--- a/src/library/text/shaping.rs
+++ b/src/library/text/shaping.rs
@@ -23,9 +23,9 @@ pub struct ShapedText<'a> {
/// The font variant.
pub variant: FontVariant,
/// The font size.
- pub size: Length,
+ pub size: Abs,
/// The width of the text's bounding box.
- pub width: Length,
+ pub width: Abs,
/// The shaped glyphs.
pub glyphs: Cow<'a, [ShapedGlyph]>,
}
@@ -80,11 +80,11 @@ impl<'a> ShapedText<'a> {
///
/// The `justification` defines how much extra advance width each
/// [justifiable glyph](ShapedGlyph::is_justifiable) will get.
- pub fn build(&self, world: Tracked<dyn World>, justification: Length) -> Frame {
+ pub fn build(&self, world: Tracked<dyn World>, justification: Abs) -> Frame {
let (top, bottom) = self.measure(world);
let size = Size::new(self.width, top + bottom);
- let mut offset = Length::zero();
+ let mut offset = Abs::zero();
let mut frame = Frame::new(size);
frame.set_baseline(top);
@@ -144,9 +144,9 @@ impl<'a> ShapedText<'a> {
}
/// Measure the top and bottom extent of this text.
- fn measure(&self, world: Tracked<dyn World>) -> (Length, Length) {
- let mut top = Length::zero();
- let mut bottom = Length::zero();
+ fn measure(&self, world: Tracked<dyn World>) -> (Abs, Abs) {
+ let mut top = Abs::zero();
+ let mut bottom = Abs::zero();
let top_edge = self.styles.get(TextNode::TOP_EDGE);
let bottom_edge = self.styles.get(TextNode::BOTTOM_EDGE);
@@ -186,7 +186,7 @@ impl<'a> ShapedText<'a> {
}
/// The width of the spaces in the text.
- pub fn stretch(&self) -> Length {
+ pub fn stretch(&self) -> Abs {
self.glyphs
.iter()
.filter(|g| g.is_justifiable())
@@ -310,7 +310,7 @@ struct ShapingContext<'a> {
glyphs: Vec<ShapedGlyph>,
used: Vec<Font>,
styles: StyleChain<'a>,
- size: Length,
+ size: Abs,
variant: FontVariant,
tags: Vec<rustybuzz::Feature>,
fallback: bool,
diff --git a/src/library/text/shift.rs b/src/library/text/shift.rs
index 6a5415e8..adad5dc0 100644
--- a/src/library/text/shift.rs
+++ b/src/library/text/shift.rs
@@ -23,7 +23,7 @@ impl<const S: ScriptKind> ShiftNode<S> {
/// font.
pub const TYPOGRAPHIC: bool = true;
/// The baseline shift for synthetic sub- and superscripts.
- pub const BASELINE: RawLength =
+ pub const BASELINE: Length =
Em::new(if S == SUPERSCRIPT { -0.5 } else { 0.2 }).into();
/// The font size for synthetic sub- and superscripts.
pub const SIZE: TextSize = TextSize(Em::new(0.6).into());