rsvg_handle_get_dimensions_sub (RsvgHandle * handle, RsvgDimensionData * dimension_data, const char *id)
{
    cairo_t *cr;
    cairo_surface_t *target;
    RsvgDrawingCtx *draw;
    RsvgNodeSvg *root = NULL;
    RsvgNode *sself = NULL;
    RsvgBbox bbox;

    gboolean handle_subelement = TRUE;

    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 == (RsvgNode *) handle->priv->treebase)
            id = NULL;
    }
    else
        sself = (RsvgNode *) handle->priv->treebase;

    if (!sself && id)
        return FALSE;

    root = (RsvgNodeSvg *) handle->priv->treebase;

    if (!root)
        return FALSE;

    bbox.rect.x = bbox.rect.y = 0;
    bbox.rect.width = bbox.rect.height = 1;

    if (!id && (root->w.factor == 'p' || root->h.factor == 'p')
            && !root->vbox.active)
        handle_subelement = TRUE;
    else if (!id && root->w.length != -1 && root->h.length != -1)
        handle_subelement = FALSE;

    if (handle_subelement == TRUE) {
        target = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
                                             1, 1);
        cr = cairo_create  (target);

        draw = rsvg_cairo_new_drawing_ctx (cr, handle);

        if (!draw) {
            cairo_destroy (cr);
            cairo_surface_destroy (target);

            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);
        bbox = RSVG_CAIRO_RENDER (draw->render)->bbox;

        cairo_restore (cr);
        rsvg_state_pop (draw);
        rsvg_drawing_ctx_free (draw);
        cairo_destroy (cr);
        cairo_surface_destroy (target);

        dimension_data->width = bbox.rect.width;
        dimension_data->height = bbox.rect.height;
    } else {
        bbox.rect.width = root->vbox.rect.width;
        bbox.rect.height = root->vbox.rect.height;

        dimension_data->width = (int) (_rsvg_css_hand_normalize_length (&root->w, handle->priv->dpi_x,
                                       bbox.rect.width + bbox.rect.x * 2, 12) + 0.5);
        dimension_data->height = (int) (_rsvg_css_hand_normalize_length (&root->h, handle->priv->dpi_y,
                                         bbox.rect.height + bbox.rect.y * 2,
                                         12) + 0.5);
    }
    
    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_handle_get_dimensions_sub (RsvgHandle * handle, RsvgDimensionData * dimension_data, const char *id)
{
    cairo_t *cr;
    cairo_surface_t *target;
    RsvgDrawingCtx *draw;
    RsvgNodeSvg *root = NULL;
    RsvgNode *sself = NULL;
    RsvgBbox bbox;

    gboolean handle_subelement = TRUE;

    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 == (RsvgNode *) handle->priv->treebase)
            id = NULL;
    }
    else
        sself = (RsvgNode *) handle->priv->treebase;

    if (!sself && id)
        return FALSE;

    root = (RsvgNodeSvg *) handle->priv->treebase;

    if (!root)
        return FALSE;

    bbox.rect.x = bbox.rect.y = 0;
    bbox.rect.width = bbox.rect.height = 1;

    if (!id && (root->w.factor == 'p' || root->h.factor == 'p')
            && !root->vbox.active)
        handle_subelement = TRUE;
    else if (!id && root->w.length != -1 && root->h.length != -1)
        handle_subelement = FALSE;

    if (handle_subelement == TRUE) {
        target = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
                                             1, 1);
        cr = cairo_create  (target);

        draw = rsvg_cairo_new_drawing_ctx (cr, handle);

        if (!draw) {
            cairo_destroy (cr);
            cairo_surface_destroy (target);

            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);
        bbox = RSVG_CAIRO_RENDER (draw->render)->bbox;

        cairo_restore (cr);
        rsvg_state_pop (draw);
        rsvg_drawing_ctx_free (draw);
        cairo_destroy (cr);
        cairo_surface_destroy (target);

        dimension_data->width = bbox.rect.width;
        dimension_data->height = bbox.rect.height;
    } else {
        bbox.rect.width = root->vbox.rect.width;
        bbox.rect.height = root->vbox.rect.height;

        dimension_data->width = (int) (_rsvg_css_hand_normalize_length (&root->w, handle->priv->dpi_x,
                                       bbox.rect.width + bbox.rect.x * 2, 12) + 0.5);
        dimension_data->height = (int) (_rsvg_css_hand_normalize_length (&root->h, handle->priv->dpi_y,
                                         bbox.rect.height + bbox.rect.y * 2,
                                         12) + 0.5);
    }
    
    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;
}