[librsvg] cnode.rs: New function rsvg_rust_cnode_get_impl() to fetch the C-side implementation



commit 5d524850efaa21ca84706977da2c2fa0f8d74e55
Author: Federico Mena Quintero <federico gnome org>
Date:   Thu Feb 9 21:00:22 2017 -0600

    cnode.rs: New function rsvg_rust_cnode_get_impl() to fetch the C-side implementation
    
    We need this for a couple of special cases that are *not*
    implementations of node methods and yet want to use the impl structures.
    For example, rsvg_handle_get_dimensions_sub() wants to peek at the
    toplevel svg->vbox.
    
    We add a Node.get_c_impl() method, and a NodeTrait.get_c_impl().  The
    CNode actually implements this last one by returning its stored
    c_node_impl.  Nodes implemented fully in Rust will return just a null
    pointer.
    
    We can hopefully remove that method once everything is implemented in Rust.
    
    * Move rsvg-structure.[ch] over to rsvg_rust_cnode_new()
    
    The new rsvg_foo_node_new() functions use rsvg_rust_cnode_new()
    internally instead of the old _rsvg_node_init().  Also, the RsvgFooNode
    structs don't have a "super" field anymore, since RsvgNode is now an
    opaque struct from the Rust code.
    
    We re-do the virtual methods for all of rsvg-structure.c.  Other files
    will follow.
    
    * Move rsvg-shapes.[ch] over to rsvg_rust_cnode_new().

 rsvg-base.c        |   25 ++-
 rsvg-private.h     |   26 +++-
 rsvg-shapes.c      |  271 ++++++++++++++++-------------
 rsvg-shapes.h      |   14 +-
 rsvg-structure.c   |  483 ++++++++++++++++++++++++----------------------------
 rsvg-structure.h   |   27 +--
 rust/src/cnode.rs  |   17 ++-
 rust/src/lib.rs    |    1 +
 rust/src/node.rs   |   24 +++-
 rust/src/shapes.rs |    6 +
 10 files changed, 466 insertions(+), 428 deletions(-)
---
diff --git a/rsvg-base.c b/rsvg-base.c
index 7a2f108..3c30018 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -239,7 +239,7 @@ free_element_name_stack (RsvgHandle *ctx)
     ctx->priv->element_name_stack = NULL;
 }
 
-typedef RsvgNode *(* CreateNodeFn) (const char *element_name);
+typedef RsvgNode *(* CreateNodeFn) (const char *element_name, RsvgNode *parent);
 
 typedef struct {
     const char   *element_name;
@@ -410,7 +410,7 @@ rsvg_standard_element_start (RsvgHandle * ctx, const char *name, RsvgPropertyBag
     creator = get_node_creator_for_element_name (name);
     g_assert (creator != NULL && creator->create_fn != NULL);
 
-    newnode = creator->create_fn (name);
+    newnode = creator->create_fn (name, ctx->priv->currentnode);
 
     if (newnode) {
         g_assert (rsvg_node_get_type (newnode) != RSVG_NODE_TYPE_INVALID);
@@ -835,8 +835,14 @@ rsvg_end_element (void *data, const xmlChar * xmlname)
         }
 
         /* FIXMEchpe: shouldn't this check that currentnode == treebase or sth like that? */
-        if (ctx->priv->treebase && !strcmp (name, "svg"))
-            _rsvg_node_svg_apply_atts ((RsvgNodeSvg *)ctx->priv->treebase, ctx);
+        if (ctx->priv->treebase && !strcmp (name, "svg")) {
+            RsvgNodeSvg *svg;
+
+            g_assert (rsvg_node_get_type (ctx->priv->treebase) == RSVG_NODE_TYPE_SVG);
+            svg = rsvg_rust_cnode_get_impl (ctx->priv->treebase);
+
+            _rsvg_node_svg_apply_atts (ctx->priv->treebase, svg, ctx);
+        }
     }
 }
 
@@ -1512,11 +1518,12 @@ rsvg_handle_get_dimensions_sub (RsvgHandle * handle, RsvgDimensionData * dimensi
     if (!sself && id)
         return FALSE;
 
-    root = (RsvgNodeSvg *) handle->priv->treebase;
-
-    if (!root)
+    if (!handle->priv->treebase)
         return FALSE;
 
+    g_assert (rsvg_node_get_type (handle->priv->treebase) == RSVG_NODE_TYPE_SVG);
+    root = rsvg_rust_cnode_get_impl (handle->priv->treebase);
+
     bbox.rect.x = bbox.rect.y = 0;
     bbox.rect.width = bbox.rect.height = 1;
 
@@ -1592,7 +1599,6 @@ gboolean
 rsvg_handle_get_position_sub (RsvgHandle * handle, RsvgPositionData * position_data, const char *id)
 {
     RsvgDrawingCtx             *draw;
-    RsvgNodeSvg                        *root;
     RsvgNode                   *node;
     RsvgBbox                    bbox;
     RsvgDimensionData    dimension_data;
@@ -1623,8 +1629,7 @@ rsvg_handle_get_position_sub (RsvgHandle * handle, RsvgPositionData * position_d
         return TRUE;
     }
 
-    root = (RsvgNodeSvg *) handle->priv->treebase;
-    if (!root)
+    if (!handle->priv->treebase)
         return FALSE;
 
     target = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1);
diff --git a/rsvg-private.h b/rsvg-private.h
index d52aede..e16f79f 100644
--- a/rsvg-private.h
+++ b/rsvg-private.h
@@ -334,11 +334,23 @@ typedef enum {
     RSVG_NODE_TYPE_FILTER_PRIMITIVE_LAST                /* just a marker; not a valid type */
 } RsvgNodeType;
 
-typedef struct {
-    void (*free) (RsvgNode * self);
-    void (*draw) (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate);
-    void (*set_atts) (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag *atts);
-} RsvgNodeVtable;
+typedef void (* CNodeSetAtts) (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *pbag);
+typedef void (* CNodeDraw) (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate);
+typedef void (* CNodeFree) (gpointer impl);
+
+/* Implemented in rust/src/node.rs */
+G_GNUC_INTERNAL
+RsvgNode *rsvg_rust_cnode_new (RsvgNodeType  node_type,
+                               RsvgNode     *parent,
+                               RsvgState    *state,
+                               gpointer      impl,
+                               CNodeSetAtts  set_atts_fn,
+                               CNodeDraw     draw_fn,
+                               CNodeFree     free_fn);
+
+/* Implemented in rust/src/node.rs */
+G_GNUC_INTERNAL
+gpointer rsvg_rust_cnode_get_impl (RsvgNode *node);
 
 /* Implemented in rust/src/node.rs */
 G_GNUC_INTERNAL
@@ -362,6 +374,10 @@ RsvgNode *rsvg_node_get_parent (RsvgNode *node);
 
 /* Implemented in rust/src/node.rs */
 G_GNUC_INTERNAL
+void rsvg_node_add_child (RsvgNode *node, RsvgNode *child);
+
+/* Implemented in rust/src/node.rs */
+G_GNUC_INTERNAL
 void rsvg_node_set_atts (RsvgNode *node, RsvgHandle *handle, RsvgPropertyBag *atts);
 
 /* Implemented in rust/src/node.rs */
diff --git a/rsvg-shapes.c b/rsvg-shapes.c
index 9d6ad50..2e0906f 100644
--- a/rsvg-shapes.c
+++ b/rsvg-shapes.c
@@ -44,38 +44,38 @@
 typedef struct _RsvgNodePath RsvgNodePath;
 
 struct _RsvgNodePath {
-    RsvgNode super;
     RsvgPathBuilder *builder;
 };
 
 static void
-rsvg_node_path_free (RsvgNode * self)
+rsvg_node_path_free (gpointer impl)
 {
-    RsvgNodePath *path = (RsvgNodePath *) self;
+    RsvgNodePath *path = impl;
+
     if (path->builder)
         rsvg_path_builder_destroy (path->builder);
 
-    _rsvg_node_free (self);
+    g_free (path);
 }
 
 static void
-rsvg_node_path_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
+rsvg_node_path_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
 {
-    RsvgNodePath *path = (RsvgNodePath *) self;
+    RsvgNodePath *path = impl;
 
     if (!path->builder)
         return;
 
-    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (self), dominate);
+    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (node), dominate);
 
     rsvg_render_path_builder (ctx, path->builder);
     rsvg_render_markers (ctx, path->builder);
 }
 
 static void
-rsvg_node_path_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
+rsvg_node_path_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag * atts)
 {
-    RsvgNodePath *path = (RsvgNodePath *) self;
+    RsvgNodePath *path = impl;
     const char *value;
 
     if ((value = rsvg_property_bag_lookup (atts, "d"))) {
@@ -86,38 +86,36 @@ rsvg_node_path_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * at
 }
 
 RsvgNode *
-rsvg_new_path (const char *element_name)
+rsvg_new_path (const char *element_name, RsvgNode *parent)
 {
     RsvgNodePath *path;
-    RsvgNodeVtable vtable = {
-        rsvg_node_path_free,
-        rsvg_node_path_draw,
-        rsvg_node_path_set_atts
-    };
-
-    path = g_new (RsvgNodePath, 1);
-    _rsvg_node_init (&path->super, RSVG_NODE_TYPE_PATH, &vtable);
 
+    path = g_new0 (RsvgNodePath, 1);
     path->builder = NULL;
 
-    return &path->super;
+    return rsvg_rust_cnode_new (RSVG_NODE_TYPE_PATH,
+                                parent,
+                                rsvg_state_new (),
+                                path,
+                                rsvg_node_path_set_atts,
+                                rsvg_node_path_draw,
+                                rsvg_node_path_free);
 }
 
+typedef struct _RsvgNodePoly RsvgNodePoly;
+
 struct _RsvgNodePoly {
-    RsvgNode super;
     RsvgPathBuilder *builder;
 };
 
-typedef struct _RsvgNodePoly RsvgNodePoly;
-
 static RsvgPathBuilder *
-_rsvg_node_poly_create_builder (const char *value,
-                                gboolean close_path);
+rsvg_node_poly_create_builder (const char *value,
+                               gboolean close_path);
 
 static void
-_rsvg_node_poly_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
+rsvg_node_poly_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
 {
-    RsvgNodePoly *poly = (RsvgNodePoly *) self;
+    RsvgNodePoly *poly = impl;
     const char *value;
 
     /* support for svg < 1.0 which used verts */
@@ -125,14 +123,14 @@ _rsvg_node_poly_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * a
         || (value = rsvg_property_bag_lookup (atts, "points"))) {
         if (poly->builder)
             rsvg_path_builder_destroy (poly->builder);
-        poly->builder = _rsvg_node_poly_create_builder (value,
-                                                        rsvg_node_get_type (self) == RSVG_NODE_TYPE_POLYGON);
+        poly->builder = rsvg_node_poly_create_builder (value,
+                                                       rsvg_node_get_type (node) == RSVG_NODE_TYPE_POLYGON);
     }
 }
 
 static RsvgPathBuilder *
-_rsvg_node_poly_create_builder (const char *value,
-                                gboolean close_path)
+rsvg_node_poly_create_builder (const char *value,
+                               gboolean close_path)
 {
     double *pointlist;
     guint pointlist_len, i;
@@ -177,70 +175,70 @@ _rsvg_node_poly_create_builder (const char *value,
 }
 
 static void
-_rsvg_node_poly_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
+rsvg_node_poly_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
 {
-    RsvgNodePoly *poly = (RsvgNodePoly *) self;
+    RsvgNodePoly *poly = impl;
 
     if (poly->builder == NULL)
         return;
 
-    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (self), dominate);
+    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (node), dominate);
 
     rsvg_render_path_builder (ctx, poly->builder);
     rsvg_render_markers (ctx, poly->builder);
 }
 
 static void
-_rsvg_node_poly_free (RsvgNode * self)
+rsvg_node_poly_free (gpointer impl)
 {
-    RsvgNodePoly *poly = (RsvgNodePoly *) self;
+    RsvgNodePoly *poly = impl;
+
     if (poly->builder)
         rsvg_path_builder_destroy (poly->builder);
 
-    _rsvg_node_free (self);
+    g_free (poly);
 }
 
 static RsvgNode *
-rsvg_new_any_poly (RsvgNodeType type)
+rsvg_new_any_poly (RsvgNodeType type, RsvgNode *parent)
 {
     RsvgNodePoly *poly;
-    RsvgNodeVtable vtable = {
-        _rsvg_node_poly_free,
-        _rsvg_node_poly_draw,
-        _rsvg_node_poly_set_atts
-    };
-
-    poly = g_new (RsvgNodePoly, 1);
-    _rsvg_node_init (&poly->super, type, &vtable);
 
+    poly = g_new0 (RsvgNodePoly, 1);
     poly->builder = NULL;
-    return &poly->super;
+
+    return rsvg_rust_cnode_new (type,
+                                parent,
+                                rsvg_state_new (),
+                                poly,
+                                rsvg_node_poly_set_atts,
+                                rsvg_node_poly_draw,
+                                rsvg_node_poly_free);
 }
 
 RsvgNode *
-rsvg_new_polygon (const char *element_name)
+rsvg_new_polygon (const char *element_name, RsvgNode *parent)
 {
-    return rsvg_new_any_poly (RSVG_NODE_TYPE_POLYGON);
+    return rsvg_new_any_poly (RSVG_NODE_TYPE_POLYGON, parent);
 }
 
 RsvgNode *
-rsvg_new_polyline (const char *element_name)
+rsvg_new_polyline (const char *element_name, RsvgNode *parent)
 {
-    return rsvg_new_any_poly (RSVG_NODE_TYPE_POLYLINE);
+    return rsvg_new_any_poly (RSVG_NODE_TYPE_POLYLINE, parent);
 }
 
 
+typedef struct _RsvgNodeLine RsvgNodeLine;
+
 struct _RsvgNodeLine {
-    RsvgNode super;
     RsvgLength x1, x2, y1, y2;
 };
 
-typedef struct _RsvgNodeLine RsvgNodeLine;
-
 static void
-_rsvg_node_line_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
+rsvg_node_line_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
 {
-    RsvgNodeLine *line = (RsvgNodeLine *) self;
+    RsvgNodeLine *line = impl;
     const char *value;
 
     if ((value = rsvg_property_bag_lookup (atts, "x1")))
@@ -254,10 +252,10 @@ _rsvg_node_line_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * a
 }
 
 static void
-_rsvg_node_line_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
+rsvg_node_line_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
 {
+    RsvgNodeLine *line = impl;
     RsvgPathBuilder *builder;
-    RsvgNodeLine *line = (RsvgNodeLine *) self;
     double x1, y1, x2, y2;
 
     builder = rsvg_path_builder_new ();
@@ -270,7 +268,7 @@ _rsvg_node_line_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
     rsvg_path_builder_move_to (builder, x1, y1);
     rsvg_path_builder_line_to (builder, x2, y2);
 
-    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (self), dominate);
+    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (node), dominate);
 
     rsvg_render_path_builder (ctx, builder);
     rsvg_render_markers (ctx, builder);
@@ -278,35 +276,42 @@ _rsvg_node_line_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
     rsvg_path_builder_destroy (builder);
 }
 
+static void
+rsvg_node_line_free (gpointer impl)
+{
+    RsvgNodeLine *line = impl;
+
+    g_free (line);
+}
+
 RsvgNode *
-rsvg_new_line (const char *element_name)
+rsvg_new_line (const char *element_name, RsvgNode *parent)
 {
     RsvgNodeLine *line;
-    RsvgNodeVtable vtable = {
-        NULL,
-        _rsvg_node_line_draw,
-        _rsvg_node_line_set_atts
-    };
-
-    line = g_new (RsvgNodeLine, 1);
-    _rsvg_node_init (&line->super, RSVG_NODE_TYPE_LINE, &vtable);
 
+    line = g_new0 (RsvgNodeLine, 1);
     line->x1 = line->x2 = line->y1 = line->y2 = rsvg_length_parse ("0", LENGTH_DIR_BOTH);
-    return &line->super;
+
+    return rsvg_rust_cnode_new (RSVG_NODE_TYPE_LINE,
+                                parent,
+                                rsvg_state_new (),
+                                line,
+                                rsvg_node_line_set_atts,
+                                rsvg_node_line_draw,
+                                rsvg_node_line_free);
 }
 
+typedef struct _RsvgNodeRect RsvgNodeRect;
+
 struct _RsvgNodeRect {
-    RsvgNode super;
     RsvgLength x, y, w, h, rx, ry;
     gboolean got_rx, got_ry;
 };
 
-typedef struct _RsvgNodeRect RsvgNodeRect;
-
 static void
-_rsvg_node_rect_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
+rsvg_node_rect_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
 {
-    RsvgNodeRect *rect = (RsvgNodeRect *) self;
+    RsvgNodeRect *rect = impl;
     const char *value;
 
     /* FIXME: negative w/h/rx/ry is an error, per http://www.w3.org/TR/SVG11/shapes.html#RectElement */
@@ -329,12 +334,12 @@ _rsvg_node_rect_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * a
 }
 
 static void
-_rsvg_node_rect_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
+rsvg_node_rect_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
 {
+    RsvgNodeRect *rect = impl;
     double x, y, w, h, rx, ry;
     double half_w, half_h;
     RsvgPathBuilder *builder;
-    RsvgNodeRect *rect = (RsvgNodeRect *) self;
 
     x = rsvg_length_normalize (&rect->x, ctx);
     y = rsvg_length_normalize (&rect->y, ctx);
@@ -455,42 +460,49 @@ _rsvg_node_rect_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
         rsvg_path_builder_close_path (builder);
     }
 
-    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (self), dominate);
+    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (node), dominate);
 
     rsvg_render_path_builder (ctx, builder);
 
     rsvg_path_builder_destroy (builder);
 }
 
+static void
+rsvg_node_rect_free (gpointer impl)
+{
+    RsvgNodeRect *rect = impl;
+
+    g_free (rect);
+}
+
 RsvgNode *
-rsvg_new_rect (const char *element_name)
+rsvg_new_rect (const char *element_name, RsvgNode *parent)
 {
     RsvgNodeRect *rect;
-    RsvgNodeVtable vtable = {
-        NULL,
-        _rsvg_node_rect_draw,
-        _rsvg_node_rect_set_atts
-    };
-
-    rect = g_new (RsvgNodeRect, 1);
-    _rsvg_node_init (&rect->super, RSVG_NODE_TYPE_RECT, &vtable);
 
+    rect = g_new0 (RsvgNodeRect, 1);
     rect->x = rect->y = rect->w = rect->h = rect->rx = rect->ry = rsvg_length_parse ("0", LENGTH_DIR_BOTH);
     rect->got_rx = rect->got_ry = FALSE;
-    return &rect->super;
+
+    return rsvg_rust_cnode_new (RSVG_NODE_TYPE_RECT,
+                                parent,
+                                rsvg_state_new (),
+                                rect,
+                                rsvg_node_rect_set_atts,
+                                rsvg_node_rect_draw,
+                                rsvg_node_rect_free);
 }
 
+typedef struct _RsvgNodeCircle RsvgNodeCircle;
+
 struct _RsvgNodeCircle {
-    RsvgNode super;
     RsvgLength cx, cy, r;
 };
 
-typedef struct _RsvgNodeCircle RsvgNodeCircle;
-
 static void
-_rsvg_node_circle_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
+rsvg_node_circle_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
 {
-    RsvgNodeCircle *circle = (RsvgNodeCircle *) self;
+    RsvgNodeCircle *circle = impl;
     const char *value;
 
     if ((value = rsvg_property_bag_lookup (atts, "cx")))
@@ -502,9 +514,9 @@ _rsvg_node_circle_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag *
 }
 
 static void
-_rsvg_node_circle_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
+rsvg_node_circle_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
 {
-    RsvgNodeCircle *circle = (RsvgNodeCircle *) self;
+    RsvgNodeCircle *circle = impl;
     double cx, cy, r;
     RsvgPathBuilder *builder;
 
@@ -543,41 +555,48 @@ _rsvg_node_circle_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
 
     rsvg_path_builder_close_path (builder);
 
-    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (self), dominate);
+    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (node), dominate);
 
     rsvg_render_path_builder (ctx, builder);
 
     rsvg_path_builder_destroy (builder);
 }
 
+static void
+rsvg_node_circle_free (gpointer impl)
+{
+    RsvgNodeCircle *circle = impl;
+
+    g_free (circle);
+}
+
 RsvgNode *
-rsvg_new_circle (const char *element_name)
+rsvg_new_circle (const char *element_name, RsvgNode *parent)
 {
     RsvgNodeCircle *circle;
-    RsvgNodeVtable vtable = {
-        NULL,
-        _rsvg_node_circle_draw,
-        _rsvg_node_circle_set_atts
-    };
-
-    circle = g_new (RsvgNodeCircle, 1);
-    _rsvg_node_init (&circle->super, RSVG_NODE_TYPE_CIRCLE, &vtable);
 
+    circle = g_new0 (RsvgNodeCircle, 1);
     circle->cx = circle->cy = circle->r = rsvg_length_parse ("0", LENGTH_DIR_BOTH);
-    return &circle->super;
+
+    return rsvg_rust_cnode_new (RSVG_NODE_TYPE_CIRCLE,
+                                parent,
+                                rsvg_state_new (),
+                                circle,
+                                rsvg_node_circle_set_atts,
+                                rsvg_node_circle_draw,
+                                rsvg_node_circle_free);
 }
 
+typedef struct _RsvgNodeEllipse RsvgNodeEllipse;
+
 struct _RsvgNodeEllipse {
-    RsvgNode super;
     RsvgLength cx, cy, rx, ry;
 };
 
-typedef struct _RsvgNodeEllipse RsvgNodeEllipse;
-
 static void
-_rsvg_node_ellipse_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
+rsvg_node_ellipse_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
 {
-    RsvgNodeEllipse *ellipse = (RsvgNodeEllipse *) self;
+    RsvgNodeEllipse *ellipse = impl;
     const char *value;
 
     if ((value = rsvg_property_bag_lookup (atts, "cx")))
@@ -591,9 +610,9 @@ _rsvg_node_ellipse_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag
 }
 
 static void
-_rsvg_node_ellipse_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
+rsvg_node_ellipse_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
 {
-    RsvgNodeEllipse *ellipse = (RsvgNodeEllipse *) self;
+    RsvgNodeEllipse *ellipse = impl;
     double cx, cy, rx, ry;
     RsvgPathBuilder *builder;
 
@@ -633,26 +652,34 @@ _rsvg_node_ellipse_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
 
     rsvg_path_builder_close_path (builder);
 
-    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (self), dominate);
+    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (node), dominate);
 
     rsvg_render_path_builder (ctx, builder);
 
     rsvg_path_builder_destroy (builder);
 }
 
+static void
+rsvg_node_ellipse_free (gpointer impl)
+{
+    RsvgNodeRect *ellipse = impl;
+
+    g_free (ellipse);
+}
+
 RsvgNode *
-rsvg_new_ellipse (const char *element_name)
+rsvg_new_ellipse (const char *element_name, RsvgNode *parent)
 {
     RsvgNodeEllipse *ellipse;
-    RsvgNodeVtable vtable = {
-        NULL,
-        _rsvg_node_ellipse_draw,
-        _rsvg_node_ellipse_set_atts
-    };
-
-    ellipse = g_new (RsvgNodeEllipse, 1);
-    _rsvg_node_init (&ellipse->super, RSVG_NODE_TYPE_ELLIPSE, &vtable);
 
+    ellipse = g_new0 (RsvgNodeEllipse, 1);
     ellipse->cx = ellipse->cy = ellipse->rx = ellipse->ry = rsvg_length_parse ("0", LENGTH_DIR_BOTH);
-    return &ellipse->super;
+
+    return rsvg_rust_cnode_new (RSVG_NODE_TYPE_ELLIPSE,
+                                parent,
+                                rsvg_state_new (),
+                                ellipse,
+                                rsvg_node_ellipse_set_atts,
+                                rsvg_node_ellipse_draw,
+                                rsvg_node_ellipse_free);
 }
diff --git a/rsvg-shapes.h b/rsvg-shapes.h
index 5b0029f..686badf 100644
--- a/rsvg-shapes.h
+++ b/rsvg-shapes.h
@@ -37,19 +37,19 @@
 G_BEGIN_DECLS 
 
 G_GNUC_INTERNAL
-RsvgNode *rsvg_new_path (const char *element_name);
+RsvgNode *rsvg_new_path (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
-RsvgNode *rsvg_new_polygon (const char *element_name);
+RsvgNode *rsvg_new_polygon (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
-RsvgNode *rsvg_new_polyline (const char *element_name);
+RsvgNode *rsvg_new_polyline (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
-RsvgNode *rsvg_new_line (const char *element_name);
+RsvgNode *rsvg_new_line (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
-RsvgNode *rsvg_new_rect (const char *element_name);
+RsvgNode *rsvg_new_rect (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
-RsvgNode *rsvg_new_circle (const char *element_name);
+RsvgNode *rsvg_new_circle (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
-RsvgNode *rsvg_new_ellipse (const char *element_name);
+RsvgNode *rsvg_new_ellipse (const char *element_name, RsvgNode *parent);
 
 G_END_DECLS
 
diff --git a/rsvg-structure.c b/rsvg-structure.c
index 5ff0b6c..bea8cd7 100644
--- a/rsvg-structure.c
+++ b/rsvg-structure.c
@@ -39,41 +39,39 @@ typedef struct _RsvgNodeUse RsvgNodeUse;
 typedef struct _RsvgNodeSymbol RsvgNodeSymbol;
 
 struct _RsvgNodeGroup {
-    RsvgNode super;
+    int dummy; /* just to avoid having an empty struct */
 };
 
 struct _RsvgNodeSymbol {
-    RsvgNode super;
     guint32 preserve_aspect_ratio;
     RsvgViewBox vbox;
 };
 
 struct _RsvgNodeUse {
-    RsvgNode super;
     char *link;
     RsvgLength x, y, w, h;
 };
 
 void
-rsvg_node_draw_from_stack (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
+rsvg_node_draw_from_stack (RsvgNode *node, RsvgDrawingCtx * ctx, int dominate)
 {
     RsvgState *state;
     GSList *stacksave;
 
     stacksave = ctx->drawsub_stack;
     if (stacksave) {
-        if (stacksave->data != self)
+        if (stacksave->data != node)
             return;
 
         ctx->drawsub_stack = stacksave->next;
     }
 
-    state = rsvg_node_get_state (self);
+    state = rsvg_node_get_state (node);
 
     if (state->visible) {
         rsvg_state_push (ctx);
 
-        rsvg_node_draw (self, ctx, dominate);
+        rsvg_node_draw (node, ctx, dominate);
 
         rsvg_state_pop (ctx);
     }
@@ -95,230 +93,90 @@ draw_child (RsvgNode *node, gpointer data)
 
 /* generic function for drawing all of the children of a particular node */
 void
-_rsvg_node_draw_children (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
+_rsvg_node_draw_children (RsvgNode *node, RsvgDrawingCtx *ctx, int dominate)
 {
     if (dominate != -1) {
-        rsvg_state_reinherit_top (ctx, rsvg_node_get_state (self), dominate);
+        rsvg_state_reinherit_top (ctx, rsvg_node_get_state (node), dominate);
 
         rsvg_push_discrete_layer (ctx);
     }
 
-    rsvg_node_foreach_child (self, draw_child, ctx);
+    rsvg_node_foreach_child (node, draw_child, ctx);
 
     if (dominate != -1)
         rsvg_pop_discrete_layer (ctx);
 }
 
-/* generic function that doesn't draw anything at all */
 static void
-_rsvg_node_draw_nothing (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
+rsvg_group_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
 {
+    /* nothing */
 }
 
 static void
-_rsvg_node_dont_set_atts (RsvgNode * node, RsvgHandle * ctx, RsvgPropertyBag * atts)
+rsvg_group_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
 {
+    _rsvg_node_draw_children (node, ctx, dominate);
 }
 
-void
-_rsvg_node_init (RsvgNode * self,
-                 RsvgNodeType type,
-                 RsvgNodeVtable *vtable)
+static void
+rsvg_group_free (gpointer impl)
 {
-    self->type = type;
-    self->parent = NULL;
-    self->children = g_ptr_array_new ();
-    self->state = rsvg_state_new ();
-    self->vtable = g_new (RsvgNodeVtable, 1);
-
-    if (vtable->free) {
-        self->vtable->free = vtable->free;
-    } else {
-        self->vtable->free = _rsvg_node_free;
-    }
-
-    if (vtable->draw) {
-        self->vtable->draw = vtable->draw;
-    } else {
-        self->vtable->draw = _rsvg_node_draw_nothing;
-    }
+    RsvgNodeGroup *group = impl;
 
-    if (vtable->set_atts) {
-        self->vtable->set_atts = vtable->set_atts;
-    } else {
-        self->vtable->set_atts = _rsvg_node_dont_set_atts;
-    }
-}
-
-void
-_rsvg_node_free (RsvgNode * self)
-{
-    if (self->state != NULL) {
-        rsvg_state_free (self->state);
-        self->state = NULL;
-    }
-    if (self->children != NULL) {
-        g_ptr_array_free (self->children, TRUE);
-        self->children = NULL;
-    }
-
-    self->parent = NULL;
-    self->type = RSVG_NODE_TYPE_INVALID;
-
-    g_free (self->vtable);
-    self->vtable = NULL;
-
-    g_free (self);
+    g_free (group);
 }
 
 RsvgNode *
-rsvg_new_group (const char *element_name)
+rsvg_new_group (const char *element_name, RsvgNode *parent)
 {
     RsvgNodeGroup *group;
-    RsvgNodeVtable vtable = {
-        NULL,
-        _rsvg_node_draw_children,
-        NULL
-    };
-
-    group = g_new (RsvgNodeGroup, 1);
-    _rsvg_node_init (&group->super, RSVG_NODE_TYPE_GROUP, &vtable);
-
-    return &group->super;
-}
-
-void
-rsvg_node_add_child (RsvgNode * self, RsvgNode * child)
-{
-    g_ptr_array_add (self->children, child);
-    child->parent = self;
-}
-
-static gboolean
-rsvg_node_is_ancestor (RsvgNode * potential_ancestor, RsvgNode * potential_descendant)
-{
-    /* work our way up the family tree */
-    while (TRUE) {
-        if (potential_ancestor == potential_descendant)
-            return TRUE;
-        else if (rsvg_node_get_parent (potential_descendant) == NULL)
-            return FALSE;
-        else
-            potential_descendant = rsvg_node_get_parent (potential_descendant);
-    }
-
-    g_assert_not_reached ();
-    return FALSE;
-}
-
-static void
-rsvg_node_use_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
-{
-    RsvgNodeUse *use = (RsvgNodeUse *) self;
-    RsvgNode *child;
-    RsvgState *state;
-    cairo_matrix_t affine;
-    double x, y, w, h;
-    x = rsvg_length_normalize (&use->x, ctx);
-    y = rsvg_length_normalize (&use->y, ctx);
-    w = rsvg_length_normalize (&use->w, ctx);
-    h = rsvg_length_normalize (&use->h, ctx);
-
-    rsvg_state_reinherit_top (ctx, self->state, dominate);
 
-    if (use->link == NULL)
-      return;
-    child = rsvg_drawing_ctx_acquire_node (ctx, use->link);
-    if (!child)
-        return;
-    else if (rsvg_node_is_ancestor (child, self)) {     /* or, if we're <use>'ing ourself */
-        rsvg_drawing_ctx_release_node (ctx, child);
-        return;
-    }
-
-    state = rsvg_current_state (ctx);
-    if (rsvg_node_get_type (child) != RSVG_NODE_TYPE_SYMBOL) {
-        cairo_matrix_init_translate (&affine, x, y);
-        cairo_matrix_multiply (&state->affine, &affine, &state->affine);
-
-        rsvg_push_discrete_layer (ctx);
-        rsvg_node_draw_from_stack (child, ctx, 1);
-        rsvg_pop_discrete_layer (ctx);
-    } else {
-        RsvgNodeSymbol *symbol = (RsvgNodeSymbol *) child;
-
-        if (symbol->vbox.active) {
-            rsvg_aspect_ratio_compute (symbol->preserve_aspect_ratio,
-                                       symbol->vbox.rect.width,
-                                       symbol->vbox.rect.height,
-                                       &x, &y, &w, &h);
-
-            cairo_matrix_init_translate (&affine, x, y);
-            cairo_matrix_multiply (&state->affine, &affine, &state->affine);
+    group = g_new0 (RsvgNodeGroup, 1);
 
-            cairo_matrix_init_scale (&affine, w / symbol->vbox.rect.width, h / symbol->vbox.rect.height);
-            cairo_matrix_multiply (&state->affine, &affine, &state->affine);
-
-            cairo_matrix_init_translate (&affine, -symbol->vbox.rect.x, -symbol->vbox.rect.y);
-            cairo_matrix_multiply (&state->affine, &affine, &state->affine);
-
-            rsvg_drawing_ctx_push_view_box (ctx, symbol->vbox.rect.width, symbol->vbox.rect.height);
-            rsvg_push_discrete_layer (ctx);
-            if (!state->overflow || (!state->has_overflow && rsvg_node_get_state (child)->overflow))
-                rsvg_add_clipping_rect (ctx, symbol->vbox.rect.x, symbol->vbox.rect.y,
-                                        symbol->vbox.rect.width, symbol->vbox.rect.height);
-        } else {
-            cairo_matrix_init_translate (&affine, x, y);
-            cairo_matrix_multiply (&state->affine, &affine, &state->affine);
-            rsvg_push_discrete_layer (ctx);
-        }
-
-        rsvg_state_push (ctx);
-        _rsvg_node_draw_children (child, ctx, 1);
-        rsvg_state_pop (ctx);
-        rsvg_pop_discrete_layer (ctx);
-        if (symbol->vbox.active)
-            rsvg_drawing_ctx_pop_view_box (ctx);
-    }
-
-    rsvg_drawing_ctx_release_node (ctx, child);
+    return rsvg_rust_cnode_new (RSVG_NODE_TYPE_GROUP,
+                                parent,
+                                rsvg_state_new (),
+                                group,
+                                rsvg_group_set_atts,
+                                rsvg_group_draw,
+                                rsvg_group_free);
 }
 
 static void
-rsvg_node_svg_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
+rsvg_node_svg_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
 {
-    RsvgNodeSvg *sself;
+    RsvgNodeSvg *svg = impl;
     RsvgState *state;
     cairo_matrix_t affine, affine_old, affine_new;
     double nx, ny, nw, nh;
-    sself = (RsvgNodeSvg *) self;
 
-    nx = rsvg_length_normalize (&sself->x, ctx);
-    ny = rsvg_length_normalize (&sself->y, ctx);
-    nw = rsvg_length_normalize (&sself->w, ctx);
-    nh = rsvg_length_normalize (&sself->h, ctx);
+    nx = rsvg_length_normalize (&svg->x, ctx);
+    ny = rsvg_length_normalize (&svg->y, ctx);
+    nw = rsvg_length_normalize (&svg->w, ctx);
+    nh = rsvg_length_normalize (&svg->h, ctx);
 
-    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (self), dominate);
+    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (node), dominate);
 
     state = rsvg_current_state (ctx);
 
     affine_old = state->affine;
 
-    if (sself->vbox.active) {
+    if (svg->vbox.active) {
         double x = nx, y = ny, w = nw, h = nh;
-        rsvg_aspect_ratio_compute (sself->preserve_aspect_ratio,
-                                   sself->vbox.rect.width,
-                                   sself->vbox.rect.height,
+        rsvg_aspect_ratio_compute (svg->preserve_aspect_ratio,
+                                   svg->vbox.rect.width,
+                                   svg->vbox.rect.height,
                                    &x, &y, &w, &h);
         cairo_matrix_init (&affine,
-                           w / sself->vbox.rect.width,
+                           w / svg->vbox.rect.width,
                            0,
                            0,
-                           h / sself->vbox.rect.height,
-                           x - sself->vbox.rect.x * w / sself->vbox.rect.width,
-                           y - sself->vbox.rect.y * h / sself->vbox.rect.height);
+                           h / svg->vbox.rect.height,
+                           x - svg->vbox.rect.x * w / svg->vbox.rect.width,
+                           y - svg->vbox.rect.y * h / svg->vbox.rect.height);
         cairo_matrix_multiply (&state->affine, &affine, &state->affine);
-        rsvg_drawing_ctx_push_view_box (ctx, sself->vbox.rect.width, sself->vbox.rect.height);
+        rsvg_drawing_ctx_push_view_box (ctx, svg->vbox.rect.width, svg->vbox.rect.height);
     } else {
         cairo_matrix_init_translate (&affine, nx, ny);
         cairo_matrix_multiply (&state->affine, &affine, &state->affine);
@@ -331,23 +189,23 @@ rsvg_node_svg_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
 
     /* Bounding box addition must be AFTER the discrete layer push,
        which must be AFTER the transformation happens. */
-    if (!state->overflow && rsvg_node_get_parent (self)) {
+    if (!state->overflow && rsvg_node_get_parent (node)) {
         state->affine = affine_old;
         rsvg_add_clipping_rect (ctx, nx, ny, nw, nh);
         state->affine = affine_new;
     }
 
-    rsvg_node_foreach_child (self, draw_child, ctx);
+    rsvg_node_foreach_child (node, draw_child, ctx);
 
     rsvg_pop_discrete_layer (ctx);
     rsvg_drawing_ctx_pop_view_box (ctx);
 }
 
 static void
-rsvg_node_svg_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
+rsvg_node_svg_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
 {
     const char *value;
-    RsvgNodeSvg *svg = (RsvgNodeSvg *) self;
+    RsvgNodeSvg *svg = impl;
 
     if ((value = rsvg_property_bag_lookup (atts, "viewBox")))
         svg->vbox = rsvg_css_parse_vbox (value);
@@ -362,7 +220,7 @@ rsvg_node_svg_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * att
      * x & y attributes have no effect on outermost svg
      * http://www.w3.org/TR/SVG/struct.html#SVGElement
      */
-    if (rsvg_node_get_parent (self)) {
+    if (rsvg_node_get_parent (node)) {
         if ((value = rsvg_property_bag_lookup (atts, "x")))
             svg->x = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
 
@@ -374,48 +232,41 @@ rsvg_node_svg_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * att
      * style element is not loaded yet here, so we need to store those attribues
      * to be applied later.
      */
-    svg->atts = rsvg_property_bag_dup(atts);
+    svg->atts = rsvg_property_bag_dup (atts);
 }
 
 void
-_rsvg_node_svg_apply_atts (RsvgNodeSvg * self, RsvgHandle * ctx)
+_rsvg_node_svg_apply_atts (RsvgNode *node, RsvgNodeSvg *svg, RsvgHandle *ctx)
 {
     const char *id = NULL, *klazz = NULL, *value;
-    if (self->atts && rsvg_property_bag_size (self->atts)) {
-        if ((value = rsvg_property_bag_lookup (self->atts, "class")))
+    if (svg->atts && rsvg_property_bag_size (svg->atts)) {
+        if ((value = rsvg_property_bag_lookup (svg->atts, "class")))
             klazz = value;
-        if ((value = rsvg_property_bag_lookup (self->atts, "id")))
+        if ((value = rsvg_property_bag_lookup (svg->atts, "id")))
             id = value;
-        rsvg_parse_style_attrs (ctx, rsvg_node_get_state ((RsvgNode *) self), "svg", klazz, id, self->atts);
+        rsvg_parse_style_attrs (ctx, rsvg_node_get_state (node), "svg", klazz, id, svg->atts);
     }
 }
 
 static void
-rsvg_node_svg_free (RsvgNode * self)
+rsvg_node_svg_free (gpointer impl)
 {
-    RsvgNodeSvg *svg = (RsvgNodeSvg *) self;
+    RsvgNodeSvg *svg = impl;
 
     if (svg->atts) {
         rsvg_property_bag_free (svg->atts);
         svg->atts = NULL;
     }
 
-    _rsvg_node_free (self);
+    g_free (svg);
 }
 
 RsvgNode *
-rsvg_new_svg (const char *element_name)
+rsvg_new_svg (const char *element_name, RsvgNode *parent)
 {
     RsvgNodeSvg *svg;
-    RsvgNodeVtable vtable = {
-        rsvg_node_svg_free,
-        rsvg_node_svg_draw,
-        rsvg_node_svg_set_atts
-    };
-
-    svg = g_new (RsvgNodeSvg, 1);
-    _rsvg_node_init (&svg->super, RSVG_NODE_TYPE_SVG, &vtable);
 
+    svg = g_new0 (RsvgNodeSvg, 1);
     svg->vbox.active = FALSE;
     svg->preserve_aspect_ratio = RSVG_ASPECT_RATIO_XMID_YMID;
     svg->x = rsvg_length_parse ("0", LENGTH_DIR_HORIZONTAL);
@@ -423,25 +274,122 @@ rsvg_new_svg (const char *element_name)
     svg->w = rsvg_length_parse ("100%", LENGTH_DIR_HORIZONTAL);
     svg->h = rsvg_length_parse ("100%", LENGTH_DIR_VERTICAL);
     svg->atts = NULL;
-    return &svg->super;
+
+    return rsvg_rust_cnode_new (RSVG_NODE_TYPE_SVG,
+                                parent,
+                                rsvg_state_new (),
+                                svg,
+                                rsvg_node_svg_set_atts,
+                                rsvg_node_svg_draw,
+                                rsvg_node_svg_free);
+}
+
+static gboolean
+rsvg_node_is_ancestor (RsvgNode * potential_ancestor, RsvgNode * potential_descendant)
+{
+    /* work our way up the family tree */
+    while (TRUE) {
+        if (potential_ancestor == potential_descendant)
+            return TRUE;
+        else if (rsvg_node_get_parent (potential_descendant) == NULL)
+            return FALSE;
+        else
+            potential_descendant = rsvg_node_get_parent (potential_descendant);
+    }
+
+    g_assert_not_reached ();
+    return FALSE;
+}
+
+static void
+rsvg_node_use_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
+{
+    RsvgNodeUse *use = impl;
+    RsvgNode *child;
+    RsvgState *state;
+    cairo_matrix_t affine;
+    double x, y, w, h;
+
+    x = rsvg_length_normalize (&use->x, ctx);
+    y = rsvg_length_normalize (&use->y, ctx);
+    w = rsvg_length_normalize (&use->w, ctx);
+    h = rsvg_length_normalize (&use->h, ctx);
+
+    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (node), dominate);
+
+    if (use->link == NULL)
+      return;
+    child = rsvg_drawing_ctx_acquire_node (ctx, use->link);
+    if (!child)
+        return;
+    else if (rsvg_node_is_ancestor (child, node)) {     /* or, if we're <use>'ing ourself */
+        rsvg_drawing_ctx_release_node (ctx, child);
+        return;
+    }
+
+    state = rsvg_current_state (ctx);
+    if (rsvg_node_get_type (child) != RSVG_NODE_TYPE_SYMBOL) {
+        cairo_matrix_init_translate (&affine, x, y);
+        cairo_matrix_multiply (&state->affine, &affine, &state->affine);
+
+        rsvg_push_discrete_layer (ctx);
+        rsvg_node_draw_from_stack (child, ctx, 1);
+        rsvg_pop_discrete_layer (ctx);
+    } else {
+        RsvgNodeSymbol *symbol = rsvg_rust_cnode_get_impl (child);
+
+        if (symbol->vbox.active) {
+            rsvg_aspect_ratio_compute (symbol->preserve_aspect_ratio,
+                                       symbol->vbox.rect.width,
+                                       symbol->vbox.rect.height,
+                                       &x, &y, &w, &h);
+
+            cairo_matrix_init_translate (&affine, x, y);
+            cairo_matrix_multiply (&state->affine, &affine, &state->affine);
+
+            cairo_matrix_init_scale (&affine, w / symbol->vbox.rect.width, h / symbol->vbox.rect.height);
+            cairo_matrix_multiply (&state->affine, &affine, &state->affine);
+
+            cairo_matrix_init_translate (&affine, -symbol->vbox.rect.x, -symbol->vbox.rect.y);
+            cairo_matrix_multiply (&state->affine, &affine, &state->affine);
+
+            rsvg_drawing_ctx_push_view_box (ctx, symbol->vbox.rect.width, symbol->vbox.rect.height);
+            rsvg_push_discrete_layer (ctx);
+            if (!state->overflow || (!state->has_overflow && rsvg_node_get_state (child)->overflow))
+                rsvg_add_clipping_rect (ctx, symbol->vbox.rect.x, symbol->vbox.rect.y,
+                                        symbol->vbox.rect.width, symbol->vbox.rect.height);
+        } else {
+            cairo_matrix_init_translate (&affine, x, y);
+            cairo_matrix_multiply (&state->affine, &affine, &state->affine);
+            rsvg_push_discrete_layer (ctx);
+        }
+
+        rsvg_state_push (ctx);
+        _rsvg_node_draw_children (child, ctx, 1);
+        rsvg_state_pop (ctx);
+        rsvg_pop_discrete_layer (ctx);
+        if (symbol->vbox.active)
+            rsvg_drawing_ctx_pop_view_box (ctx);
+    }
+
+    rsvg_drawing_ctx_release_node (ctx, child);
 }
 
 static void
-rsvg_node_use_free (RsvgNode * node)
+rsvg_node_use_free (gpointer impl)
 {
-    RsvgNodeUse *use = (RsvgNodeUse *) node;
+    RsvgNodeUse *use = impl;
+
     g_free (use->link);
-    _rsvg_node_free (node);
+    g_free (use);
 }
 
 static void
-rsvg_node_use_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
+rsvg_node_use_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
 {
-    RsvgNodeUse *use;
+    RsvgNodeUse *use = impl;
     const char *value;
 
-    use = (RsvgNodeUse *) self;
-
     if ((value = rsvg_property_bag_lookup (atts, "x")))
         use->x = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
     if ((value = rsvg_property_bag_lookup (atts, "y")))
@@ -458,30 +406,30 @@ rsvg_node_use_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * att
 }
 
 RsvgNode *
-rsvg_new_use (const char *element_name)
+rsvg_new_use (const char *element_name, RsvgNode *parent)
 {
     RsvgNodeUse *use;
-    RsvgNodeVtable vtable = {
-        rsvg_node_use_free,
-        rsvg_node_use_draw,
-        rsvg_node_use_set_atts
-    };
-
-    use = g_new (RsvgNodeUse, 1);
-    _rsvg_node_init (&use->super, RSVG_NODE_TYPE_USE, &vtable);
 
+    use = g_new0 (RsvgNodeUse, 1);
     use->x = rsvg_length_parse ("0", LENGTH_DIR_HORIZONTAL);
     use->y = rsvg_length_parse ("0", LENGTH_DIR_VERTICAL);
     use->w = rsvg_length_parse ("0", LENGTH_DIR_HORIZONTAL);
     use->h = rsvg_length_parse ("0", LENGTH_DIR_VERTICAL);
     use->link = NULL;
-    return (RsvgNode *) use;
+
+    return rsvg_rust_cnode_new (RSVG_NODE_TYPE_USE,
+                                parent,
+                                rsvg_state_new (),
+                                use,
+                                rsvg_node_use_set_atts,
+                                rsvg_node_use_draw,
+                                rsvg_node_use_free);
 }
 
 static void
-rsvg_node_symbol_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
+rsvg_node_symbol_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
 {
-    RsvgNodeSymbol *symbol = (RsvgNodeSymbol *) self;
+    RsvgNodeSymbol *symbol = impl;
     const char *value;
 
     if ((value = rsvg_property_bag_lookup (atts, "viewBox")))
@@ -490,39 +438,59 @@ rsvg_node_symbol_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag *
         symbol->preserve_aspect_ratio = rsvg_aspect_ratio_parse (value);
 }
 
+static void
+rsvg_node_symbol_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
+{
+    /* nothing; this gets drawn specially in rsvg_node_use_draw() */
+}
+
+static void
+rsvg_node_symbol_free (gpointer impl)
+{
+    RsvgNodeSymbol *symbol = impl;
+
+    g_free (symbol);
+}
+
 
 RsvgNode *
-rsvg_new_symbol (const char *element_name)
+rsvg_new_symbol (const char *element_name, RsvgNode *parent)
 {
     RsvgNodeSymbol *symbol;
-    RsvgNodeVtable vtable = {
-        NULL,
-        NULL,
-        rsvg_node_symbol_set_atts
-    };
-
-    symbol = g_new (RsvgNodeSymbol, 1);
-    _rsvg_node_init (&symbol->super, RSVG_NODE_TYPE_SYMBOL, &vtable);
 
+    symbol = g_new0 (RsvgNodeSymbol, 1);
     symbol->vbox.active = FALSE;
     symbol->preserve_aspect_ratio = RSVG_ASPECT_RATIO_XMID_YMID;
-    return &symbol->super;
+
+    return rsvg_rust_cnode_new (RSVG_NODE_TYPE_SYMBOL,
+                                parent,
+                                rsvg_state_new (),
+                                symbol,
+                                rsvg_node_symbol_set_atts,
+                                rsvg_node_symbol_draw,
+                                rsvg_node_symbol_free);
+}
+
+static void
+rsvg_defs_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
+{
+    /* nothing */
 }
 
 RsvgNode *
-rsvg_new_defs (const char *element_name)
+rsvg_new_defs (const char *element_name, RsvgNode *parent)
 {
     RsvgNodeGroup *group;
-    RsvgNodeVtable vtable = {
-        NULL,
-        NULL,
-        NULL,
-    };
 
-    group = g_new (RsvgNodeGroup, 1);
-    _rsvg_node_init (&group->super, RSVG_NODE_TYPE_DEFS, &vtable);
+    group = g_new0 (RsvgNodeGroup, 1);
 
-    return &group->super;
+    return rsvg_rust_cnode_new (RSVG_NODE_TYPE_DEFS,
+                                parent,
+                                rsvg_state_new (),
+                                group,
+                                rsvg_group_set_atts,
+                                rsvg_defs_draw,
+                                rsvg_group_free);
 }
 
 static gboolean
@@ -542,29 +510,28 @@ draw_child_if_cond_true_and_stop (RsvgNode *node, gpointer data)
 }
 
 static void
-_rsvg_node_switch_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
+rsvg_node_switch_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
 {
-    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (self), dominate);
+    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (node), dominate);
 
     rsvg_push_discrete_layer (ctx);
 
-    rsvg_node_foreach_child (self, draw_child_if_cond_true_and_stop, ctx);
+    rsvg_node_foreach_child (node, draw_child_if_cond_true_and_stop, ctx);
 
     rsvg_pop_discrete_layer (ctx);
 }
 
 RsvgNode *
-rsvg_new_switch (const char *element_name)
+rsvg_new_switch (const char *element_name, RsvgNode *parent)
 {
     RsvgNodeGroup *group;
-    RsvgNodeVtable vtable = {
-        NULL,
-        _rsvg_node_switch_draw,
-        NULL
-    };
-
-    group = g_new (RsvgNodeGroup, 1);
-    _rsvg_node_init (&group->super, RSVG_NODE_TYPE_SWITCH, &vtable);
 
-    return &group->super;
+    group = g_new0 (RsvgNodeGroup, 1);
+    return rsvg_rust_cnode_new (RSVG_NODE_TYPE_SWITCH,
+                                parent,
+                                rsvg_state_new (),
+                                group,
+                                rsvg_group_set_atts,
+                                rsvg_node_switch_draw,
+                                rsvg_group_free);
 }
diff --git a/rsvg-structure.h b/rsvg-structure.h
index cfd0af4..50d012b 100644
--- a/rsvg-structure.h
+++ b/rsvg-structure.h
@@ -37,17 +37,17 @@
 G_BEGIN_DECLS 
 
 G_GNUC_INTERNAL
-RsvgNode *rsvg_new_use (const char *element_name);
+RsvgNode *rsvg_new_use (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
-RsvgNode *rsvg_new_symbol (const char *element_name);
+RsvgNode *rsvg_new_symbol (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
-RsvgNode *rsvg_new_svg (const char *element_name);
+RsvgNode *rsvg_new_svg (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
-RsvgNode *rsvg_new_defs (const char *element_name);
+RsvgNode *rsvg_new_defs (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
-RsvgNode *rsvg_new_group (const char *element_name);
+RsvgNode *rsvg_new_group (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
-RsvgNode *rsvg_new_switch (const char *element_name);
+RsvgNode *rsvg_new_switch (const char *element_name, RsvgNode *parent);
 
 typedef struct _RsvgNodeSvg RsvgNodeSvg;
 
@@ -60,21 +60,12 @@ struct _RsvgNodeSvg {
 };
 
 G_GNUC_INTERNAL
-void rsvg_node_add_child   (RsvgNode * self, RsvgNode * child);
+void rsvg_node_draw_from_stack  (RsvgNode *node, RsvgDrawingCtx * ctx, int dominate);
 G_GNUC_INTERNAL
-void rsvg_node_draw_from_stack  (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate);
-G_GNUC_INTERNAL
-void _rsvg_node_draw_children   (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate);
-G_GNUC_INTERNAL
-void _rsvg_node_free        (RsvgNode * self);
-
-G_GNUC_INTERNAL
-void _rsvg_node_init        (RsvgNode * self,
-                             RsvgNodeType type,
-                             RsvgNodeVtable *vtable);
+void _rsvg_node_draw_children   (RsvgNode *node, RsvgDrawingCtx * ctx, int dominate);
 
 G_GNUC_INTERNAL
-void _rsvg_node_svg_apply_atts  (RsvgNodeSvg * self, RsvgHandle * ctx);
+void _rsvg_node_svg_apply_atts  (RsvgNode *node, RsvgNodeSvg *svg, RsvgHandle * ctx);
 
 G_END_DECLS
 
diff --git a/rust/src/cnode.rs b/rust/src/cnode.rs
index 7dd6bfd..2ad4a69 100644
--- a/rust/src/cnode.rs
+++ b/rust/src/cnode.rs
@@ -6,11 +6,6 @@ use state::RsvgState;
 
 use std::rc::*;
 
-/* A *const RsvgCNodeImpl is just an opaque pointer to the C code's
- * struct for a particular node type.
- */
-pub enum RsvgCNodeImpl {}
-
 type CNodeSetAtts = unsafe extern "C" fn (node: *const RsvgNode, node_impl: *const RsvgCNodeImpl, handle: 
*const RsvgHandle, pbag: *const RsvgPropertyBag);
 type CNodeDraw = unsafe extern "C" fn (node: *const RsvgNode, node_impl: *const RsvgCNodeImpl, draw_ctx: 
*const RsvgDrawingCtx, dominate: i32);
 type CNodeFree = unsafe extern "C" fn (node_impl: *const RsvgCNodeImpl);
@@ -31,6 +26,10 @@ impl NodeTrait for CNode {
     fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
         unsafe { (self.draw_fn) (node as *const RsvgNode, self.c_node_impl, draw_ctx, dominate); }
     }
+
+    fn get_c_impl (&self) -> *const RsvgCNodeImpl {
+        self.c_node_impl
+    }
 }
 
 impl Drop for CNode {
@@ -70,3 +69,11 @@ pub extern fn rsvg_rust_cnode_new (node_type:   NodeType,
                                                  state,
                                                  Box::new (cnode)))))
 }
+
+#[no_mangle]
+pub extern fn rsvg_rust_cnode_get_impl (raw_node: *const RsvgNode) -> *const RsvgCNodeImpl {
+    assert! (!raw_node.is_null ());
+    let node: &RsvgNode = unsafe { & *raw_node };
+
+    node.get_c_impl ()
+}
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 62c7f75..7ea6920 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -67,6 +67,7 @@ pub use node::{
 
 pub use cnode::{
     rsvg_rust_cnode_new,
+    rsvg_rust_cnode_get_impl
 };
 
 pub use viewbox::{
diff --git a/rust/src/node.rs b/rust/src/node.rs
index 64b8f1a..8946ef0 100644
--- a/rust/src/node.rs
+++ b/rust/src/node.rs
@@ -19,9 +19,15 @@ use state::RsvgState;
  */
 pub type RsvgNode = Rc<Node>;
 
+/* A *const RsvgCNodeImpl is just an opaque pointer to the C code's
+ * struct for a particular node type.
+ */
+pub enum RsvgCNodeImpl {}
+
 pub trait NodeTrait {
     fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag);
     fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32);
+    fn get_c_impl (&self) -> *const RsvgCNodeImpl;
 }
 
 pub struct Node {
@@ -114,6 +120,18 @@ impl Node {
     pub fn add_child (&self, child: &Rc<Node>) {
         self.children.borrow_mut ().push (child.clone ());
     }
+
+    pub fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
+        self.node_impl.set_atts (node, handle, pbag);
+    }
+
+    pub fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
+        self.node_impl.draw (node, draw_ctx, dominate);
+    }
+
+    pub fn get_c_impl (&self) -> *const RsvgCNodeImpl {
+        self.node_impl.get_c_impl ()
+    }
 }
 
 extern "C" {
@@ -193,13 +211,13 @@ pub extern fn rsvg_node_draw (raw_node: *const RsvgNode, draw_ctx: *const RsvgDr
 type NodeForeachChild = unsafe extern "C" fn (node: *const RsvgNode, data: *const libc::c_void) -> bool;
 
 #[no_mangle]
-pub extern fn rsvg_node_foreach_child (raw_node: *const RsvgNode, fn: NodeForeachChild, data: *const 
libc::c_void)
+pub extern fn rsvg_node_foreach_child (raw_node: *const RsvgNode, func: NodeForeachChild, data: *const 
libc::c_void)
 {
     assert! (!raw_node.is_null ());
     let node: &RsvgNode = unsafe { & *raw_node };
 
-    for child in node.children.borrow () {
-        let next = unsafe = { (*fn) (child as *const RsvgNode, data) };
+    for child in node.children.borrow ().iter () {
+        let next = unsafe { func (child as *const RsvgNode, data) };
         if !next {
             break;
         }
diff --git a/rust/src/shapes.rs b/rust/src/shapes.rs
index e3f0028..78b2ccd 100644
--- a/rust/src/shapes.rs
+++ b/rust/src/shapes.rs
@@ -1,4 +1,5 @@
 use std::cell::RefCell;
+use std::ptr;
 
 use drawing_ctx;
 use drawing_ctx::*;
@@ -40,4 +41,9 @@ impl NodeTrait for NodePath {
         drawing_ctx::state_reinherit_top (draw_ctx, self.state, dominate);
         drawing_ctx::render_path_builder (draw_ctx, & *self.builder.borrow ());
     }
+
+
+    fn get_c_impl (&self) -> *const RsvgCNodeImpl {
+        ptr::null ()
+    }
 }


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