[librsvg] New macro coord_units! to create newtypes over CoordUnits with a default value



commit f06ae87ff5910ea4bba9e8fd99b18a7e2d93f906
Author: Federico Mena Quintero <federico gnome org>
Date:   Fri Dec 1 08:00:39 2017 -0600

    New macro coord_units! to create newtypes over CoordUnits with a default value
    
    Different SVG elements have attributes that can take "userSpaceOnUse"
    or "objectBoundingBox" as a value; that's our CoordUnits enum.
    
    However, those different SVG elements/attributes have different
    defaults among those two possible values.
    
    Now we have a macro coord_units! that defines a newtype around
    CoordUnits, and provides an `impl Default` with a user-provided
    default value.  The idea is that each SVG element/attribute will
    call coord_units! to create a suitable type for itself, with the
    default value it needs.

 Makefile.am              |    1 +
 rust/src/clip_path.rs    |   11 +++---
 rust/src/coord_units.rs  |   83 ++++++++++++++++++++++++++++++++++++++++++++++
 rust/src/gradient.rs     |   25 ++++++++------
 rust/src/lib.rs          |    3 ++
 rust/src/paint_server.rs |   43 ------------------------
 rust/src/pattern.rs      |   54 +++++++----------------------
 7 files changed, 119 insertions(+), 101 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index cf9d5d1..b4a4225 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -74,6 +74,7 @@ RUST_SOURCES =                                        \
        rust/src/clip_path.rs                   \
        rust/src/cnode.rs                       \
        rust/src/color.rs                       \
+       rust/src/coord_units.rs                 \
        rust/src/drawing_ctx.rs                 \
        rust/src/error.rs                       \
        rust/src/gradient.rs                    \
diff --git a/rust/src/clip_path.rs b/rust/src/clip_path.rs
index 6f7a819..0a3eab0 100644
--- a/rust/src/clip_path.rs
+++ b/rust/src/clip_path.rs
@@ -4,11 +4,10 @@ use std::cell::Cell;
 use drawing_ctx::RsvgDrawingCtx;
 use handle::RsvgHandle;
 use node::{NodeResult, NodeTrait, NodeType, RsvgCNodeImpl, RsvgNode, boxed_node_new};
-use paint_server::CoordUnits;
-use pattern::PatternContentUnits;
+use coord_units::CoordUnits;
 use property_bag::{self, RsvgPropertyBag};
 
-type ClipPathUnits = PatternContentUnits;
+coord_units!(ClipPathUnits, CoordUnits::UserSpaceOnUse);
 
 struct NodeClipPath {
     units: Cell<ClipPathUnits>
@@ -17,7 +16,7 @@ struct NodeClipPath {
 impl NodeClipPath {
     fn new() -> NodeClipPath {
         NodeClipPath {
-            units: Cell::new(PatternContentUnits::from(CoordUnits::UserSpaceOnUse))
+            units: Cell::new(ClipPathUnits::default())
         }
     }
 }
@@ -50,11 +49,11 @@ pub extern fn rsvg_node_clip_path_get_units(raw_node: *const RsvgNode) -> CoordU
     assert! (!raw_node.is_null ());
     let node: &RsvgNode = unsafe { & *raw_node };
 
-    let mut units = PatternContentUnits::default();
+    let mut units = ClipPathUnits::default();
 
     node.with_impl(|clip_path: &NodeClipPath| {
         units = clip_path.units.get();
     });
 
-    units.0
+    CoordUnits::from(units)
 }
diff --git a/rust/src/coord_units.rs b/rust/src/coord_units.rs
new file mode 100644
index 0000000..564e232
--- /dev/null
+++ b/rust/src/coord_units.rs
@@ -0,0 +1,83 @@
+use error::AttributeError;
+use parsers::{Parse, ParseError};
+
+/// Defines the units to be used for things that can consider a
+/// coordinate system in terms of the current transformation, or in
+/// terms of the current object's bounding box.
+///
+/// Keep in sync with rsvg-private.h:RsvgCoordUnits
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum CoordUnits {
+    UserSpaceOnUse,
+    ObjectBoundingBox
+}
+
+impl Parse for CoordUnits {
+    type Data = ();
+    type Err = AttributeError;
+
+    fn parse (s: &str, _: ()) -> Result<CoordUnits, AttributeError> {
+        match s {
+            "userSpaceOnUse"    => Ok (CoordUnits::UserSpaceOnUse),
+            "objectBoundingBox" => Ok (CoordUnits::ObjectBoundingBox),
+            _                   => Err (AttributeError::Parse (ParseError::new ("expected 'userSpaceOnUse' 
or 'objectBoundingBox'")))
+        }
+    }
+}
+
+/// Creates a newtype around `CoordUnits`, with a default value.
+///
+/// SVG attributes that can take `userSpaceOnUse` or
+/// `objectBoundingBox` values often have different default values
+/// depending on the type of SVG element.  We use this macro to create
+/// a newtype for each SVG element and attribute that requires values
+/// of this type.  The newtype provides an `impl Default` with the
+/// specified `$default` value.
+#[macro_export]
+macro_rules! coord_units {
+    ($name:ident, $default:expr) => {
+        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
+        struct $name(CoordUnits);
+
+        impl Default for $name {
+            fn default() -> Self {
+                $name($default)
+            }
+        }
+
+        impl From<$name> for CoordUnits {
+            fn from(u: $name) -> Self {
+                u.0
+            }
+        }
+
+        impl $crate::parsers::Parse for $name {
+            type Data = ();
+            type Err = $crate::error::AttributeError;
+
+            fn parse(s: &str, _: ()) -> Result<Self, $crate::error::AttributeError> {
+                Ok($name($crate::coord_units::CoordUnits::parse(s, ())?))
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    coord_units!(MyUnits, CoordUnits::ObjectBoundingBox);
+
+    #[test]
+    fn parsing_invalid_strings_yields_error () {
+        assert! (MyUnits::parse ("", ()).is_err ());
+        assert! (MyUnits::parse ("foo", ()).is_err ());
+    }
+
+    #[test]
+    fn parses_paint_server_units () {
+        assert_eq! (MyUnits::parse ("userSpaceOnUse", ()), Ok (MyUnits(CoordUnits::UserSpaceOnUse)));
+        assert_eq! (MyUnits::parse ("objectBoundingBox", ()), Ok (MyUnits(CoordUnits::ObjectBoundingBox)));
+    }
+}
diff --git a/rust/src/gradient.rs b/rust/src/gradient.rs
index d4fa8e3..c52a07c 100644
--- a/rust/src/gradient.rs
+++ b/rust/src/gradient.rs
@@ -8,6 +8,7 @@ use std::cell::RefCell;
 use cairo::MatrixTrait;
 
 use bbox::*;
+use coord_units::CoordUnits;
 use drawing_ctx;
 use drawing_ctx::RsvgDrawingCtx;
 use handle::RsvgHandle;
@@ -22,18 +23,20 @@ use util::*;
 
 
 #[derive(Copy, Clone)]
-pub struct ColorStop {
+struct ColorStop {
     pub offset: f64,
     pub rgba:   u32
 }
 
+coord_units!(GradientUnits, CoordUnits::ObjectBoundingBox);
+
 /* Any of the attributes in gradient elements may be omitted.  In turn, the missing
  * ones can be inherited from the gradient referenced by its "fallback" IRI.  We
  * represent these possibly-missing attributes as Option<foo>.
  */
 #[derive(Clone)]
-pub struct GradientCommon {
-    pub units:    Option<CoordUnits>,
+struct GradientCommon {
+    pub units:    Option<GradientUnits>,
     pub affine:   Option<cairo::Matrix>,
     pub spread:   Option<PaintServerSpread>,
     pub fallback: Option<String>,
@@ -41,7 +44,7 @@ pub struct GradientCommon {
 }
 
 #[derive(Copy, Clone)]
-pub enum GradientVariant {
+enum GradientVariant {
     Linear {
         x1: Option<RsvgLength>,
         y1: Option<RsvgLength>,
@@ -59,7 +62,7 @@ pub enum GradientVariant {
 }
 
 #[derive(Clone)]
-pub struct Gradient {
+struct Gradient {
     pub common: GradientCommon,
     pub variant: GradientVariant
 }
@@ -118,7 +121,7 @@ impl GradientCommon {
     fn resolve_from_defaults (&mut self) {
         /* These are per the spec */
 
-        fallback_to! (self.units,  Some (CoordUnits::default ()));
+        fallback_to! (self.units,  Some (GradientUnits::default ()));
         fallback_to! (self.affine, Some (cairo::Matrix::identity ()));
         fallback_to! (self.spread, Some (PaintServerSpread::default ()));
         fallback_to! (self.stops,  Some (Vec::<ColorStop>::new ())); // empty array of color stops
@@ -362,7 +365,7 @@ fn set_common_on_pattern<P: cairo::Pattern + cairo::Gradient> (gradient: &Gradie
 
     let units = gradient.common.units.unwrap ();
 
-    if units == CoordUnits::ObjectBoundingBox {
+    if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
         let bbox_matrix = cairo::Matrix::new (bbox.rect.width, 0.0,
                                               0.0, bbox.rect.height,
                                               bbox.rect.x, bbox.rect.y);
@@ -385,7 +388,7 @@ fn set_linear_gradient_on_pattern (gradient: &Gradient,
     if let GradientVariant::Linear { x1, y1, x2, y2 } = gradient.variant {
         let units = gradient.common.units.unwrap ();
 
-        if units == CoordUnits::ObjectBoundingBox {
+        if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
             drawing_ctx::push_view_box (draw_ctx, 1.0, 1.0);
         }
 
@@ -394,7 +397,7 @@ fn set_linear_gradient_on_pattern (gradient: &Gradient,
                                                       x2.as_ref ().unwrap ().normalize (draw_ctx),
                                                       y2.as_ref ().unwrap ().normalize (draw_ctx));
 
-        if units == CoordUnits::ObjectBoundingBox {
+        if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
             drawing_ctx::pop_view_box (draw_ctx);
         }
 
@@ -467,7 +470,7 @@ fn set_radial_gradient_on_pattern (gradient: &Gradient,
     if let GradientVariant::Radial { cx, cy, r, fx, fy } = gradient.variant {
         let units = gradient.common.units.unwrap ();
 
-        if units == CoordUnits::ObjectBoundingBox {
+        if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
             drawing_ctx::push_view_box (draw_ctx, 1.0, 1.0);
         }
 
@@ -481,7 +484,7 @@ fn set_radial_gradient_on_pattern (gradient: &Gradient,
 
         let mut pattern = cairo::RadialGradient::new (new_fx, new_fy, 0.0, n_cx, n_cy, n_r);
 
-        if units == CoordUnits::ObjectBoundingBox {
+        if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
             drawing_ctx::pop_view_box (draw_ctx);
         }
 
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 52721d8..46f1059 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -133,6 +133,9 @@ pub use viewbox::{
 };
 
 
+#[macro_use]
+mod coord_units;
+
 mod aspect_ratio;
 mod bbox;
 mod clip_path;
diff --git a/rust/src/paint_server.rs b/rust/src/paint_server.rs
index 10f4d8b..b624644 100644
--- a/rust/src/paint_server.rs
+++ b/rust/src/paint_server.rs
@@ -4,37 +4,6 @@ use error::*;
 use parsers::Parse;
 use parsers::ParseError;
 
-/// Defines the units to be used for scaling paint servers, per the [svg specification].
-///
-/// [svg spec]: https://www.w3.org/TR/SVG/pservers.html
-///
-/// Keep in sync with rsvg-private.h:RsvgCoordUnits
-#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum CoordUnits {
-    UserSpaceOnUse,
-    ObjectBoundingBox
-}
-
-impl Parse for CoordUnits {
-    type Data = ();
-    type Err = AttributeError;
-
-    fn parse (s: &str, _: ()) -> Result<CoordUnits, AttributeError> {
-        match s {
-            "userSpaceOnUse"    => Ok (CoordUnits::UserSpaceOnUse),
-            "objectBoundingBox" => Ok (CoordUnits::ObjectBoundingBox),
-            _                   => Err (AttributeError::Parse (ParseError::new ("expected 'userSpaceOnUse' 
or 'objectBoundingBox'")))
-        }
-    }
-}
-
-impl Default for CoordUnits {
-    fn default () -> CoordUnits {
-        CoordUnits::ObjectBoundingBox
-    }
-}
-
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub struct PaintServerSpread (pub cairo::enums::Extend);
 
@@ -63,18 +32,6 @@ mod tests {
     use super::*;
 
     #[test]
-    fn parsing_invalid_strings_yields_error () {
-        assert! (CoordUnits::parse ("", ()).is_err ());
-        assert! (CoordUnits::parse ("foo", ()).is_err ());
-    }
-
-    #[test]
-    fn parses_paint_server_units () {
-        assert_eq! (CoordUnits::parse ("userSpaceOnUse", ()), Ok (CoordUnits::UserSpaceOnUse));
-        assert_eq! (CoordUnits::parse ("objectBoundingBox", ()), Ok (CoordUnits::ObjectBoundingBox));
-    }
-
-    #[test]
     fn parses_spread_method () {
         assert_eq! (PaintServerSpread::parse ("pad", ()),
                     Ok (PaintServerSpread (cairo::enums::Extend::Pad)));
diff --git a/rust/src/pattern.rs b/rust/src/pattern.rs
index 79ce689..5822ee6 100644
--- a/rust/src/pattern.rs
+++ b/rust/src/pattern.rs
@@ -11,22 +11,23 @@ use cairo::Pattern as CairoPattern;
 
 use aspect_ratio::*;
 use bbox::*;
+use coord_units::CoordUnits;
 use drawing_ctx;
 use drawing_ctx::RsvgDrawingCtx;
-use error::*;
 use handle::RsvgHandle;
 use length::*;
 use node::*;
-use paint_server::*;
-use parsers::Parse;
 use property_bag;
 use property_bag::*;
 use util::*;
 use viewbox::*;
 
+coord_units!(PatternUnits, CoordUnits::ObjectBoundingBox);
+coord_units!(PatternContentUnits, CoordUnits::UserSpaceOnUse);
+
 #[derive(Clone)]
-pub struct Pattern {
-    pub units:                 Option<CoordUnits>,
+ struct Pattern {
+    pub units:                 Option<PatternUnits>,
     pub content_units:         Option<PatternContentUnits>,
     // This Option<Option<ViewBox>> is a bit strange.  We want a field
     // with value None to mean, "this field isn't resolved yet".  However,
@@ -63,35 +64,6 @@ impl Default for Pattern {
     }
 }
 
-// A pattern's patternUnits attribute (in our Pattern::units field) defines the coordinate
-// system relative to the x/y/width/height of the Pattern.  However, patterns also
-// have a patternContentUnits attribute, which refers to the pattern's contents (i.e. the
-// objects which it references.  We define PatternContentUnits as a newtype, so that
-// it can have its own default value, different from the one in CoordUnits.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct PatternContentUnits(pub CoordUnits);
-
-impl From<CoordUnits> for PatternContentUnits {
-    fn from (units: CoordUnits) -> PatternContentUnits {
-        PatternContentUnits(units)
-    }
-}
-
-impl Default for PatternContentUnits {
-    fn default () -> PatternContentUnits {
-        PatternContentUnits (CoordUnits::UserSpaceOnUse)
-    }
-}
-
-impl Parse for PatternContentUnits {
-    type Data = ();
-    type Err = AttributeError;
-
-    fn parse (s: &str, _: ()) -> Result<PatternContentUnits, AttributeError> {
-        Ok (PatternContentUnits::from (CoordUnits::parse (s, ())?))
-    }
-}
-
 fn node_has_children (node: &Option<Weak<Node>>) -> bool {
     match *node {
         None => false,
@@ -144,7 +116,7 @@ impl Pattern {
     fn resolve_from_defaults (&mut self) {
         /* These are per the spec */
 
-        fallback_to! (self.units,                 Some (CoordUnits::default ()));
+        fallback_to! (self.units,                 Some (PatternUnits::default ()));
         fallback_to! (self.content_units,         Some (PatternContentUnits::default ()));
         fallback_to! (self.vbox,                  Some (None));
         fallback_to! (self.preserve_aspect_ratio, Some (AspectRatio::default ()));
@@ -305,7 +277,7 @@ fn set_pattern_on_draw_context (pattern: &Pattern,
     let vbox                  = pattern.vbox.unwrap ();
     let preserve_aspect_ratio = pattern.preserve_aspect_ratio.unwrap ();
 
-    if units == CoordUnits::ObjectBoundingBox {
+    if units == PatternUnits(CoordUnits::ObjectBoundingBox) {
         drawing_ctx::push_view_box (draw_ctx, 1.0, 1.0);
     }
 
@@ -314,7 +286,7 @@ fn set_pattern_on_draw_context (pattern: &Pattern,
     let pattern_width  = pattern.width.unwrap ().normalize (draw_ctx);
     let pattern_height = pattern.height.unwrap ().normalize (draw_ctx);
 
-    if units == CoordUnits::ObjectBoundingBox {
+    if units == PatternUnits(CoordUnits::ObjectBoundingBox) {
         drawing_ctx::pop_view_box (draw_ctx);
     }
 
@@ -324,12 +296,12 @@ fn set_pattern_on_draw_context (pattern: &Pattern,
     let bbhscale: f64;
 
     match units {
-        CoordUnits::ObjectBoundingBox => {
+        PatternUnits(CoordUnits::ObjectBoundingBox) => {
             bbwscale = bbox.rect.width;
             bbhscale = bbox.rect.height;
         },
 
-        CoordUnits::UserSpaceOnUse => {
+        PatternUnits(CoordUnits::UserSpaceOnUse) => {
             bbwscale = 1.0;
             bbhscale = 1.0;
         }
@@ -358,12 +330,12 @@ fn set_pattern_on_draw_context (pattern: &Pattern,
 
     // Create the pattern coordinate system
     match units {
-        CoordUnits::ObjectBoundingBox => {
+        PatternUnits(CoordUnits::ObjectBoundingBox) => {
             affine.translate (bbox.rect.x + pattern_x * bbox.rect.width,
                               bbox.rect.y + pattern_y * bbox.rect.height);
         },
 
-        CoordUnits::UserSpaceOnUse => {
+        PatternUnits(CoordUnits::UserSpaceOnUse) => {
             affine.translate (pattern_x, pattern_y);
         }
     }


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