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.
parent 22d1459f
......@@ -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, */
......
......@@ -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;
......
......@@ -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);
}
......@@ -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);
......
......@@ -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) } };