transform.rs: Implement rsvg_parse_transform() fully in Rust

And remove it from rsvg-styles.c.  Yay!
parent c06fbc77
......@@ -61,21 +61,6 @@ typedef struct _StyleValueData {
gboolean important;
} StyleValueData;
/*
* _rsvg_cairo_matrix_init_shear: Set up a shearing matrix.
* @dst: Where to store the resulting affine transform.
* @theta: Shear angle in degrees.
*
* Sets up a shearing matrix. In the standard libart coordinate system
* and a small value for theta, || becomes \\. Horizontal lines remain
* unchanged.
**/
static void
_rsvg_cairo_matrix_init_shear (cairo_matrix_t *dst, double theta)
{
cairo_matrix_init (dst, 1., 0., tan (theta * M_PI / 180.0), 1., 0., 0);
}
static StyleValueData *
style_value_data_new (const gchar *value, gboolean important)
{
......@@ -1302,148 +1287,6 @@ ccss_import_style (CRDocHandler * a_this,
g_free (mime_type);
}
/* Parse an SVG transform string into an affine matrix. Reference: SVG
working draft dated 1999-07-06, section 8.5. Return TRUE on
success. */
gboolean
rsvg_parse_transform (cairo_matrix_t *out_matrix, const char *src)
{
cairo_matrix_t dst;
int idx;
char keyword[32];
double args[6];
int n_args;
guint key_len;
cairo_matrix_t affine;
cairo_matrix_t inverse;
cairo_matrix_init_identity (&dst);
idx = 0;
while (src[idx]) {
/* skip initial whitespace */
while (g_ascii_isspace (src[idx]))
idx++;
if (src[idx] == '\0')
break;
/* parse keyword */
for (key_len = 0; key_len < sizeof (keyword); key_len++) {
char c;
c = src[idx];
if (g_ascii_isalpha (c) || c == '-')
keyword[key_len] = src[idx++];
else
break;
}
if (key_len >= sizeof (keyword))
return FALSE;
keyword[key_len] = '\0';
/* skip whitespace */
while (g_ascii_isspace (src[idx]))
idx++;
if (src[idx] != '(')
return FALSE;
idx++;
for (n_args = 0;; n_args++) {
char c;
char *end_ptr;
/* skip whitespace */
while (g_ascii_isspace (src[idx]))
idx++;
c = src[idx];
if (g_ascii_isdigit (c) || c == '+' || c == '-' || c == '.') {
if (n_args == sizeof (args) / sizeof (args[0]))
return FALSE; /* too many args */
args[n_args] = g_ascii_strtod (src + idx, &end_ptr);
if (errno == ERANGE)
return FALSE; /* overflow / underflow */
idx = end_ptr - src;
while (g_ascii_isspace (src[idx]))
idx++;
/* skip optional comma */
if (src[idx] == ',')
idx++;
} else if (c == ')')
break;
else
return FALSE;
}
idx++;
/* ok, have parsed keyword and args, now modify the transform */
if (!strcmp (keyword, "matrix")) {
if (n_args != 6)
return FALSE;
cairo_matrix_init (&affine, args[0], args[1], args[2], args[3], args[4], args[5]);
cairo_matrix_multiply (&dst, &affine, &dst);
} else if (!strcmp (keyword, "translate")) {
if (n_args == 1)
args[1] = 0;
else if (n_args != 2)
return FALSE;
cairo_matrix_init_translate (&affine, args[0], args[1]);
cairo_matrix_multiply (&dst, &affine, &dst);
} else if (!strcmp (keyword, "scale")) {
if (n_args == 1)
args[1] = args[0];
else if (n_args != 2)
return FALSE;
cairo_matrix_init_scale (&affine, args[0], args[1]);
cairo_matrix_multiply (&dst, &affine, &dst);
} else if (!strcmp (keyword, "rotate")) {
if (n_args == 1) {
cairo_matrix_init_rotate (&affine, args[0] * M_PI / 180.);
cairo_matrix_multiply (&dst, &affine, &dst);
} else if (n_args == 3) {
cairo_matrix_init_translate (&affine, args[1], args[2]);
cairo_matrix_multiply (&dst, &affine, &dst);
cairo_matrix_init_rotate (&affine, args[0] * M_PI / 180.);
cairo_matrix_multiply (&dst, &affine, &dst);
cairo_matrix_init_translate (&affine, -args[1], -args[2]);
cairo_matrix_multiply (&dst, &affine, &dst);
} else
return FALSE;
} else if (!strcmp (keyword, "skewX")) {
if (n_args != 1)
return FALSE;
_rsvg_cairo_matrix_init_shear (&affine, args[0]);
cairo_matrix_multiply (&dst, &affine, &dst);
} else if (!strcmp (keyword, "skewY")) {
if (n_args != 1)
return FALSE;
_rsvg_cairo_matrix_init_shear (&affine, args[0]);
/* transpose the affine, given that we know [1] is zero */
affine.yx = affine.xy;
affine.xy = 0.;
cairo_matrix_multiply (&dst, &affine, &dst);
} else
return FALSE; /* unknown keyword */
}
inverse = dst;
if (cairo_matrix_invert (&inverse) != CAIRO_STATUS_SUCCESS) {
return FALSE; /* we got passed an invalid matrix */
}
*out_matrix = dst;
return TRUE;
}
/**
* rsvg_parse_transform_attr:
* @ctx: Rsvg context.
......
......@@ -230,6 +230,7 @@ G_GNUC_INTERNAL
void rsvg_parse_style_attrs (RsvgHandle *ctx, RsvgNode *node, const char *tag,
const char *klazz, const char *id, RsvgPropertyBag * atts);
/* Implemented in rust/src/transform.rs */
G_GNUC_INTERNAL
gboolean rsvg_parse_transform (cairo_matrix_t *matrix, const char *src) G_GNUC_WARN_UNUSED_RESULT;
......
......@@ -97,6 +97,10 @@ pub use structure::{
rsvg_node_switch_new,
};
pub use transform::{
rsvg_parse_transform,
};
pub use viewbox::{
RsvgViewBox
};
......
extern crate lalrpop_util;
extern crate glib;
extern crate libc;
extern crate cairo;
use self::cairo::MatrixTrait;
use self::glib::translate::*;
use std::f64::consts::*;
......@@ -38,6 +41,27 @@ fn make_rotation_matrix (angle_degrees: f64, tx: f64, ty: f64) -> cairo::Matrix
m
}
#[no_mangle]
pub fn rsvg_parse_transform (out_matrix: *mut cairo::Matrix, s: *const libc::c_char) -> bool {
assert! (!out_matrix.is_null ());
assert! (!s.is_null ());
let string = unsafe { String::from_glib_none (s) };
let matrix: &mut cairo::Matrix = unsafe { &mut *out_matrix };
match parse_transform (&string) {
Ok (m) => {
*matrix = m;
true
},
Err (_) => {
*matrix = cairo::Matrix::identity ();
false
}
}
}
#[cfg(test)]
mod test {
use super::*;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment