[librsvg: 9/10] Make Length<O> the one and only length type



commit 93cb8e78581a3fd7aa45aeb07ec6b9204e5fe89c
Author: Federico Mena Quintero <federico gnome org>
Date:   Tue Nov 12 21:33:13 2019 -0600

    Make Length<O> the one and only length type
    
    This is Length<O: Orientation>, and we have three implementations of
    Orientation, so one can declare things like
    
      let width:  Length<Horizontal> = ...;
      let height: Length<Vertical>   = ...;
      let radius: Length<Both>       = ...;
    
    This removes LengthTrait.
    
    This removes Length.length() and .unit() and turns them into plain
    fields.
    
    We now have a public RsvgLength with a conversion from Length.

 rsvg_internals/src/drawing_ctx.rs    |   2 +-
 rsvg_internals/src/filter.rs         |  42 +--
 rsvg_internals/src/filters/bounds.rs |  18 +-
 rsvg_internals/src/filters/mod.rs    |  26 +-
 rsvg_internals/src/font_props.rs     |  44 +--
 rsvg_internals/src/gradient.rs       |  74 ++---
 rsvg_internals/src/image.rs          |  14 +-
 rsvg_internals/src/length.rs         | 516 ++++++++++++++---------------------
 rsvg_internals/src/marker.rs         |  18 +-
 rsvg_internals/src/mask.rs           |  22 +-
 rsvg_internals/src/pattern.rs        |  20 +-
 rsvg_internals/src/property_defs.rs  |  30 +-
 rsvg_internals/src/shapes.rs         |  48 ++--
 rsvg_internals/src/structure.rs      |  54 ++--
 rsvg_internals/src/text.rs           |  52 ++--
 15 files changed, 439 insertions(+), 541 deletions(-)
---
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index 834c3424..95661d52 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -13,7 +13,7 @@ use crate::dpi::Dpi;
 use crate::error::{AcquireError, RenderingError};
 use crate::filters;
 use crate::gradient::{LinearGradient, RadialGradient};
-use crate::length::{Dasharray, LengthTrait};
+use crate::length::Dasharray;
 use crate::limits;
 use crate::mask::Mask;
 use crate::node::{CascadedValues, NodeDraw, NodeType, RsvgNode};
diff --git a/rsvg_internals/src/filter.rs b/rsvg_internals/src/filter.rs
index e5791159..a1494fe4 100644
--- a/rsvg_internals/src/filter.rs
+++ b/rsvg_internals/src/filter.rs
@@ -5,7 +5,7 @@ use crate::bbox::BoundingBox;
 use crate::coord_units::CoordUnits;
 use crate::drawing_ctx::DrawingCtx;
 use crate::error::ValueErrorKind;
-use crate::length::{LengthHorizontal, LengthUnit, LengthTrait, LengthVertical};
+use crate::length::*;
 use crate::node::{NodeResult, NodeTrait, RsvgNode};
 use crate::parsers::{Parse, ParseError, ParseValue};
 use crate::properties::ComputedValues;
@@ -13,10 +13,10 @@ use crate::property_bag::PropertyBag;
 
 /// The <filter> node.
 pub struct Filter {
-    x: LengthHorizontal,
-    y: LengthVertical,
-    width: LengthHorizontal,
-    height: LengthVertical,
+    x: Length<Horizontal>,
+    y: Length<Vertical>,
+    width: Length<Horizontal>,
+    height: Length<Vertical>,
     filterunits: CoordUnits,
     primitiveunits: CoordUnits,
 }
@@ -25,10 +25,10 @@ impl Default for Filter {
     /// Constructs a new `Filter` with default properties.
     fn default() -> Self {
         Self {
-            x: LengthHorizontal::parse_str("-10%").unwrap(),
-            y: LengthVertical::parse_str("-10%").unwrap(),
-            width: LengthHorizontal::parse_str("120%").unwrap(),
-            height: LengthVertical::parse_str("120%").unwrap(),
+            x: Length::<Horizontal>::parse_str("-10%").unwrap(),
+            y: Length::<Vertical>::parse_str("-10%").unwrap(),
+            width: Length::<Horizontal>::parse_str("120%").unwrap(),
+            height: Length::<Vertical>::parse_str("120%").unwrap(),
             filterunits: CoordUnits::ObjectBoundingBox,
             primitiveunits: CoordUnits::UserSpaceOnUse,
         }
@@ -77,10 +77,10 @@ impl Filter {
         // referencing node. No units are allowed (it's checked during attribute parsing).
         let rect = if self.filterunits == CoordUnits::ObjectBoundingBox {
             cairo::Rectangle {
-                x: self.x.length(),
-                y: self.y.length(),
-                width: self.width.length(),
-                height: self.height.length(),
+                x: self.x.length,
+                y: self.y.length,
+                width: self.width.length,
+                height: self.height.length,
             }
         } else {
             cairo::Rectangle {
@@ -124,12 +124,12 @@ impl NodeTrait for Filter {
         // With ObjectBoundingBox, only fractions and percents are allowed.
         let no_units_allowed = self.filterunits == CoordUnits::ObjectBoundingBox;
 
-        let check_units_horizontal = |length: LengthHorizontal| {
+        let check_units_horizontal = |length: Length<Horizontal>| {
             if !no_units_allowed {
                 return Ok(length);
             }
 
-            match length.unit() {
+            match length.unit {
                 LengthUnit::Px | LengthUnit::Percent => Ok(length),
                 _ => Err(ValueErrorKind::Parse(ParseError::new(
                     "unit identifiers are not allowed with filterUnits set to objectBoundingBox",
@@ -137,12 +137,12 @@ impl NodeTrait for Filter {
             }
         };
 
-        let check_units_vertical = |length: LengthVertical| {
+        let check_units_vertical = |length: Length<Vertical>| {
             if !no_units_allowed {
                 return Ok(length);
             }
 
-            match length.unit() {
+            match length.unit {
                 LengthUnit::Px | LengthUnit::Percent => Ok(length),
                 _ => Err(ValueErrorKind::Parse(ParseError::new(
                     "unit identifiers are not allowed with filterUnits set to objectBoundingBox",
@@ -150,12 +150,12 @@ impl NodeTrait for Filter {
             }
         };
 
-        let check_units_horizontal_and_ensure_nonnegative = |length: LengthHorizontal| {
-            check_units_horizontal(length).and_then(LengthHorizontal::check_nonnegative)
+        let check_units_horizontal_and_ensure_nonnegative = |length: Length<Horizontal>| {
+            check_units_horizontal(length).and_then(Length::<Horizontal>::check_nonnegative)
         };
 
-        let check_units_vertical_and_ensure_nonnegative = |length: LengthVertical| {
-            check_units_vertical(length).and_then(LengthVertical::check_nonnegative)
+        let check_units_vertical_and_ensure_nonnegative = |length: Length<Vertical>| {
+            check_units_vertical(length).and_then(Length::<Vertical>::check_nonnegative)
         };
 
         // Parse the rest of the attributes.
diff --git a/rsvg_internals/src/filters/bounds.rs b/rsvg_internals/src/filters/bounds.rs
index ef137ee2..1fc8cc1f 100644
--- a/rsvg_internals/src/filters/bounds.rs
+++ b/rsvg_internals/src/filters/bounds.rs
@@ -3,7 +3,7 @@ use cairo;
 
 use crate::bbox::BoundingBox;
 use crate::drawing_ctx::DrawingCtx;
-use crate::length::{LengthHorizontal, LengthTrait, LengthVertical};
+use crate::length::*;
 use crate::rect::IRect;
 
 use super::context::{FilterContext, FilterInput, FilterOutput};
@@ -21,10 +21,10 @@ pub struct BoundsBuilder<'a> {
     standard_input_was_referenced: bool,
 
     /// Filter primitive properties.
-    x: Option<LengthHorizontal>,
-    y: Option<LengthVertical>,
-    width: Option<LengthHorizontal>,
-    height: Option<LengthVertical>,
+    x: Option<Length<Horizontal>>,
+    y: Option<Length<Vertical>>,
+    width: Option<Length<Horizontal>>,
+    height: Option<Length<Vertical>>,
 }
 
 impl<'a> BoundsBuilder<'a> {
@@ -32,10 +32,10 @@ impl<'a> BoundsBuilder<'a> {
     #[inline]
     pub fn new(
         ctx: &'a FilterContext,
-        x: Option<LengthHorizontal>,
-        y: Option<LengthVertical>,
-        width: Option<LengthHorizontal>,
-        height: Option<LengthVertical>,
+        x: Option<Length<Horizontal>>,
+        y: Option<Length<Vertical>>,
+        width: Option<Length<Horizontal>>,
+        height: Option<Length<Vertical>>,
     ) -> Self {
         Self {
             ctx,
diff --git a/rsvg_internals/src/filters/mod.rs b/rsvg_internals/src/filters/mod.rs
index 41a60897..11ab0c7c 100644
--- a/rsvg_internals/src/filters/mod.rs
+++ b/rsvg_internals/src/filters/mod.rs
@@ -9,7 +9,7 @@ use crate::coord_units::CoordUnits;
 use crate::drawing_ctx::DrawingCtx;
 use crate::error::{RenderingError, ValueErrorKind};
 use crate::filter::Filter;
-use crate::length::{LengthHorizontal, LengthUnit, LengthTrait, LengthVertical};
+use crate::length::*;
 use crate::node::{CascadedValues, NodeResult, NodeTrait, NodeType, RsvgNode};
 use crate::parsers::{ParseError, ParseValue};
 use crate::properties::ComputedValues;
@@ -76,10 +76,10 @@ pub mod turbulence;
 
 /// The base filter primitive node containing common properties.
 struct Primitive {
-    x: Option<LengthHorizontal>,
-    y: Option<LengthVertical>,
-    width: Option<LengthHorizontal>,
-    height: Option<LengthVertical>,
+    x: Option<Length<Horizontal>>,
+    y: Option<Length<Vertical>>,
+    width: Option<Length<Horizontal>>,
+    height: Option<Length<Vertical>>,
     result: Option<String>,
 }
 
@@ -124,12 +124,12 @@ impl NodeTrait for Primitive {
 
         let no_units_allowed = primitiveunits == CoordUnits::ObjectBoundingBox;
 
-        let check_units_horizontal = |length: LengthHorizontal| {
+        let check_units_horizontal = |length: Length<Horizontal>| {
             if !no_units_allowed {
                 return Ok(length);
             }
 
-            match length.unit() {
+            match length.unit {
                 LengthUnit::Px | LengthUnit::Percent => Ok(length),
                 _ => Err(ValueErrorKind::Parse(ParseError::new(
                     "unit identifiers are not allowed with primitiveUnits set to objectBoundingBox",
@@ -137,12 +137,12 @@ impl NodeTrait for Primitive {
             }
         };
 
-        let check_units_vertical = |length: LengthVertical| {
+        let check_units_vertical = |length: Length<Vertical>| {
             if !no_units_allowed {
                 return Ok(length);
             }
 
-            match length.unit() {
+            match length.unit {
                 LengthUnit::Px | LengthUnit::Percent => Ok(length),
                 _ => Err(ValueErrorKind::Parse(ParseError::new(
                     "unit identifiers are not allowed with primitiveUnits set to objectBoundingBox",
@@ -150,12 +150,12 @@ impl NodeTrait for Primitive {
             }
         };
 
-        let check_units_horizontal_and_ensure_nonnegative = |length: LengthHorizontal| {
-            check_units_horizontal(length).and_then(LengthHorizontal::check_nonnegative)
+        let check_units_horizontal_and_ensure_nonnegative = |length: Length<Horizontal>| {
+            check_units_horizontal(length).and_then(Length::<Horizontal>::check_nonnegative)
         };
 
-        let check_units_vertical_and_ensure_nonnegative = |length: LengthVertical| {
-            check_units_vertical(length).and_then(LengthVertical::check_nonnegative)
+        let check_units_vertical_and_ensure_nonnegative = |length: Length<Vertical>| {
+            check_units_vertical(length).and_then(Length::<Vertical>::check_nonnegative)
         };
 
         for (attr, value) in pbag.iter() {
diff --git a/rsvg_internals/src/font_props.rs b/rsvg_internals/src/font_props.rs
index a8bc4e08..616c9499 100644
--- a/rsvg_internals/src/font_props.rs
+++ b/rsvg_internals/src/font_props.rs
@@ -2,7 +2,7 @@ use cssparser::{BasicParseError, Parser, Token};
 
 use crate::drawing_ctx::ViewParams;
 use crate::error::*;
-use crate::length::{LengthBoth, LengthHorizontal, LengthTrait, LengthUnit, POINTS_PER_INCH};
+use crate::length::*;
 use crate::parsers::{Parse, ParseError};
 use crate::properties::ComputedValues;
 
@@ -18,11 +18,11 @@ pub enum FontSizeSpec {
     Large,
     XLarge,
     XXLarge,
-    Value(LengthBoth),
+    Value(Length<Both>),
 }
 
 impl FontSizeSpec {
-    pub fn value(&self) -> LengthBoth {
+    pub fn value(&self) -> Length<Both> {
         match self {
             FontSizeSpec::Value(s) => *s,
             _ => unreachable!(),
@@ -35,17 +35,17 @@ impl FontSizeSpec {
         let size = v.font_size.0.value();
 
         let new_size = match self {
-            FontSizeSpec::Smaller => LengthBoth::new(size.length() / 1.2, size.unit()),
-            FontSizeSpec::Larger => LengthBoth::new(size.length() * 1.2, size.unit()),
-            FontSizeSpec::XXSmall => LengthBoth::new(compute_points(-3.0), LengthUnit::In),
-            FontSizeSpec::XSmall => LengthBoth::new(compute_points(-2.0), LengthUnit::In),
-            FontSizeSpec::Small => LengthBoth::new(compute_points(-1.0), LengthUnit::In),
-            FontSizeSpec::Medium => LengthBoth::new(compute_points(0.0), LengthUnit::In),
-            FontSizeSpec::Large => LengthBoth::new(compute_points(1.0), LengthUnit::In),
-            FontSizeSpec::XLarge => LengthBoth::new(compute_points(2.0), LengthUnit::In),
-            FontSizeSpec::XXLarge => LengthBoth::new(compute_points(3.0), LengthUnit::In),
-            FontSizeSpec::Value(s) if s.unit() == LengthUnit::Percent => {
-                LengthBoth::new(size.length() * s.length(), size.unit())
+            FontSizeSpec::Smaller => Length::<Both>::new(size.length / 1.2, size.unit),
+            FontSizeSpec::Larger => Length::<Both>::new(size.length * 1.2, size.unit),
+            FontSizeSpec::XXSmall => Length::<Both>::new(compute_points(-3.0), LengthUnit::In),
+            FontSizeSpec::XSmall => Length::<Both>::new(compute_points(-2.0), LengthUnit::In),
+            FontSizeSpec::Small => Length::<Both>::new(compute_points(-1.0), LengthUnit::In),
+            FontSizeSpec::Medium => Length::<Both>::new(compute_points(0.0), LengthUnit::In),
+            FontSizeSpec::Large => Length::<Both>::new(compute_points(1.0), LengthUnit::In),
+            FontSizeSpec::XLarge => Length::<Both>::new(compute_points(2.0), LengthUnit::In),
+            FontSizeSpec::XXLarge => Length::<Both>::new(compute_points(3.0), LengthUnit::In),
+            FontSizeSpec::Value(s) if s.unit == LengthUnit::Percent => {
+                Length::<Both>::new(size.length * s.length, size.unit)
             }
             FontSizeSpec::Value(s) => *s,
         };
@@ -64,7 +64,7 @@ impl Parse for FontSizeSpec {
     fn parse(parser: &mut Parser<'_, '_>) -> Result<FontSizeSpec, crate::error::ValueErrorKind> {
         let parser_state = parser.state();
 
-        LengthBoth::parse(parser)
+        Length::<Both>::parse(parser)
             .and_then(|s| Ok(FontSizeSpec::Value(s)))
             .or_else(|e| {
                 parser.reset(&parser_state);
@@ -164,11 +164,11 @@ impl Parse for FontWeightSpec {
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub enum LetterSpacingSpec {
     Normal,
-    Value(LengthHorizontal),
+    Value(Length<Horizontal>),
 }
 
 impl LetterSpacingSpec {
-    pub fn value(&self) -> LengthHorizontal {
+    pub fn value(&self) -> Length<Horizontal> {
         match self {
             LetterSpacingSpec::Value(s) => *s,
             _ => unreachable!(),
@@ -177,7 +177,7 @@ impl LetterSpacingSpec {
 
     pub fn compute(&self) -> Self {
         let spacing = match self {
-            LetterSpacingSpec::Normal => LengthHorizontal::new(0.0, LengthUnit::Px),
+            LetterSpacingSpec::Normal => Length::<Horizontal>::new(0.0, LengthUnit::Px),
             LetterSpacingSpec::Value(s) => *s,
         };
 
@@ -197,7 +197,7 @@ impl Parse for LetterSpacingSpec {
     ) -> Result<LetterSpacingSpec, crate::error::ValueErrorKind> {
         let parser_state = parser.state();
 
-        LengthHorizontal::parse(parser)
+        Length::<Horizontal>::parse(parser)
             .and_then(|s| Ok(LetterSpacingSpec::Value(s)))
             .or_else(|e| {
                 parser.reset(&parser_state);
@@ -296,7 +296,7 @@ mod tests {
         );
         assert_eq!(
             <LetterSpacingSpec as Parse>::parse_str("10em"),
-            Ok(LetterSpacingSpec::Value(LengthHorizontal::new(
+            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                 10.0,
                 LengthUnit::Em,
             )))
@@ -307,14 +307,14 @@ mod tests {
     fn computes_letter_spacing() {
         assert_eq!(
             <LetterSpacingSpec as Parse>::parse_str("normal").map(|s| s.compute()),
-            Ok(LetterSpacingSpec::Value(LengthHorizontal::new(
+            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                 0.0,
                 LengthUnit::Px,
             )))
         );
         assert_eq!(
             <LetterSpacingSpec as Parse>::parse_str("10em").map(|s| s.compute()),
-            Ok(LetterSpacingSpec::Value(LengthHorizontal::new(
+            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                 10.0,
                 LengthUnit::Em,
             )))
diff --git a/rsvg_internals/src/gradient.rs b/rsvg_internals/src/gradient.rs
index 1c2d46b9..e30ad815 100644
--- a/rsvg_internals/src/gradient.rs
+++ b/rsvg_internals/src/gradient.rs
@@ -131,8 +131,8 @@ pub struct Stop {
     // they go into property_defs.rs
 }
 
-fn validate_offset(length: LengthBoth) -> Result<LengthBoth, ValueErrorKind> {
-    match length.unit() {
+fn validate_offset(length: Length<Both>) -> Result<Length<Both>, ValueErrorKind> {
+    match length.unit {
         LengthUnit::Px | LengthUnit::Percent => Ok(length),
         _ => Err(ValueErrorKind::Value(
             "stop offset must be in default or percent units".to_string(),
@@ -147,7 +147,7 @@ impl NodeTrait for Stop {
                 expanded_name!(svg "offset") => {
                     self.offset = attr
                         .parse_and_validate(value, validate_offset)
-                        .map(|l| UnitInterval::clamp(l.length()))?
+                        .map(|l| UnitInterval::clamp(l.length))?
                 }
                 _ => (),
             }
@@ -164,18 +164,18 @@ impl NodeTrait for Stop {
 #[derive(Copy, Clone)]
 enum UnresolvedVariant {
     Linear {
-        x1: Option<LengthHorizontal>,
-        y1: Option<LengthVertical>,
-        x2: Option<LengthHorizontal>,
-        y2: Option<LengthVertical>,
+        x1: Option<Length<Horizontal>>,
+        y1: Option<Length<Vertical>>,
+        x2: Option<Length<Horizontal>>,
+        y2: Option<Length<Vertical>>,
     },
 
     Radial {
-        cx: Option<LengthHorizontal>,
-        cy: Option<LengthVertical>,
-        r: Option<LengthBoth>,
-        fx: Option<LengthHorizontal>,
-        fy: Option<LengthVertical>,
+        cx: Option<Length<Horizontal>>,
+        cy: Option<Length<Vertical>>,
+        r: Option<Length<Both>>,
+        fx: Option<Length<Horizontal>>,
+        fy: Option<Length<Vertical>>,
     },
 }
 
@@ -183,18 +183,18 @@ enum UnresolvedVariant {
 #[derive(Clone)]
 enum Variant {
     Linear {
-        x1: LengthHorizontal,
-        y1: LengthVertical,
-        x2: LengthHorizontal,
-        y2: LengthVertical,
+        x1: Length<Horizontal>,
+        y1: Length<Vertical>,
+        x2: Length<Horizontal>,
+        y2: Length<Vertical>,
     },
 
     Radial {
-        cx: LengthHorizontal,
-        cy: LengthVertical,
-        r: LengthBoth,
-        fx: LengthHorizontal,
-        fy: LengthVertical,
+        cx: Length<Horizontal>,
+        cy: Length<Vertical>,
+        r: Length<Both>,
+        fx: Length<Horizontal>,
+        fy: Length<Vertical>,
     },
 }
 
@@ -260,16 +260,16 @@ impl UnresolvedVariant {
     fn resolve_from_defaults(&self) -> UnresolvedVariant {
         match self {
             UnresolvedVariant::Linear { x1, y1, x2, y2 } => UnresolvedVariant::Linear {
-                x1: x1.or_else(|| Some(LengthHorizontal::parse_str("0%").unwrap())),
-                y1: y1.or_else(|| Some(LengthVertical::parse_str("0%").unwrap())),
-                x2: x2.or_else(|| Some(LengthHorizontal::parse_str("100%").unwrap())),
-                y2: y2.or_else(|| Some(LengthVertical::parse_str("0%").unwrap())),
+                x1: x1.or_else(|| Some(Length::<Horizontal>::parse_str("0%").unwrap())),
+                y1: y1.or_else(|| Some(Length::<Vertical>::parse_str("0%").unwrap())),
+                x2: x2.or_else(|| Some(Length::<Horizontal>::parse_str("100%").unwrap())),
+                y2: y2.or_else(|| Some(Length::<Vertical>::parse_str("0%").unwrap())),
             },
 
             UnresolvedVariant::Radial { cx, cy, r, fx, fy } => {
-                let cx = cx.or_else(|| Some(LengthHorizontal::parse_str("50%").unwrap()));
-                let cy = cy.or_else(|| Some(LengthVertical::parse_str("50%").unwrap()));
-                let r = r.or_else(|| Some(LengthBoth::parse_str("50%").unwrap()));
+                let cx = cx.or_else(|| Some(Length::<Horizontal>::parse_str("50%").unwrap()));
+                let cy = cy.or_else(|| Some(Length::<Vertical>::parse_str("50%").unwrap()));
+                let r = r.or_else(|| Some(Length::<Both>::parse_str("50%").unwrap()));
 
                 // fx and fy fall back to the presentational value of cx and cy
                 let fx = fx.or(cx);
@@ -329,10 +329,10 @@ struct Common {
 pub struct LinearGradient {
     common: Common,
 
-    x1: Option<LengthHorizontal>,
-    y1: Option<LengthVertical>,
-    x2: Option<LengthHorizontal>,
-    y2: Option<LengthVertical>,
+    x1: Option<Length<Horizontal>>,
+    y1: Option<Length<Vertical>>,
+    x2: Option<Length<Horizontal>>,
+    y2: Option<Length<Vertical>>,
 }
 
 /// Node for the <radialGradient> element
@@ -340,11 +340,11 @@ pub struct LinearGradient {
 pub struct RadialGradient {
     common: Common,
 
-    cx: Option<LengthHorizontal>,
-    cy: Option<LengthVertical>,
-    r: Option<LengthBoth>,
-    fx: Option<LengthHorizontal>,
-    fy: Option<LengthVertical>,
+    cx: Option<Length<Horizontal>>,
+    cy: Option<Length<Vertical>>,
+    r: Option<Length<Both>>,
+    fx: Option<Length<Horizontal>>,
+    fy: Option<Length<Vertical>>,
 }
 
 /// Main structure used during gradient resolution.  For unresolved
diff --git a/rsvg_internals/src/image.rs b/rsvg_internals/src/image.rs
index cee2a1ae..7c5972d3 100644
--- a/rsvg_internals/src/image.rs
+++ b/rsvg_internals/src/image.rs
@@ -8,7 +8,7 @@ use crate::bbox::BoundingBox;
 use crate::drawing_ctx::{ClipMode, DrawingCtx};
 use crate::error::{NodeError, RenderingError};
 use crate::float_eq_cairo::ApproxEqCairo;
-use crate::length::{LengthHorizontal, LengthTrait, LengthVertical};
+use crate::length::*;
 use crate::node::*;
 use crate::parsers::{ParseError, ParseValue};
 use crate::property_bag::PropertyBag;
@@ -17,10 +17,10 @@ use crate::viewbox::ViewBox;
 
 #[derive(Default)]
 pub struct Image {
-    x: LengthHorizontal,
-    y: LengthVertical,
-    w: LengthHorizontal,
-    h: LengthVertical,
+    x: Length<Horizontal>,
+    y: Length<Vertical>,
+    w: Length<Horizontal>,
+    h: Length<Vertical>,
     aspect: AspectRatio,
     href: Option<Href>,
 }
@@ -32,10 +32,10 @@ impl NodeTrait for Image {
                 expanded_name!(svg "x") => self.x = attr.parse(value)?,
                 expanded_name!(svg "y") => self.y = attr.parse(value)?,
                 expanded_name!(svg "width") => {
-                    self.w = attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?
+                    self.w = attr.parse_and_validate(value, Length::check_nonnegative)?
                 }
                 expanded_name!(svg "height") => {
-                    self.h = attr.parse_and_validate(value, LengthVertical::check_nonnegative)?
+                    self.h = attr.parse_and_validate(value, Length::check_nonnegative)?
                 }
                 expanded_name!(svg "preserveAspectRatio") => self.aspect = attr.parse(value)?,
 
diff --git a/rsvg_internals/src/length.rs b/rsvg_internals/src/length.rs
index bb76e738..88dd6905 100644
--- a/rsvg_internals/src/length.rs
+++ b/rsvg_internals/src/length.rs
@@ -3,8 +3,6 @@
 //! While the actual representation of CSS lengths is in the
 //! [`Length`] struct, most of librsvg's internals use the newtypes
 //! [`LengthHorizontal`], [`LengthVertical`], or [`LengthBoth`] depending on
-//! whether the length value in question needs to be normalized with respect to
-//! the width, height, or both dimensions of the current viewport.
 //!
 //! For example, the implementation of [`Circle`] defines this structure:
 //!
@@ -32,6 +30,7 @@
 
 use cssparser::{Parser, Token};
 use std::f64::consts::*;
+use std::marker::PhantomData;
 
 use crate::drawing_ctx::ViewParams;
 use crate::error::*;
@@ -39,47 +38,6 @@ use crate::parsers::Parse;
 use crate::parsers::{finite_f32, ParseError};
 use crate::properties::ComputedValues;
 
-/// A CSS length value.
-///
-/// This is equivalent to [CSS lengths].
-///
-/// [CSS lengths]: https://www.w3.org/TR/CSS21/syndata.html#length-units
-///
-/// It is up to the calling application to convert lengths in non-pixel units
-/// (i.e. those where the [`unit`] field is not [`LengthUnit::Px`]) into something
-/// meaningful to the application.  For example, if your application knows the
-/// dots-per-inch (DPI) it is using, it can convert lengths with [`unit`] in
-/// [`LengthUnit::In`] or other physical units.
-///
-/// [`unit`]: #structfield.unit
-/// [`LengthUnit::Px`]: enum.LengthUnit.html#variant.Px
-/// [`LengthUnit::In`]: enum.LengthUnit.html#variant.In
-// Keep this in sync with rsvg.h:RsvgLength
-#[repr(C)]
-#[derive(Debug, PartialEq, Copy, Clone)]
-pub struct RsvgLength {
-    /// Numeric part of the length
-    pub length: f64,
-
-    /// Unit part of the length
-    pub unit: LengthUnit,
-}
-
-impl From<Length> for RsvgLength {
-    fn from(l: Length) -> RsvgLength {
-        RsvgLength {
-            length: l.length,
-            unit: l.unit,
-        }
-    }
-}
-
-impl RsvgLength {
-    pub fn new(l: f64, unit: LengthUnit) -> RsvgLength {
-        RsvgLength { length: l, unit }
-    }
-}
-
 /// Units for length values.
 // This needs to be kept in sync with `rsvg.h:RsvgUnit`.
 #[repr(C)]
@@ -113,17 +71,56 @@ pub enum LengthUnit {
     Pc,
 }
 
+/// A CSS length value.
+///
+/// This is equivalent to [CSS lengths].
+///
+/// [CSS lengths]: https://www.w3.org/TR/CSS21/syndata.html#length-units
+///
+/// It is up to the calling application to convert lengths in non-pixel units
+/// (i.e. those where the [`unit`] field is not [`LengthUnit::Px`]) into something
+/// meaningful to the application.  For example, if your application knows the
+/// dots-per-inch (DPI) it is using, it can convert lengths with [`unit`] in
+/// [`LengthUnit::In`] or other physical units.
+///
+/// [`unit`]: #structfield.unit
+/// [`LengthUnit::Px`]: enum.LengthUnit.html#variant.Px
+/// [`LengthUnit::In`]: enum.LengthUnit.html#variant.In
+// Keep this in sync with rsvg.h:RsvgLength
+#[repr(C)]
+#[derive(Debug, PartialEq, Copy, Clone)]
+pub struct RsvgLength {
+    /// Numeric part of the length
+    pub length: f64,
+
+    /// Unit part of the length
+    pub unit: LengthUnit,
+}
+
+impl RsvgLength {
+    pub fn new(l: f64, unit: LengthUnit) -> RsvgLength {
+        RsvgLength { length: l, unit }
+    }
+}
+
 pub trait Orientation {
     /// Computes a direction-based scaling factor.
     ///
-    /// This is so that `LengthDir::Both` will use the "normalized
-    /// diagonal length" of the current viewport, per
-    /// https://www.w3.org/TR/SVG/coords.html#Units
+    /// This is so that `Length<Both>` will use the "normalized diagonal length" of the current
+    /// viewport, per https://www.w3.org/TR/SVG/coords.html#Units
     fn normalize(x: f64, y: f64) -> f64;
 }
 
+/// Struct to be able to declare `Length<Horizontal>`
+#[derive(Debug, PartialEq, Copy, Clone)]
 pub struct Horizontal;
+
+/// Struct to be able to declare `Length<Vertical>`
+#[derive(Debug, PartialEq, Copy, Clone)]
 pub struct Vertical;
+
+/// Struct to be able to declare `Length<Both>`
+#[derive(Debug, PartialEq, Copy, Clone)]
 pub struct Both;
 
 impl Orientation for Horizontal {
@@ -147,163 +144,46 @@ impl Orientation for Both {
     }
 }
 
-pub trait LengthTrait: Sized {
-    type Orientation: Orientation;
-
-    /// Getter for the `length` field
-    fn length(&self) -> f64;
-
-    /// Getter for the `unit` field
-    fn unit(&self) -> LengthUnit;
-
-    /// Extracts the interior [`Length`].
-    ///
-    /// [`Length`]: struct.Length.html
-    fn to_length(&self) -> Length;
-
-    /// Returns `self` if the length is >= 0, or an error.
-    ///
-    /// ```ignore
-    /// let mut parser = Parser::new(...);
-    ///
-    /// let length = LENGTH::parse(&mut parser).and_then($name::check_nonnegative)?;
-    /// ```
-    fn check_nonnegative(self) -> Result<Self, ValueErrorKind> {
-        if self.length() >= 0.0 {
-            Ok(self)
-        } else {
-            Err(ValueErrorKind::Value(
-                "value must be non-negative".to_string(),
-            ))
-        }
-    }
-
-    /// Normalizes a specified length into a used value.
-    ///
-    /// Lengths may come with non-pixel units, and when rendering, they need to be
-    /// normalized to pixels based on the current viewport (e.g. for lengths with
-    /// percent units), and on the current element's set of `ComputedValues` (e.g. for
-    /// lengths with `Em` units that need to be resolved against the current font
-    /// size).
-    fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
-        match self.unit() {
-            LengthUnit::Px => self.length(),
-
-            LengthUnit::Percent => {
-                self.length()
-                    * <Self::Orientation>::normalize(params.view_box_width, params.view_box_height)
-            }
-
-            LengthUnit::Em => self.length() * font_size_from_values(values, params),
-
-            LengthUnit::Ex => self.length() * font_size_from_values(values, params) / 2.0,
-
-            LengthUnit::In => {
-                self.length() * <Self::Orientation>::normalize(params.dpi_x, params.dpi_y)
-            }
-
-            LengthUnit::Cm => {
-                self.length() * <Self::Orientation>::normalize(params.dpi_x, params.dpi_y)
-                    / CM_PER_INCH
-            }
+/// A CSS length value.
+///
+/// https://www.w3.org/TR/SVG/types.html#DataTypeLength
+/// https://www.w3.org/TR/2008/REC-CSS2-20080411/syndata.html#length-units
+///
+/// Length values need to know whether they will be normalized with respect to the width,
+/// height, or both dimensions of the current viewport.  So, a `Length` has a type parameter
+/// [`Orientation`].  We provide [`Horizontal`], [`Vertical`], and [`Both`] implementations of
+/// [`Orientation`]; these let length values know how to normalize themselves with respect to
+/// the current viewport.
+///
+/// [`Orientation`]: trait.Orientation.html
+/// [`Horizontal`]: struct.Horizontal.html
+/// [`Vertical`]: struct.Vertical.html
+/// [`Both`]: struct.Both.html
 
-            LengthUnit::Mm => {
-                self.length() * <Self::Orientation>::normalize(params.dpi_x, params.dpi_y)
-                    / MM_PER_INCH
-            }
+#[derive(Debug, PartialEq, Copy, Clone)]
+pub struct Length<O: Orientation> {
+    /// Numeric part of the length
+    pub length: f64,
 
-            LengthUnit::Pt => {
-                self.length() * <Self::Orientation>::normalize(params.dpi_x, params.dpi_y)
-                    / POINTS_PER_INCH
-            }
+    /// Unit part of the length
+    pub unit: LengthUnit,
 
-            LengthUnit::Pc => {
-                self.length() * <Self::Orientation>::normalize(params.dpi_x, params.dpi_y)
-                    / PICA_PER_INCH
-            }
-        }
-    }
+    orientation: PhantomData<O>,
 }
 
-macro_rules! define_length_type {
-    {$(#[$docs:meta])* $name:ident, $orient:ty} => {
-        $(#[$docs])*
-        #[derive(Debug, PartialEq, Copy, Clone)]
-        pub struct $name(Length);
-
-        impl LengthTrait for $name {
-            type Orientation = $orient;
-
-            fn length(&self) -> f64 {
-                self.0.length
-            }
-
-            fn unit(&self) -> LengthUnit {
-                self.0.unit
-            }
-
-            fn to_length(&self) -> Length {
-                self.0
-            }
-        }
-
-        impl $name {
-            #[allow(unused)]
-            pub fn new(length: f64, unit: LengthUnit) -> Self {
-                $name(Length::new(length, unit))
-            }
-        }
-
-        impl Default for $name {
-            fn default() -> Self {
-                $name(Length::new(0.0, LengthUnit::Px))
-            }
-        }
-
-        impl Parse for $name {
-            type Err = ValueErrorKind;
-
-            fn parse(parser: &mut Parser<'_, '_>) -> Result<$name, ValueErrorKind> {
-                Ok($name(Length::parse(parser)?))
-            }
+impl<O: Orientation> From<Length<O>> for RsvgLength {
+    fn from(l: Length<O>) -> RsvgLength {
+        RsvgLength {
+            length: l.length,
+            unit: l.unit,
         }
-    };
-}
-
-define_length_type! {
-    /// Horizontal length.
-    ///
-    /// When this is specified as a percent value, it will get normalized
-    /// against the current viewport's width.
-
-    LengthHorizontal, Horizontal
-}
-
-define_length_type! {
-    /// Vertical length.
-    ///
-    /// When this is specified as a percent value, it will get normalized
-    /// against the current viewport's height.
-    LengthVertical, Vertical
-}
-
-define_length_type! {
-    /// "Both" length.
-    ///
-    /// When this is specified as a percent value, it will get normalized
-    /// against the current viewport's width and height.
-
-    LengthBoth, Both
+    }
 }
 
-/// A CSS length value.
-#[derive(Debug, PartialEq, Copy, Clone)]
-pub struct Length {
-    /// Numeric part of the length
-    pub length: f64,
-
-    /// Unit part of the length
-    pub unit: LengthUnit,
+impl<O: Orientation> Default for Length<O> {
+    fn default() -> Self {
+        Length::new(0.0, LengthUnit::Px)
+    }
 }
 
 pub const POINTS_PER_INCH: f64 = 72.0;
@@ -311,16 +191,6 @@ const CM_PER_INCH: f64 = 2.54;
 const MM_PER_INCH: f64 = 25.4;
 const PICA_PER_INCH: f64 = 6.0;
 
-// https://www.w3.org/TR/SVG/types.html#DataTypeLength
-// https://www.w3.org/TR/2008/REC-CSS2-20080411/syndata.html#length-units
-// Lengths have units.  When they need to be need resolved to
-// units in the user's coordinate system, some unit types
-// need to know if they are horizontal/vertical/both.  For example,
-// a some_object.width="50%" is 50% with respect to the current
-// viewport's width.  In this case, the @dir argument is used
-// inside Length::normalize(), when it needs to know to what the
-// length refers.
-
 fn make_err() -> ValueErrorKind {
     ValueErrorKind::Parse(ParseError::new(
         "expected length: number(\"em\" | \"ex\" | \"px\" | \"in\" | \"cm\" | \"mm\" | \"pt\" | \
@@ -328,10 +198,10 @@ fn make_err() -> ValueErrorKind {
     ))
 }
 
-impl Parse for Length {
+impl<O: Orientation> Parse for Length<O> {
     type Err = ValueErrorKind;
 
-    fn parse(parser: &mut Parser<'_, '_>) -> Result<Length, ValueErrorKind> {
+    fn parse(parser: &mut Parser<'_, '_>) -> Result<Length<O>, ValueErrorKind> {
         let length = {
             let token = parser.next().map_err(|_| {
                 ValueErrorKind::Parse(ParseError::new(
@@ -340,15 +210,15 @@ impl Parse for Length {
             })?;
 
             match *token {
-                Token::Number { value, .. } => Length {
-                    length: f64::from(finite_f32(value)?),
-                    unit: LengthUnit::Px,
-                },
+                Token::Number { value, .. } => Length::new(
+                    f64::from(finite_f32(value)?),
+                    LengthUnit::Px,
+                ),
 
-                Token::Percentage { unit_value, .. } => Length {
-                    length: f64::from(finite_f32(unit_value)?),
-                    unit: LengthUnit::Percent,
-                },
+                Token::Percentage { unit_value, .. } => Length::new(
+                    f64::from(finite_f32(unit_value)?),
+                    LengthUnit::Percent,
+                ),
 
                 Token::Dimension {
                     value, ref unit, ..
@@ -356,45 +226,14 @@ impl Parse for Length {
                     let value = f64::from(finite_f32(value)?);
 
                     match unit.as_ref() {
-                        "px" => Length {
-                            length: value,
-                            unit: LengthUnit::Px,
-                        },
-
-                        "em" => Length {
-                            length: value,
-                            unit: LengthUnit::Em,
-                        },
-
-                        "ex" => Length {
-                            length: value,
-                            unit: LengthUnit::Ex,
-                        },
-
-                        "in" => Length {
-                            length: value,
-                            unit: LengthUnit::In,
-                        },
-
-                        "cm" => Length {
-                            length: value,
-                            unit: LengthUnit::Cm,
-                        },
-
-                        "mm" => Length {
-                            length: value,
-                            unit: LengthUnit::Mm,
-                        },
-
-                        "pt" => Length {
-                            length: value,
-                            unit: LengthUnit::Pt,
-                        },
-
-                        "pc" => Length {
-                            length: value,
-                            unit: LengthUnit::Pc,
-                        },
+                        "px" => Length::new(value, LengthUnit::Px),
+                        "em" => Length::new(value, LengthUnit::Em),
+                        "ex" => Length::new(value, LengthUnit::Ex),
+                        "in" => Length::new(value, LengthUnit::In),
+                        "cm" => Length::new(value, LengthUnit::Cm),
+                        "mm" => Length::new(value, LengthUnit::Mm),
+                        "pt" => Length::new(value, LengthUnit::Pt),
+                        "pc" => Length::new(value, LengthUnit::Pc),
 
                         _ => return Err(make_err()),
                     }
@@ -408,14 +247,81 @@ impl Parse for Length {
     }
 }
 
-impl Length {
-    pub fn new(l: f64, unit: LengthUnit) -> Length {
-        Length { length: l, unit }
+impl<O: Orientation> Length<O> {
+    pub fn new(l: f64, unit: LengthUnit) -> Length<O> {
+        Length {
+            length: l,
+            unit,
+            orientation: PhantomData,
+        }
+    }
+
+    /// Returns `self` if the length is >= 0, or an error.
+    ///
+    /// ```ignore
+    /// let mut parser = Parser::new(...);
+    ///
+    /// let length = LENGTH::parse(&mut parser).and_then($name::check_nonnegative)?;
+    /// ```
+    pub fn check_nonnegative(self) -> Result<Self, ValueErrorKind> {
+        if self.length >= 0.0 {
+            Ok(self)
+        } else {
+            Err(ValueErrorKind::Value(
+                "value must be non-negative".to_string(),
+            ))
+        }
+    }
+
+    /// Normalizes a specified length into a used value.
+    ///
+    /// Lengths may come with non-pixel units, and when rendering, they need to be
+    /// normalized to pixels based on the current viewport (e.g. for lengths with
+    /// percent units), and on the current element's set of `ComputedValues` (e.g. for
+    /// lengths with `Em` units that need to be resolved against the current font
+    /// size).
+    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
+        match self.unit {
+            LengthUnit::Px => self.length,
+
+            LengthUnit::Percent => {
+                self.length 
+                    * <O as Orientation>::normalize(params.view_box_width, params.view_box_height)
+            }
+
+            LengthUnit::Em => self.length * font_size_from_values(values, params),
+
+            LengthUnit::Ex => self.length * font_size_from_values(values, params) / 2.0,
+
+            LengthUnit::In => {
+                self.length * <O as Orientation>::normalize(params.dpi_x, params.dpi_y)
+            }
+
+            LengthUnit::Cm => {
+                self.length * <O as Orientation>::normalize(params.dpi_x, params.dpi_y)
+                    / CM_PER_INCH
+            }
+
+            LengthUnit::Mm => {
+                self.length * <O as Orientation>::normalize(params.dpi_x, params.dpi_y)
+                    / MM_PER_INCH
+            }
+
+            LengthUnit::Pt => {
+                self.length * <O as Orientation>::normalize(params.dpi_x, params.dpi_y)
+                    / POINTS_PER_INCH
+            }
+
+            LengthUnit::Pc => {
+                self.length * <O as Orientation>::normalize(params.dpi_x, params.dpi_y)
+                    / PICA_PER_INCH
+            }
+        }
     }
 }
 
 fn font_size_from_values(values: &ComputedValues, params: &ViewParams) -> f64 {
-    let v = &values.font_size.0.value().0;
+    let v = &values.font_size.0.value();
 
     match v.unit {
         LengthUnit::Percent => unreachable!("ComputedValues can't have a relative font size"),
@@ -430,18 +336,10 @@ fn font_size_from_values(values: &ComputedValues, params: &ViewParams) -> f64 {
 
         // FontSize always is a Both, per properties.rs
         LengthUnit::In => v.length * Both::normalize(params.dpi_x, params.dpi_y),
-        LengthUnit::Cm => {
-            v.length * Both::normalize(params.dpi_x, params.dpi_y) / CM_PER_INCH
-        }
-        LengthUnit::Mm => {
-            v.length * Both::normalize(params.dpi_x, params.dpi_y) / MM_PER_INCH
-        }
-        LengthUnit::Pt => {
-            v.length * Both::normalize(params.dpi_x, params.dpi_y) / POINTS_PER_INCH
-        }
-        LengthUnit::Pc => {
-            v.length * Both::normalize(params.dpi_x, params.dpi_y) / PICA_PER_INCH
-        }
+        LengthUnit::Cm => v.length * Both::normalize(params.dpi_x, params.dpi_y) / CM_PER_INCH,
+        LengthUnit::Mm => v.length * Both::normalize(params.dpi_x, params.dpi_y) / MM_PER_INCH,
+        LengthUnit::Pt => v.length * Both::normalize(params.dpi_x, params.dpi_y) / POINTS_PER_INCH,
+        LengthUnit::Pc => v.length * Both::normalize(params.dpi_x, params.dpi_y) / PICA_PER_INCH,
     }
 }
 
@@ -456,7 +354,7 @@ fn viewport_percentage(x: f64, y: f64) -> f64 {
 #[derive(Debug, PartialEq, Clone)]
 pub enum Dasharray {
     None,
-    Array(Vec<LengthBoth>),
+    Array(Vec<Length<Both>>),
 }
 
 impl Default for Dasharray {
@@ -481,11 +379,11 @@ impl Parse for Dasharray {
 }
 
 // This does not handle "inherit" or "none" state, the caller is responsible for that.
-fn parse_dash_array(parser: &mut Parser<'_, '_>) -> Result<Vec<LengthBoth>, ValueErrorKind> {
+fn parse_dash_array(parser: &mut Parser<'_, '_>) -> Result<Vec<Length<Both>>, ValueErrorKind> {
     let mut dasharray = Vec::new();
 
     loop {
-        dasharray.push(LengthBoth::parse(parser).and_then(LengthBoth::check_nonnegative)?);
+        dasharray.push(Length::<Both>::parse(parser).and_then(Length::<Both>::check_nonnegative)?);
 
         if parser.is_exhausted() {
             break;
@@ -506,84 +404,84 @@ mod tests {
     #[test]
     fn parses_default() {
         assert_eq!(
-            LengthHorizontal::parse_str("42"),
-            Ok(LengthHorizontal(Length::new(42.0, LengthUnit::Px)))
+            Length::<Horizontal>::parse_str("42"),
+            Ok(Length::<Horizontal>::new(42.0, LengthUnit::Px))
         );
 
         assert_eq!(
-            LengthHorizontal::parse_str("-42px"),
-            Ok(LengthHorizontal(Length::new(-42.0, LengthUnit::Px)))
+            Length::<Horizontal>::parse_str("-42px"),
+            Ok(Length::<Horizontal>::new(-42.0, LengthUnit::Px))
         );
     }
 
     #[test]
     fn parses_percent() {
         assert_eq!(
-            LengthHorizontal::parse_str("50.0%"),
-            Ok(LengthHorizontal(Length::new(0.5, LengthUnit::Percent)))
+            Length::<Horizontal>::parse_str("50.0%"),
+            Ok(Length::<Horizontal>::new(0.5, LengthUnit::Percent))
         );
     }
 
     #[test]
     fn parses_font_em() {
         assert_eq!(
-            LengthVertical::parse_str("22.5em"),
-            Ok(LengthVertical(Length::new(22.5, LengthUnit::Em)))
+            Length::<Vertical>::parse_str("22.5em"),
+            Ok(Length::<Vertical>::new(22.5, LengthUnit::Em))
         );
     }
 
     #[test]
     fn parses_font_ex() {
         assert_eq!(
-            LengthVertical::parse_str("22.5ex"),
-            Ok(LengthVertical(Length::new(22.5, LengthUnit::Ex)))
+            Length::<Vertical>::parse_str("22.5ex"),
+            Ok(Length::<Vertical>::new(22.5, LengthUnit::Ex))
         );
     }
 
     #[test]
     fn parses_physical_units() {
         assert_eq!(
-            LengthBoth::parse_str("72pt"),
-            Ok(LengthBoth(Length::new(72.0, LengthUnit::Pt)))
+            Length::<Both>::parse_str("72pt"),
+            Ok(Length::<Both>::new(72.0, LengthUnit::Pt))
         );
 
         assert_eq!(
-            LengthBoth::parse_str("-22.5in"),
-            Ok(LengthBoth(Length::new(-22.5, LengthUnit::In)))
+            Length::<Both>::parse_str("-22.5in"),
+            Ok(Length::<Both>::new(-22.5, LengthUnit::In))
         );
 
         assert_eq!(
-            LengthBoth::parse_str("-254cm"),
-            Ok(LengthBoth(Length::new(-254.0, LengthUnit::Cm)))
+            Length::<Both>::parse_str("-254cm"),
+            Ok(Length::<Both>::new(-254.0, LengthUnit::Cm))
         );
 
         assert_eq!(
-            LengthBoth::parse_str("254mm"),
-            Ok(LengthBoth(Length::new(254.0, LengthUnit::Mm)))
+            Length::<Both>::parse_str("254mm"),
+            Ok(Length::<Both>::new(254.0, LengthUnit::Mm))
         );
 
         assert_eq!(
-            LengthBoth::parse_str("60pc"),
-            Ok(LengthBoth(Length::new(60.0, LengthUnit::Pc)))
+            Length::<Both>::parse_str("60pc"),
+            Ok(Length::<Both>::new(60.0, LengthUnit::Pc))
         );
     }
 
     #[test]
     fn empty_length_yields_error() {
-        assert!(is_parse_error(&LengthBoth::parse_str("")));
+        assert!(is_parse_error(&Length::<Both>::parse_str("")));
     }
 
     #[test]
     fn invalid_unit_yields_error() {
-        assert!(is_parse_error(&LengthBoth::parse_str("8furlong")));
+        assert!(is_parse_error(&Length::<Both>::parse_str("8furlong")));
     }
 
     #[test]
     fn check_nonnegative_works() {
-        assert!(LengthBoth::parse_str("0")
+        assert!(Length::<Both>::parse_str("0")
             .and_then(|l| l.check_nonnegative())
             .is_ok());
-        assert!(LengthBoth::parse_str("-10")
+        assert!(Length::<Both>::parse_str("-10")
             .and_then(|l| l.check_nonnegative())
             .is_err());
     }
@@ -595,7 +493,7 @@ mod tests {
         let values = ComputedValues::default();
 
         assert_approx_eq_cairo!(
-            LengthBoth::new(10.0, LengthUnit::Px).normalize(&values, &params),
+            Length::<Both>::new(10.0, LengthUnit::Px).normalize(&values, &params),
             10.0
         );
     }
@@ -607,28 +505,28 @@ mod tests {
         let values = ComputedValues::default();
 
         assert_approx_eq_cairo!(
-            LengthHorizontal::new(10.0, LengthUnit::In).normalize(&values, &params),
+            Length::<Horizontal>::new(10.0, LengthUnit::In).normalize(&values, &params),
             400.0
         );
         assert_approx_eq_cairo!(
-            LengthVertical::new(10.0, LengthUnit::In).normalize(&values, &params),
+            Length::<Vertical>::new(10.0, LengthUnit::In).normalize(&values, &params),
             500.0
         );
 
         assert_approx_eq_cairo!(
-            LengthHorizontal::new(10.0, LengthUnit::Cm).normalize(&values, &params),
+            Length::<Horizontal>::new(10.0, LengthUnit::Cm).normalize(&values, &params),
             400.0 / CM_PER_INCH
         );
         assert_approx_eq_cairo!(
-            LengthHorizontal::new(10.0, LengthUnit::Mm).normalize(&values, &params),
+            Length::<Horizontal>::new(10.0, LengthUnit::Mm).normalize(&values, &params),
             400.0 / MM_PER_INCH
         );
         assert_approx_eq_cairo!(
-            LengthHorizontal::new(10.0, LengthUnit::Pt).normalize(&values, &params),
+            Length::<Horizontal>::new(10.0, LengthUnit::Pt).normalize(&values, &params),
             400.0 / POINTS_PER_INCH
         );
         assert_approx_eq_cairo!(
-            LengthHorizontal::new(10.0, LengthUnit::Pc).normalize(&values, &params),
+            Length::<Horizontal>::new(10.0, LengthUnit::Pc).normalize(&values, &params),
             400.0 / PICA_PER_INCH
         );
     }
@@ -640,11 +538,11 @@ mod tests {
         let values = ComputedValues::default();
 
         assert_approx_eq_cairo!(
-            LengthHorizontal::new(0.05, LengthUnit::Percent).normalize(&values, &params),
+            Length::<Horizontal>::new(0.05, LengthUnit::Percent).normalize(&values, &params),
             5.0
         );
         assert_approx_eq_cairo!(
-            LengthVertical::new(0.05, LengthUnit::Percent).normalize(&values, &params),
+            Length::<Vertical>::new(0.05, LengthUnit::Percent).normalize(&values, &params),
             10.0
         );
     }
@@ -659,12 +557,12 @@ mod tests {
         // property and the way we compute Em/Ex from that.
 
         assert_approx_eq_cairo!(
-            LengthVertical::new(1.0, LengthUnit::Em).normalize(&values, &params),
+            Length::<Vertical>::new(1.0, LengthUnit::Em).normalize(&values, &params),
             12.0
         );
 
         assert_approx_eq_cairo!(
-            LengthVertical::new(1.0, LengthUnit::Ex).normalize(&values, &params),
+            Length::<Vertical>::new(1.0, LengthUnit::Ex).normalize(&values, &params),
             6.0
         );
     }
@@ -676,7 +574,7 @@ mod tests {
     #[test]
     fn parses_dash_array() {
         // helper to cut down boilderplate
-        let length_parse = |s| LengthBoth::parse_str(s).unwrap();
+        let length_parse = |s| Length::<Both>::parse_str(s).unwrap();
 
         let expected = Dasharray::Array(vec![
             length_parse("1"),
diff --git a/rsvg_internals/src/marker.rs b/rsvg_internals/src/marker.rs
index 265bbc5f..e181d865 100644
--- a/rsvg_internals/src/marker.rs
+++ b/rsvg_internals/src/marker.rs
@@ -13,7 +13,7 @@ use crate::drawing_ctx::DrawingCtx;
 use crate::error::*;
 use crate::float_eq_cairo::ApproxEqCairo;
 use crate::iri::IRI;
-use crate::length::{LengthHorizontal, LengthTrait, LengthVertical};
+use crate::length::*;
 use crate::node::*;
 use crate::parsers::{Parse, ParseError, ParseValue};
 use crate::path_builder::*;
@@ -90,10 +90,10 @@ impl Parse for MarkerOrient {
 
 pub struct Marker {
     units: MarkerUnits,
-    ref_x: LengthHorizontal,
-    ref_y: LengthVertical,
-    width: LengthHorizontal,
-    height: LengthVertical,
+    ref_x: Length<Horizontal>,
+    ref_y: Length<Vertical>,
+    width: Length<Horizontal>,
+    height: Length<Vertical>,
     orient: MarkerOrient,
     aspect: AspectRatio,
     vbox: Option<ViewBox>,
@@ -106,8 +106,8 @@ impl Default for Marker {
             ref_x: Default::default(),
             ref_y: Default::default(),
             // the following two are per the spec
-            width: LengthHorizontal::parse_str("3").unwrap(),
-            height: LengthVertical::parse_str("3").unwrap(),
+            width: Length::<Horizontal>::parse_str("3").unwrap(),
+            height: Length::<Vertical>::parse_str("3").unwrap(),
             orient: MarkerOrient::default(),
             aspect: AspectRatio::default(),
             vbox: None,
@@ -202,11 +202,11 @@ impl NodeTrait for Marker {
                 expanded_name!(svg "refY") => self.ref_y = attr.parse(value)?,
                 expanded_name!(svg "markerWidth") => {
                     self.width =
-                        attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?
+                        attr.parse_and_validate(value, Length::<Horizontal>::check_nonnegative)?
                 }
                 expanded_name!(svg "markerHeight") => {
                     self.height =
-                        attr.parse_and_validate(value, LengthVertical::check_nonnegative)?
+                        attr.parse_and_validate(value, Length::<Vertical>::check_nonnegative)?
                 }
                 expanded_name!(svg "orient") => self.orient = attr.parse(value)?,
                 expanded_name!(svg "preserveAspectRatio") => self.aspect = attr.parse(value)?,
diff --git a/rsvg_internals/src/mask.rs b/rsvg_internals/src/mask.rs
index 9f70114e..4f67d197 100644
--- a/rsvg_internals/src/mask.rs
+++ b/rsvg_internals/src/mask.rs
@@ -5,7 +5,7 @@ use crate::bbox::BoundingBox;
 use crate::coord_units::CoordUnits;
 use crate::drawing_ctx::{CompositingAffines, DrawingCtx};
 use crate::error::RenderingError;
-use crate::length::{LengthHorizontal, LengthTrait, LengthVertical};
+use crate::length::*;
 use crate::node::{CascadedValues, NodeDraw, NodeResult, NodeTrait, RsvgNode};
 use crate::parsers::{Parse, ParseValue};
 use crate::property_bag::PropertyBag;
@@ -16,10 +16,10 @@ coord_units!(MaskUnits, CoordUnits::ObjectBoundingBox);
 coord_units!(MaskContentUnits, CoordUnits::UserSpaceOnUse);
 
 pub struct Mask {
-    x: LengthHorizontal,
-    y: LengthVertical,
-    width: LengthHorizontal,
-    height: LengthVertical,
+    x: Length<Horizontal>,
+    y: Length<Vertical>,
+    width: Length<Horizontal>,
+    height: Length<Vertical>,
 
     units: MaskUnits,
     content_units: MaskContentUnits,
@@ -29,10 +29,10 @@ impl Default for Mask {
     fn default() -> Mask {
         Mask {
             // these values are per the spec
-            x: LengthHorizontal::parse_str("-10%").unwrap(),
-            y: LengthVertical::parse_str("-10%").unwrap(),
-            width: LengthHorizontal::parse_str("120%").unwrap(),
-            height: LengthVertical::parse_str("120%").unwrap(),
+            x: Length::<Horizontal>::parse_str("-10%").unwrap(),
+            y: Length::<Vertical>::parse_str("-10%").unwrap(),
+            width: Length::<Horizontal>::parse_str("120%").unwrap(),
+            height: Length::<Vertical>::parse_str("120%").unwrap(),
 
             units: MaskUnits::default(),
             content_units: MaskContentUnits::default(),
@@ -145,11 +145,11 @@ impl NodeTrait for Mask {
                 expanded_name!(svg "y") => self.y = attr.parse(value)?,
                 expanded_name!(svg "width") => {
                     self.width =
-                        attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?
+                        attr.parse_and_validate(value, Length::<Horizontal>::check_nonnegative)?
                 }
                 expanded_name!(svg "height") => {
                     self.height =
-                        attr.parse_and_validate(value, LengthVertical::check_nonnegative)?
+                        attr.parse_and_validate(value, Length::<Vertical>::check_nonnegative)?
                 }
                 expanded_name!(svg "maskUnits") => self.units = attr.parse(value)?,
                 expanded_name!(svg "maskContentUnits") => self.content_units = attr.parse(value)?,
diff --git a/rsvg_internals/src/pattern.rs b/rsvg_internals/src/pattern.rs
index 91bbe4b4..f68b81a8 100644
--- a/rsvg_internals/src/pattern.rs
+++ b/rsvg_internals/src/pattern.rs
@@ -34,10 +34,10 @@ struct Common {
     vbox: Option<Option<ViewBox>>,
     preserve_aspect_ratio: Option<AspectRatio>,
     affine: Option<cairo::Matrix>,
-    x: Option<LengthHorizontal>,
-    y: Option<LengthVertical>,
-    width: Option<LengthHorizontal>,
-    height: Option<LengthVertical>,
+    x: Option<Length<Horizontal>>,
+    y: Option<Length<Vertical>>,
+    width: Option<Length<Horizontal>>,
+    height: Option<Length<Vertical>>,
 }
 
 /// State used during the pattern resolution process
@@ -98,10 +98,10 @@ pub struct ResolvedPattern {
     vbox: Option<ViewBox>,
     preserve_aspect_ratio: AspectRatio,
     affine: cairo::Matrix,
-    x: LengthHorizontal,
-    y: LengthVertical,
-    width: LengthHorizontal,
-    height: LengthVertical,
+    x: Length<Horizontal>,
+    y: Length<Vertical>,
+    width: Length<Horizontal>,
+    height: Length<Vertical>,
 
     // Link to the node whose children are the pattern's resolved children.
     children: Children,
@@ -134,11 +134,11 @@ impl NodeTrait for Pattern {
                 expanded_name!(svg "y") => self.common.y = Some(attr.parse(value)?),
                 expanded_name!(svg "width") => {
                     self.common.width =
-                        Some(attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?)
+                        Some(attr.parse_and_validate(value, Length::<Horizontal>::check_nonnegative)?)
                 }
                 expanded_name!(svg "height") => {
                     self.common.height =
-                        Some(attr.parse_and_validate(value, LengthVertical::check_nonnegative)?)
+                        Some(attr.parse_and_validate(value, Length::<Vertical>::check_nonnegative)?)
                 }
                 _ => (),
             }
diff --git a/rsvg_internals/src/property_defs.rs b/rsvg_internals/src/property_defs.rs
index f5802b5f..70a415da 100644
--- a/rsvg_internals/src/property_defs.rs
+++ b/rsvg_internals/src/property_defs.rs
@@ -3,7 +3,7 @@ use cssparser::{self, Parser, Token};
 use crate::error::*;
 use crate::font_props::{FontSizeSpec, FontWeightSpec, LetterSpacingSpec, SingleFontFamily};
 use crate::iri::IRI;
-use crate::length::{Dasharray, LengthBoth, LengthTrait, LengthUnit};
+use crate::length::*;
 use crate::paint_server::PaintServer;
 use crate::parsers::{Parse, ParseError};
 use crate::properties::ComputedValues;
@@ -14,8 +14,8 @@ use crate::unit_interval::UnitInterval;
 make_property!(
     ComputedValues,
     BaselineShift,
-    default: LengthBoth::parse_str("0.0").unwrap(),
-    newtype: LengthBoth,
+    default: Length::<Both>::parse_str("0.0").unwrap(),
+    newtype: Length<Both>,
     property_impl: {
         impl Property<ComputedValues> for BaselineShift {
             fn inherits_automatically() -> bool {
@@ -29,11 +29,11 @@ make_property!(
                 // 1) we only handle 'percent' shifts, but it could also be an absolute offset
                 // 2) we should be able to normalize the lengths and add even if they have
                 //    different units, but at the moment that requires access to the draw_ctx
-                if self.0.unit() != LengthUnit::Percent || v.baseline_shift.0.unit() != font_size.unit() {
-                    return BaselineShift(LengthBoth::new(v.baseline_shift.0.length(), 
v.baseline_shift.0.unit()));
+                if self.0.unit != LengthUnit::Percent || v.baseline_shift.0.unit != font_size.unit {
+                    return BaselineShift(Length::<Both>::new(v.baseline_shift.0.length, 
v.baseline_shift.0.unit));
                 }
 
-                BaselineShift(LengthBoth::new(self.0.length() * font_size.length() + 
v.baseline_shift.0.length(), font_size.unit()))
+                BaselineShift(Length::<Both>::new(self.0.length * font_size.length + 
v.baseline_shift.0.length, font_size.unit))
             }
         }
     },
@@ -54,15 +54,15 @@ make_property!(
                     if let Token::Ident(ref cow) = token {
                         match cow.as_ref() {
                             "baseline" => return Ok(BaselineShift(
-                                LengthBoth::new(0.0, LengthUnit::Percent)
+                                Length::<Both>::new(0.0, LengthUnit::Percent)
                             )),
 
                             "sub" => return Ok(BaselineShift(
-                                LengthBoth::new(-0.2, LengthUnit::Percent)
+                                Length::<Both>::new(-0.2, LengthUnit::Percent)
                             )),
 
                             "super" => return Ok(BaselineShift(
-                                LengthBoth::new(0.4, LengthUnit::Percent),
+                                Length::<Both>::new(0.4, LengthUnit::Percent),
                             )),
 
                             _ => (),
@@ -72,7 +72,7 @@ make_property!(
 
                 parser.reset(&parser_state);
 
-                Ok(BaselineShift(LengthBoth::parse(parser)?))
+                Ok(BaselineShift(Length::<Both>::parse(parser)?))
             }
         }
     }
@@ -248,7 +248,7 @@ make_property!(
 make_property!(
     ComputedValues,
     FontSize,
-    default: FontSizeSpec::Value(LengthBoth::parse_str("12.0").unwrap()),
+    default: FontSizeSpec::Value(Length::<Both>::parse_str("12.0").unwrap()),
     newtype_parse: FontSizeSpec,
     property_impl: {
         impl Property<ComputedValues> for FontSize {
@@ -467,9 +467,9 @@ make_property!(
 make_property!(
     ComputedValues,
     StrokeDashoffset,
-    default: LengthBoth::default(),
+    default: Length::<Both>::default(),
     inherits_automatically: true,
-    newtype_parse: LengthBoth,
+    newtype_parse: Length<Both>,
 );
 
 // https://www.w3.org/TR/SVG/painting.html#StrokeLinecapProperty
@@ -520,9 +520,9 @@ make_property!(
 make_property!(
     ComputedValues,
     StrokeWidth,
-    default: LengthBoth::parse_str("1.0").unwrap(),
+    default: Length::<Both>::parse_str("1.0").unwrap(),
     inherits_automatically: true,
-    newtype_parse: LengthBoth,
+    newtype_parse: Length::<Both>,
 );
 
 // https://www.w3.org/TR/SVG/text.html#TextAnchorProperty
diff --git a/rsvg_internals/src/shapes.rs b/rsvg_internals/src/shapes.rs
index e0a91f62..8443c25a 100644
--- a/rsvg_internals/src/shapes.rs
+++ b/rsvg_internals/src/shapes.rs
@@ -286,10 +286,10 @@ impl NodeTrait for Polyline {
 
 #[derive(Default)]
 pub struct Line {
-    x1: LengthHorizontal,
-    y1: LengthVertical,
-    x2: LengthHorizontal,
-    y2: LengthVertical,
+    x1: Length<Horizontal>,
+    y1: Length<Vertical>,
+    x2: Length<Horizontal>,
+    y2: Length<Vertical>,
 }
 
 impl NodeTrait for Line {
@@ -334,14 +334,14 @@ impl NodeTrait for Line {
 
 #[derive(Default)]
 pub struct Rect {
-    x: LengthHorizontal,
-    y: LengthVertical,
-    w: LengthHorizontal,
-    h: LengthVertical,
+    x: Length<Horizontal>,
+    y: Length<Vertical>,
+    w: Length<Horizontal>,
+    h: Length<Vertical>,
 
     // Radiuses for rounded corners
-    rx: Option<LengthHorizontal>,
-    ry: Option<LengthVertical>,
+    rx: Option<Length<Horizontal>>,
+    ry: Option<Length<Vertical>>,
 }
 
 impl NodeTrait for Rect {
@@ -351,19 +351,19 @@ impl NodeTrait for Rect {
                 expanded_name!(svg "x") => self.x = attr.parse(value)?,
                 expanded_name!(svg "y") => self.y = attr.parse(value)?,
                 expanded_name!(svg "width") => {
-                    self.w = attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?
+                    self.w = attr.parse_and_validate(value, Length::<Horizontal>::check_nonnegative)?
                 }
                 expanded_name!(svg "height") => {
-                    self.h = attr.parse_and_validate(value, LengthVertical::check_nonnegative)?
+                    self.h = attr.parse_and_validate(value, Length::<Vertical>::check_nonnegative)?
                 }
                 expanded_name!(svg "rx") => {
                     self.rx = attr
-                        .parse_and_validate(value, LengthHorizontal::check_nonnegative)
+                        .parse_and_validate(value, Length::<Horizontal>::check_nonnegative)
                         .map(Some)?
                 }
                 expanded_name!(svg "ry") => {
                     self.ry = attr
-                        .parse_and_validate(value, LengthVertical::check_nonnegative)
+                        .parse_and_validate(value, Length::<Vertical>::check_nonnegative)
                         .map(Some)?
                 }
                 _ => (),
@@ -555,9 +555,9 @@ impl NodeTrait for Rect {
 
 #[derive(Default)]
 pub struct Circle {
-    cx: LengthHorizontal,
-    cy: LengthVertical,
-    r: LengthBoth,
+    cx: Length<Horizontal>,
+    cy: Length<Vertical>,
+    r: Length<Both>,
 }
 
 impl NodeTrait for Circle {
@@ -567,7 +567,7 @@ impl NodeTrait for Circle {
                 expanded_name!(svg "cx") => self.cx = attr.parse(value)?,
                 expanded_name!(svg "cy") => self.cy = attr.parse(value)?,
                 expanded_name!(svg "r") => {
-                    self.r = attr.parse_and_validate(value, LengthBoth::check_nonnegative)?
+                    self.r = attr.parse_and_validate(value, Length::<Both>::check_nonnegative)?
                 }
                 _ => (),
             }
@@ -597,10 +597,10 @@ impl NodeTrait for Circle {
 
 #[derive(Default)]
 pub struct Ellipse {
-    cx: LengthHorizontal,
-    cy: LengthVertical,
-    rx: LengthHorizontal,
-    ry: LengthVertical,
+    cx: Length<Horizontal>,
+    cy: Length<Vertical>,
+    rx: Length<Horizontal>,
+    ry: Length<Vertical>,
 }
 
 impl NodeTrait for Ellipse {
@@ -610,10 +610,10 @@ impl NodeTrait for Ellipse {
                 expanded_name!(svg "cx") => self.cx = attr.parse(value)?,
                 expanded_name!(svg "cy") => self.cy = attr.parse(value)?,
                 expanded_name!(svg "rx") => {
-                    self.rx = attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?
+                    self.rx = attr.parse_and_validate(value, Length::<Horizontal>::check_nonnegative)?
                 }
                 expanded_name!(svg "ry") => {
-                    self.ry = attr.parse_and_validate(value, LengthVertical::check_nonnegative)?
+                    self.ry = attr.parse_and_validate(value, Length::<Vertical>::check_nonnegative)?
                 }
                 _ => (),
             }
diff --git a/rsvg_internals/src/structure.rs b/rsvg_internals/src/structure.rs
index 0a894eb5..02c6aa6e 100644
--- a/rsvg_internals/src/structure.rs
+++ b/rsvg_internals/src/structure.rs
@@ -87,18 +87,18 @@ impl NodeTrait for Switch {
 /// Intrinsic dimensions of an SVG document fragment
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub struct IntrinsicDimensions {
-    pub width: Option<Length>,
-    pub height: Option<Length>,
+    pub width: Option<Length<Horizontal>>,
+    pub height: Option<Length<Vertical>>,
     pub vbox: Option<ViewBox>,
 }
 
 #[derive(Default)]
 pub struct Svg {
     preserve_aspect_ratio: AspectRatio,
-    x: Option<LengthHorizontal>,
-    y: Option<LengthVertical>,
-    w: Option<LengthHorizontal>,
-    h: Option<LengthVertical>,
+    x: Option<Length<Horizontal>>,
+    y: Option<Length<Vertical>>,
+    w: Option<Length<Horizontal>>,
+    h: Option<Length<Vertical>>,
     vbox: Option<ViewBox>,
 }
 
@@ -116,7 +116,7 @@ impl Svg {
                 ))
             }
 
-            (w, h, None) if w.unit() != LengthUnit::Percent && h.unit() != LengthUnit::Percent => {
+            (w, h, None) if w.unit != LengthUnit::Percent && h.unit != LengthUnit::Percent => {
                 let params = ViewParams::new(dpi.x(), dpi.y(), 0.0, 0.0);
 
                 Some((
@@ -130,8 +130,8 @@ impl Svg {
 
     pub fn get_intrinsic_dimensions(&self) -> IntrinsicDimensions {
         IntrinsicDimensions {
-            width: self.w.map(|l| l.to_length()),
-            height: self.h.map(|l| l.to_length()),
+            width: self.w.map(Into::into),
+            height: self.h.map(Into::into),
             vbox: self.vbox,
         }
     }
@@ -140,24 +140,24 @@ impl Svg {
     fn get_unnormalized_viewport(
         &self,
     ) -> (
-        LengthHorizontal,
-        LengthVertical,
-        LengthHorizontal,
-        LengthVertical,
+        Length<Horizontal>,
+        Length<Vertical>,
+        Length<Horizontal>,
+        Length<Vertical>,
     ) {
         // these defaults are per the spec
         let x = self
             .x
-            .unwrap_or_else(|| LengthHorizontal::parse_str("0").unwrap());
+            .unwrap_or_else(|| Length::<Horizontal>::parse_str("0").unwrap());
         let y = self
             .y
-            .unwrap_or_else(|| LengthVertical::parse_str("0").unwrap());
+            .unwrap_or_else(|| Length::<Vertical>::parse_str("0").unwrap());
         let w = self
             .w
-            .unwrap_or_else(|| LengthHorizontal::parse_str("100%").unwrap());
+            .unwrap_or_else(|| Length::<Horizontal>::parse_str("100%").unwrap());
         let h = self
             .h
-            .unwrap_or_else(|| LengthVertical::parse_str("100%").unwrap());
+            .unwrap_or_else(|| Length::<Vertical>::parse_str("100%").unwrap());
 
         (x, y, w, h)
     }
@@ -189,11 +189,11 @@ impl NodeTrait for Svg {
                 expanded_name!(svg "y") if is_inner_svg => self.y = Some(attr.parse(value)?),
                 expanded_name!(svg "width") => {
                     self.w =
-                        Some(attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?)
+                        Some(attr.parse_and_validate(value, Length::<Horizontal>::check_nonnegative)?)
                 }
                 expanded_name!(svg "height") => {
                     self.h =
-                        Some(attr.parse_and_validate(value, LengthVertical::check_nonnegative)?)
+                        Some(attr.parse_and_validate(value, Length::<Vertical>::check_nonnegative)?)
                 }
                 expanded_name!(svg "viewBox") => self.vbox = attr.parse(value).map(Some)?,
                 _ => (),
@@ -266,10 +266,10 @@ impl NodeTrait for Svg {
 #[derive(Default)]
 pub struct Use {
     link: Option<Fragment>,
-    x: LengthHorizontal,
-    y: LengthVertical,
-    w: Option<LengthHorizontal>,
-    h: Option<LengthVertical>,
+    x: Length<Horizontal>,
+    y: Length<Vertical>,
+    w: Option<Length<Horizontal>>,
+    h: Option<Length<Vertical>>,
 }
 
 impl NodeTrait for Use {
@@ -283,12 +283,12 @@ impl NodeTrait for Use {
                 expanded_name!(svg "y") => self.y = attr.parse(value)?,
                 expanded_name!(svg "width") => {
                     self.w = attr
-                        .parse_and_validate(value, LengthHorizontal::check_nonnegative)
+                        .parse_and_validate(value, Length::<Horizontal>::check_nonnegative)
                         .map(Some)?
                 }
                 expanded_name!(svg "height") => {
                     self.h = attr
-                        .parse_and_validate(value, LengthVertical::check_nonnegative)
+                        .parse_and_validate(value, Length::<Vertical>::check_nonnegative)
                         .map(Some)?
                 }
                 _ => (),
@@ -363,11 +363,11 @@ impl NodeTrait for Use {
 
         let nw = self
             .w
-            .unwrap_or_else(|| LengthHorizontal::parse_str("100%").unwrap())
+            .unwrap_or_else(|| Length::<Horizontal>::parse_str("100%").unwrap())
             .normalize(values, &params);
         let nh = self
             .h
-            .unwrap_or_else(|| LengthVertical::parse_str("100%").unwrap())
+            .unwrap_or_else(|| Length::<Vertical>::parse_str("100%").unwrap())
             .normalize(values, &params);
 
         // width or height set to 0 disables rendering of the element
diff --git a/rsvg_internals/src/text.rs b/rsvg_internals/src/text.rs
index 3807e664..29f13c84 100644
--- a/rsvg_internals/src/text.rs
+++ b/rsvg_internals/src/text.rs
@@ -45,15 +45,15 @@ use crate::space::{xml_space_normalize, NormalizeDefault, XmlSpaceNormalize};
 /// [text chunk]: https://www.w3.org/TR/SVG11/text.html#TextLayoutIntroduction
 struct Chunk {
     values: ComputedValues,
-    x: Option<LengthHorizontal>,
-    y: Option<LengthVertical>,
+    x: Option<Length<Horizontal>>,
+    y: Option<Length<Vertical>>,
     spans: Vec<Span>,
 }
 
 struct MeasuredChunk {
     values: ComputedValues,
-    x: Option<LengthHorizontal>,
-    y: Option<LengthVertical>,
+    x: Option<Length<Horizontal>>,
+    y: Option<Length<Vertical>>,
     advance: (f64, f64),
     spans: Vec<MeasuredSpan>,
 }
@@ -67,8 +67,8 @@ struct PositionedChunk {
 struct Span {
     values: ComputedValues,
     text: String,
-    dx: Option<LengthHorizontal>,
-    dy: Option<LengthVertical>,
+    dx: Option<Length<Horizontal>>,
+    dy: Option<Length<Vertical>>,
     _depth: usize,
 }
 
@@ -77,8 +77,8 @@ struct MeasuredSpan {
     layout: pango::Layout,
     _layout_size: (f64, f64),
     advance: (f64, f64),
-    dx: Option<LengthHorizontal>,
-    dy: Option<LengthVertical>,
+    dx: Option<Length<Horizontal>>,
+    dy: Option<Length<Vertical>>,
 }
 
 struct PositionedSpan {
@@ -93,8 +93,8 @@ struct PositionedSpan {
 impl Chunk {
     fn new(
         values: &ComputedValues,
-        x: Option<LengthHorizontal>,
-        y: Option<LengthVertical>,
+        x: Option<Length<Horizontal>>,
+        y: Option<Length<Vertical>>,
     ) -> Chunk {
         Chunk {
             values: values.clone(),
@@ -190,8 +190,8 @@ impl Span {
     fn new(
         text: &str,
         values: ComputedValues,
-        dx: Option<LengthHorizontal>,
-        dy: Option<LengthVertical>,
+        dx: Option<Length<Horizontal>>,
+        dy: Option<Length<Vertical>>,
         depth: usize,
     ) -> Span {
         Span {
@@ -422,8 +422,8 @@ fn children_to_chunks(
     node: &RsvgNode,
     cascaded: &CascadedValues<'_>,
     draw_ctx: &mut DrawingCtx,
-    dx: Option<LengthHorizontal>,
-    dy: Option<LengthVertical>,
+    dx: Option<Length<Horizontal>>,
+    dy: Option<Length<Vertical>>,
     depth: usize,
 ) {
     for child in node.children() {
@@ -529,8 +529,8 @@ impl NodeChars {
         &self,
         node: &RsvgNode,
         values: &ComputedValues,
-        dx: Option<LengthHorizontal>,
-        dy: Option<LengthVertical>,
+        dx: Option<Length<Horizontal>>,
+        dy: Option<Length<Vertical>>,
         depth: usize,
     ) -> Span {
         self.ensure_normalized_string(node, values);
@@ -549,8 +549,8 @@ impl NodeChars {
         node: &RsvgNode,
         values: &ComputedValues,
         chunks: &mut Vec<Chunk>,
-        dx: Option<LengthHorizontal>,
-        dy: Option<LengthVertical>,
+        dx: Option<Length<Horizontal>>,
+        dy: Option<Length<Vertical>>,
         depth: usize,
     ) {
         let span = self.make_span(&node, values, dx, dy, depth);
@@ -574,10 +574,10 @@ impl NodeTrait for NodeChars {
 
 #[derive(Default)]
 pub struct Text {
-    x: LengthHorizontal,
-    y: LengthVertical,
-    dx: Option<LengthHorizontal>,
-    dy: Option<LengthVertical>,
+    x: Length<Horizontal>,
+    y: Length<Vertical>,
+    dx: Option<Length<Horizontal>>,
+    dy: Option<Length<Vertical>>,
 }
 
 impl Text {
@@ -729,10 +729,10 @@ impl NodeTrait for TRef {
 
 #[derive(Default)]
 pub struct TSpan {
-    x: Option<LengthHorizontal>,
-    y: Option<LengthVertical>,
-    dx: Option<LengthHorizontal>,
-    dy: Option<LengthVertical>,
+    x: Option<Length<Horizontal>>,
+    y: Option<Length<Vertical>>,
+    dx: Option<Length<Horizontal>>,
+    dy: Option<Length<Vertical>>,
 }
 
 impl TSpan {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]