[librsvg: 12/25] rsvg_parse_stroke_dasharray(): New function, implemented in Rust



commit 8ebc8675c88791cceaa8040e5d00b1c107b7e0cc
Author: Federico Mena Quintero <federico gnome org>
Date:   Mon Jan 29 18:35:11 2018 -0600

    rsvg_parse_stroke_dasharray(): New function, implemented in Rust
    
    We use this now instead of the shitty C parser for the
    stroke-dasharray attribute.  We still need to handle errors and
    inheritance.

 rsvg-cairo-draw.c  | 41 ++++++++++++++++++++++++++++++++--
 rsvg-styles.c      | 51 +++++-------------------------------------
 rsvg-styles.h      | 18 ++++++++++-----
 rust/src/length.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 rust/src/lib.rs    |  1 +
 5 files changed, 120 insertions(+), 56 deletions(-)
---
diff --git a/rsvg-cairo-draw.c b/rsvg-cairo-draw.c
index 83109f4..c0f9949 100644
--- a/rsvg-cairo-draw.c
+++ b/rsvg-cairo-draw.c
@@ -230,6 +230,43 @@ rsvg_cairo_get_pango_context (RsvgDrawingCtx * ctx)
     return context;
 }
 
+static void
+set_stroke_dasharray(cairo_t *cr, RsvgDrawingCtx *ctx, RsvgStrokeDasharray *dash, RsvgLength *dash_offset)
+{
+    double *dashes;
+    int i;
+
+    switch (dash->kind) {
+    case RSVG_STROKE_DASHARRAY_NONE:
+        cairo_set_dash (cr, NULL, 0, 0.0);
+        break;
+
+    case RSVG_STROKE_DASHARRAY_INHERIT:
+        /* FIXME: do inheritance in the caller */
+        cairo_set_dash (cr, NULL, 0, 0.0);
+        break;
+
+    case RSVG_STROKE_DASHARRAY_DASHES:
+        dashes = g_new(double, dash->num_dashes);
+
+        for (i = 0; i < dash->num_dashes; i++) {
+            dashes[i] = rsvg_length_normalize(&dash->dashes[i], ctx);
+        }
+
+        cairo_set_dash (cr,
+                        dashes,
+                        dash->num_dashes,
+                        rsvg_length_normalize (dash_offset, ctx));
+        g_free(dashes);
+        break;
+
+    case RSVG_STROKE_DASHARRAY_ERROR:
+    default:
+        g_assert_not_reached ();
+        break;
+    }
+}
+
 static void
 setup_cr_for_stroke (cairo_t *cr, RsvgDrawingCtx *ctx, RsvgState *state)
 {
@@ -237,8 +274,8 @@ setup_cr_for_stroke (cairo_t *cr, RsvgDrawingCtx *ctx, RsvgState *state)
     cairo_set_miter_limit (cr, state->miter_limit);
     cairo_set_line_cap (cr, (cairo_line_cap_t) state->cap);
     cairo_set_line_join (cr, (cairo_line_join_t) state->join);
-    cairo_set_dash (cr, state->dash.dashes, state->dash.num_dashes,
-                    rsvg_length_normalize (&state->dash_offset, ctx));
+
+    set_stroke_dasharray(cr, ctx, &state->dash, &state->dash_offset);
 }
 
 void
diff --git a/rsvg-styles.c b/rsvg-styles.c
index d733fef..6667ab0 100644
--- a/rsvg-styles.c
+++ b/rsvg-styles.c
@@ -288,7 +288,7 @@ rsvg_state_clone (RsvgState * dst, const RsvgState * src)
     dst->styles = g_hash_table_ref (src->styles);
 
     if (src->dash.num_dashes > 0) {
-        dst->dash.dashes = g_new0 (gdouble, src->dash.num_dashes);
+        dst->dash.dashes = g_new0 (RsvgLength, src->dash.num_dashes);
         for (i = 0; i < src->dash.num_dashes; i++)
             dst->dash.dashes[i] = src->dash.dashes[i];
     }
@@ -419,7 +419,7 @@ rsvg_state_inherit_run (RsvgState * dst, const RsvgState * src,
         if (dst->has_dash)
             g_free (dst->dash.dashes);
 
-        dst->dash.dashes = g_new0 (gdouble, src->dash.num_dashes);
+        dst->dash.dashes = g_new0 (RsvgLength, src->dash.num_dashes);
         dst->dash.num_dashes = src->dash.num_dashes;
         for (i = 0; i < src->dash.num_dashes; i++)
             dst->dash.dashes[i] = src->dash.dashes[i];
@@ -518,6 +518,9 @@ rsvg_state_inherit (RsvgState * dst, const RsvgState * src)
     rsvg_state_inherit_run (dst, src, inheritfunction, 1);
 }
 
+/* Defined in rust/src/length.rs */
+extern RsvgStrokeDasharray rsvg_parse_stroke_dasharray(const char *str);
+
 /* Parse a CSS2 style argument, setting the SVG context attributes. */
 static void
 rsvg_parse_style_pair (RsvgState * state,
@@ -956,49 +959,7 @@ rsvg_parse_style_pair (RsvgState * state,
 
     } else if (g_str_equal (name, "stroke-dasharray")) {
         state->has_dash = TRUE;
-        if (g_str_equal (value, "none")) {
-            if (state->dash.num_dashes != 0) {
-                /* free any cloned dash data */
-                g_free (state->dash.dashes);
-                state->dash.dashes = NULL;
-                state->dash.num_dashes = 0;
-            }
-        } else {
-            gchar **dashes = g_strsplit (value, ",", -1);
-            if (NULL != dashes) {
-                gint n_dashes, i;
-                gboolean is_even = FALSE;
-                gdouble total = 0;
-
-                /* count the #dashes */
-                for (n_dashes = 0; dashes[n_dashes] != NULL; n_dashes++);
-
-                is_even = (n_dashes % 2 == 0);
-                state->dash.num_dashes = (is_even ? n_dashes : n_dashes * 2);
-                state->dash.dashes = g_new0 (double, state->dash.num_dashes);
-
-                /* TODO: handle negative value == error case */
-
-                /* the even and base case */
-                for (i = 0; i < n_dashes; i++) {
-                    state->dash.dashes[i] = g_ascii_strtod (dashes[i], NULL);
-                    total += state->dash.dashes[i];
-                }
-                /* if an odd number of dashes is found, it gets repeated */
-                if (!is_even)
-                    for (; i < state->dash.num_dashes; i++)
-                        state->dash.dashes[i] = state->dash.dashes[i - n_dashes];
-
-                g_strfreev (dashes);
-                /* If the dashes add up to 0, then it should 
-                   be ignored */
-                if (total == 0) {
-                    g_free (state->dash.dashes);
-                    state->dash.dashes = NULL;
-                    state->dash.num_dashes = 0;
-                }
-            }
-        }
+        state->dash = rsvg_parse_stroke_dasharray (value);
     }
 }
 
diff --git a/rsvg-styles.h b/rsvg-styles.h
index 9089166..b89f2c1 100644
--- a/rsvg-styles.h
+++ b/rsvg-styles.h
@@ -61,12 +61,18 @@ typedef enum {
     RSVG_ENABLE_BACKGROUND_NEW
 } RsvgEnableBackgroundType;
 
-typedef struct _RsvgVpathDash RsvgVpathDash;
+typedef enum {
+    RSVG_STROKE_DASHARRAY_NONE,
+    RSVG_STROKE_DASHARRAY_INHERIT,
+    RSVG_STROKE_DASHARRAY_DASHES,
+    RSVG_STROKE_DASHARRAY_ERROR
+} RsvgStrokeDasharrayKind;
 
-struct _RsvgVpathDash {
+typedef struct {
+    RsvgStrokeDasharrayKind kind;
     gsize num_dashes;
-    double *dashes;
-};
+    RsvgLength *dashes;
+} RsvgStrokeDasharray;
 
 struct _RsvgState {
     RsvgState *parent;
@@ -150,10 +156,10 @@ struct _RsvgState {
     gboolean has_cond;
     gboolean cond_true;
 
-    RsvgVpathDash dash;
+    RsvgStrokeDasharray dash;
     gboolean has_dash;
-    gboolean has_dashoffset;
     RsvgLength dash_offset;
+    gboolean has_dashoffset;
 
     guint32 current_color;
     gboolean has_current_color;
diff --git a/rust/src/length.rs b/rust/src/length.rs
index f9ba3c1..0d658c0 100644
--- a/rust/src/length.rs
+++ b/rust/src/length.rs
@@ -1,8 +1,11 @@
-use ::cssparser::{Parser, ParserInput, Token};
-use ::glib::translate::*;
-use ::libc;
+use cssparser::{Parser, ParserInput, Token};
+use glib_sys;
+use glib::translate::*;
+use libc;
 
 use std::f64::consts::*;
+use std::mem;
+use std::ptr;
 
 use drawing_ctx;
 use drawing_ctx::RsvgDrawingCtx;
@@ -290,6 +293,23 @@ fn viewport_percentage (x: f64, y: f64) -> f64 {
     (x * x + y * y).sqrt () / SQRT_2
 }
 
+// Keep in sync with rsvg-styles.h:RsvgStrokeDasharrayKind
+#[repr(C)]
+pub enum RsvgStrokeDasharrayKind {
+    None,
+    Inherit,
+    Dashes,
+    Error
+}
+
+// Keep in sync with rsvg-styles.h:RsvgStrokeDasharray
+#[repr(C)]
+pub struct RsvgStrokeDasharray {
+    pub kind: RsvgStrokeDasharrayKind,
+    pub num_dashes: usize,
+    pub dashes: *mut RsvgLength
+}
+
 #[derive(Debug)]
 enum StrokeDasharray {
     None,
@@ -363,6 +383,45 @@ pub extern fn rsvg_length_hand_normalize (raw_length: *const RsvgLength,
     length.hand_normalize (pixels_per_inch, width_or_height, font_size)
 }
 
+#[no_mangle]
+pub extern fn rsvg_parse_stroke_dasharray(string: *const libc::c_char) -> RsvgStrokeDasharray {
+    let my_string = unsafe { &String::from_glib_none (string) };
+
+    match parse_stroke_dash_array(my_string) {
+        Ok(StrokeDasharray::None) => RsvgStrokeDasharray {
+            kind: RsvgStrokeDasharrayKind::None,
+            num_dashes: 0,
+            dashes: ptr::null_mut()
+        },
+
+        Ok(StrokeDasharray::Inherit) => RsvgStrokeDasharray {
+            kind: RsvgStrokeDasharrayKind::Inherit,
+            num_dashes: 0,
+            dashes: ptr::null_mut()
+        },
+
+        Ok(StrokeDasharray::Dasharray(ref v)) => RsvgStrokeDasharray {
+            kind: RsvgStrokeDasharrayKind::Dashes,
+            num_dashes: v.len(),
+            dashes: to_c_array(&v)
+        },
+
+        Err(_) => RsvgStrokeDasharray {
+            kind: RsvgStrokeDasharrayKind::Error,
+            num_dashes: 0,
+            dashes: ptr::null_mut()
+        }
+    }
+}
+
+fn to_c_array<T>(v: &[T]) -> *mut T {
+    unsafe {
+        let res = glib_sys::g_malloc(mem::size_of::<T>() * v.len()) as *mut T;
+        ptr::copy_nonoverlapping(v.as_ptr(), res, v.len());
+        res
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index fd308b5..8c6f1b6 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -59,6 +59,7 @@ pub use length::{
     rsvg_length_parse,
     rsvg_length_normalize,
     rsvg_length_hand_normalize,
+    rsvg_parse_stroke_dasharray
 };
 
 pub use image::{


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