[librsvg] New macro coord_units! to create newtypes over CoordUnits with a default value
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] New macro coord_units! to create newtypes over CoordUnits with a default value
- Date: Fri, 1 Dec 2017 16:21:30 +0000 (UTC)
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]