[librsvg] gradient.rs: Fully move gradients to Rust. Yay!
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] gradient.rs: Fully move gradients to Rust. Yay!
- Date: Tue, 6 Jun 2017 22:19:03 +0000 (UTC)
commit 7c991a72cecaed2e8252682f5b6e3c1b74694f61
Author: Federico Mena Quintero <federico gnome org>
Date: Tue Jun 6 17:16:44 2017 -0500
gradient.rs: Fully move gradients to Rust. Yay!
We introduce NodeGradient, and move all the machinery to turn a node
with children for color stops into our existing Gradient structure.
rsvg-base.c | 6 +-
rsvg-cairo-draw.c | 100 +---------------
rsvg-paint-server.c | 181 -----------------------------
rsvg-paint-server.h | 78 +------------
rust/src/gradient.rs | 312 +++++++++++++++++++++++++++-----------------------
rust/src/lib.rs | 6 +-
6 files changed, 186 insertions(+), 497 deletions(-)
---
diff --git a/rsvg-base.c b/rsvg-base.c
index 5205424..deb2d54 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -263,7 +263,7 @@ static const NodeCreator node_creators[] = {
{ "circle", TRUE, rsvg_node_circle_new },
{ "clipPath", TRUE, rsvg_new_clip_path },
/* "color-profile", FALSE, */
- { "conicalGradient", TRUE, rsvg_new_radial_gradient },
+ { "conicalGradient", TRUE, rsvg_node_radial_gradient_new },
/* "cursor", FALSE, */
{ "defs", TRUE, rsvg_node_defs_new },
/* "desc", TRUE, */
@@ -306,7 +306,7 @@ static const NodeCreator node_creators[] = {
/* "hkern", FALSE, */
{ "image", TRUE, rsvg_new_image },
{ "line", TRUE, rsvg_node_line_new },
- { "linearGradient", TRUE, rsvg_new_linear_gradient },
+ { "linearGradient", TRUE, rsvg_node_linear_gradient_new },
{ "marker", TRUE, rsvg_node_marker_new },
{ "mask", TRUE, rsvg_new_mask },
/* "metadata", FALSE, */
@@ -317,7 +317,7 @@ static const NodeCreator node_creators[] = {
{ "pattern", TRUE, rsvg_node_pattern_new },
{ "polygon", TRUE, rsvg_node_polygon_new },
{ "polyline", TRUE, rsvg_node_polyline_new },
- { "radialGradient", TRUE, rsvg_new_radial_gradient },
+ { "radialGradient", TRUE, rsvg_node_radial_gradient_new },
{ "rect", TRUE, rsvg_node_rect_new },
/* "script", FALSE, */
/* "set", FALSE, */
diff --git a/rsvg-cairo-draw.c b/rsvg-cairo-draw.c
index d240987..76abbb3 100644
--- a/rsvg-cairo-draw.c
+++ b/rsvg-cairo-draw.c
@@ -42,93 +42,6 @@
#include <pango/pangocairo.h>
#include <pango/pangofc-fontmap.h>
-static Gradient *
-linear_gradient_to_rust (RsvgNode *node)
-{
- RsvgLinearGradient *linear;
- Gradient *gradient;
-
- g_assert (rsvg_node_get_type (node) == RSVG_NODE_TYPE_LINEAR_GRADIENT);
- linear = rsvg_rust_cnode_get_impl (node);
-
- gradient = gradient_linear_new (linear->hasx1 ? &linear->x1 : NULL,
- linear->hasy1 ? &linear->y1 : NULL,
- linear->hasx2 ? &linear->x2 : NULL,
- linear->hasy2 ? &linear->y2 : NULL,
- linear->hasbbox ? &linear->obj_bbox : NULL,
- linear->hastransform ? &linear->affine : NULL,
- linear->hasspread ? &linear->spread : NULL,
- linear->fallback);
-
- gradient_add_color_stops_from_node (gradient, node);
-
- return gradient;
-}
-
-static Gradient *
-radial_gradient_to_rust (RsvgNode *node)
-{
- RsvgRadialGradient *radial;
- Gradient *gradient;
-
- g_assert (rsvg_node_get_type (node) == RSVG_NODE_TYPE_RADIAL_GRADIENT);
- radial = rsvg_rust_cnode_get_impl (node);
-
- gradient = gradient_radial_new (radial->hascx ? &radial->cx : NULL,
- radial->hascy ? &radial->cy : NULL,
- radial->hasr ? &radial->r : NULL,
- radial->hasfx ? &radial->fx : NULL,
- radial->hasfy ? &radial->fy : NULL,
- radial->hasbbox ? &radial->obj_bbox : NULL,
- radial->hastransform ? &radial->affine : NULL,
- radial->hasspread ? &radial->spread : NULL,
- radial->fallback);
-
- gradient_add_color_stops_from_node (gradient, node);
-
- return gradient;
-}
-
-Gradient *
-rsvg_gradient_node_to_rust_gradient (RsvgNode *node)
-{
- if (rsvg_node_get_type (node) == RSVG_NODE_TYPE_LINEAR_GRADIENT) {
- return linear_gradient_to_rust (node);
- } else if (rsvg_node_get_type (node) == RSVG_NODE_TYPE_RADIAL_GRADIENT) {
- return radial_gradient_to_rust (node);
- } else {
- return NULL;
- }
-}
-
-static void
-_set_source_rsvg_linear_gradient (RsvgDrawingCtx *ctx,
- RsvgNode *node,
- guint8 opacity, RsvgBbox bbox)
-{
- Gradient *gradient;
-
- gradient = linear_gradient_to_rust (node);
-
- gradient_resolve_fallbacks_and_set_pattern (gradient, ctx, opacity, bbox);
-
- gradient_destroy (gradient);
-}
-
-static void
-_set_source_rsvg_radial_gradient (RsvgDrawingCtx * ctx,
- RsvgNode *node,
- guint8 opacity, RsvgBbox bbox)
-{
- Gradient *gradient;
-
- gradient = radial_gradient_to_rust (node);
-
- gradient_resolve_fallbacks_and_set_pattern (gradient, ctx, opacity, bbox);
-
- gradient_destroy (gradient);
-}
-
static void
_set_source_rsvg_solid_color (RsvgDrawingCtx * ctx,
RsvgSolidColor * color, guint8 opacity, guint32 current_color)
@@ -169,12 +82,13 @@ _set_source_rsvg_paint_server (RsvgDrawingCtx * ctx,
node = rsvg_drawing_ctx_acquire_node (ctx, ps->core.iri->iri_str);
if (node == NULL) {
use_alternate = TRUE;
- } else if (rsvg_node_get_type (node) == RSVG_NODE_TYPE_LINEAR_GRADIENT) {
- _set_source_rsvg_linear_gradient (ctx, node, opacity, bbox);
- had_paint_server = TRUE;
- } else if (rsvg_node_get_type (node) == RSVG_NODE_TYPE_RADIAL_GRADIENT) {
- _set_source_rsvg_radial_gradient (ctx, node, opacity, bbox);
- had_paint_server = TRUE;
+ } else if (rsvg_node_get_type (node) == RSVG_NODE_TYPE_LINEAR_GRADIENT
+ || rsvg_node_get_type (node) == RSVG_NODE_TYPE_RADIAL_GRADIENT) {
+ if (gradient_resolve_fallbacks_and_set_pattern (node, ctx, opacity, bbox)) {
+ had_paint_server = TRUE;
+ } else {
+ use_alternate = TRUE;
+ }
} else if (rsvg_node_get_type (node) == RSVG_NODE_TYPE_PATTERN) {
if (pattern_resolve_fallbacks_and_set_pattern (node, ctx, bbox)) {
had_paint_server = TRUE;
diff --git a/rsvg-paint-server.c b/rsvg-paint-server.c
index 3e94ae2..ab418d9 100644
--- a/rsvg-paint-server.c
+++ b/rsvg-paint-server.c
@@ -208,184 +208,3 @@ rsvg_paint_server_unref (RsvgPaintServer * ps)
g_free (ps);
}
}
-
-static void
-rsvg_paint_server_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
-{
- /* nothing; paint servers are handled specially */
-}
-
-static void
-rsvg_linear_gradient_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
-{
- RsvgLinearGradient *grad = impl;
- const char *value;
-
- if ((value = rsvg_property_bag_lookup (atts, "x1"))) {
- grad->x1 = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
- grad->hasx1 = TRUE;
- }
- if ((value = rsvg_property_bag_lookup (atts, "y1"))) {
- grad->y1 = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
- grad->hasy1 = TRUE;
- }
- if ((value = rsvg_property_bag_lookup (atts, "x2"))) {
- grad->x2 = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
- grad->hasx2 = TRUE;
- }
- if ((value = rsvg_property_bag_lookup (atts, "y2"))) {
- grad->y2 = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
- grad->hasy2 = TRUE;
- }
- if ((value = rsvg_property_bag_lookup (atts, "spreadMethod"))) {
- if (!strcmp (value, "pad")) {
- grad->spread = CAIRO_EXTEND_PAD;
- } else if (!strcmp (value, "reflect")) {
- grad->spread = CAIRO_EXTEND_REFLECT;
- } else if (!strcmp (value, "repeat")) {
- grad->spread = CAIRO_EXTEND_REPEAT;
- }
- grad->hasspread = TRUE;
- }
- g_free (grad->fallback);
- grad->fallback = g_strdup (rsvg_property_bag_lookup (atts, "xlink:href"));
- if ((value = rsvg_property_bag_lookup (atts, "gradientTransform"))) {
- if (rsvg_parse_transform (&grad->affine, value)) {
- grad->hastransform = TRUE;
- } else {
- rsvg_node_set_attribute_parse_error (node,
- "gradientTransform",
- "Invalid transformation");
- }
- }
- if ((value = rsvg_property_bag_lookup (atts, "gradientUnits"))) {
- if (!strcmp (value, "userSpaceOnUse"))
- grad->obj_bbox = FALSE;
- else if (!strcmp (value, "objectBoundingBox"))
- grad->obj_bbox = TRUE;
- grad->hasbbox = TRUE;
- }
-}
-
-static void
-rsvg_linear_gradient_free (gpointer impl)
-{
- RsvgLinearGradient *self = impl;
-
- g_free (self->fallback);
- g_free (self);
-}
-
-RsvgNode *
-rsvg_new_linear_gradient (const char *element_name, RsvgNode *parent)
-{
- RsvgLinearGradient *grad = NULL;
-
- grad = g_new0 (RsvgLinearGradient, 1);
- cairo_matrix_init_identity (&grad->affine);
- grad->x1 = rsvg_length_parse ("0", LENGTH_DIR_HORIZONTAL);
- grad->y1 = grad->y2 = rsvg_length_parse ("0", LENGTH_DIR_VERTICAL);
- grad->x2 = rsvg_length_parse ("1", LENGTH_DIR_HORIZONTAL);
- grad->fallback = NULL;
- grad->obj_bbox = TRUE;
- grad->spread = CAIRO_EXTEND_PAD;
- grad->hasx1 = grad->hasy1 = grad->hasx2 = grad->hasy2 = grad->hasbbox = grad->hasspread =
- grad->hastransform = FALSE;
-
- return rsvg_rust_cnode_new (RSVG_NODE_TYPE_LINEAR_GRADIENT,
- parent,
- rsvg_state_new (),
- grad,
- rsvg_linear_gradient_set_atts,
- rsvg_paint_server_draw,
- rsvg_linear_gradient_free);
-}
-
-static void
-rsvg_radial_gradient_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
-{
- RsvgRadialGradient *grad = impl;
- const char *value;
-
- if ((value = rsvg_property_bag_lookup (atts, "cx"))) {
- grad->cx = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
- grad->hascx = TRUE;
- if (!grad->hasfx)
- grad->fx = grad->cx;
- }
- if ((value = rsvg_property_bag_lookup (atts, "cy"))) {
- grad->cy = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
- grad->hascy = TRUE;
- if (!grad->hasfy)
- grad->fy = grad->cy;
- }
- if ((value = rsvg_property_bag_lookup (atts, "r"))) {
- grad->r = rsvg_length_parse (value, LENGTH_DIR_BOTH);
- grad->hasr = TRUE;
- }
- if ((value = rsvg_property_bag_lookup (atts, "fx"))) {
- grad->fx = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
- grad->hasfx = TRUE;
- }
- if ((value = rsvg_property_bag_lookup (atts, "fy"))) {
- grad->fy = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
- grad->hasfy = TRUE;
- }
- g_free (grad->fallback);
- grad->fallback = g_strdup (rsvg_property_bag_lookup (atts, "xlink:href"));
- if ((value = rsvg_property_bag_lookup (atts, "gradientTransform"))) {
- if (rsvg_parse_transform (&grad->affine, value)) {
- grad->hastransform = TRUE;
- } else {
- rsvg_node_set_attribute_parse_error (node,
- "gradientTransform",
- "Invalid transformation");
- }
- }
- if ((value = rsvg_property_bag_lookup (atts, "spreadMethod"))) {
- if (!strcmp (value, "pad"))
- grad->spread = CAIRO_EXTEND_PAD;
- else if (!strcmp (value, "reflect"))
- grad->spread = CAIRO_EXTEND_REFLECT;
- else if (!strcmp (value, "repeat"))
- grad->spread = CAIRO_EXTEND_REPEAT;
- grad->hasspread = TRUE;
- }
- if ((value = rsvg_property_bag_lookup (atts, "gradientUnits"))) {
- if (!strcmp (value, "userSpaceOnUse"))
- grad->obj_bbox = FALSE;
- else if (!strcmp (value, "objectBoundingBox"))
- grad->obj_bbox = TRUE;
- grad->hasbbox = TRUE;
- }
-}
-
-static void
-rsvg_radial_gradient_free (gpointer impl)
-{
- RsvgRadialGradient *self = impl;
-
- g_free (self->fallback);
- g_free (self);
-}
-
-RsvgNode *
-rsvg_new_radial_gradient (const char *element_name, RsvgNode *parent)
-{
- RsvgRadialGradient *grad = g_new0 (RsvgRadialGradient, 1);
- cairo_matrix_init_identity (&grad->affine);
- grad->obj_bbox = TRUE;
- grad->spread = CAIRO_EXTEND_PAD;
- grad->fallback = NULL;
- grad->cx = grad->cy = grad->r = grad->fx = grad->fy = rsvg_length_parse ("0.5", LENGTH_DIR_BOTH);
- grad->hascx = grad->hascy = grad->hasfx = grad->hasfy = grad->hasr = grad->hasbbox =
- grad->hasspread = grad->hastransform = FALSE;
-
- return rsvg_rust_cnode_new (RSVG_NODE_TYPE_RADIAL_GRADIENT,
- parent,
- rsvg_state_new (),
- grad,
- rsvg_radial_gradient_set_atts,
- rsvg_paint_server_draw,
- rsvg_radial_gradient_free);
-}
diff --git a/rsvg-paint-server.h b/rsvg-paint-server.h
index 7022ed4..5154f86 100644
--- a/rsvg-paint-server.h
+++ b/rsvg-paint-server.h
@@ -32,90 +32,24 @@
G_BEGIN_DECLS
-typedef struct _RsvgLinearGradient RsvgLinearGradient;
-typedef struct _RsvgRadialGradient RsvgRadialGradient;
typedef struct _RsvgSolidColor RsvgSolidColor;
typedef struct _RsvgPaintServer RsvgPaintServer;
-typedef struct _RsvgPSCtx RsvgPSCtx;
-
-struct _RsvgLinearGradient {
- gboolean obj_bbox;
- cairo_matrix_t affine; /* user space to actual at time of gradient def */
- cairo_extend_t spread;
- RsvgLength x1, y1, x2, y2;
- gboolean hasx1;
- gboolean hasy1;
- gboolean hasx2;
- gboolean hasy2;
- gboolean hasbbox;
- gboolean hastransform;
- gboolean hasspread;
- char *fallback;
-};
-
-struct _RsvgRadialGradient {
- gboolean obj_bbox;
- cairo_matrix_t affine; /* user space to actual at time of gradient def */
- cairo_extend_t spread;
- RsvgLength cx, cy, r, fx, fy;
- gboolean hascx;
- gboolean hascy;
- gboolean hasr;
- gboolean hasfx;
- gboolean hasfy;
- gboolean hasbbox;
- gboolean hastransform;
- gboolean hasspread;
- char *fallback;
-};
-
-/* This is a Rust gradient from rust/src/gradient.rs */
-typedef struct _Gradient Gradient;
-
-/* Implemented in rust/src/gradient.rs */
-G_GNUC_INTERNAL
-Gradient *gradient_linear_new (RsvgLength *x1,
- RsvgLength *y1,
- RsvgLength *x2,
- RsvgLength *y2,
- gboolean *obj_bbox,
- cairo_matrix_t *affine,
- cairo_extend_t *extend,
- const char *fallback_name);
-
-/* Implemented in rust/src/gradient.rs */
-G_GNUC_INTERNAL
-Gradient *gradient_radial_new (RsvgLength *cx,
- RsvgLength *cy,
- RsvgLength *r,
- RsvgLength *fx,
- RsvgLength *fy,
- gboolean *obj_bbox,
- cairo_matrix_t *affine,
- cairo_extend_t *extend,
- const char *fallback_name);
-
/* Implemented in rust/src/gradient.rs */
G_GNUC_INTERNAL
-void gradient_destroy (Gradient *gradient);
+RsvgNode *rsvg_node_linear_gradient_new (const char *element_name, RsvgNode *parent);
/* Implemented in rust/src/gradient.rs */
G_GNUC_INTERNAL
-void gradient_add_color_stops_from_node (Gradient *gradient,
- RsvgNode *node);
+RsvgNode *rsvg_node_radial_gradient_new (const char *element_name, RsvgNode *parent);
/* Implemented in rust/src/gradient.rs */
G_GNUC_INTERNAL
-void gradient_resolve_fallbacks_and_set_pattern (Gradient *gradient,
- RsvgDrawingCtx *draw_ctx,
- guint8 opacity,
- RsvgBbox bbox);
-
-G_GNUC_INTERNAL
-Gradient *rsvg_gradient_node_to_rust_gradient (RsvgNode *node);
-
+gboolean gradient_resolve_fallbacks_and_set_pattern (RsvgNode *node,
+ RsvgDrawingCtx *draw_ctx,
+ guint8 opacity,
+ RsvgBbox bbox);
/* Implemented in rust/src/pattern.rs */
G_GNUC_INTERNAL
RsvgNode *rsvg_node_pattern_new (const char *element_name, RsvgNode *parent);
diff --git a/rust/src/gradient.rs b/rust/src/gradient.rs
index 269bd67..c298b36 100644
--- a/rust/src/gradient.rs
+++ b/rust/src/gradient.rs
@@ -3,12 +3,17 @@ use ::glib_sys;
use ::glib::translate::*;
use ::libc;
+use std::cell::RefCell;
+
use bbox::*;
use drawing_ctx;
use drawing_ctx::RsvgDrawingCtx;
+use handle::RsvgHandle;
use length::*;
use node::*;
use paint_server::*;
+use property_bag;
+use property_bag::*;
use stop::*;
use util::*;
@@ -55,6 +60,18 @@ pub struct Gradient {
pub variant: GradientVariant
}
+impl Default for GradientCommon {
+ fn default () -> GradientCommon {
+ GradientCommon {
+ units: None,
+ affine: None,
+ spread: None,
+ fallback: None,
+ stops: None,
+ }
+ }
+}
+
// All of the Gradient's fields are Option<foo> values, because
// those fields can be omitted in the SVG file. We need to resolve
// them to default values, or to fallback values that come from
@@ -79,20 +96,6 @@ macro_rules! fallback_to (
);
impl GradientCommon {
- fn new (units: Option<PaintServerUnits>,
- affine: Option<cairo::Matrix>,
- spread: Option<PaintServerSpread>,
- fallback: Option<String>,
- stops: Option<Vec<ColorStop>>) -> GradientCommon {
- GradientCommon {
- units: units,
- affine: affine,
- spread: spread,
- fallback: fallback,
- stops: stops
- }
- }
-
fn clone_stops (&self) -> Option<Vec<ColorStop>> {
if let Some (ref stops) = self.stops {
Some (stops.clone ())
@@ -188,6 +191,7 @@ impl GradientVariant {
/* These are per the spec */
match *self {
+ // https://www.w3.org/TR/SVG/pservers.html#LinearGradients
GradientVariant::Linear { ref mut x1, ref mut y1, ref mut x2, ref mut y2 } => {
fallback_to! (*x1, Some (RsvgLength::parse ("0%", LengthDir::Horizontal).unwrap ()));
fallback_to! (*y1, Some (RsvgLength::parse ("0%", LengthDir::Vertical).unwrap ()));
@@ -195,6 +199,7 @@ impl GradientVariant {
fallback_to! (*y2, Some (RsvgLength::parse ("0%", LengthDir::Vertical).unwrap ()));
},
+ // https://www.w3.org/TR/SVG/pservers.html#RadialGradients
GradientVariant::Radial { ref mut cx, ref mut cy, ref mut r, ref mut fx, ref mut fy } => {
fallback_to! (*cx, Some (RsvgLength::parse ("50%", LengthDir::Horizontal).unwrap ()));
fallback_to! (*cy, Some (RsvgLength::parse ("50%", LengthDir::Vertical).unwrap ()));
@@ -232,13 +237,6 @@ impl GradientVariant {
}
impl Gradient {
- fn new (common: GradientCommon, variant: GradientVariant) -> Gradient {
- Gradient {
- common: common,
- variant: variant
- }
- }
-
fn is_resolved (&self) -> bool {
self.common.is_resolved () && self.variant.is_resolved ()
}
@@ -253,6 +251,24 @@ impl Gradient {
self.variant.resolve_from_fallback (&fallback.variant);
}
+ fn add_color_stops_from_node (&mut self, node: &RsvgNode) {
+ assert! (node.get_type () == NodeType::LinearGradient || node.get_type () ==
NodeType::RadialGradient);
+
+ for child in &*node.children.borrow () {
+ if child.get_type () != NodeType::Stop {
+ continue; // just ignore this child; we are only interested in gradient stops
+ }
+
+ if child.get_result ().is_err () {
+ break; // don't add any more stops
+ }
+
+ child.with_impl (|stop: &NodeStop| {
+ self.add_color_stop (stop.get_offset (), stop.get_rgba ());
+ });
+ }
+ }
+
fn add_color_stop (&mut self, offset: f64, rgba: u32) {
self.common.add_color_stop (offset, rgba);
}
@@ -283,21 +299,26 @@ impl Clone for Gradient {
}
trait FallbackSource {
- fn get_fallback (&mut self, name: &str) -> Option<Box<Gradient>>;
+ fn get_fallback (&mut self, name: &str) -> Option<RsvgNode>;
}
fn resolve_gradient (gradient: &Gradient, fallback_source: &mut FallbackSource) -> Gradient {
let mut result = gradient.clone ();
while !result.is_resolved () {
- let mut opt_fallback: Option<Box<Gradient>> = None;
+ let mut opt_fallback: Option<RsvgNode> = None;
if let Some (ref fallback_name) = result.common.fallback {
opt_fallback = fallback_source.get_fallback (&**fallback_name);
}
- if let Some (fallback_gradient) = opt_fallback {
- result.resolve_from_fallback (&*fallback_gradient);
+ if let Some (fallback_node) = opt_fallback {
+ fallback_node.with_impl (|i: &NodeGradient| {
+ let mut fallback_gradient = i.gradient.borrow ().clone ();
+ fallback_gradient.add_color_stops_from_node (&fallback_node);
+
+ result.resolve_from_fallback (&fallback_gradient)
+ });
} else {
result.resolve_from_defaults ();
break;
@@ -329,29 +350,22 @@ impl Drop for NodeFallbackSource {
}
}
-extern "C" {
- fn rsvg_gradient_node_to_rust_gradient (node: *const RsvgNode) -> *mut Gradient;
-}
-
impl FallbackSource for NodeFallbackSource {
- fn get_fallback (&mut self, name: &str) -> Option<Box<Gradient>> {
+ fn get_fallback (&mut self, name: &str) -> Option<RsvgNode> {
let fallback_node = drawing_ctx::acquire_node (self.draw_ctx, name);
if fallback_node.is_null () {
return None;
}
- self.acquired_nodes.push (fallback_node);
-
- let raw_fallback_gradient = unsafe { rsvg_gradient_node_to_rust_gradient (fallback_node) };
-
- if raw_fallback_gradient.is_null () {
+ let node: &RsvgNode = unsafe { & *fallback_node };
+ if !(node.get_type () == NodeType::LinearGradient || node.get_type () == NodeType::RadialGradient) {
return None;
}
- let fallback_gradient = unsafe { Box::from_raw (raw_fallback_gradient) };
+ self.acquired_nodes.push (fallback_node);
- return Some (fallback_gradient);
+ return Some (node.clone ());
}
}
@@ -386,8 +400,7 @@ fn set_common_on_pattern<P: cairo::Pattern + cairo::Gradient> (gradient: &Gradie
fn set_linear_gradient_on_pattern (gradient: &Gradient,
draw_ctx: *mut RsvgDrawingCtx,
bbox: &RsvgBbox,
- opacity: u8)
-{
+ opacity: u8) -> bool {
if let GradientVariant::Linear { x1, y1, x2, y2 } = gradient.variant {
let units = gradient.common.units.unwrap ();
@@ -408,6 +421,8 @@ fn set_linear_gradient_on_pattern (gradient: &Gradient,
} else {
unreachable! ();
}
+
+ true
}
/* SVG defines radial gradients as being inside a circle (cx, cy, radius). The
@@ -467,7 +482,7 @@ fn fix_focus_point (mut fx: f64,
fn set_radial_gradient_on_pattern (gradient: &Gradient,
draw_ctx: *mut RsvgDrawingCtx,
bbox: &RsvgBbox,
- opacity: u8) {
+ opacity: u8) -> bool {
if let GradientVariant::Radial { cx, cy, r, fx, fy } = gradient.variant {
let units = gradient.common.units.unwrap ();
@@ -493,145 +508,154 @@ fn set_radial_gradient_on_pattern (gradient: &Gradient,
} else {
unreachable! ();
}
+
+ true
}
fn set_pattern_on_draw_context (gradient: &Gradient,
draw_ctx: *mut RsvgDrawingCtx,
opacity: u8,
- bbox: &RsvgBbox) {
+ bbox: &RsvgBbox) -> bool {
assert! (gradient.is_resolved ());
match gradient.variant {
GradientVariant::Linear { .. } => {
- set_linear_gradient_on_pattern (gradient, draw_ctx, bbox, opacity);
+ set_linear_gradient_on_pattern (gradient, draw_ctx, bbox, opacity)
}
GradientVariant::Radial { .. } => {
- set_radial_gradient_on_pattern (gradient, draw_ctx, bbox, opacity);
+ set_radial_gradient_on_pattern (gradient, draw_ctx, bbox, opacity)
}
}
}
-fn paint_server_units_from_gboolean (v: glib_sys::gboolean) -> PaintServerUnits {
- if from_glib (v) {
- PaintServerUnits::ObjectBoundingBox
- } else {
- PaintServerUnits::UserSpaceOnUse
- }
+struct NodeGradient {
+ gradient: RefCell <Gradient>
}
-/* All the arguments are pointers because they are in fact optional in
- * SVG. We turn the arguments into Option<foo>: NULL into None, and
- * anything else into a Some().
- */
-#[no_mangle]
-pub unsafe extern fn gradient_linear_new (x1: *const RsvgLength,
- y1: *const RsvgLength,
- x2: *const RsvgLength,
- y2: *const RsvgLength,
- obj_bbox: *const glib_sys::gboolean,
- affine: *const cairo::Matrix,
- spread: *const cairo::enums::Extend,
- fallback_name: *const libc::c_char) -> *mut Gradient {
- let my_units = { if obj_bbox.is_null () { None } else { Some
(paint_server_units_from_gboolean (*obj_bbox)) } };
- let my_affine = { if affine.is_null () { None } else { Some (*affine) } };
- let my_spread = { if spread.is_null () { None } else { Some (PaintServerSpread (*spread))
} };
- let my_fallback_name = { if fallback_name.is_null () { None } else { Some (String::from_glib_none
(fallback_name)) } };
-
- let my_x1 = { if x1.is_null () { None } else { Some (*x1) } };
- let my_y1 = { if y1.is_null () { None } else { Some (*y1) } };
- let my_x2 = { if x2.is_null () { None } else { Some (*x2) } };
- let my_y2 = { if y2.is_null () { None } else { Some (*y2) } };
-
- let gradient = Gradient::new (GradientCommon::new (my_units, my_affine, my_spread, my_fallback_name,
None),
- GradientVariant::Linear { x1: my_x1,
- y1: my_y1,
- x2: my_x2,
- y2: my_y2 });
-
- let boxed_gradient = Box::new (gradient);
-
- Box::into_raw (boxed_gradient)
-}
+impl NodeGradient {
+ fn new_linear () -> NodeGradient {
+ NodeGradient {
+ gradient: RefCell::new (Gradient {
+ common: GradientCommon::default (),
+ variant: GradientVariant::Linear {
+ x1: None,
+ y1: None,
+ x2: None,
+ y2: None
+ }
+ })
+ }
+ }
-#[no_mangle]
-pub unsafe extern fn gradient_radial_new (cx: *const RsvgLength,
- cy: *const RsvgLength,
- r: *const RsvgLength,
- fx: *const RsvgLength,
- fy: *const RsvgLength,
- obj_bbox: *const glib_sys::gboolean,
- affine: *const cairo::Matrix,
- spread: *const cairo::enums::Extend,
- fallback_name: *const libc::c_char) -> *mut Gradient {
- let my_units = { if obj_bbox.is_null () { None } else { Some
(paint_server_units_from_gboolean (*obj_bbox)) } };
- let my_affine = { if affine.is_null () { None } else { Some (*affine) } };
- let my_spread = { if spread.is_null () { None } else { Some (PaintServerSpread (*spread))
} };
- let my_fallback_name = { if fallback_name.is_null () { None } else { Some (String::from_glib_none
(fallback_name)) } };
-
- let my_cx = { if cx.is_null () { None } else { Some (*cx) } };
- let my_cy = { if cy.is_null () { None } else { Some (*cy) } };
- let my_r = { if r.is_null () { None } else { Some (*r) } };
- let my_fx = { if fx.is_null () { None } else { Some (*fx) } };
- let my_fy = { if fy.is_null () { None } else { Some (*fy) } };
-
- let gradient = Gradient::new (GradientCommon::new (my_units, my_affine, my_spread, my_fallback_name,
None),
- GradientVariant::Radial { cx: my_cx,
- cy: my_cy,
- r: my_r,
- fx: my_fx,
- fy: my_fy });
-
- let boxed_gradient = Box::new (gradient);
-
- Box::into_raw (boxed_gradient)
+ fn new_radial () -> NodeGradient {
+ NodeGradient {
+ gradient: RefCell::new (Gradient {
+ common: GradientCommon::default (),
+ variant: GradientVariant::Radial {
+ cx: None,
+ cy: None,
+ r: None,
+ fx: None,
+ fy: None
+ }
+ })
+ }
+ }
}
-#[no_mangle]
-pub unsafe extern fn gradient_destroy (raw_gradient: *mut Gradient) {
- assert! (!raw_gradient.is_null ());
+impl NodeTrait for NodeGradient {
+ fn set_atts (&self, node: &RsvgNode, _: *const RsvgHandle, pbag: *const RsvgPropertyBag) -> NodeResult {
+ let mut g = self.gradient.borrow_mut ();
- let _ = Box::from_raw (raw_gradient);
-}
+ // Attributes common to linear and radial gradients
-#[no_mangle]
-pub extern fn gradient_add_color_stops_from_node (raw_gradient: *mut Gradient,
- raw_node: *const RsvgNode) {
- assert! (!raw_gradient.is_null ());
- assert! (!raw_node.is_null ());
+ g.common.units = property_bag::parse_or_none (pbag, "gradientUnits")?;
+ g.common.affine = property_bag::transform_or_none (pbag, "gradientTransform")?;
+ g.common.spread = property_bag::parse_or_none (pbag, "spreadMethod")?;
+ g.common.fallback = property_bag::lookup (pbag, "xlink:href");
- let gradient: &mut Gradient = unsafe { &mut (*raw_gradient) };
- let node: &RsvgNode = unsafe { & *raw_node };
+ // Attributes specific to each gradient type. The defaults mandated by the spec
+ // are in GradientVariant::resolve_from_defaults()
- for child in &*node.children.borrow () {
- if child.get_type () != NodeType::Stop {
- continue; // just ignore this child; we are only interested in gradient stops
- }
+ match node.get_type () {
+ NodeType::LinearGradient => {
+ g.variant = GradientVariant::Linear {
+ x1: property_bag::length_or_none (pbag, "x1", LengthDir::Horizontal)?,
+ y1: property_bag::length_or_none (pbag, "y1", LengthDir::Vertical)?,
+ x2: property_bag::length_or_none (pbag, "x2", LengthDir::Horizontal)?,
+ y2: property_bag::length_or_none (pbag, "y2", LengthDir::Vertical)?
+ };
+ },
+
+ NodeType::RadialGradient => {
+ g.variant = GradientVariant::Radial {
+ cx: property_bag::length_or_none (pbag, "cx", LengthDir::Horizontal)?,
+ cy: property_bag::length_or_none (pbag, "cy", LengthDir::Vertical)?,
+ r: property_bag::length_or_none (pbag, "r", LengthDir::Both)?,
+ fx: property_bag::length_or_none (pbag, "fx", LengthDir::Horizontal)?,
+ fy: property_bag::length_or_none (pbag, "fy", LengthDir::Vertical)?
+ };
+ },
- if child.get_result ().is_err () {
- break; // don't add any more stops
+ _ => unreachable! ()
}
- child.with_impl (|stop: &NodeStop| {
- gradient.add_color_stop (stop.get_offset (), stop.get_rgba ());
- });
+ Ok (())
+ }
+
+ fn draw (&self, _: &RsvgNode, _: *const RsvgDrawingCtx, _: i32) {
+ // nothing; paint servers are handled specially
+ }
+
+ fn get_c_impl (&self) -> *const RsvgCNodeImpl {
+ unreachable! ();
}
}
#[no_mangle]
-pub extern fn gradient_resolve_fallbacks_and_set_pattern (raw_gradient: *mut Gradient,
- draw_ctx: *mut RsvgDrawingCtx,
- opacity: u8,
- bbox: RsvgBbox) {
- assert! (!raw_gradient.is_null ());
- let gradient: &mut Gradient = unsafe { &mut (*raw_gradient) };
+pub extern fn rsvg_node_linear_gradient_new (_: *const libc::c_char, raw_parent: *const RsvgNode) -> *const
RsvgNode {
+ boxed_node_new (NodeType::LinearGradient,
+ raw_parent,
+ Box::new (NodeGradient::new_linear ()))
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_radial_gradient_new (_: *const libc::c_char, raw_parent: *const RsvgNode) -> *const
RsvgNode {
+ boxed_node_new (NodeType::RadialGradient,
+ raw_parent,
+ Box::new (NodeGradient::new_radial ()))
+}
+fn resolve_fallbacks_and_set_pattern (gradient: &Gradient,
+ draw_ctx: *mut RsvgDrawingCtx,
+ opacity: u8,
+ bbox: RsvgBbox) -> bool {
let mut fallback_source = NodeFallbackSource::new (draw_ctx);
let resolved = resolve_gradient (gradient, &mut fallback_source);
- set_pattern_on_draw_context (&resolved,
- draw_ctx,
- opacity,
- &bbox);
+ set_pattern_on_draw_context (&resolved, draw_ctx, opacity, &bbox)
+}
+
+#[no_mangle]
+pub extern fn gradient_resolve_fallbacks_and_set_pattern (raw_node: *const RsvgNode,
+ draw_ctx: *mut RsvgDrawingCtx,
+ opacity: u8,
+ bbox: RsvgBbox) -> glib_sys::gboolean {
+ assert! (!raw_node.is_null ());
+ let node: &RsvgNode = unsafe { & *raw_node };
+
+ assert! (node.get_type () == NodeType::LinearGradient || node.get_type () == NodeType::RadialGradient);
+
+ let mut did_set_gradient = false;
+
+ node.with_impl (|node_gradient: &NodeGradient| {
+ let mut gradient = node_gradient.gradient.borrow ().clone ();
+ gradient.add_color_stops_from_node (node);
+
+ did_set_gradient = resolve_fallbacks_and_set_pattern (&gradient, draw_ctx, opacity, bbox);
+ });
+
+ did_set_gradient.to_glib ()
}
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index db675c7..c25a2f6 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -39,10 +39,8 @@ pub use color::{
};
pub use gradient::{
- gradient_linear_new,
- gradient_radial_new,
- gradient_destroy,
- gradient_add_color_stops_from_node,
+ rsvg_node_linear_gradient_new,
+ rsvg_node_radial_gradient_new,
gradient_resolve_fallbacks_and_set_pattern
};
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]