librsvg r1190 - trunk



Author: doml
Date: Sat Nov 22 16:44:34 2008
New Revision: 1190
URL: http://svn.gnome.org/viewvc/librsvg?rev=1190&view=rev

Log:
2008-11-22  Dominic Lachowicz  <domlachowicz gmail com>

	* rsvg-cairo-render.h: Feature request: 
rsvg_handle_get_dimensions_sub()
	(#555682). Patches from Hagen Schink (troja84 gmail com) and 
	Robert Staudinger (robert staudinger gmail com)
	* librsvg.def: 
	* rsvg-private.h:
	* ChangeLog:
	* rsvg-structure.c:
	* rsvg-base.c:
	* rsvg-css.c:
	* rsvg.h:
	* rsvg-dimensions.c:
	* Makefile.am:
	* rsvg-cairo-render.c:
	* rsvg-gobject.c: ditto



Added:
   trunk/rsvg-dimensions.c
Modified:
   trunk/ChangeLog
   trunk/Makefile.am
   trunk/librsvg.def
   trunk/rsvg-base.c
   trunk/rsvg-cairo-render.c
   trunk/rsvg-cairo-render.h
   trunk/rsvg-css.c
   trunk/rsvg-gobject.c
   trunk/rsvg-private.h
   trunk/rsvg-structure.c
   trunk/rsvg.h

Modified: trunk/Makefile.am
==============================================================================
--- trunk/Makefile.am	(original)
+++ trunk/Makefile.am	Sat Nov 22 16:44:34 2008
@@ -8,7 +8,7 @@
 
 lib_LTLIBRARIES = librsvg-2.la
 bin_PROGRAMS = rsvg-convert $(target_rsvg_view)
-noinst_PROGRAMS = test-performance
+noinst_PROGRAMS = test-performance rsvg-dimensions
 
 man_MANS = rsvg.1
 
@@ -109,6 +109,11 @@
 test_performance_DEPENDENCIES = $(DEPS)
 test_performance_LDADD = $(LDADDS) $(libm)
 
+rsvg_dimensions_SOURCES=rsvg-dimensions.c
+rsvg_dimensions_LDFLAGS =
+rsvg_dimensions_DEPENDENCIES = $(DEPS)
+rsvg_dimensions_LDADD = $(LDADDS) $(libm)
+
 rsvg_view_SOURCES = 		\
 	test-display.c
 rsvg_view_LDFLAGS =

Modified: trunk/librsvg.def
==============================================================================
--- trunk/librsvg.def	(original)
+++ trunk/librsvg.def	Sat Nov 22 16:44:34 2008
@@ -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: trunk/rsvg-base.c
==============================================================================
--- trunk/rsvg-base.c	(original)
+++ trunk/rsvg-base.c	Sat Nov 22 16:44:34 2008
@@ -42,6 +42,7 @@
 #include "rsvg-filter.h"
 #include "rsvg-mask.h"
 #include "rsvg-marker.h"
+#include "rsvg-cairo-render.h"
 
 #include <libxml/uri.h>
 
@@ -1224,132 +1225,6 @@
         return NULL;
 }
 
-typedef struct {
-    RsvgRender super;
-    RsvgBbox bbox;
-} RsvgBboxRender;
-
-static void
-rsvg_bbox_render_path (RsvgDrawingCtx * ctx, const RsvgBpathDef * bpath_def)
-{
-    RsvgState *state = rsvg_state_current (ctx);
-    RsvgBpath *bpath;
-    RsvgBboxRender *render = (RsvgBboxRender *) ctx->render;
-    RsvgBbox bbox;
-    int i;
-
-    rsvg_bbox_init (&bbox, state->affine);
-    bbox.w = bbox.h = bbox.virgin = 0;
-
-    for (i = 0; i < bpath_def->n_bpath; i++) {
-        bpath = &bpath_def->bpath[i];
-
-        switch (bpath->code) {
-        case RSVG_MOVETO:
-        case RSVG_MOVETO_OPEN:
-        case RSVG_CURVETO:
-        case RSVG_LINETO:
-            bbox.x = bpath->x3;
-            bbox.y = bpath->y3;
-            rsvg_bbox_insert (&render->bbox, &bbox);
-            break;
-        default:
-            break;
-        }
-    }
-}
-
-static void
-rsvg_bbox_render_image (RsvgDrawingCtx * ctx,
-                        const GdkPixbuf * pixbuf,
-                        double pixbuf_x, double pixbuf_y, double w, double h)
-{
-    RsvgState *state = rsvg_state_current (ctx);
-    RsvgBboxRender *render = (RsvgBboxRender *) ctx->render;
-    RsvgBbox bbox;
-
-    rsvg_bbox_init (&bbox, state->affine);
-    bbox.x = pixbuf_x;
-    bbox.y = pixbuf_y;
-    bbox.w = w;
-    bbox.h = h;
-    bbox.virgin = 0;
-
-    rsvg_bbox_insert (&render->bbox, &bbox);
-}
-
-
-static void
-rsvg_bbox_render_free (RsvgRender * self)
-{
-    g_free (self);
-}
-
-static void
-rsvg_bbox_push_discrete_layer (RsvgDrawingCtx * ctx)
-{
-}
-
-static void
-rsvg_bbox_pop_discrete_layer (RsvgDrawingCtx * ctx)
-{
-}
-
-static void
-rsvg_bbox_add_clipping_rect (RsvgDrawingCtx * ctx, double x, double y, double w, double h)
-{
-}
-
-static RsvgBboxRender *
-rsvg_bbox_render_new ()
-{
-    RsvgBboxRender *render = g_new0 (RsvgBboxRender, 1);
-    double affine[6];
-
-    render->super.free = rsvg_bbox_render_free;
-    render->super.render_image = rsvg_bbox_render_image;
-    render->super.render_path = rsvg_bbox_render_path;
-    render->super.pop_discrete_layer = rsvg_bbox_pop_discrete_layer;
-    render->super.push_discrete_layer = rsvg_bbox_push_discrete_layer;
-    render->super.add_clipping_rect = rsvg_bbox_add_clipping_rect;
-    render->super.get_image_of_node = NULL;
-    _rsvg_affine_identity (affine);
-    rsvg_bbox_init (&render->bbox, affine);
-
-    return render;
-}
-
-static RsvgBbox
-_rsvg_find_bbox (RsvgHandle * handle)
-{
-    RsvgDrawingCtx *ctx = g_new (RsvgDrawingCtx, 1);
-    RsvgBbox output;
-    RsvgBboxRender *render = rsvg_bbox_render_new ();
-    ctx->drawsub_stack = NULL;
-    ctx->ptrs = 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);
-    _rsvg_node_draw_children ((RsvgNode *) handle->priv->treebase, 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
@@ -1362,43 +1237,135 @@
 void
 rsvg_handle_get_dimensions (RsvgHandle * handle, RsvgDimensionData * dimension_data)
 {
-    RsvgNodeSvg *sself;
+    /* This function is probably called from the cairo_render functions.
+     * To prevent an infinite loop we are saving the state.
+     */
+    if (!handle->priv->in_loop) {
+	handle->priv->in_loop = TRUE;
+	rsvg_handle_get_dimensions_sub (handle, dimension_data, NULL);
+	handle->priv->in_loop = FALSE;
+    } else {
+	/* Called within the size function, so return a standard size */
+	dimension_data->em = dimension_data->width = 1;
+	dimension_data->ex = dimension_data->height = 1;
+    }
+}
+
+/**
+ * rsvg_handle_get_dimensions_sub
+ * @handle: A #RsvgHandle
+ * @dimension_data: A place to store the SVG's size
+ * @id: An element's id within the SVG, or NULL to get the dimension of the whole SVG. 
+ * For example, if you have a layer called "layer1" for that you want to get the dimension, 
+ * pass "#layer1" as the id.
+ *
+ * Get the size of a subelement of the SVG file. Do not call from within the size_func callback, because an infinite loop will occur.
+ *
+ * Since: 2.22
+ */
+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_if_fail (handle);
-    g_return_if_fail (dimension_data);
+    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));
 
-    sself = (RsvgNodeSvg *) handle->priv->treebase;
-    if (!sself)
-        return;
+    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.x = bbox.y = 0;
     bbox.w = bbox.h = 1;
 
-    if (sself->w.factor == 'p' || sself->h.factor == 'p') {
-        if (sself->vbox.active && sself->vbox.w > 0. && sself->vbox.h > 0.) {
-            bbox.w = sself->vbox.w;
-            bbox.h = sself->vbox.h;
-        } else
-            bbox = _rsvg_find_bbox (handle);
-    }
+    if (!id && (root->w.factor == 'p' || root->h.factor == 'p')
+	    && root->vbox.active && root->vbox.w > 0. && root->vbox.h > 0.)
+	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)
+	    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);
 
-    dimension_data->width = (int) (_rsvg_css_hand_normalize_length (&sself->w, handle->priv->dpi_x,
-                                                                    bbox.w + bbox.x * 2, 12) + 0.5);
-    dimension_data->height = (int) (_rsvg_css_hand_normalize_length (&sself->h, handle->priv->dpi_y,
-                                                                     bbox.h + bbox.y * 2,
-                                                                     12) + 0.5);
+	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);
+    } else {
+	bbox.w = root->vbox.w; 
+	bbox.h = root->vbox.h; 
 
+	dimension_data->width = (int) (_rsvg_css_hand_normalize_length (&root->w, handle->priv->dpi_x,
+									bbox.w + bbox.x * 2, 12) + 0.5);
+	dimension_data->height = (int) (_rsvg_css_hand_normalize_length (&root->h, handle->priv->dpi_y, 
+									bbox.h + bbox.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_set_default_dpi
  * @dpi: Dots Per Inch (aka Pixels Per Inch)

Modified: trunk/rsvg-cairo-render.c
==============================================================================
--- trunk/rsvg-cairo-render.c	(original)
+++ trunk/rsvg-cairo-render.c	Sat Nov 22 16:44:34 2008
@@ -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: trunk/rsvg-cairo-render.h
==============================================================================
--- trunk/rsvg-cairo-render.h	(original)
+++ trunk/rsvg-cairo-render.h	Sat Nov 22 16:44:34 2008
@@ -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: trunk/rsvg-css.c
==============================================================================
--- trunk/rsvg-css.c	(original)
+++ trunk/rsvg-css.c	Sat Nov 22 16:44:34 2008
@@ -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)
 {

Added: trunk/rsvg-dimensions.c
==============================================================================
--- (empty file)
+++ trunk/rsvg-dimensions.c	Sat Nov 22 16:44:34 2008
@@ -0,0 +1,128 @@
+
+/*
+ * License: Public Domain.
+ * Author: Robert Staudinger <robsta gnome org>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <rsvg.h>
+
+static void
+show_help (GOptionContext *context)
+{
+	char *help;
+	help = g_option_context_get_help (context, TRUE, NULL);
+	perror (help);
+	g_free (help), help = NULL;
+}
+
+int
+main (int	  argc,
+      char	**argv)
+{
+	GOptionContext		 *context;
+	char const		 *fragment;
+	char const	 	**filenames;
+	char const		 *file;
+	RsvgHandle		 *handle;
+	RsvgDimensionData	  dimensions;
+	GError			 *error;
+	int			  exit_code;
+	int                       i;
+
+	GOptionEntry options[] = {
+		{ "fragment", 'f', 0, G_OPTION_ARG_STRING, &fragment, "The SVG fragment to address.", "<string>" },
+		{ G_OPTION_REMAINING, 0, G_OPTION_FLAG_FILENAME, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, "[FILE...]" },
+		{ NULL }
+	};
+
+	rsvg_init ();
+
+	fragment = NULL;
+	filenames = NULL;
+
+	context = g_option_context_new ("- SVG measuring tool.");
+	g_option_context_add_main_entries (context, options, NULL);
+
+	/* No args? */
+	if (argc < 2) {
+		show_help (context);
+		exit_code = EXIT_SUCCESS;
+		goto bail1;
+	}
+
+	error = NULL;
+	g_option_context_parse (context, &argc, &argv, &error);
+	if (error) {
+		show_help (context);
+		g_warning (error->message);
+		exit_code = EXIT_FAILURE;
+		goto bail2;
+	}
+
+	/* Invalid / missing args? */
+	if (filenames == NULL) {
+		show_help (context);
+		exit_code = EXIT_FAILURE;
+		goto bail2;
+	}
+
+	g_option_context_free (context), context = NULL;
+
+	for (i = 0; NULL != (file = filenames[i]); i++) {
+
+		error = NULL;
+		handle = rsvg_handle_new_from_file (file, &error);
+		if (error) {
+			g_warning (error->message);
+			exit_code = EXIT_FAILURE;
+			goto bail2;
+		}
+
+		if (fragment && handle) {
+			gboolean have_fragment;
+			have_fragment = rsvg_handle_get_dimensions_sub (handle,
+						&dimensions, fragment);
+			if (!have_fragment) {
+				g_warning ("%s: fragment `'%s' not found.",
+						file, fragment);
+				exit_code = EXIT_FAILURE;
+				goto bail3;
+			}
+
+			printf ("%s, fragment `%s': %dx%d, em=%f, ex=%f\n",
+					file, fragment,
+					dimensions.width, dimensions.height,
+					dimensions.em, dimensions.ex);
+
+		} else if (handle) {
+			rsvg_handle_get_dimensions (handle, &dimensions);
+			printf ("%s: %dx%d, em=%f, ex=%f\n", file,
+					dimensions.width, dimensions.height,
+					dimensions.em, dimensions.ex);
+		} else {
+			g_warning ("Could not open file `%s'", file);
+			exit_code = EXIT_FAILURE;
+			goto bail2;
+		}
+
+		g_object_unref (G_OBJECT (handle)), handle = NULL;
+	}
+
+	exit_code = EXIT_SUCCESS;
+
+bail3:
+	if (handle)
+		g_object_unref (G_OBJECT (handle)), handle = NULL;
+bail2:
+	if (context)
+		g_option_context_free (context), context = NULL;
+	if (error)
+		g_error_free (error), error = NULL;
+bail1:
+	rsvg_term ();
+	return exit_code;
+}
+

Modified: trunk/rsvg-gobject.c
==============================================================================
--- trunk/rsvg-gobject.c	(original)
+++ trunk/rsvg-gobject.c	Sat Nov 22 16:44:34 2008
@@ -63,6 +63,7 @@
     self->priv->first_write = TRUE;
 
     self->priv->is_disposed = FALSE;
+    self->priv->in_loop = FALSE;
 }
 
 static void

Modified: trunk/rsvg-private.h
==============================================================================
--- trunk/rsvg-private.h	(original)
+++ trunk/rsvg-private.h	Sat Nov 22 16:44:34 2008
@@ -167,6 +167,7 @@
     gboolean first_write;
     gboolean is_gzipped;
     void *gzipped_data;         /* really a GsfOutput */
+    gboolean in_loop;		/* see get_dimension() */
 };
 
 typedef struct {
@@ -345,6 +346,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: trunk/rsvg-structure.c
==============================================================================
--- trunk/rsvg-structure.c	(original)
+++ trunk/rsvg-structure.c	Sat Nov 22 16:44:34 2008
@@ -345,9 +345,16 @@
             svg->preserve_aspect_ratio = rsvg_css_parse_aspect_ratio (value);
         if ((value = rsvg_property_bag_lookup (atts, "width")))
             svg->w = _rsvg_css_parse_length (value);
+	else {
+	    svg->w.length = -1;
+	    svg->w.factor = '\0';
+	}
         if ((value = rsvg_property_bag_lookup (atts, "height")))
             svg->h = _rsvg_css_parse_length (value);
-
+	else {
+	    svg->h.length = -1;
+	    svg->h.factor = '\0';
+	}
 		/* 
 		 * x & y attributes have no effect on outermost svg
 		 * http://www.w3.org/TR/SVG/struct.html#SVGElement 

Modified: trunk/rsvg.h
==============================================================================
--- trunk/rsvg.h	(original)
+++ trunk/rsvg.h	Sat Nov 22 16:44:34 2008
@@ -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);



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