[librsvg/rustification] path_builder.rs: Move to Rust versions of _add_to_cairo_context(), _new(), _destroy()



commit 720f378ebc3917424329a4a93889981572bbb4f9
Author: Federico Mena Quintero <federico gnome org>
Date:   Tue Nov 1 18:08:15 2016 -0600

    path_builder.rs: Move to Rust versions of _add_to_cairo_context(), _new(), _destroy()
    
    These are no longer in the C code:
    
      rsvg_path_builder_new()
      rsvg_path_builder_destroy()
      rsvg_path_builder_add_to_cairo_context()
      rsvg_cairo_path_destroy()
    
    RsvgPathBuilder (in Rust) represents its path data as a
    Vec<cairo::PathSegment>, in contrast to the C version, which used a
    hand-built array of cairo_path_data_t with all their idiosyncrasies.
    
    This new version of rsvg_path_builder_add_to_cairo_context() replays the
    path data onto a given cairo_t; it basically replicates the behavior of
    cairo_append_path(), but based on our internal representation of path
    data.

 rsvg-path.c              |  296 +++++++++++-----------------------------------
 rsvg-path.h              |    6 +-
 rust/src/lib.rs          |    3 +-
 rust/src/path_builder.rs |   39 ++++++
 4 files changed, 114 insertions(+), 230 deletions(-)
---
diff --git a/rsvg-path.c b/rsvg-path.c
index f54d80a..7150a83 100644
--- a/rsvg-path.c
+++ b/rsvg-path.c
@@ -44,168 +44,19 @@
    Reference: https://www.w3.org/TR/SVG/paths.html#PathDataBNF
 */
 
-struct _RsvgPathBuilder {
-    GArray *path_data;
-    int     last_move_to_index;
-};
+typedef struct _RsvgPathBuilder RsvgPathBuilder; /* This is in rust/src/path_builder.rs */
 
-typedef struct _RSVGParsePathCtx RSVGParsePathCtx;
-
-struct _RSVGParsePathCtx {
+typedef struct {
     RsvgPathBuilder *builder;
 
-    cairo_path_data_t cp;       /* current point */
-    cairo_path_data_t rp;       /* reflection point (for 's' and 't' commands) */
+    double cp_x, cp_y;          /* current point */
+    double rp_x, rp_y;          /* reflection point (for 's' and 't' commands) */
+    double last_moveto_x, last_moveto_y; /* Location of last move_to command, so close_path can go back to 
it */
     char cmd;                   /* current command (lowercase) */
     int param;                  /* parameter number */
     gboolean rel;               /* true if relative coords */
     double params[7];           /* parameters that have been parsed */
-};
-
-static inline void
-rsvg_path_builder_add_element (RsvgPathBuilder *builder,
-                               cairo_path_data_t *data)
-{
-  g_array_append_val (builder->path_data, *data);
-}
-
-RsvgPathBuilder *
-rsvg_path_builder_new (void)
-{
-    RsvgPathBuilder *builder;
-
-    builder = g_new (RsvgPathBuilder, 1);
-
-    /* The starting capacity is just to avoid lots of little resizes while growing
-     * a small path.  After that, it will grow as needed.
-     */
-    builder->path_data = g_array_sized_new (FALSE, FALSE, sizeof (cairo_path_data_t), 32);
-    builder->last_move_to_index = -1;
-
-    return builder;
-}
-
-void
-rsvg_path_builder_destroy (RsvgPathBuilder *builder)
-{
-    g_assert (builder != NULL);
-
-    g_array_free (builder->path_data, TRUE);
-    builder->path_data = NULL;
-    builder->last_move_to_index = -1;
-    g_free (builder);
-}
-
-void
-rsvg_path_builder_move_to (RsvgPathBuilder *builder,
-                           double x,
-                           double y)
-{
-  cairo_path_data_t data;
-
-  data.header.type = CAIRO_PATH_MOVE_TO;
-  data.header.length = 2;
-  rsvg_path_builder_add_element (builder, &data);
-  builder->last_move_to_index = builder->path_data->len - 1;
-
-  data.point.x = x;
-  data.point.y = y;
-  rsvg_path_builder_add_element (builder, &data);
-}
-
-void
-rsvg_path_builder_line_to (RsvgPathBuilder *builder,
-                           double x,
-                           double y)
-{
-  cairo_path_data_t data;
-
-  data.header.type = CAIRO_PATH_LINE_TO;
-  data.header.length = 2;
-  rsvg_path_builder_add_element (builder, &data);
-  data.point.x = x;
-  data.point.y = y;
-  rsvg_path_builder_add_element (builder, &data);
-}
-
-void
-rsvg_path_builder_curve_to (RsvgPathBuilder *builder,
-                            double x1,
-                            double y1,
-                            double x2,
-                            double y2,
-                            double x3,
-                            double y3)
-{
-  cairo_path_data_t data;
-
-  data.header.type = CAIRO_PATH_CURVE_TO;
-  data.header.length = 4;
-  rsvg_path_builder_add_element (builder, &data);
-  data.point.x = x1;
-  data.point.y = y1;
-  rsvg_path_builder_add_element (builder, &data);
-  data.point.x = x2;
-  data.point.y = y2;
-  rsvg_path_builder_add_element (builder, &data);
-  data.point.x = x3;
-  data.point.y = y3;
-  rsvg_path_builder_add_element (builder, &data);
-}
-
-void
-rsvg_path_builder_close_path (RsvgPathBuilder *builder)
-{
-  cairo_path_data_t data;
-
-  data.header.type = CAIRO_PATH_CLOSE_PATH;
-  data.header.length = 1;
-  rsvg_path_builder_add_element (builder, &data);
-
-  /* Add a 'move-to' element */
-  if (builder->last_move_to_index >= 0) {
-    cairo_path_data_t *moveto = &g_array_index (builder->path_data, cairo_path_data_t, 
builder->last_move_to_index);
-
-    rsvg_path_builder_move_to (builder, moveto[1].point.x, moveto[1].point.y);
-  }
-}
-
-cairo_path_t *
-rsvg_path_builder_copy_path (RsvgPathBuilder *builder)
-{
-    cairo_path_t *path;
-    int i;
-
-    path = g_new (cairo_path_t, 1);
-    path->status = CAIRO_STATUS_SUCCESS;
-    path->num_data = builder->path_data->len;
-    path->data = g_new (cairo_path_data_t, path->num_data);
-
-    for (i = 0; i < path->num_data; i++) {
-        cairo_path_data_t *data;
-
-        data = &g_array_index (builder->path_data, cairo_path_data_t, i);
-        path->data[i] = *data;
-    }
-
-    return path;
-}
-
-void
-rsvg_path_builder_add_to_cairo_context (RsvgPathBuilder *builder, cairo_t *cr)
-{
-    cairo_path_t *path;
-
-    g_assert (builder != NULL);
-    g_assert (cr != NULL);
-
-    path = rsvg_path_builder_copy_path (builder);
-
-    cairo_new_path (cr);
-    cairo_append_path (cr, path);
-
-    rsvg_cairo_path_destroy (path);
-}
+} RSVGParsePathCtx;
 
 static void
 rsvg_path_arc_segment (RsvgPathBuilder *builder,
@@ -380,9 +231,9 @@ rsvg_parse_path_default_xy (RSVGParsePathCtx * ctx, int n_params)
             /* we shouldn't get 0 here (usually ctx->param > 0 as
                precondition) */
             if (i == 0)
-                ctx->params[i] = ctx->cp.point.x;
+                ctx->params[i] = ctx->cp_x;
             else if (i == 1)
-                ctx->params[i] = ctx->cp.point.y;
+                ctx->params[i] = ctx->cp_y;
             else
                 ctx->params[i] = ctx->params[i - 2];
         }
@@ -403,8 +254,10 @@ rsvg_parse_path_do_cmd (RSVGParsePathCtx * ctx, gboolean final)
         if (ctx->param == 2 || final) {
             rsvg_parse_path_default_xy (ctx, 2);
             rsvg_path_builder_move_to (ctx->builder, ctx->params[0], ctx->params[1]);
-            ctx->cp.point.x = ctx->rp.point.x = ctx->params[0];
-            ctx->cp.point.y = ctx->rp.point.y = ctx->params[1];
+            ctx->cp_x = ctx->rp_x = ctx->params[0];
+            ctx->cp_y = ctx->rp_y = ctx->params[1];
+            ctx->last_moveto_x = ctx->cp_x;
+            ctx->last_moveto_y = ctx->cp_y;
             ctx->param = 0;
             ctx->cmd = 'l'; /* implicit linetos after a moveto */
         }
@@ -414,8 +267,8 @@ rsvg_parse_path_do_cmd (RSVGParsePathCtx * ctx, gboolean final)
         if (ctx->param == 2 || final) {
             rsvg_parse_path_default_xy (ctx, 2);
             rsvg_path_builder_line_to (ctx->builder, ctx->params[0], ctx->params[1]);
-            ctx->cp.point.x = ctx->rp.point.x = ctx->params[0];
-            ctx->cp.point.y = ctx->rp.point.y = ctx->params[1];
+            ctx->cp_x = ctx->rp_x = ctx->params[0];
+            ctx->cp_y = ctx->rp_y = ctx->params[1];
             ctx->param = 0;
         }
         break;
@@ -430,10 +283,10 @@ rsvg_parse_path_do_cmd (RSVGParsePathCtx * ctx, gboolean final)
             x3 = ctx->params[4];
             y3 = ctx->params[5];
             rsvg_path_builder_curve_to (ctx->builder, x1, y1, x2, y2, x3, y3);
-            ctx->rp.point.x = x2;
-            ctx->rp.point.y = y2;
-            ctx->cp.point.x = x3;
-            ctx->cp.point.y = y3;
+            ctx->rp_x = x2;
+            ctx->rp_y = y2;
+            ctx->cp_x = x3;
+            ctx->cp_y = y3;
             ctx->param = 0;
         }
         break;
@@ -441,35 +294,35 @@ rsvg_parse_path_do_cmd (RSVGParsePathCtx * ctx, gboolean final)
         /* smooth curveto */
         if (ctx->param == 4 || final) {
             rsvg_parse_path_default_xy (ctx, 4);
-            x1 = 2 * ctx->cp.point.x - ctx->rp.point.x;
-            y1 = 2 * ctx->cp.point.y - ctx->rp.point.y;
+            x1 = 2 * ctx->cp_x - ctx->rp_x;
+            y1 = 2 * ctx->cp_y - ctx->rp_y;
             x2 = ctx->params[0];
             y2 = ctx->params[1];
             x3 = ctx->params[2];
             y3 = ctx->params[3];
             rsvg_path_builder_curve_to (ctx->builder, x1, y1, x2, y2, x3, y3);
-            ctx->rp.point.x = x2;
-            ctx->rp.point.y = y2;
-            ctx->cp.point.x = x3;
-            ctx->cp.point.y = y3;
+            ctx->rp_x = x2;
+            ctx->rp_y = y2;
+            ctx->cp_x = x3;
+            ctx->cp_y = y3;
             ctx->param = 0;
         }
         break;
     case 'h':
         /* horizontal lineto */
         if (ctx->param == 1) {
-            rsvg_path_builder_line_to (ctx->builder, ctx->params[0], ctx->cp.point.y);
-            ctx->cp.point.x = ctx->rp.point.x = ctx->params[0];
-            ctx->rp.point.y = ctx->cp.point.y;
+            rsvg_path_builder_line_to (ctx->builder, ctx->params[0], ctx->cp_y);
+            ctx->cp_x = ctx->rp_x = ctx->params[0];
+            ctx->rp_y = ctx->cp_y;
             ctx->param = 0;
         }
         break;
     case 'v':
         /* vertical lineto */
         if (ctx->param == 1) {
-            rsvg_path_builder_line_to (ctx->builder, ctx->cp.point.x, ctx->params[0]);
-            ctx->rp.point.x = ctx->cp.point.x;
-            ctx->cp.point.y = ctx->rp.point.y = ctx->params[0];
+            rsvg_path_builder_line_to (ctx->builder, ctx->cp_x, ctx->params[0]);
+            ctx->rp_x = ctx->cp_x;
+            ctx->cp_y = ctx->rp_y = ctx->params[0];
             ctx->param = 0;
         }
         break;
@@ -482,17 +335,17 @@ rsvg_parse_path_do_cmd (RSVGParsePathCtx * ctx, gboolean final)
         if (ctx->param == 4 || final) {
             rsvg_parse_path_default_xy (ctx, 4);
             /* raise quadratic bezier to cubic */
-            x1 = (ctx->cp.point.x + 2 * ctx->params[0]) * (1.0 / 3.0);
-            y1 = (ctx->cp.point.y + 2 * ctx->params[1]) * (1.0 / 3.0);
+            x1 = (ctx->cp_x + 2 * ctx->params[0]) * (1.0 / 3.0);
+            y1 = (ctx->cp_y + 2 * ctx->params[1]) * (1.0 / 3.0);
             x3 = ctx->params[2];
             y3 = ctx->params[3];
             x2 = (x3 + 2 * ctx->params[0]) * (1.0 / 3.0);
             y2 = (y3 + 2 * ctx->params[1]) * (1.0 / 3.0);
             rsvg_path_builder_curve_to (ctx->builder, x1, y1, x2, y2, x3, y3);
-            ctx->rp.point.x = ctx->params[0];
-            ctx->rp.point.y = ctx->params[1];
-            ctx->cp.point.x = x3;
-            ctx->cp.point.y = y3;
+            ctx->rp_x = ctx->params[0];
+            ctx->rp_y = ctx->params[1];
+            ctx->cp_x = x3;
+            ctx->cp_y = y3;
             ctx->param = 0;
         }
         break;
@@ -501,41 +354,41 @@ rsvg_parse_path_do_cmd (RSVGParsePathCtx * ctx, gboolean final)
         if (ctx->param == 2 || final) {
             double xc, yc;      /* quadratic control point */
 
-            xc = 2 * ctx->cp.point.x - ctx->rp.point.x;
-            yc = 2 * ctx->cp.point.y - ctx->rp.point.y;
+            xc = 2 * ctx->cp_x - ctx->rp_x;
+            yc = 2 * ctx->cp_y - ctx->rp_y;
             /* generate a quadratic bezier with control point = xc, yc */
-            x1 = (ctx->cp.point.x + 2 * xc) * (1.0 / 3.0);
-            y1 = (ctx->cp.point.y + 2 * yc) * (1.0 / 3.0);
+            x1 = (ctx->cp_x + 2 * xc) * (1.0 / 3.0);
+            y1 = (ctx->cp_y + 2 * yc) * (1.0 / 3.0);
             x3 = ctx->params[0];
             y3 = ctx->params[1];
             x2 = (x3 + 2 * xc) * (1.0 / 3.0);
             y2 = (y3 + 2 * yc) * (1.0 / 3.0);
             rsvg_path_builder_curve_to (ctx->builder, x1, y1, x2, y2, x3, y3);
-            ctx->rp.point.x = xc;
-            ctx->rp.point.y = yc;
-            ctx->cp.point.x = x3;
-            ctx->cp.point.y = y3;
+            ctx->rp_x = xc;
+            ctx->rp_y = yc;
+            ctx->cp_x = x3;
+            ctx->cp_y = y3;
             ctx->param = 0;
         } else if (final) {
             if (ctx->param > 2) {
                 rsvg_parse_path_default_xy (ctx, 4);
                 /* raise quadratic bezier to cubic */
-                x1 = (ctx->cp.point.x + 2 * ctx->params[0]) * (1.0 / 3.0);
-                y1 = (ctx->cp.point.y + 2 * ctx->params[1]) * (1.0 / 3.0);
+                x1 = (ctx->cp_x + 2 * ctx->params[0]) * (1.0 / 3.0);
+                y1 = (ctx->cp_y + 2 * ctx->params[1]) * (1.0 / 3.0);
                 x3 = ctx->params[2];
                 y3 = ctx->params[3];
                 x2 = (x3 + 2 * ctx->params[0]) * (1.0 / 3.0);
                 y2 = (y3 + 2 * ctx->params[1]) * (1.0 / 3.0);
                 rsvg_path_builder_curve_to (ctx->builder, x1, y1, x2, y2, x3, y3);
-                ctx->rp.point.x = ctx->params[0];
-                ctx->rp.point.y = ctx->params[1];
-                ctx->cp.point.x = x3;
-                ctx->cp.point.y = y3;
+                ctx->rp_x = ctx->params[0];
+                ctx->rp_y = ctx->params[1];
+                ctx->cp_x = x3;
+                ctx->cp_y = y3;
             } else {
                 rsvg_parse_path_default_xy (ctx, 2);
                 rsvg_path_builder_line_to (ctx->builder, ctx->params[0], ctx->params[1]);
-                ctx->cp.point.x = ctx->rp.point.x = ctx->params[0];
-                ctx->cp.point.y = ctx->rp.point.y = ctx->params[1];
+                ctx->cp_x = ctx->rp_x = ctx->params[0];
+                ctx->cp_y = ctx->rp_y = ctx->params[1];
             }
             ctx->param = 0;
         }
@@ -549,8 +402,8 @@ rsvg_parse_path_do_cmd (RSVGParsePathCtx * ctx, gboolean final)
             gboolean sweep_flag;
             double x2, y2;
 
-            x1 = ctx->cp.point.x;
-            y1 = ctx->cp.point.y;
+            x1 = ctx->cp_x;
+            y1 = ctx->cp_y;
 
             rx = ctx->params[0];
             ry = ctx->params[1];
@@ -571,8 +424,8 @@ rsvg_parse_path_do_cmd (RSVGParsePathCtx * ctx, gboolean final)
                                    sweep_flag,
                                    x2, y2);
 
-            ctx->rp.point.x = ctx->cp.point.x = x2;
-            ctx->rp.point.y = ctx->cp.point.y = y2;
+            ctx->rp_x = ctx->cp_x = x2;
+            ctx->rp_y = ctx->cp_y = y2;
 
             ctx->param = 0;
         }
@@ -600,25 +453,25 @@ rsvg_path_end_of_number (RSVGParsePathCtx * ctx, double val, int sign, int exp_s
             /* rule: even-numbered params are x-relative, odd-numbered
                are y-relative */
             if ((ctx->param & 1) == 0)
-                val += ctx->cp.point.x;
+                val += ctx->cp_x;
             else if ((ctx->param & 1) == 1)
-                val += ctx->cp.point.y;
+                val += ctx->cp_y;
             break;
         case 'a':
             /* rule: sixth and seventh are x and y, rest are not
                relative */
             if (ctx->param == 5)
-                val += ctx->cp.point.x;
+                val += ctx->cp_x;
             else if (ctx->param == 6)
-                val += ctx->cp.point.y;
+                val += ctx->cp_y;
             break;
         case 'h':
             /* rule: x-relative */
-            val += ctx->cp.point.x;
+            val += ctx->cp_x;
             break;
         case 'v':
             /* rule: y-relative */
-            val += ctx->cp.point.y;
+            val += ctx->cp_y;
             break;
         }
     }
@@ -748,7 +601,10 @@ rsvg_parse_path_data (RSVGParsePathCtx * ctx, const char *data)
                 rsvg_parse_path_do_cmd (ctx, TRUE);
             rsvg_path_builder_close_path (ctx->builder);
 
-            ctx->cp = ctx->rp = g_array_index (ctx->builder->path_data, cairo_path_data_t, 
ctx->builder->path_data->len - 1);
+            ctx->cp_x = ctx->last_moveto_x;
+            ctx->cp_y = ctx->last_moveto_y;
+            ctx->rp_x = ctx->cp_x;
+            ctx->rp_y = ctx->cp_y;
         } else if (c >= 'A' && c < 'Z' && c != 'E') {
             if (ctx->param)
                 rsvg_parse_path_do_cmd (ctx, TRUE);
@@ -771,10 +627,12 @@ rsvg_path_builder_parse_path (const char *path_str)
 
     ctx.builder = rsvg_path_builder_new ();
 
-    ctx.cp.point.x = 0.0;
-    ctx.cp.point.y = 0.0;
-    ctx.rp.point.x = 0.0;
-    ctx.rp.point.y = 0.0;
+    ctx.cp_x = 0.0;
+    ctx.cp_y = 0.0;
+    ctx.rp_x = 0.0;
+    ctx.rp_y = 0.0;
+    ctx.last_moveto_x = 0.0;
+    ctx.last_moveto_y = 0.0;
     ctx.cmd = 0;
     ctx.param = 0;
 
@@ -785,13 +643,3 @@ rsvg_path_builder_parse_path (const char *path_str)
 
     return ctx.builder;
 }
-
-void
-rsvg_cairo_path_destroy (cairo_path_t *path)
-{
-    if (path == NULL)
-        return;
-
-    g_free (path->data);
-    g_free (path);
-}
diff --git a/rsvg-path.h b/rsvg-path.h
index 1dfff58..7166421 100644
--- a/rsvg-path.h
+++ b/rsvg-path.h
@@ -69,17 +69,13 @@ void rsvg_path_builder_arc (RsvgPathBuilder *builder,
 
 G_GNUC_INTERNAL
 void rsvg_path_builder_close_path (RsvgPathBuilder *builder);
-G_GNUC_INTERNAL
-cairo_path_t *rsvg_path_builder_copy_path (RsvgPathBuilder *builder);
+
 G_GNUC_INTERNAL
 void rsvg_path_builder_add_to_cairo_context (RsvgPathBuilder *builder, cairo_t *cr);
 
 G_GNUC_INTERNAL
 RsvgPathBuilder *rsvg_path_builder_parse_path (const char *path_str);
 
-G_GNUC_INTERNAL
-void rsvg_cairo_path_destroy (cairo_path_t *path);
-
 G_END_DECLS
 
 #endif /* RSVG_PATH_H */
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 5dc77a9..b27892e 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -4,7 +4,8 @@ pub use path_builder::{
     rsvg_path_builder_move_to,
     rsvg_path_builder_line_to,
     rsvg_path_builder_curve_to,
-    rsvg_path_builder_close_path
+    rsvg_path_builder_close_path,
+    rsvg_path_builder_add_to_cairo_context
 };
 
 pub use marker::{
diff --git a/rust/src/path_builder.rs b/rust/src/path_builder.rs
index 0ce54d4..43eadfb 100644
--- a/rust/src/path_builder.rs
+++ b/rust/src/path_builder.rs
@@ -1,4 +1,5 @@
 extern crate cairo;
+extern crate cairo_sys;
 
 #[repr(C)]
 pub struct RsvgPathBuilder {
@@ -31,6 +32,10 @@ impl RsvgPathBuilder {
             }
         }
     }
+
+    fn get_path_segments (&mut self) -> &Vec<cairo::PathSegment> {
+        &self.path_segments
+    }
 }
 
 #[no_mangle]
@@ -94,3 +99,37 @@ pub extern fn rsvg_path_builder_close_path (raw_builder: *mut RsvgPathBuilder) {
 
     builder.close_path ();
 }
+
+#[no_mangle]
+pub extern fn rsvg_path_builder_add_to_cairo_context (raw_builder: *mut RsvgPathBuilder, cr: *mut 
cairo_sys::cairo_t) {
+    assert! (!raw_builder.is_null ());
+
+    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };
+
+    unsafe {
+        let path_segments = builder.get_path_segments ();
+
+        for s in path_segments {
+            match *s {
+                cairo::PathSegment::MoveTo ((x, y)) => {
+                    cairo_sys::cairo_move_to (cr, x, y);
+                },
+
+                cairo::PathSegment::LineTo ((x, y)) => {
+                    cairo_sys::cairo_line_to (cr, x, y);
+                },
+
+                cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)) => {
+                    cairo_sys::cairo_curve_to (cr, x2, y2, x3, y3, x4, y4);
+                },
+
+                cairo::PathSegment::ClosePath => {
+                    cairo_sys::cairo_close_path (cr);
+                    /* FIXME: we'll get a MoveTo from the path builder.  Do we need to omit it
+                     * if Cairo will add a similar Moveto by itself?
+                     */
+                }
+            }
+        }
+    }
+}


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