diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-10-28 16:43:38 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-10-28 16:43:38 +0200 |
| commit | 95e9134a3c7d7a14d8c8928413fdffc665671895 (patch) | |
| tree | 822b5f6c2d23aba33cfe4d199405e493e37c3d70 /src/library | |
| parent | 66030ae5d73d85a0463562230b87f8ec7554c746 (diff) | |
Refactor `geom` module
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/graphics/image.rs | 4 | ||||
| -rw-r--r-- | src/library/graphics/line.rs | 17 | ||||
| -rw-r--r-- | src/library/graphics/shape.rs | 29 | ||||
| -rw-r--r-- | src/library/layout/align.rs | 10 | ||||
| -rw-r--r-- | src/library/layout/columns.rs | 8 | ||||
| -rw-r--r-- | src/library/layout/container.rs | 2 | ||||
| -rw-r--r-- | src/library/layout/flow.rs | 18 | ||||
| -rw-r--r-- | src/library/layout/grid.rs | 77 | ||||
| -rw-r--r-- | src/library/layout/pad.rs | 6 | ||||
| -rw-r--r-- | src/library/layout/page.rs | 25 | ||||
| -rw-r--r-- | src/library/layout/place.rs | 6 | ||||
| -rw-r--r-- | src/library/layout/spacing.rs | 16 | ||||
| -rw-r--r-- | src/library/layout/stack.rs | 65 | ||||
| -rw-r--r-- | src/library/layout/transform.rs | 8 | ||||
| -rw-r--r-- | src/library/math/mod.rs | 19 | ||||
| -rw-r--r-- | src/library/mod.rs | 12 | ||||
| -rw-r--r-- | src/library/prelude.rs | 9 | ||||
| -rw-r--r-- | src/library/structure/list.rs | 8 | ||||
| -rw-r--r-- | src/library/structure/table.rs | 10 | ||||
| -rw-r--r-- | src/library/text/deco.rs | 24 | ||||
| -rw-r--r-- | src/library/text/link.rs | 6 | ||||
| -rw-r--r-- | src/library/text/mod.rs | 24 | ||||
| -rw-r--r-- | src/library/text/par.rs | 66 | ||||
| -rw-r--r-- | src/library/text/shaping.rs | 18 | ||||
| -rw-r--r-- | src/library/text/shift.rs | 2 |
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, ®ions, 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()); |
