[librsvg/rustification] Initialize the RsvgNode vtables in _rsvg_node_init()



commit 126455c4ccb537b65e7aea8041efee2a9e977b76
Author: Federico Mena Quintero <federico gnome org>
Date:   Fri Dec 2 16:19:04 2016 -0600

    Initialize the RsvgNode vtables in _rsvg_node_init()
    
    Previously each node implementation would set its own vtable;
    instead, we'll pass the vtable down to _rsvg_node_init().  This
    will help in moving RsvgNode to Rust.

 rsvg-base.c         |   10 ++-
 rsvg-filter.c       |  273 +++++++++++++++++++++++++++++++++++----------------
 rsvg-gobject.c      |    4 +-
 rsvg-image.c        |   12 ++-
 rsvg-marker.c       |   10 ++-
 rsvg-mask.c         |   19 +++-
 rsvg-paint-server.c |   43 ++++++--
 rsvg-private.h      |   10 ++-
 rsvg-shapes.c       |   68 +++++++++----
 rsvg-structure.c    |   97 ++++++++++++++-----
 rsvg-structure.h    |    6 +-
 rsvg-text.c         |   32 +++++--
 12 files changed, 415 insertions(+), 169 deletions(-)
---
diff --git a/rsvg-base.c b/rsvg-base.c
index b1500e5..61e0474 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -382,7 +382,7 @@ node_set_atts (RsvgNode * node, RsvgHandle * ctx, const NodeCreator *creator, Rs
         const char *id;
         const char *klazz;
 
-        node->set_atts (node, ctx, atts);
+        node->vtable->set_atts (node, ctx, atts);
 
         /* The "svg" node is special; it will load its id/class
          * attributes until the end, when rsvg_end_element() calls
@@ -890,9 +890,14 @@ rsvg_new_node_chars (const char *text,
                      int len)
 {
     RsvgNodeChars *self;
+    RsvgNodeVtable vtable = {
+        _rsvg_node_chars_free,
+        NULL,
+        NULL
+    };
 
     self = g_new (RsvgNodeChars, 1);
-    _rsvg_node_init (&self->super, RSVG_NODE_TYPE_CHARS);
+    _rsvg_node_init (&self->super, RSVG_NODE_TYPE_CHARS, &vtable);
 
     if (!g_utf8_validate (text, len, NULL)) {
         char *utf8;
@@ -903,7 +908,6 @@ rsvg_new_node_chars (const char *text,
         self->contents = g_string_new_len (text, len);
     }
 
-    self->super.free = _rsvg_node_chars_free;
     self->super.state->cond_true = FALSE;
 
     return self;
diff --git a/rsvg-filter.c b/rsvg-filter.c
index 10df9c8..bc9d8c3 100644
--- a/rsvg-filter.c
+++ b/rsvg-filter.c
@@ -1,25 +1,25 @@
 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set sw=4 sts=4 ts=4 expandtab: */
-/* 
+/*
    rsvg-filter.c: Provides filters
- 
+
    Copyright (C) 2004 Caleb Moore
-  
+
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.
-  
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.
-  
+
    You should have received a copy of the GNU Library General Public
    License along with this program; if not, write to the
    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
-  
+
    Author: Caleb Moore <c moore student unsw edu au>
 */
 
@@ -412,10 +412,10 @@ rsvg_alpha_blt (cairo_surface_t *src,
 }
 
 static gboolean
-rsvg_art_affine_image (cairo_surface_t *img, 
+rsvg_art_affine_image (cairo_surface_t *img,
                        cairo_surface_t *intermediate,
-                       cairo_matrix_t *affine, 
-                       double w, 
+                       cairo_matrix_t *affine,
+                       double w,
                        double h)
 {
     cairo_matrix_t inv_affine, raw_inv_affine;
@@ -553,14 +553,14 @@ node_is_filter_primitive (RsvgNode *node)
  * Create a new surface applied the filter. This function will create
  * a context for itself, set up the coordinate systems execute all its
  * little primatives and then clean up its own mess.
- * 
+ *
  * Returns: (transfer full): a new #cairo_surface_t
  **/
 cairo_surface_t *
 rsvg_filter_render (RsvgFilter *self,
                     cairo_surface_t *source,
-                    RsvgDrawingCtx *context, 
-                    RsvgBbox *bounds, 
+                    RsvgDrawingCtx *context,
+                    RsvgBbox *bounds,
                     char *channelmap)
 {
     RsvgFilterContext *ctx;
@@ -658,7 +658,7 @@ surface_get_alpha (cairo_surface_t *source,
 
     cairo_surface_flush (source);
 
-    pbsize = cairo_image_surface_get_width (source) * 
+    pbsize = cairo_image_surface_get_width (source) *
              cairo_image_surface_get_height (source);
 
     surface = _rsvg_image_surface_new (cairo_image_surface_get_width (source),
@@ -707,7 +707,7 @@ rsvg_compile_bg (RsvgDrawingCtx * ctx)
 
 /**
  * rsvg_filter_get_bg:
- * 
+ *
  * Returns: (transfer none) (nullable): a #cairo_surface_t, or %NULL
  */
 static cairo_surface_t *
@@ -776,7 +776,7 @@ rsvg_filter_get_result (GString * name, RsvgFilterContext * ctx)
  * rsvg_filter_get_in:
  * @name:
  * @ctx:
- * 
+ *
  * Returns: (transfer full) (nullable): a new #cairo_surface_t, or %NULL
  */
 static cairo_surface_t *
@@ -824,16 +824,21 @@ RsvgNode *
 rsvg_new_filter (const char *element_name)
 {
     RsvgFilter *filter;
+    RsvgNodeVtable vtable = {
+        NULL,
+        NULL,
+        rsvg_filter_set_atts,
+    };
 
     filter = g_new (RsvgFilter, 1);
-    _rsvg_node_init (&filter->super, RSVG_NODE_TYPE_FILTER);
+    _rsvg_node_init (&filter->super, RSVG_NODE_TYPE_FILTER, &vtable);
+
     filter->filterunits = objectBoundingBox;
     filter->primitiveunits = userSpaceOnUse;
     filter->x = rsvg_length_parse ("-10%", LENGTH_DIR_HORIZONTAL);
     filter->y = rsvg_length_parse ("-10%", LENGTH_DIR_VERTICAL);
     filter->width = rsvg_length_parse ("120%", LENGTH_DIR_HORIZONTAL);
     filter->height = rsvg_length_parse ("120%", LENGTH_DIR_VERTICAL);
-    filter->super.set_atts = rsvg_filter_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -854,11 +859,11 @@ struct _RsvgFilterPrimitiveBlend {
 };
 
 static void
-rsvg_filter_blend (RsvgFilterPrimitiveBlendMode mode, 
-                   cairo_surface_t *in, 
+rsvg_filter_blend (RsvgFilterPrimitiveBlendMode mode,
+                   cairo_surface_t *in,
                    cairo_surface_t *in2,
-                   cairo_surface_t* output, 
-                   RsvgIRect boundarys, 
+                   cairo_surface_t* output,
+                   RsvgIRect boundarys,
                    int *channelmap)
 {
     guchar i;
@@ -1056,15 +1061,20 @@ RsvgNode *
 rsvg_new_filter_primitive_blend (const char *element_name)
 {
     RsvgFilterPrimitiveBlend *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_blend_free,
+        NULL,
+        rsvg_filter_primitive_blend_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitiveBlend, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_BLEND);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_BLEND, &vtable);
+
     filter->mode = normal;
     filter->super.in = g_string_new ("none");
     filter->in2 = g_string_new ("none");
     filter->super.result = g_string_new ("none");
     filter->super.render = rsvg_filter_primitive_blend_render;
-    filter->super.super.free = rsvg_filter_primitive_blend_free;
-    filter->super.super.set_atts = rsvg_filter_primitive_blend_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -1307,8 +1317,15 @@ RsvgNode *
 rsvg_new_filter_primitive_convolve_matrix (const char *element_name)
 {
     RsvgFilterPrimitiveConvolveMatrix *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_convolve_matrix_free,
+        NULL,
+        rsvg_filter_primitive_convolve_matrix_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitiveConvolveMatrix, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_CONVOLVE_MATRIX);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_CONVOLVE_MATRIX, &vtable);
+
     filter->super.in = g_string_new ("none");
     filter->super.result = g_string_new ("none");
     filter->KernelMatrix = NULL;
@@ -1319,8 +1336,6 @@ rsvg_new_filter_primitive_convolve_matrix (const char *element_name)
     filter->preservealpha = FALSE;
     filter->edgemode = 0;
     filter->super.render = rsvg_filter_primitive_convolve_matrix_render;
-    filter->super.super.free = rsvg_filter_primitive_convolve_matrix_free;
-    filter->super.super.set_atts = rsvg_filter_primitive_convolve_matrix_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -1432,7 +1447,7 @@ box_blur_line (gint box_width, gint even_offset,
             } else if (output >= 0) {
                 /* If the output is on the image, but the trailing edge isn't yet
                  * on the image. */
-            
+
                 for (i = 0; i < bpp; i++) {
                     ac[i] += src[bpp * lead + i];
                     dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / coverage;
@@ -1712,7 +1727,7 @@ gaussian_blur_surface (cairo_surface_t *in,
     guchar *in_data, *out_data;
     gint bpp;
     gboolean out_has_data;
-    
+
     cairo_surface_flush (in);
 
     width = cairo_image_surface_get_width (in);
@@ -1953,15 +1968,20 @@ RsvgNode *
 rsvg_new_filter_primitive_gaussian_blur (const char *element_name)
 {
     RsvgFilterPrimitiveGaussianBlur *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_free,
+        NULL,
+        rsvg_filter_primitive_gaussian_blur_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitiveGaussianBlur, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_GAUSSIAN_BLUR);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_GAUSSIAN_BLUR, &vtable);
+
     filter->super.in = g_string_new ("none");
     filter->super.result = g_string_new ("none");
     filter->sdx = 0;
     filter->sdy = 0;
     filter->super.render = rsvg_filter_primitive_gaussian_blur_render;
-    filter->super.super.free = rsvg_filter_primitive_free;
-    filter->super.super.set_atts = rsvg_filter_primitive_gaussian_blur_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -2073,15 +2093,20 @@ RsvgNode *
 rsvg_new_filter_primitive_offset (const char *element_name)
 {
     RsvgFilterPrimitiveOffset *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_free,
+        NULL,
+        rsvg_filter_primitive_offset_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitiveOffset, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_OFFSET);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_OFFSET, &vtable);
+
     filter->super.in = g_string_new ("none");
     filter->super.result = g_string_new ("none");
     filter->dx = rsvg_length_parse ("0", LENGTH_DIR_HORIZONTAL);
     filter->dy = rsvg_length_parse ("0", LENGTH_DIR_VERTICAL);
     filter->super.render = rsvg_filter_primitive_offset_render;
-    filter->super.super.free = rsvg_filter_primitive_free;
-    filter->super.super.set_atts = rsvg_filter_primitive_offset_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -2160,13 +2185,18 @@ RsvgNode *
 rsvg_new_filter_primitive_merge (const char *element_name)
 {
     RsvgFilterPrimitiveMerge *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_merge_free,
+        NULL,
+        rsvg_filter_primitive_merge_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitiveMerge, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_MERGE);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_MERGE, &vtable);
+
     filter->super.result = g_string_new ("none");
     filter->super.render = rsvg_filter_primitive_merge_render;
-    filter->super.super.free = rsvg_filter_primitive_merge_free;
 
-    filter->super.super.set_atts = rsvg_filter_primitive_merge_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -2202,12 +2232,17 @@ RsvgNode *
 rsvg_new_filter_primitive_merge_node (const char *element_name)
 {
     RsvgFilterPrimitive *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_merge_node_free,
+        NULL,
+        rsvg_filter_primitive_merge_node_set_atts
+    };
+
     filter = g_new (RsvgFilterPrimitive, 1);
-    _rsvg_node_init (&filter->super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_MERGE_NODE);
+    _rsvg_node_init (&filter->super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_MERGE_NODE, &vtable);
+
     filter->in = g_string_new ("none");
-    filter->super.free = rsvg_filter_primitive_merge_node_free;
     filter->render = rsvg_filter_primitive_merge_node_render;
-    filter->super.set_atts = rsvg_filter_primitive_merge_node_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -2324,7 +2359,7 @@ rsvg_filter_primitive_color_matrix_free (RsvgNode * self)
 
     matrix = (RsvgFilterPrimitiveColorMatrix *) self;
     g_free (matrix->KernelMatrix);
-    
+
     rsvg_filter_primitive_free (self);
 }
 
@@ -2436,15 +2471,20 @@ RsvgNode *
 rsvg_new_filter_primitive_color_matrix (const char *element_name)
 {
     RsvgFilterPrimitiveColorMatrix *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_color_matrix_free,
+        NULL,
+        rsvg_filter_primitive_color_matrix_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitiveColorMatrix, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_COLOR_MATRIX);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_COLOR_MATRIX, &vtable);
+
     filter->super.in = g_string_new ("none");
     filter->super.result = g_string_new ("none");
     filter->KernelMatrix = NULL;
     filter->super.render = rsvg_filter_primitive_color_matrix_render;
-    filter->super.super.free = rsvg_filter_primitive_color_matrix_free;
 
-    filter->super.super.set_atts = rsvg_filter_primitive_color_matrix_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -2658,14 +2698,19 @@ RsvgNode *
 rsvg_new_filter_primitive_component_transfer (const char *element_name)
 {
     RsvgFilterPrimitiveComponentTransfer *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_free,
+        NULL,
+        rsvg_filter_primitive_component_transfer_set_atts
+    };
+
 
     filter = g_new0 (RsvgFilterPrimitiveComponentTransfer, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_COMPONENT_TRANSFER);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_COMPONENT_TRANSFER, &vtable);
+
     filter->super.result = g_string_new ("none");
     filter->super.in = g_string_new ("none");
     filter->super.render = rsvg_filter_primitive_component_transfer_render;
-    filter->super.super.free = rsvg_filter_primitive_free;
-    filter->super.super.set_atts = rsvg_filter_primitive_component_transfer_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -2715,7 +2760,7 @@ rsvg_node_component_transfer_function_set_atts (RsvgNode * self,
 }
 
 static void
-rsvg_component_transfer_function_free (RsvgNode * self)
+rsvg_node_component_transfer_function_free (RsvgNode * self)
 {
     RsvgNodeComponentTransferFunc *filter = (RsvgNodeComponentTransferFunc *) self;
     if (filter->nbTableValues)
@@ -2727,6 +2772,12 @@ RsvgNode *
 rsvg_new_node_component_transfer_function (const char *element_name)
 {
     RsvgNodeComponentTransferFunc *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_node_component_transfer_function_free,
+        NULL,
+        rsvg_node_component_transfer_function_set_atts
+    };
+
     char channel;
 
     if (strcmp (element_name, "feFuncR") == 0)
@@ -2743,9 +2794,8 @@ rsvg_new_node_component_transfer_function (const char *element_name)
     }
 
     filter = g_new0 (RsvgNodeComponentTransferFunc, 1);
-    _rsvg_node_init (&filter->super, RSVG_NODE_TYPE_COMPONENT_TRANFER_FUNCTION);
-    filter->super.free = rsvg_component_transfer_function_free;
-    filter->super.set_atts = rsvg_node_component_transfer_function_set_atts;
+    _rsvg_node_init (&filter->super, RSVG_NODE_TYPE_COMPONENT_TRANFER_FUNCTION, &vtable);
+
     filter->function = identity_component_transfer_func;
     filter->nbTableValues = 0;
     filter->channel = channel;
@@ -2876,16 +2926,21 @@ RsvgNode *
 rsvg_new_filter_primitive_erode (const char *element_name)
 {
     RsvgFilterPrimitiveErode *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_free,
+        NULL,
+        rsvg_filter_primitive_erode_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitiveErode, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_ERODE);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_ERODE, &vtable);
+
     filter->super.in = g_string_new ("none");
     filter->super.result = g_string_new ("none");
     filter->rx = 0;
     filter->ry = 0;
     filter->mode = 0;
     filter->super.render = rsvg_filter_primitive_erode_render;
-    filter->super.super.free = rsvg_filter_primitive_free;
-    filter->super.super.set_atts = rsvg_filter_primitive_erode_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -3107,8 +3162,15 @@ RsvgNode *
 rsvg_new_filter_primitive_composite (const char *element_name)
 {
     RsvgFilterPrimitiveComposite *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_composite_free,
+        NULL,
+        rsvg_filter_primitive_composite_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitiveComposite, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_COMPOSITE);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_COMPOSITE, &vtable);
+
     filter->mode = COMPOSITE_MODE_OVER;
     filter->super.in = g_string_new ("none");
     filter->in2 = g_string_new ("none");
@@ -3118,8 +3180,6 @@ rsvg_new_filter_primitive_composite (const char *element_name)
     filter->k3 = 0;
     filter->k4 = 0;
     filter->super.render = rsvg_filter_primitive_composite_render;
-    filter->super.super.free = rsvg_filter_primitive_composite_free;
-    filter->super.super.set_atts = rsvg_filter_primitive_composite_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -3189,13 +3249,18 @@ RsvgNode *
 rsvg_new_filter_primitive_flood (const char *element_name)
 {
     RsvgFilterPrimitive *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_free,
+        NULL,
+        rsvg_filter_primitive_flood_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitive, 1);
-    _rsvg_node_init (&filter->super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_FLOOD);
+    _rsvg_node_init (&filter->super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_FLOOD, &vtable);
+
     filter->in = g_string_new ("none");
     filter->result = g_string_new ("none");
     filter->render = rsvg_filter_primitive_flood_render;
-    filter->super.free = rsvg_filter_primitive_free;
-    filter->super.set_atts = rsvg_filter_primitive_flood_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -3359,7 +3424,7 @@ rsvg_filter_primitive_displacement_map_set_atts (RsvgNode * self, RsvgHandle * c
         g_string_assign (filter->super.result, value);
 
     filter_primitive_set_x_y_width_height_atts ((RsvgFilterPrimitive *) filter, atts);
-        
+
     if ((value = rsvg_property_bag_lookup (atts, "xChannelSelector")))
         filter->xChannelSelector = (value)[0];
     if ((value = rsvg_property_bag_lookup (atts, "yChannelSelector")))
@@ -3372,8 +3437,15 @@ RsvgNode *
 rsvg_new_filter_primitive_displacement_map (const char *element_name)
 {
     RsvgFilterPrimitiveDisplacementMap *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_displacement_map_free,
+        NULL,
+        rsvg_filter_primitive_displacement_map_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitiveDisplacementMap, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_DISPLACEMENT_MAP);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_DISPLACEMENT_MAP, &vtable);
+
     filter->super.in = g_string_new ("none");
     filter->in2 = g_string_new ("none");
     filter->super.result = g_string_new ("none");
@@ -3381,8 +3453,6 @@ rsvg_new_filter_primitive_displacement_map (const char *element_name)
     filter->yChannelSelector = ' ';
     filter->scale = 0;
     filter->super.render = rsvg_filter_primitive_displacement_map_render;
-    filter->super.super.free = rsvg_filter_primitive_displacement_map_free;
-    filter->super.super.set_atts = rsvg_filter_primitive_displacement_map_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -3717,7 +3787,7 @@ rsvg_filter_primitive_turbulence_set_atts (RsvgNode * self, RsvgHandle * ctx,
         g_string_assign (filter->super.result, value);
 
     filter_primitive_set_x_y_width_height_atts ((RsvgFilterPrimitive *) filter, atts);
-        
+
     if ((value = rsvg_property_bag_lookup (atts, "baseFrequency")))
         rsvg_css_parse_number_optional_number (value, &filter->fBaseFreqX, &filter->fBaseFreqY);
     if ((value = rsvg_property_bag_lookup (atts, "numOctaves")))
@@ -3734,8 +3804,15 @@ RsvgNode *
 rsvg_new_filter_primitive_turbulence (const char *element_name)
 {
     RsvgFilterPrimitiveTurbulence *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_free,
+        NULL,
+        rsvg_filter_primitive_turbulence_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitiveTurbulence, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_TURBULENCE);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_TURBULENCE, &vtable);
+
     filter->super.in = g_string_new ("none");
     filter->super.result = g_string_new ("none");
     filter->fBaseFreqX = 0;
@@ -3746,8 +3823,6 @@ rsvg_new_filter_primitive_turbulence (const char *element_name)
     filter->bFractalSum = 0;
     feTurbulence_init (filter);
     filter->super.render = rsvg_filter_primitive_turbulence_render;
-    filter->super.super.free = rsvg_filter_primitive_free;
-    filter->super.super.set_atts = rsvg_filter_primitive_turbulence_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -3834,7 +3909,7 @@ rsvg_filter_primitive_image_render_ext (RsvgFilterPrimitive * self, RsvgFilterCo
 
     cairo_surface_destroy (img);
 
-    length = cairo_image_surface_get_height (intermediate) * 
+    length = cairo_image_surface_get_height (intermediate) *
              cairo_image_surface_get_stride (intermediate);
     for (i = 0; i < 4; i++)
         channelmap[i] = ctx->channelmap[i];
@@ -3951,13 +4026,18 @@ RsvgNode *
 rsvg_new_filter_primitive_image (const char *element_name)
 {
     RsvgFilterPrimitiveImage *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_image_free,
+        NULL,
+        rsvg_filter_primitive_image_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitiveImage, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_IMAGE);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_IMAGE, &vtable);
+
     filter->super.in = g_string_new ("none");
     filter->super.result = g_string_new ("none");
     filter->super.render = rsvg_filter_primitive_image_render;
-    filter->super.super.free = rsvg_filter_primitive_image_free;
-    filter->super.super.set_atts = rsvg_filter_primitive_image_set_atts;
     filter->href = NULL;
     return (RsvgNode *) filter;
 }
@@ -4346,11 +4426,15 @@ RsvgNode *
 rsvg_new_node_light_source (const char *element_name)
 {
     RsvgNodeLightSource *data;
+    RsvgNodeVtable vtable = {
+        NULL,
+        NULL,
+        rsvg_node_light_source_set_atts
+    };
 
     data = g_new (RsvgNodeLightSource, 1);
-    _rsvg_node_init (&data->super, RSVG_NODE_TYPE_LIGHT_SOURCE);
-    data->super.free = _rsvg_node_free;
-    data->super.set_atts = rsvg_node_light_source_set_atts;
+    _rsvg_node_init (&data->super, RSVG_NODE_TYPE_LIGHT_SOURCE, &vtable);
+
     data->specularExponent = 1;
 
     if (strcmp (element_name, "feDistantLight") == 0)
@@ -4501,7 +4585,7 @@ rsvg_filter_primitive_diffuse_lighting_set_atts (RsvgNode * self, RsvgHandle * c
         g_string_assign (filter->super.result, value);
 
     filter_primitive_set_x_y_width_height_atts ((RsvgFilterPrimitive *) filter, atts);
-        
+
     if ((value = rsvg_property_bag_lookup (atts, "kernelUnitLength")))
         rsvg_css_parse_number_optional_number (value, &filter->dx, &filter->dy);
     if ((value = rsvg_property_bag_lookup (atts, "lighting-color")))
@@ -4516,8 +4600,15 @@ RsvgNode *
 rsvg_new_filter_primitive_diffuse_lighting (const char *element_name)
 {
     RsvgFilterPrimitiveDiffuseLighting *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_free,
+        NULL,
+        rsvg_filter_primitive_diffuse_lighting_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitiveDiffuseLighting, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_DIFFUSE_LIGHTING);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_DIFFUSE_LIGHTING, &vtable);
+
     filter->super.in = g_string_new ("none");
     filter->super.result = g_string_new ("none");
     filter->surfaceScale = 1;
@@ -4526,8 +4617,6 @@ rsvg_new_filter_primitive_diffuse_lighting (const char *element_name)
     filter->dy = 1;
     filter->lightingcolor = 0xFFFFFFFF;
     filter->super.render = rsvg_filter_primitive_diffuse_lighting_render;
-    filter->super.super.free = rsvg_filter_primitive_free;
-    filter->super.super.set_atts = rsvg_filter_primitive_diffuse_lighting_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -4669,7 +4758,7 @@ rsvg_filter_primitive_specular_lighting_set_atts (RsvgNode * self, RsvgHandle *
         g_string_assign (filter->super.result, value);
 
     filter_primitive_set_x_y_width_height_atts ((RsvgFilterPrimitive *) filter, atts);
-        
+
     if ((value = rsvg_property_bag_lookup (atts, "lighting-color")))
         filter->lightingcolor = rsvg_css_parse_color (value, 0);
     if ((value = rsvg_property_bag_lookup (atts, "specularConstant")))
@@ -4685,8 +4774,15 @@ RsvgNode *
 rsvg_new_filter_primitive_specular_lighting (const char *element_name)
 {
     RsvgFilterPrimitiveSpecularLighting *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_free,
+        NULL,
+        rsvg_filter_primitive_specular_lighting_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitiveSpecularLighting, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_SPECULAR_LIGHTING);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_SPECULAR_LIGHTING, &vtable);
+
     filter->super.in = g_string_new ("none");
     filter->super.result = g_string_new ("none");
     filter->surfaceScale = 1;
@@ -4694,8 +4790,6 @@ rsvg_new_filter_primitive_specular_lighting (const char *element_name)
     filter->specularExponent = 1;
     filter->lightingcolor = 0xFFFFFFFF;
     filter->super.render = rsvg_filter_primitive_specular_lighting_render;
-    filter->super.super.free = rsvg_filter_primitive_free;
-    filter->super.super.set_atts = rsvg_filter_primitive_specular_lighting_set_atts;
     return (RsvgNode *) filter;
 }
 
@@ -4789,12 +4883,17 @@ RsvgNode *
 rsvg_new_filter_primitive_tile (const char *element_name)
 {
     RsvgFilterPrimitiveTile *filter;
+    RsvgNodeVtable vtable = {
+        rsvg_filter_primitive_free,
+        NULL,
+        rsvg_filter_primitive_tile_set_atts
+    };
+
     filter = g_new0 (RsvgFilterPrimitiveTile, 1);
-    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_TILE);
+    _rsvg_node_init (&filter->super.super, RSVG_NODE_TYPE_FILTER_PRIMITIVE_TILE, &vtable);
+
     filter->super.in = g_string_new ("none");
     filter->super.result = g_string_new ("none");
     filter->super.render = rsvg_filter_primitive_tile_render;
-    filter->super.super.free = rsvg_filter_primitive_free;
-    filter->super.super.set_atts = rsvg_filter_primitive_tile_set_atts;
     return (RsvgNode *) filter;
 }
diff --git a/rsvg-gobject.c b/rsvg-gobject.c
index 65f11d0..d0a965d 100644
--- a/rsvg-gobject.c
+++ b/rsvg-gobject.c
@@ -106,8 +106,8 @@ free_nodes (RsvgHandle *self)
         RsvgNode *node;
 
         node = g_ptr_array_index (self->priv->all_nodes, i);
-        g_assert (node->free != NULL);
-        node->free (node);
+        g_assert (node->vtable->free != NULL);
+        node->vtable->free (node);
     }
 
     g_ptr_array_free (self->priv->all_nodes, TRUE);
diff --git a/rsvg-image.c b/rsvg-image.c
index 2692a6b..77e3b18 100644
--- a/rsvg-image.c
+++ b/rsvg-image.c
@@ -231,14 +231,18 @@ RsvgNode *
 rsvg_new_image (const char *element_name)
 {
     RsvgNodeImage *image;
+    RsvgNodeVtable vtable = {
+        rsvg_node_image_free,
+        rsvg_node_image_draw,
+        rsvg_node_image_set_atts
+    };
+
     image = g_new (RsvgNodeImage, 1);
-    _rsvg_node_init (&image->super, RSVG_NODE_TYPE_IMAGE);
+    _rsvg_node_init (&image->super, RSVG_NODE_TYPE_IMAGE, &vtable);
+
     g_assert (image->super.state);
     image->surface = NULL;
     image->preserve_aspect_ratio = RSVG_ASPECT_RATIO_XMID_YMID;
     image->x = image->y = image->w = image->h = rsvg_length_parse ("0", LENGTH_DIR_BOTH);
-    image->super.free = rsvg_node_image_free;
-    image->super.draw = rsvg_node_image_draw;
-    image->super.set_atts = rsvg_node_image_set_atts;
     return &image->super;
 }
diff --git a/rsvg-marker.c b/rsvg-marker.c
index 180db73..8e44f02 100644
--- a/rsvg-marker.c
+++ b/rsvg-marker.c
@@ -90,8 +90,15 @@ RsvgNode *
 rsvg_new_marker (const char *element_name)
 {
     RsvgMarker *marker;
+    RsvgNodeVtable vtable = {
+        NULL,
+        NULL,
+        rsvg_node_marker_set_atts
+    };
+
     marker = g_new (RsvgMarker, 1);
-    _rsvg_node_init (&marker->super, RSVG_NODE_TYPE_MARKER);
+    _rsvg_node_init (&marker->super, RSVG_NODE_TYPE_MARKER, &vtable);
+
     marker->orient = 0;
     marker->orientAuto = FALSE;
     marker->preserve_aspect_ratio = RSVG_ASPECT_RATIO_XMID_YMID;
@@ -99,7 +106,6 @@ rsvg_new_marker (const char *element_name)
     marker->width = marker->height = rsvg_length_parse ("3", LENGTH_DIR_BOTH);
     marker->bbox = TRUE;
     marker->vbox.active = FALSE;
-    marker->super.set_atts = rsvg_node_marker_set_atts;
     return &marker->super;
 }
 
diff --git a/rsvg-mask.c b/rsvg-mask.c
index d145cd6..d167f94 100644
--- a/rsvg-mask.c
+++ b/rsvg-mask.c
@@ -63,16 +63,21 @@ RsvgNode *
 rsvg_new_mask (const char *element_name)
 {
     RsvgMask *mask;
+    RsvgNodeVtable vtable = {
+        NULL,
+        NULL,
+        rsvg_mask_set_atts
+    };
 
     mask = g_new (RsvgMask, 1);
-    _rsvg_node_init (&mask->super, RSVG_NODE_TYPE_MASK);
+    _rsvg_node_init (&mask->super, RSVG_NODE_TYPE_MASK, &vtable);
+
     mask->maskunits = objectBoundingBox;
     mask->contentunits = userSpaceOnUse;
     mask->x = rsvg_length_parse ("0", LENGTH_DIR_HORIZONTAL);
     mask->y = rsvg_length_parse ("0", LENGTH_DIR_VERTICAL);
     mask->width = rsvg_length_parse ("1", LENGTH_DIR_HORIZONTAL);
     mask->height = rsvg_length_parse ("1", LENGTH_DIR_VERTICAL);
-    mask->super.set_atts = rsvg_mask_set_atts;
     return &mask->super;
 }
 
@@ -113,11 +118,15 @@ RsvgNode *
 rsvg_new_clip_path (const char *element_name)
 {
     RsvgClipPath *clip_path;
+    RsvgNodeVtable vtable = {
+        NULL,
+        NULL,
+        rsvg_clip_path_set_atts
+    };
 
     clip_path = g_new (RsvgClipPath, 1);
-    _rsvg_node_init (&clip_path->super, RSVG_NODE_TYPE_CLIP_PATH);
+    _rsvg_node_init (&clip_path->super, RSVG_NODE_TYPE_CLIP_PATH, &vtable);
+
     clip_path->units = userSpaceOnUse;
-    clip_path->super.set_atts = rsvg_clip_path_set_atts;
-    clip_path->super.free = _rsvg_node_free;
     return &clip_path->super;
 }
diff --git a/rsvg-paint-server.c b/rsvg-paint-server.c
index bfc7f87..4c801f6 100644
--- a/rsvg-paint-server.c
+++ b/rsvg-paint-server.c
@@ -225,8 +225,14 @@ RsvgNode *
 rsvg_new_stop (const char *element_name)
 {
     RsvgGradientStop *stop = g_new (RsvgGradientStop, 1);
-    _rsvg_node_init (&stop->super, RSVG_NODE_TYPE_STOP);
-    stop->super.set_atts = rsvg_stop_set_atts;
+    RsvgNodeVtable vtable = {
+        NULL,
+        NULL,
+        rsvg_stop_set_atts
+    };
+
+    _rsvg_node_init (&stop->super, RSVG_NODE_TYPE_STOP, &vtable);
+
     stop->offset = 0;
     stop->rgba = 0xff000000;
     stop->is_valid = FALSE;
@@ -292,8 +298,15 @@ RsvgNode *
 rsvg_new_linear_gradient (const char *element_name)
 {
     RsvgLinearGradient *grad = NULL;
+    RsvgNodeVtable vtable = {
+        rsvg_linear_gradient_free,
+        NULL,
+        rsvg_linear_gradient_set_atts
+    };
+
     grad = g_new (RsvgLinearGradient, 1);
-    _rsvg_node_init (&grad->super, RSVG_NODE_TYPE_LINEAR_GRADIENT);
+    _rsvg_node_init (&grad->super, RSVG_NODE_TYPE_LINEAR_GRADIENT, &vtable);
+
     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);
@@ -301,8 +314,6 @@ rsvg_new_linear_gradient (const char *element_name)
     grad->fallback = NULL;
     grad->obj_bbox = TRUE;
     grad->spread = CAIRO_EXTEND_PAD;
-    grad->super.free = rsvg_linear_gradient_free;
-    grad->super.set_atts = rsvg_linear_gradient_set_atts;
     grad->hasx1 = grad->hasy1 = grad->hasx2 = grad->hasy2 = grad->hasbbox = grad->hasspread =
         grad->hastransform = FALSE;
     return &grad->super;
@@ -374,15 +385,20 @@ RsvgNode *
 rsvg_new_radial_gradient (const char *element_name)
 {
 
+    RsvgNodeVtable vtable = {
+        rsvg_radial_gradient_free,
+        NULL,
+        rsvg_radial_gradient_set_atts
+    };
+
     RsvgRadialGradient *grad = g_new (RsvgRadialGradient, 1);
-    _rsvg_node_init (&grad->super, RSVG_NODE_TYPE_RADIAL_GRADIENT);
+    _rsvg_node_init (&grad->super, RSVG_NODE_TYPE_RADIAL_GRADIENT, &vtable);
+
     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->super.free = rsvg_radial_gradient_free;
-    grad->super.set_atts = rsvg_radial_gradient_set_atts;
     grad->hascx = grad->hascy = grad->hasfx = grad->hasfy = grad->hasr = grad->hasbbox =
         grad->hasspread = grad->hastransform = FALSE;
     return &grad->super;
@@ -453,7 +469,14 @@ RsvgNode *
 rsvg_new_pattern (const char *element_name)
 {
     RsvgPattern *pattern = g_new (RsvgPattern, 1);
-    _rsvg_node_init (&pattern->super, RSVG_NODE_TYPE_PATTERN);
+    RsvgNodeVtable vtable = {
+        rsvg_pattern_free,
+        NULL,
+        rsvg_pattern_set_atts
+    };
+
+    _rsvg_node_init (&pattern->super, RSVG_NODE_TYPE_PATTERN, &vtable);
+
     cairo_matrix_init_identity (&pattern->affine);
     pattern->obj_bbox = TRUE;
     pattern->obj_cbbox = FALSE;
@@ -461,8 +484,6 @@ rsvg_new_pattern (const char *element_name)
     pattern->fallback = NULL;
     pattern->preserve_aspect_ratio = RSVG_ASPECT_RATIO_XMID_YMID;
     pattern->vbox.active = FALSE;
-    pattern->super.free = rsvg_pattern_free;
-    pattern->super.set_atts = rsvg_pattern_set_atts;
     pattern->hasx = pattern->hasy = pattern->haswidth = pattern->hasheight = pattern->hasbbox =
         pattern->hascbox = pattern->hasvbox = pattern->hasaspect = pattern->hastransform = FALSE;
     return &pattern->super;
diff --git a/rsvg-private.h b/rsvg-private.h
index 4bc3a48..3dffc3b 100644
--- a/rsvg-private.h
+++ b/rsvg-private.h
@@ -329,14 +329,18 @@ 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;
+
 struct _RsvgNode {
     RsvgState *state;
     RsvgNode *parent;
     GPtrArray *children;
     RsvgNodeType type;
-    void (*free) (RsvgNode * self);
-    void (*draw) (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate);
-    void (*set_atts) (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag *);
+    RsvgNodeVtable *vtable;
 };
 
 G_GNUC_INTERNAL
diff --git a/rsvg-shapes.c b/rsvg-shapes.c
index e7f407c..31bb1c7 100644
--- a/rsvg-shapes.c
+++ b/rsvg-shapes.c
@@ -87,12 +87,16 @@ RsvgNode *
 rsvg_new_path (const char *element_name)
 {
     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);
+    _rsvg_node_init (&path->super, RSVG_NODE_TYPE_PATH, &vtable);
+
     path->builder = NULL;
-    path->super.free = rsvg_node_path_free;
-    path->super.draw = rsvg_node_path_draw;
-    path->super.set_atts = rsvg_node_path_set_atts;
 
     return &path->super;
 }
@@ -197,11 +201,15 @@ static RsvgNode *
 rsvg_new_any_poly (RsvgNodeType type)
 {
     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);
-    poly->super.free = _rsvg_node_poly_free;
-    poly->super.draw = _rsvg_node_poly_draw;
-    poly->super.set_atts = _rsvg_node_poly_set_atts;
+    _rsvg_node_init (&poly->super, type, &vtable);
+
     poly->builder = NULL;
     return &poly->super;
 }
@@ -270,10 +278,15 @@ RsvgNode *
 rsvg_new_line (const char *element_name)
 {
     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);
-    line->super.draw = _rsvg_node_line_draw;
-    line->super.set_atts = _rsvg_node_line_set_atts;
+    _rsvg_node_init (&line->super, RSVG_NODE_TYPE_LINE, &vtable);
+
     line->x1 = line->x2 = line->y1 = line->y2 = rsvg_length_parse ("0", LENGTH_DIR_BOTH);
     return &line->super;
 }
@@ -454,10 +467,15 @@ RsvgNode *
 rsvg_new_rect (const char *element_name)
 {
     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);
-    rect->super.draw = _rsvg_node_rect_draw;
-    rect->super.set_atts = _rsvg_node_rect_set_atts;
+    _rsvg_node_init (&rect->super, RSVG_NODE_TYPE_RECT, &vtable);
+
     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;
@@ -537,10 +555,15 @@ RsvgNode *
 rsvg_new_circle (const char *element_name)
 {
     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);
-    circle->super.draw = _rsvg_node_circle_draw;
-    circle->super.set_atts = _rsvg_node_circle_set_atts;
+    _rsvg_node_init (&circle->super, RSVG_NODE_TYPE_CIRCLE, &vtable);
+
     circle->cx = circle->cy = circle->r = rsvg_length_parse ("0", LENGTH_DIR_BOTH);
     return &circle->super;
 }
@@ -622,10 +645,15 @@ RsvgNode *
 rsvg_new_ellipse (const char *element_name)
 {
     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);
-    ellipse->super.draw = _rsvg_node_ellipse_draw;
-    ellipse->super.set_atts = _rsvg_node_ellipse_set_atts;
+    _rsvg_node_init (&ellipse->super, RSVG_NODE_TYPE_ELLIPSE, &vtable);
+
     ellipse->cx = ellipse->cy = ellipse->rx = ellipse->ry = rsvg_length_parse ("0", LENGTH_DIR_BOTH);
     return &ellipse->super;
 }
diff --git a/rsvg-structure.c b/rsvg-structure.c
index 0152202..0d8af08 100644
--- a/rsvg-structure.c
+++ b/rsvg-structure.c
@@ -53,7 +53,7 @@ rsvg_node_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
     if (state->visible) {
         rsvg_state_push (ctx);
 
-        self->draw (self, ctx, dominate);
+        self->vtable->draw (self, ctx, dominate);
 
         rsvg_state_pop (ctx);
     }
@@ -102,15 +102,32 @@ _rsvg_node_dont_set_atts (RsvgNode * node, RsvgHandle * ctx, RsvgPropertyBag * a
 
 void
 _rsvg_node_init (RsvgNode * self,
-                 RsvgNodeType type)
+                 RsvgNodeType type,
+                 RsvgNodeVtable *vtable)
 {
     self->type = type;
     self->parent = NULL;
     self->children = g_ptr_array_new ();
     self->state = rsvg_state_new ();
-    self->free = _rsvg_node_free;
-    self->draw = _rsvg_node_draw_nothing;
-    self->set_atts = _rsvg_node_dont_set_atts;
+    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;
+    }
+
+    if (vtable->set_atts) {
+        self->vtable->set_atts = vtable->set_atts;
+    } else {
+        self->vtable->set_atts = _rsvg_node_dont_set_atts;
+    }
 }
 
 void
@@ -128,6 +145,9 @@ _rsvg_node_free (RsvgNode * self)
     self->parent = NULL;
     self->type = RSVG_NODE_TYPE_INVALID;
 
+    g_free (self->vtable);
+    self->vtable = NULL;
+
     g_free (self);
 }
 
@@ -135,9 +155,15 @@ RsvgNode *
 rsvg_new_group (const char *element_name)
 {
     RsvgNodeGroup *group;
+    RsvgNodeVtable vtable = {
+        NULL,
+        _rsvg_node_draw_children,
+        NULL
+    };
+
     group = g_new (RsvgNodeGroup, 1);
-    _rsvg_node_init (&group->super, RSVG_NODE_TYPE_GROUP);
-    group->super.draw = _rsvg_node_draw_children;
+    _rsvg_node_init (&group->super, RSVG_NODE_TYPE_GROUP, &vtable);
+
     return &group->super;
 }
 
@@ -344,7 +370,7 @@ _rsvg_node_svg_apply_atts (RsvgNodeSvg * self, RsvgHandle * ctx)
 }
 
 static void
-_rsvg_svg_free (RsvgNode * self)
+rsvg_node_svg_free (RsvgNode * self)
 {
     RsvgNodeSvg *svg = (RsvgNodeSvg *) self;
 
@@ -360,17 +386,21 @@ RsvgNode *
 rsvg_new_svg (const char *element_name)
 {
     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);
+    _rsvg_node_init (&svg->super, RSVG_NODE_TYPE_SVG, &vtable);
+
     svg->vbox.active = FALSE;
     svg->preserve_aspect_ratio = RSVG_ASPECT_RATIO_XMID_YMID;
     svg->x = rsvg_length_parse ("0", LENGTH_DIR_HORIZONTAL);
     svg->y = rsvg_length_parse ("0", LENGTH_DIR_VERTICAL);
     svg->w = rsvg_length_parse ("100%", LENGTH_DIR_HORIZONTAL);
     svg->h = rsvg_length_parse ("100%", LENGTH_DIR_VERTICAL);
-    svg->super.draw = rsvg_node_svg_draw;
-    svg->super.free = _rsvg_svg_free;
-    svg->super.set_atts = rsvg_node_svg_set_atts;
     svg->atts = NULL;
     return &svg->super;
 }
@@ -410,11 +440,15 @@ RsvgNode *
 rsvg_new_use (const char *element_name)
 {
     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);
-    use->super.draw = rsvg_node_use_draw;
-    use->super.free = rsvg_node_use_free;
-    use->super.set_atts = rsvg_node_use_set_atts;
+    _rsvg_node_init (&use->super, RSVG_NODE_TYPE_USE, &vtable);
+
     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);
@@ -440,12 +474,17 @@ RsvgNode *
 rsvg_new_symbol (const char *element_name)
 {
     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);
+    _rsvg_node_init (&symbol->super, RSVG_NODE_TYPE_SYMBOL, &vtable);
+
     symbol->vbox.active = FALSE;
     symbol->preserve_aspect_ratio = RSVG_ASPECT_RATIO_XMID_YMID;
-    symbol->super.draw = _rsvg_node_draw_nothing;
-    symbol->super.set_atts = rsvg_node_symbol_set_atts;
     return &symbol->super;
 }
 
@@ -453,9 +492,15 @@ RsvgNode *
 rsvg_new_defs (const char *element_name)
 {
     RsvgNodeGroup *group;
+    RsvgNodeVtable vtable = {
+        NULL,
+        NULL,
+        NULL,
+    };
+
     group = g_new (RsvgNodeGroup, 1);
-    _rsvg_node_init (&group->super, RSVG_NODE_TYPE_DEFS);
-    group->super.draw = _rsvg_node_draw_nothing;
+    _rsvg_node_init (&group->super, RSVG_NODE_TYPE_DEFS, &vtable);
+
     return &group->super;
 }
 
@@ -491,8 +536,14 @@ RsvgNode *
 rsvg_new_switch (const char *element_name)
 {
     RsvgNodeGroup *group;
+    RsvgNodeVtable vtable = {
+        NULL,
+        _rsvg_node_switch_draw,
+        NULL
+    };
+
     group = g_new (RsvgNodeGroup, 1);
-    _rsvg_node_init (&group->super, RSVG_NODE_TYPE_SWITCH);
-    group->super.draw = _rsvg_node_switch_draw;
+    _rsvg_node_init (&group->super, RSVG_NODE_TYPE_SWITCH, &vtable);
+
     return &group->super;
 }
diff --git a/rsvg-structure.h b/rsvg-structure.h
index cd75176..03d4694 100644
--- a/rsvg-structure.h
+++ b/rsvg-structure.h
@@ -86,8 +86,12 @@ 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);
+void _rsvg_node_init        (RsvgNode * self,
+                             RsvgNodeType type,
+                             RsvgNodeVtable *vtable);
+
 G_GNUC_INTERNAL
 void _rsvg_node_svg_apply_atts  (RsvgNodeSvg * self, RsvgHandle * ctx);
 
diff --git a/rsvg-text.c b/rsvg-text.c
index 50ab02b..0090386 100644
--- a/rsvg-text.c
+++ b/rsvg-text.c
@@ -383,10 +383,15 @@ RsvgNode *
 rsvg_new_text (const char *element_name)
 {
     RsvgNodeText *text;
+    RsvgNodeVtable vtable = {
+        NULL,
+        _rsvg_node_text_draw,
+        _rsvg_node_text_set_atts
+    };
+
     text = g_new (RsvgNodeText, 1);
-    _rsvg_node_init (&text->super, RSVG_NODE_TYPE_TEXT);
-    text->super.draw = _rsvg_node_text_draw;
-    text->super.set_atts = _rsvg_node_text_set_atts;
+    _rsvg_node_init (&text->super, RSVG_NODE_TYPE_TEXT, &vtable);
+
     text->x = text->y = text->dx = text->dy = rsvg_length_parse ("0", LENGTH_DIR_BOTH);
     return &text->super;
 }
@@ -466,9 +471,15 @@ RsvgNode *
 rsvg_new_tspan (const char *element_name)
 {
     RsvgNodeText *text;
+    RsvgNodeVtable vtable = {
+        NULL,
+        NULL,
+        _rsvg_node_tspan_set_atts
+    };
+
     text = g_new0 (RsvgNodeText, 1);
-    _rsvg_node_init (&text->super, RSVG_NODE_TYPE_TSPAN);
-    text->super.set_atts = _rsvg_node_tspan_set_atts;
+    _rsvg_node_init (&text->super, RSVG_NODE_TYPE_TSPAN, &vtable);
+
     text->dx = text->dy = rsvg_length_parse ("0", LENGTH_DIR_BOTH);
     return &text->super;
 }
@@ -536,10 +547,15 @@ RsvgNode *
 rsvg_new_tref (const char *element_name)
 {
     RsvgNodeTref *text;
+    RsvgNodeVtable vtable = {
+        rsvg_node_tref_free,
+        NULL,
+        _rsvg_node_tref_set_atts
+    };
+
     text = g_new (RsvgNodeTref, 1);
-    _rsvg_node_init (&text->super, RSVG_NODE_TYPE_TREF);
-    text->super.free = rsvg_node_tref_free;
-    text->super.set_atts = _rsvg_node_tref_set_atts;
+    _rsvg_node_init (&text->super, RSVG_NODE_TYPE_TREF, &vtable);
+
     text->link = NULL;
     return &text->super;
 }



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