[librsvg: 1/13] handle: add new API to get node geometry
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 1/13] handle: add new API to get node geometry
- Date: Fri, 30 Nov 2018 23:49:22 +0000 (UTC)
commit aac1da9be2ccf25918f9bd47f3008a775a2a52cd
Author: Julian Sparber <julian sparber net>
Date: Sun Nov 18 12:13:31 2018 +0200
handle: add new API to get node geometry
This adds a new API called rsvg_handle_get_geometry_sub(), it returns the
exact position and dimension of a svg node.
librsvg/rsvg-handle.c | 87 +++++++++++++++++++++++++++++++++++++--
librsvg/rsvg-private.h | 2 +-
librsvg/rsvg.h | 2 +
rsvg_internals/src/drawing_ctx.rs | 19 ++++++++-
rsvg_internals/src/lib.rs | 2 +-
tests/api.c | 12 +++++-
tests/dimensions.c | 12 ++++++
7 files changed, 127 insertions(+), 9 deletions(-)
---
diff --git a/librsvg/rsvg-handle.c b/librsvg/rsvg-handle.c
index a0d582c9..025c6ed1 100644
--- a/librsvg/rsvg-handle.c
+++ b/librsvg/rsvg-handle.c
@@ -1196,7 +1196,7 @@ rsvg_handle_get_dimensions (RsvgHandle * handle, RsvgDimensionData * dimension_d
}
static gboolean
-get_node_ink_rect(RsvgHandle *handle, RsvgNode *node, cairo_rectangle_t *ink_rect)
+get_node_geometry(RsvgHandle *handle, RsvgNode *node, cairo_rectangle_t *ink_rect, cairo_rectangle_t
*logical_rect)
{
RsvgDimensionData dimensions;
cairo_surface_t *target;
@@ -1219,7 +1219,7 @@ get_node_ink_rect(RsvgHandle *handle, RsvgNode *node, cairo_rectangle_t *ink_rec
rsvg_tree_cascade (handle->priv->tree);
res = rsvg_drawing_ctx_draw_node_from_stack (draw, handle->priv->tree);
if (res) {
- res = rsvg_drawing_ctx_get_ink_rect (draw, ink_rect);
+ res = rsvg_drawing_ctx_get_geometry (draw, ink_rect, logical_rect);
}
rsvg_drawing_ctx_free (draw);
@@ -1280,7 +1280,7 @@ rsvg_handle_get_dimensions_sub (RsvgHandle * handle, RsvgDimensionData * dimensi
if (id || !has_size) {
cairo_rectangle_t ink_rect;
- if (!get_node_ink_rect (handle, node, &ink_rect)) {
+ if (!get_node_geometry (handle, node, &ink_rect, NULL)) {
goto out;
}
@@ -1307,6 +1307,85 @@ out:
return res;
}
+/**
+ * rsvg_handle_get_geometry_sub:
+ * @handle: A #RsvgHandle
+ * @ink_rect: (out): A place to store the SVG fragment's geometry.
+ * @logical_rect: (out): A place to store the SVG fragment's logical geometry.
+ * @id: (nullable): An element's id within the SVG, starting with "##", for
+ * example, "##layer1"; or %NULL to use the whole SVG.
+ *
+ * Get the geometry of a subelement of the SVG file. Do not call from within
+ * the size_func callback, because an infinite loop will occur.
+ *
+ */
+gboolean
+rsvg_handle_get_geometry_sub (RsvgHandle * handle, cairo_rectangle_t * ink_rect, cairo_rectangle_t *
logical_rect, const char *id)
+{
+ RsvgNode *root = NULL;
+ RsvgNode *node;
+ gboolean has_size;
+ int root_width, root_height;
+ gboolean res = FALSE;
+
+ g_return_val_if_fail (handle, FALSE);
+ g_return_val_if_fail (ink_rect, FALSE);
+ g_return_val_if_fail (logical_rect, FALSE);
+
+ memset (ink_rect, 0, sizeof (cairo_rectangle_t));
+ memset (logical_rect, 0, sizeof (cairo_rectangle_t));
+
+ if (handle->priv->tree == NULL)
+ return FALSE;
+
+ root = rsvg_tree_get_root (handle->priv->tree);
+
+ if (id && *id) {
+ node = rsvg_defs_lookup (handle->priv->defs, id);
+
+ if (node && rsvg_tree_is_root (handle->priv->tree, node))
+ id = NULL;
+ } else {
+ node = root;
+ }
+
+ if (!node && id) {
+ goto out;
+ }
+
+ has_size = rsvg_node_svg_get_size (root,
+ handle->priv->dpi_x, handle->priv->dpi_y,
+ &root_width, &root_height);
+
+ if (id || !has_size) {
+ if (!get_node_geometry (handle, node, ink_rect, logical_rect)) {
+ goto out;
+ }
+ } else {
+ ink_rect->width = root_width;
+ ink_rect->height = root_height;
+ ink_rect->x = 0;
+ ink_rect->y = 0;
+
+ logical_rect->width = root_width;
+ logical_rect->height = root_height;
+ logical_rect->x = 0;
+ logical_rect->y = 0;
+ }
+
+ if (handle->priv->size_func)
+ (*handle->priv->size_func) ((gint *)&ink_rect->width, (gint *)&ink_rect->height,
+ handle->priv->user_data);
+
+ res = TRUE;
+
+out:
+
+ g_clear_pointer (&root, rsvg_node_unref);
+
+ return res;
+}
+
/**
* rsvg_handle_get_position_sub:
* @handle: A #RsvgHandle
@@ -1345,7 +1424,7 @@ rsvg_handle_get_position_sub (RsvgHandle * handle, RsvgPositionData * position_d
if (rsvg_tree_is_root (handle->priv->tree, node))
return TRUE;
- if (!get_node_ink_rect (handle, node, &ink_rect))
+ if (!get_node_geometry (handle, node, &ink_rect, NULL))
return FALSE;
position_data->x = ink_rect.x;
diff --git a/librsvg/rsvg-private.h b/librsvg/rsvg-private.h
index c439dca8..e201ab67 100644
--- a/librsvg/rsvg-private.h
+++ b/librsvg/rsvg-private.h
@@ -223,7 +223,7 @@ gboolean rsvg_drawing_ctx_draw_node_from_stack (RsvgDrawingCtx *ctx, RsvgTree *t
/* Defined in rsvg_internals/src/drawing_ctx.rs */
G_GNUC_INTERNAL
-gboolean rsvg_drawing_ctx_get_ink_rect (RsvgDrawingCtx *ctx, cairo_rectangle_t *ink_rect);
+gboolean rsvg_drawing_ctx_get_geometry (RsvgDrawingCtx *ctx, cairo_rectangle_t *ink_rect, cairo_rectangle_t
*logical_rect);
/* Implemented in rust/src/node.rs */
G_GNUC_INTERNAL
diff --git a/librsvg/rsvg.h b/librsvg/rsvg.h
index 2e73dbf9..8c4998eb 100644
--- a/librsvg/rsvg.h
+++ b/librsvg/rsvg.h
@@ -31,6 +31,7 @@
#include <glib-object.h>
#include <gio/gio.h>
+#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
G_BEGIN_DECLS
@@ -151,6 +152,7 @@ void rsvg_handle_get_dimensions (RsvgHandle * handle, RsvgDimensionData * dimens
gboolean rsvg_handle_get_dimensions_sub (RsvgHandle * handle, RsvgDimensionData * dimension_data, const char
*id);
gboolean rsvg_handle_get_position_sub (RsvgHandle * handle, RsvgPositionData * position_data, const char
*id);
+gboolean rsvg_handle_get_geometry_sub (RsvgHandle * handle, cairo_rectangle_t * ink_rect, cairo_rectangle_t
* logical_rect, const char *id);
gboolean rsvg_handle_has_sub (RsvgHandle * handle, const char *id);
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index 447b8eb7..f63b9fb7 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -1094,16 +1094,17 @@ pub extern "C" fn rsvg_drawing_ctx_add_node_and_ancestors_to_stack(
}
#[no_mangle]
-pub extern "C" fn rsvg_drawing_ctx_get_ink_rect(
+pub extern "C" fn rsvg_drawing_ctx_get_geometry(
raw_draw_ctx: *const RsvgDrawingCtx,
ink_rect: *mut cairo_sys::cairo_rectangle_t,
+ logical_rect: *mut cairo_sys::cairo_rectangle_t,
) -> glib_sys::gboolean {
assert!(!raw_draw_ctx.is_null());
let draw_ctx = unsafe { &mut *(raw_draw_ctx as *mut DrawingCtx<'_>) };
assert!(!ink_rect.is_null());
- let res = match draw_ctx.get_bbox().ink_rect {
+ let mut res = match draw_ctx.get_bbox().ink_rect {
Some(r) => unsafe {
(*ink_rect).x = r.x;
(*ink_rect).y = r.y;
@@ -1114,6 +1115,20 @@ pub extern "C" fn rsvg_drawing_ctx_get_ink_rect(
_ => false,
};
+ if !logical_rect.is_null() {
+ res = res
+ && match draw_ctx.get_bbox().rect {
+ Some(r) => unsafe {
+ (*logical_rect).x = r.x;
+ (*logical_rect).y = r.y;
+ (*logical_rect).width = r.width;
+ (*logical_rect).height = r.height;
+ true
+ },
+ _ => false,
+ }
+ }
+
res.to_glib()
}
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index 9149bdeb..616ba2bd 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -42,7 +42,7 @@ pub use drawing_ctx::{
rsvg_drawing_ctx_add_node_and_ancestors_to_stack,
rsvg_drawing_ctx_draw_node_from_stack,
rsvg_drawing_ctx_free,
- rsvg_drawing_ctx_get_ink_rect,
+ rsvg_drawing_ctx_get_geometry,
rsvg_drawing_ctx_new,
};
diff --git a/tests/api.c b/tests/api.c
index 587f06d5..33504e3b 100644
--- a/tests/api.c
+++ b/tests/api.c
@@ -5,6 +5,7 @@
#include <stdio.h>
#include <glib.h>
+#include <cairo.h>
#define RSVG_DISABLE_DEPRECATION_WARNINGS /* so we can test deprecated API */
#include "librsvg/rsvg.h"
@@ -499,8 +500,18 @@ dimensions_and_position (void)
g_assert_cmpint (pos.x, ==, EXAMPLE_TWO_X);
g_assert_cmpint (pos.y, ==, EXAMPLE_TWO_Y);
+ /* TODO: test logical_rect */
+ cairo_rectangle_t ink_rect;
+ cairo_rectangle_t logical_rect;
+ g_assert (rsvg_handle_get_geometry_sub (handle, &ink_rect, &logical_rect, EXAMPLE_TWO_ID));
+ g_assert_cmpint (ink_rect.x, ==, EXAMPLE_TWO_X);
+ g_assert_cmpint (ink_rect.y, ==, EXAMPLE_TWO_Y);
+ g_assert_cmpint (ink_rect.width, ==, EXAMPLE_TWO_W);
+ g_assert_cmpint (ink_rect.height, ==, EXAMPLE_TWO_H);
+
g_assert (!rsvg_handle_get_position_sub (handle, &pos, EXAMPLE_NONEXISTENT_ID));
g_assert (!rsvg_handle_get_dimensions_sub (handle, &dim, EXAMPLE_NONEXISTENT_ID));
+ g_assert (!rsvg_handle_get_geometry_sub (handle, &ink_rect, &logical_rect, EXAMPLE_NONEXISTENT_ID));
g_object_unref (handle);
}
@@ -519,7 +530,6 @@ detects_cairo_context_in_error (void)
/* this is wrong; it is to simulate creating a surface and a cairo_t in error */
cairo_surface_t *surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, -1, -1);
cairo_t *cr = cairo_create (surf);
-
/* rsvg_handle_render_cairo() should return FALSE when it gets a cr in an error state */
g_assert (!rsvg_handle_render_cairo (handle, cr));
diff --git a/tests/dimensions.c b/tests/dimensions.c
index 6f390cf2..21c1b260 100644
--- a/tests/dimensions.c
+++ b/tests/dimensions.c
@@ -2,6 +2,7 @@
/* vim: set ts=4 nowrap ai expandtab sw=4: */
#include <glib.h>
+#include <cairo.h>
#include "librsvg/rsvg.h"
#include "test-utils.h"
@@ -24,6 +25,8 @@ test_dimensions (FixtureData *fixture)
RsvgHandle *handle;
RsvgPositionData position;
RsvgDimensionData dimension;
+ cairo_rectangle_t ink_rect;
+ cairo_rectangle_t logical_rect;
gchar *target_file;
GError *error = NULL;
@@ -37,20 +40,29 @@ test_dimensions (FixtureData *fixture)
g_assert (rsvg_handle_has_sub (handle, fixture->id));
g_assert (rsvg_handle_get_position_sub (handle, &position, fixture->id));
g_assert (rsvg_handle_get_dimensions_sub (handle, &dimension, fixture->id));
+ g_assert (rsvg_handle_get_geometry_sub (handle, &ink_rect, &logical_rect, fixture->id));
g_message ("w=%d h=%d", dimension.width, dimension.height);
} else {
rsvg_handle_get_dimensions (handle, &dimension);
+ rsvg_handle_get_geometry_sub (handle, &ink_rect, &logical_rect, NULL);
}
+ /* TODO: test logical position and dimension */
if (fixture->has_position) {
g_assert_cmpint (fixture->x, ==, position.x);
g_assert_cmpint (fixture->y, ==, position.y);
+
+ g_assert_cmpint (fixture->x, ==, ink_rect.x);
+ g_assert_cmpint (fixture->y, ==, ink_rect.y);
}
if (fixture->has_dimensions) {
g_assert_cmpint (fixture->width, ==, dimension.width);
g_assert_cmpint (fixture->height, ==, dimension.height);
+
+ g_assert_cmpint (fixture->width, ==, ink_rect.width);
+ g_assert_cmpint (fixture->height, ==, ink_rect.height);
}
g_object_unref (handle);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]