=== modified file 'librsvg.def'
--- librsvg.def	2006-11-03 01:32:16 +0000
+++ librsvg.def	2008-10-07 12:25:27 +0000
@@ -15,6 +15,7 @@
 rsvg_handle_get_base_uri
 rsvg_handle_set_base_uri
 rsvg_handle_get_dimensions
+rsvg_handle_get_dimensions_sub
 rsvg_handle_get_title
 rsvg_handle_get_desc
 rsvg_handle_get_metadata

=== modified file 'rsvg-base.c'
--- rsvg-base.c	2008-08-26 16:51:17 +0000
+++ rsvg-base.c	2008-10-16 09:38:07 +0000
@@ -42,6 +42,7 @@
 #include "rsvg-filter.h"
 #include "rsvg-mask.h"
 #include "rsvg-marker.h"
+#include "rsvg-cairo-render.h"
 
 #include <math.h>
 #include <string.h>
@@ -1210,6 +1211,211 @@
 } RsvgBboxRender;
 
 static void
+_rsvg_bbox_render_path_quad_curve (RsvgBbox * bbox, 
+				    const RsvgBpath * bpath_old, 
+				    const RsvgBpath * bpath_new)
+{
+    g_return_if_fail (bpath_new != NULL);
+    /* To compute the width and length */
+    gdouble max_x, max_y;
+
+    /* Save the starting point of the curve (P0) */
+    gdouble p0_x = (bpath_old == NULL) ? 0 : bpath_old->x3;
+    gdouble p0_y = (bpath_old == NULL) ? 0 : bpath_old->y3;
+
+    /* Compute the vector between the starting (P0) and the midpoint (P1) and
+     * the midpoint (P1) and the end point (P3). 
+     *
+     * P1 = (p1_x | p1_y) 
+     * P2 = (p3_x | p3_y)  -> it's (x3|y3) because the standard assumes (x3|y3) as the last point
+     */
+    gdouble v01[] = { bpath_new->x1 - p0_x,  bpath_new->y1 - p0_y };
+    gdouble v12[] = { bpath_new->x3 - bpath_new->x1,  bpath_new->y3 - bpath_new->y1 };
+
+    /* The points (ph0, ph1) where the linear Bezier curve is parallel
+     * to the x- OR y-axis and the point which points to the highest 
+     * point of the curve.
+     */
+    gdouble ph0[2], ph1[2], ph[2];
+    
+    /* A factor to resize the vectors v01 and v12 
+     * so both vectors point on the same point on the 
+     * x- OR y-axis.
+     *
+     * If this point is reached we've found the highest point
+     * of the curve.
+     */
+    gdouble factor;
+
+    if ((factor = (bpath_new->y1 - p0_y) / (v01[1] - v12[1])) >= 1
+	    || factor <= 0) {
+	
+	factor = (bpath_new->x1 - p0_x) / (v01[0] - v12[0]);
+    }
+
+    ph0[0] = p0_x + v01[0] * factor;
+    ph0[1] = p0_y + v01[1] * factor;
+    ph1[0] = bpath_new->x1 + v12[0] * factor;
+    ph1[1] = bpath_new->y1 + v12[1] * factor;
+
+    ph[0] = ph0[0] + (ph1[0] - ph0[0]) * factor;
+    ph[1] = ph0[1] + (ph1[1] - ph0[1]) * factor;
+
+    bbox->x = MIN(p0_x, MIN(bpath_new->x3, ph[0]));
+    bbox->y = MIN(p0_y, MIN(bpath_new->y3, ph[1]));
+ 
+    max_x = MAX(p0_x, MAX(bpath_new->x3, ph[0]));
+    max_y = MAX(p0_y, MAX(bpath_new->y3, ph[1]));
+
+    bbox->w = max_x - bbox->x;
+    bbox->h = max_y - bbox->y;
+}
+
+static void
+_rsvg_bbox_render_path_cube_curve (RsvgBbox * bbox, 
+				    const RsvgBpath * bpath_old, 
+				    const RsvgBpath * bpath_new)
+{
+    g_return_if_fail (bpath_new != NULL);
+    /* loop variable */
+    int a = -1;
+    /* To compute the width and length */
+    gdouble max_x, max_y;
+
+    /* Save the starting point of the curve (P0) */
+    gdouble p0_x = (bpath_old == NULL) ? 0 : bpath_old->x3;
+    gdouble p0_y = (bpath_old == NULL) ? 0 : bpath_old->y3;
+
+    /* Compute the vector between the starting (P0) and the midpoint (P1) and
+     * the midpoint (P1) and the end point (P3). 
+     *
+     * P1 = (p1_x | p1_y) 
+     * P2 = (p2_x | p2_y) 
+     * P3 = (p3_x | p3_y) 
+     */
+    gdouble v01[] = { bpath_new->x1 - p0_x,  bpath_new->y1 - p0_y };
+    gdouble v12[] = { bpath_new->x2 - bpath_new->x1,  bpath_new->y2 - bpath_new->y1 };
+    gdouble v23[] = { bpath_new->x3 - bpath_new->x2,  bpath_new->y3 - bpath_new->y2 };
+    gdouble vh01[2];
+    gdouble vh12[2];
+
+    /* init the min max values */
+    bbox->x = MIN(p0_x, bpath_new->x3);
+    bbox->y = MIN(p0_y, bpath_new->y3);
+ 
+    max_x = MAX(p0_x, bpath_new->x3);
+    max_y = MAX(p0_y, bpath_new->y3);
+
+
+    /* The points (ph0, ph1) where the linear Bezier curve is parallel
+     * to the x- OR y-axis and the point which points to the highest 
+     * point of the curve.
+     */
+    gdouble ph0[2], ph1[2], ph2[2], ph00[2], ph01[2], ph[2];
+    
+    /* A factor to resize the vectors v01 and v12 
+     * so both vectors point on the same point on the 
+     * x- OR y-axis.
+     *
+     * If this point is reached we've found the highest point
+     * of the curve.
+     */
+    gdouble factors[4] = {0, 0, 0, 0};
+
+    /* for the computation of the factor */
+    double denom, p, q, first, last;
+
+    /* p-q formula to find the roots 
+     * this finds the factors for the left and right or bottom and top border
+     */
+    denom = 2 * v12[0] - v01[0] - v23[0];
+
+    if (denom != 0) {
+	p = (v01[0] - v12[0] + 2*bpath_new->x1 - p0_x - bpath_new->x2) / denom;
+	q = (p0_x - bpath_new->x1) / denom;
+	first = -(p / 2);
+	last = sqrt((p / 2) * (p / 2) - q);
+		
+	factors[0] = ABS(first - last);
+	factors[1] = ABS(first + last);
+    } else {
+	factors[0] = (bpath_new->x2 - p0_x) / (v01[0] - v23[0]);
+    }
+
+    denom = 2 * v12[1] - v01[1] - v23[1];
+
+    if (denom != 0) {
+	p = (v01[1] - v12[1] + 2*bpath_new->y1 - p0_y - bpath_new->y2) / denom;
+	q = (p0_y - bpath_new->y1) / denom;
+	first = -(p / 2);
+	last = sqrt((p / 2) * (p / 2) - q);
+		
+	factors[2] = ABS(first - last);
+	factors[3] = ABS(first + last);
+    } else {
+	factors[2] = (bpath_new->y2 - p0_y) / (v01[1] - v23[1]);
+    }
+
+    for (a=0; a < 4; a++) {
+	if (factors[a] <= 0 || factors[a] >= 1 
+		|| isinf(factors[a]) || isnan(factors[a])) 
+	    continue;
+
+	ph0[0] = p0_x + v01[0] * factors[a];
+	ph0[1] = p0_y + v01[1] * factors[a];
+	ph1[0] = bpath_new->x1 + v12[0] * factors[a];
+	ph1[1] = bpath_new->y1 + v12[1] * factors[a];
+	ph2[0] = bpath_new->x2 + v23[0] * factors[a];
+	ph2[1] = bpath_new->y2 + v23[1] * factors[a];
+			
+	vh01[0] = ph1[0] - ph0[0];
+	vh01[1] = ph1[1] - ph0[1];
+	vh12[0] = ph2[0] - ph1[0];
+	vh12[1] = ph2[1] - ph1[1];
+		
+	ph00[0] = ph0[0] + vh01[0] * factors[a];
+	ph00[1] = ph0[1] + vh01[1] * factors[a];
+	ph01[0] = ph1[0] + vh12[0] * factors[a];
+	ph01[1] = ph1[1] + vh12[1] * factors[a];
+			
+	ph[0] = ph00[0] + (ph01[0] - ph00[0]) * factors[a];
+	ph[1] = ph00[1] + (ph01[1] - ph00[1]) * factors[a];
+
+	bbox->x = MIN(bbox->x, ph[0]);
+	bbox->y = MIN(bbox->y, ph[1]);
+ 
+	max_x = MAX(max_x, ph[0]);
+	max_y = MAX(max_y, ph[1]);
+    }
+
+    if (a < 0) {
+	bbox->x = MIN(p0_x, bpath_new->x3);
+	bbox->y = MIN(p0_y, bpath_new->y3);
+ 
+	max_x = MAX(p0_x, bpath_new->x3);
+	max_y = MAX(p0_y, bpath_new->y3);
+    }
+    
+    bbox->w = max_x - bbox->x;
+    bbox->h = max_y - bbox->y;
+}
+
+static void
+_rsvg_bbox_render_path_curve (RsvgBbox * bbox, 
+			      const RsvgBpath * bpath_old, 
+			      const RsvgBpath * bpath_new)
+{
+    if (bpath_new->x2 == bpath_new->x3 && bpath_new->y2 == bpath_new->y3) {
+	/* a quadratic Bézier curve */
+	_rsvg_bbox_render_path_quad_curve (bbox, bpath_old, bpath_new);
+	return;
+    }
+
+    /* a cubic Bézier curve */
+    _rsvg_bbox_render_path_cube_curve (bbox, bpath_old, bpath_new);
+}
+
+static void
 rsvg_bbox_render_path (RsvgDrawingCtx * ctx, const RsvgBpathDef * bpath_def)
 {
     RsvgState *state = rsvg_state_current (ctx);
@@ -1225,15 +1431,37 @@
         bpath = &bpath_def->bpath[i];
 
         switch (bpath->code) {
+        case RSVG_CURVETO:
+	    if (!i)
+		_rsvg_bbox_render_path_curve (&bbox, NULL, bpath);
+	    else
+		_rsvg_bbox_render_path_curve (&bbox, &bpath_def->bpath[i-1], 
+					      bpath);
+
+	    rsvg_bbox_insert (&render->bbox, &bbox);
+	    break;
         case RSVG_MOVETO:
         case RSVG_MOVETO_OPEN:
-        case RSVG_CURVETO:
         case RSVG_LINETO:
-            bbox.x = bpath->x3;
-            bbox.y = bpath->y3;
+	    if (!i) {
+		bbox.x = bpath->x3;
+		bbox.y = bpath->y3;
+	    } else {
+		bbox.x = MIN(bpath_def->bpath[i-1].x3, bpath->x3);
+		bbox.y = MIN(bpath_def->bpath[i-1].y3, bpath->y3);
+
+		bbox.w = MAX(bpath_def->bpath[i-1].x3, bpath->x3) - bbox.x;
+		bbox.h = MAX(bpath_def->bpath[i-1].y3, bpath->y3) - bbox.y;
+	    }
+
             rsvg_bbox_insert (&render->bbox, &bbox);
             break;
         default:
+	    /*
+	    printf ("New box: x: %f y: %f w: %f h: %f\n",
+		    render->bbox.x, render->bbox.y, 
+		    render->bbox.w, render->bbox.h);
+	    */
             break;
         }
     }
@@ -1329,6 +1557,43 @@
     return output;
 }
 
+static RsvgBbox
+_rsvg_find_bbox_sub (RsvgHandle * handle, RsvgNode * node)
+{
+    RsvgDrawingCtx *ctx = g_new (RsvgDrawingCtx, 1);
+    RsvgBbox output;
+    RsvgBboxRender *render = rsvg_bbox_render_new ();
+    ctx->drawsub_stack = NULL;
+    ctx->render = (RsvgRender *) render;
+
+    ctx->state = NULL;
+
+    ctx->defs = handle->priv->defs;
+    ctx->base_uri = g_strdup (handle->priv->base_uri);
+    ctx->dpi_x = handle->priv->dpi_x;
+    ctx->dpi_y = handle->priv->dpi_y;
+    ctx->vb.w = 512;
+    ctx->vb.h = 512;
+    ctx->pango_context = NULL;
+
+    rsvg_state_push (ctx);
+    _rsvg_affine_identity (rsvg_state_current (ctx)->affine);
+    
+    if (node->children->len > 0 && g_strcmp0 (node->type->str, "text")) {
+	// printf ("Children in <%s>: %d\n", node->type->str, node->children->len);
+	_rsvg_node_draw_children (node, ctx, 0);
+    }
+    else
+	rsvg_node_draw (node, ctx, 0);
+
+    rsvg_state_pop (ctx);
+
+    output = render->bbox;
+    rsvg_render_free (ctx->render);
+    g_free (ctx);
+    return output;
+}
+
 /**
  * rsvg_handle_get_dimensions
  * @handle: A #RsvgHandle
@@ -1378,6 +1643,89 @@
                                     handle->priv->user_data);
 }
 
+gboolean
+rsvg_handle_get_dimensions_sub (RsvgHandle * handle, RsvgDimensionData * dimension_data, const char *id)
+{
+    cairo_t *cr;
+    cairo_surface_t *target;
+    RsvgDrawingCtx *draw;
+    RsvgCairoRender *render;
+    RsvgNodeSvg *root = NULL;
+    RsvgNode *sself = NULL;
+    RsvgBbox bbox;
+
+    g_return_val_if_fail (handle, FALSE);
+    g_return_val_if_fail (dimension_data, FALSE);
+
+    memset (dimension_data, 0, sizeof (RsvgDimensionData));
+
+    if (id && *id)
+	sself = (RsvgNode *) rsvg_defs_lookup (handle->priv->defs, id);
+
+    if (!sself)
+        return FALSE;
+
+    root = (RsvgNodeSvg *) handle->priv->treebase;
+
+    if (!root)
+	return FALSE;
+
+    bbox.x = bbox.y = 0;
+    bbox.w = bbox.h = 1;
+
+    target = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+					 1, 1);
+    cr = cairo_create  (target);
+
+    draw = rsvg_cairo_new_drawing_ctx (cr, handle);
+    
+    if (!draw)
+	return FALSE;
+
+    while (sself != NULL) {
+        draw->drawsub_stack = g_slist_prepend (draw->drawsub_stack, sself);
+        sself = sself->parent;
+    }
+
+    rsvg_state_push (draw);
+    cairo_save (cr);
+
+    rsvg_node_draw ((RsvgNode *) handle->priv->treebase, draw, 0);
+    render = (RsvgCairoRender *) draw->render;
+
+    bbox.x = render->bbox.x;
+    bbox.y = render->bbox.y;
+    bbox.w = render->bbox.w;
+    bbox.h = render->bbox.h;
+
+    cairo_restore (cr);
+    rsvg_state_pop (draw);
+    rsvg_drawing_ctx_free (draw);
+    cairo_destroy (cr);
+    cairo_surface_destroy (target);
+    
+    dimension_data->width = (int) (_rsvg_css_hand_normalize_length_sub (&root->w, bbox.w, handle->priv->dpi_x,
+                                                                    bbox.w + bbox.x * 2, 12) + 0.5);
+    dimension_data->height = (int) (_rsvg_css_hand_normalize_length_sub (&root->h, bbox.h, handle->priv->dpi_y,
+                                                                     bbox.h + bbox.y * 2,
+                                                                     12) + 0.5);
+    /*
+    printf("Bbox x: %f y: %f w: %f h: %f\n",
+	    bbox.x, bbox.y, bbox.w, bbox.h);
+    printf("Dimension width: %d height: %d\n\n", dimension_data->width, dimension_data->height);
+    */
+
+    dimension_data->em = dimension_data->width;
+    dimension_data->ex = dimension_data->height;
+
+    if (handle->priv->size_func)
+        (*handle->priv->size_func) (&dimension_data->width, &dimension_data->height,
+                                    handle->priv->user_data);
+
+    return TRUE;
+}
+
+
 /** 
  * rsvg_set_default_dpi
  * @dpi: Dots Per Inch (aka Pixels Per Inch)

=== modified file 'rsvg-cairo-render.c'
--- rsvg-cairo-render.c	2008-08-26 17:07:12 +0000
+++ rsvg-cairo-render.c	2008-10-16 08:52:57 +0000
@@ -107,7 +107,7 @@
     *y1 = ceil (t > y11 ? t : y11);
 }
 
-static RsvgDrawingCtx *
+RsvgDrawingCtx *
 rsvg_cairo_new_drawing_ctx (cairo_t * cr, RsvgHandle * handle)
 {
     RsvgDimensionData data;

=== modified file 'rsvg-cairo-render.h'
--- rsvg-cairo-render.h	2008-01-19 16:47:05 +0000
+++ rsvg-cairo-render.h	2008-10-16 08:53:11 +0000
@@ -51,6 +51,7 @@
 
 RsvgCairoRender *rsvg_cairo_render_new		(cairo_t * cr, double width, double height);
 void		 rsvg_cairo_render_rsvg_handle	(cairo_t * cr, RsvgHandle * handle);
+RsvgDrawingCtx *rsvg_cairo_new_drawing_ctx (cairo_t * cr, RsvgHandle * handle);
 
 G_END_DECLS
 

=== modified file 'rsvg-css.c'
--- rsvg-css.c	2008-04-25 14:27:44 +0000
+++ rsvg-css.c	2008-10-10 08:18:54 +0000
@@ -252,6 +252,25 @@
     return 0;
 }
 
+double
+_rsvg_css_hand_normalize_length_sub (const RsvgLength * in, gdouble length, 
+				     gdouble pixels_per_inch, gdouble width_or_height, 
+				     gdouble font_size)
+{
+    if (in->factor == '\0')
+        return length;
+    else if (in->factor == 'p')
+        return length * width_or_height;
+    else if (in->factor == 'm')
+        return length * font_size;
+    else if (in->factor == 'x')
+        return length * font_size / 2.;
+    else if (in->factor == 'i')
+        return length * pixels_per_inch;
+
+    return 0;
+}
+
 gboolean
 rsvg_css_param_match (const char *str, const char *param_name)
 {

=== modified file 'rsvg-private.h'
--- rsvg-private.h	2008-08-26 16:51:17 +0000
+++ rsvg-private.h	2008-10-09 09:21:21 +0000
@@ -344,6 +344,9 @@
 double _rsvg_css_normalize_length	(const RsvgLength * in, RsvgDrawingCtx * ctx, char dir);
 double _rsvg_css_hand_normalize_length	(const RsvgLength * in, gdouble pixels_per_inch,
 					 gdouble width_or_height, gdouble font_size);
+double _rsvg_css_hand_normalize_length_sub	(const RsvgLength * in, gdouble length,
+						 gdouble pixels_per_inch, gdouble width_or_height, 
+						 gdouble font_size);
 
 RsvgLength _rsvg_css_parse_length (const char *str);
 

=== modified file 'rsvg.h'
--- rsvg.h	2007-01-13 15:22:25 +0000
+++ rsvg.h	2008-10-09 14:05:11 +0000
@@ -118,6 +118,8 @@
 
 void rsvg_handle_get_dimensions (RsvgHandle * handle, RsvgDimensionData * dimension_data);
 
+gboolean rsvg_handle_get_dimensions_sub (RsvgHandle * handle, RsvgDimensionData * dimension_data, const char *id);
+
 /* Accessibility API */
 
 G_CONST_RETURN char *rsvg_handle_get_title	(RsvgHandle * handle);

