Commit 15c32004 authored by Federico Mena Quintero's avatar Federico Mena Quintero

Merge branch 'jsparber/librsvg-geometry'

parents 8f259d25 1b15fc5f
Pipeline #43524 passed with stages
in 28 minutes and 32 seconds
......@@ -23,6 +23,7 @@ rsvg_handle_set_base_uri
rsvg_handle_get_dimensions
rsvg_handle_get_dimensions_sub
rsvg_handle_get_position_sub
rsvg_handle_get_geometry_sub
rsvg_handle_has_sub
rsvg_handle_get_title
rsvg_handle_get_desc
......
......@@ -1181,6 +1181,9 @@ rsvg_handle_render_cairo (RsvgHandle * handle, cairo_t * cr)
void
rsvg_handle_get_dimensions (RsvgHandle * handle, RsvgDimensionData * dimension_data)
{
g_return_if_fail (RSVG_IS_HANDLE (handle));
g_return_if_fail (dimension_data != NULL);
/* This function is probably called from the cairo_render functions.
* To prevent an infinite loop we are saving the state.
*/
......@@ -1196,7 +1199,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, RsvgRectangle *ink_rect, RsvgRectangle *logical_rect)
{
RsvgDimensionData dimensions;
cairo_surface_t *target;
......@@ -1217,9 +1220,10 @@ get_node_ink_rect(RsvgHandle *handle, RsvgNode *node, cairo_rectangle_t *ink_rec
rsvg_drawing_ctx_add_node_and_ancestors_to_stack (draw, node);
rsvg_tree_cascade (handle->priv->tree);
/* FIXME: expose this as a RenderingError in the public API */
res = rsvg_drawing_ctx_draw_node_from_stack (draw, handle->priv->tree);
if (res) {
res = rsvg_drawing_ctx_get_ink_rect (draw, ink_rect);
rsvg_drawing_ctx_get_geometry (draw, ink_rect, logical_rect);
}
rsvg_drawing_ctx_free (draw);
......@@ -1239,21 +1243,65 @@ get_node_ink_rect(RsvgHandle *handle, RsvgNode *node, cairo_rectangle_t *ink_rec
* 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.
*
* Deprecated: Use rsvg_handle_get_geometry_sub() instead.
*
* Since: 2.22
*/
gboolean
rsvg_handle_get_dimensions_sub (RsvgHandle * handle, RsvgDimensionData * dimension_data, const char *id)
{
RsvgRectangle ink_r;
g_return_val_if_fail (RSVG_IS_HANDLE (handle), FALSE);
g_return_val_if_fail (dimension_data, FALSE);
memset (&ink_r, 0, sizeof (RsvgRectangle));
memset (dimension_data, 0, sizeof (RsvgDimensionData));
if (!rsvg_handle_get_geometry_sub (handle, &ink_r, NULL, id)) {
return FALSE;
}
dimension_data->width = ink_r.width;
dimension_data->height = ink_r.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_handle_get_geometry_sub:
* @handle: A #RsvgHandle
* @ink_rect: (out)(nullable): A place to store the SVG fragment's geometry.
* @logical_rect: (out)(nullable): 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.
*
* Note that unlike rsvg_handle_get_position_sub() and
* rsvg_handle_get_dimensions_sub(), this function does not call the size_func.
*
* Since: 2.46
*/
gboolean
rsvg_handle_get_geometry_sub (RsvgHandle * handle, RsvgRectangle * ink_rect, RsvgRectangle * logical_rect, const char *id)
{
RsvgNode *root = NULL;
RsvgNode *node;
gboolean has_size;
int root_width, root_height;
gboolean res = FALSE;
RsvgRectangle ink_r, logical_r;
g_return_val_if_fail (handle, FALSE);
g_return_val_if_fail (dimension_data, FALSE);
g_return_val_if_fail (RSVG_IS_HANDLE (handle), FALSE);
memset (dimension_data, 0, sizeof (RsvgDimensionData));
memset (&ink_r, 0, sizeof (RsvgRectangle));
memset (&logical_r, 0, sizeof (RsvgRectangle));
if (handle->priv->tree == NULL)
return FALSE;
......@@ -1278,30 +1326,34 @@ rsvg_handle_get_dimensions_sub (RsvgHandle * handle, RsvgDimensionData * dimensi
&root_width, &root_height);
if (id || !has_size) {
cairo_rectangle_t ink_rect;
if (!get_node_ink_rect (handle, node, &ink_rect)) {
res = get_node_geometry (handle, node, &ink_r, &logical_r);
if (!res) {
goto out;
}
dimension_data->width = ink_rect.width;
dimension_data->height = ink_rect.height;
} else {
dimension_data->width = root_width;
dimension_data->height = root_height;
ink_r.width = root_width;
ink_r.height = root_height;
ink_r.x = 0;
ink_r.y = 0;
logical_r.width = root_width;
logical_r.height = root_height;
logical_r.x = 0;
logical_r.y = 0;
}
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);
res = TRUE;
out:
if (ink_rect != NULL) {
*ink_rect = ink_r;
}
if (logical_rect != NULL) {
*logical_rect = logical_r;
}
g_clear_pointer (&root, rsvg_node_unref);
return res;
......@@ -1317,42 +1369,33 @@ out:
* Get the position of a subelement of the SVG file. Do not call from within
* the size_func callback, because an infinite loop will occur.
*
* Deprecated: Use rsvg_handle_get_geometry_sub() instead.
*
* Since: 2.22
*/
gboolean
rsvg_handle_get_position_sub (RsvgHandle * handle, RsvgPositionData * position_data, const char *id)
{
RsvgNode *node;
cairo_rectangle_t ink_rect;
RsvgRectangle ink_r;
int width, height;
g_return_val_if_fail (handle, FALSE);
g_return_val_if_fail (position_data, FALSE);
g_return_val_if_fail (RSVG_IS_HANDLE (handle), FALSE);
g_return_val_if_fail (position_data != NULL, FALSE);
memset (position_data, 0, sizeof (*position_data));
if (handle->priv->tree == NULL)
return FALSE;
/* Short-cut when no id is given. */
if (NULL == id || '\0' == *id)
return TRUE;
node = rsvg_defs_lookup (handle->priv->defs, handle, id);
if (!node)
return FALSE;
if (rsvg_tree_is_root (handle->priv->tree, node))
return TRUE;
if (!get_node_ink_rect (handle, node, &ink_rect))
if (!rsvg_handle_get_geometry_sub (handle, &ink_r, NULL, id))
return FALSE;
position_data->x = ink_rect.x;
position_data->y = ink_rect.y;
position_data->x = ink_r.x;
position_data->y = ink_r.y;
width = ink_rect.width;
height = ink_rect.height;
width = ink_r.width;
height = ink_r.height;
if (handle->priv->size_func)
(*handle->priv->size_func) (&width, &height, handle->priv->user_data);
......
......@@ -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);
void rsvg_drawing_ctx_get_geometry (RsvgDrawingCtx *ctx, RsvgRectangle *ink_rect, RsvgRectangle *logical_rect);
/* Implemented in rust/src/node.rs */
G_GNUC_INTERNAL
......
......@@ -31,6 +31,7 @@
#include <glib-object.h>
#include <gio/gio.h>
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
G_BEGIN_DECLS
......@@ -70,6 +71,7 @@ typedef struct RsvgHandlePrivate RsvgHandlePrivate;
typedef struct _RsvgHandleClass RsvgHandleClass;
typedef struct _RsvgDimensionData RsvgDimensionData;
typedef struct _RsvgPositionData RsvgPositionData;
typedef struct _RsvgRectangle RsvgRectangle;
/**
* RsvgHandleClass:
......@@ -106,6 +108,8 @@ struct _RsvgHandle {
* @height: SVG's height, in pixels
* @em: em
* @ex: ex
*
* Deprecated: 2.46
*/
struct _RsvgDimensionData {
int width;
......@@ -120,12 +124,33 @@ struct _RsvgDimensionData {
* @y: position on the y axis
*
* Position of an SVG fragment.
*
* Deprecated: 2.46
*/
struct _RsvgPositionData {
int x;
int y;
};
/**
* RsvgRectangle:
* @x: X coordinate of the left side of the rectangle
* @y: Y coordinate of the the top side of the rectangle
* @width: width of the rectangle
* @height: height of the rectangle
*
* A data structure for holding a rectangle.
*
* Since: 2.46
*/
struct _RsvgRectangle {
double x;
double y;
double width;
double height;
};
void rsvg_cleanup (void);
RSVG_DEPRECATED
......@@ -151,6 +176,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, RsvgRectangle * ink_rect, RsvgRectangle * logical_rect, const char *id);
gboolean rsvg_handle_has_sub (RsvgHandle * handle, const char *id);
......
......@@ -1094,28 +1094,59 @@ pub extern "C" fn rsvg_drawing_ctx_add_node_and_ancestors_to_stack(
draw_ctx.add_node_and_ancestors_to_stack(node);
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
pub struct RsvgRectangle {
pub x: f64,
pub y: f64,
pub width: f64,
pub height: f64,
}
#[no_mangle]
pub extern "C" fn rsvg_drawing_ctx_get_ink_rect(
pub unsafe extern "C" fn rsvg_drawing_ctx_get_geometry(
raw_draw_ctx: *const RsvgDrawingCtx,
ink_rect: *mut cairo_sys::cairo_rectangle_t,
) -> glib_sys::gboolean {
ink_rect: *mut RsvgRectangle,
logical_rect: *mut RsvgRectangle,
) {
assert!(!raw_draw_ctx.is_null());
let draw_ctx = unsafe { &mut *(raw_draw_ctx as *mut DrawingCtx<'_>) };
let draw_ctx = &mut *(raw_draw_ctx as *mut DrawingCtx<'_>);
assert!(!ink_rect.is_null());
assert!(!logical_rect.is_null());
let res = match draw_ctx.get_bbox().ink_rect {
Some(r) => unsafe {
(*ink_rect).x = r.x;
(*ink_rect).y = r.y;
(*ink_rect).width = r.width;
(*ink_rect).height = r.height;
true
},
_ => false,
};
let ink_rect: &mut RsvgRectangle = &mut *ink_rect;
let logical_rect: &mut RsvgRectangle = &mut *logical_rect;
res.to_glib()
match draw_ctx.get_bbox().ink_rect {
Some(r) => {
ink_rect.x = r.x;
ink_rect.y = r.y;
ink_rect.width = r.width;
ink_rect.height = r.height;
}
None => {
ink_rect.x = 0.0;
ink_rect.y = 0.0;
ink_rect.width = 0.0;
ink_rect.height = 0.0;
}
}
match draw_ctx.get_bbox().rect {
Some(r) => {
logical_rect.x = r.x;
logical_rect.y = r.y;
logical_rect.width = r.width;
logical_rect.height = r.height;
}
None => {
logical_rect.x = 0.0;
logical_rect.y = 0.0;
logical_rect.width = 0.0;
logical_rect.height = 0.0;
}
}
}
pub struct AcquiredNode(Rc<RefCell<Vec<RsvgNode>>>, RsvgNode);
......
......@@ -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,
};
......
......@@ -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 */
RsvgRectangle ink_rect;
RsvgRectangle 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));
......
......@@ -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"
......@@ -10,12 +11,15 @@ typedef struct
const gchar *test_name;
const gchar *file_path;
const gchar *id;
gint x;
gint y;
gint width;
gint height;
gdouble x;
gdouble y;
gdouble width;
gdouble height;
gdouble logical_width;
gdouble logical_height;
gboolean has_position;
gboolean has_dimensions;
gboolean has_logical_dimensions;
} FixtureData;
static void
......@@ -24,6 +28,8 @@ test_dimensions (FixtureData *fixture)
RsvgHandle *handle;
RsvgPositionData position;
RsvgDimensionData dimension;
RsvgRectangle ink_rect;
RsvgRectangle logical_rect;
gchar *target_file;
GError *error = NULL;
......@@ -37,20 +43,33 @@ 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);
}
if (fixture->has_position) {
g_assert_cmpint (fixture->x, ==, position.x);
g_assert_cmpint (fixture->y, ==, position.y);
g_assert_cmpfloat_with_epsilon (fixture->x, ink_rect.x, 0.01);
g_assert_cmpfloat_with_epsilon (fixture->y, ink_rect.y, 0.01);
}
if (fixture->has_dimensions) {
g_assert_cmpint (fixture->width, ==, dimension.width);
g_assert_cmpint (fixture->height, ==, dimension.height);
g_assert_cmpfloat_with_epsilon (fixture->width, ink_rect.width, 0.01);
g_assert_cmpfloat_with_epsilon (fixture->height, ink_rect.height, 0.01);
}
if (fixture->has_logical_dimensions) {
g_assert_cmpfloat_with_epsilon (fixture->logical_width, logical_rect.width, 0.01);
g_assert_cmpfloat_with_epsilon (fixture->logical_height, logical_rect.height, 0.01);
}
g_object_unref (handle);
......@@ -62,37 +81,46 @@ static FixtureData fixtures[] =
"/dimensions/no viewbox, width and height",
"dimensions/bug608102.svg",
NULL,
0, 0, 16, 16,
FALSE, TRUE
0, 0, 16, 16, 16, 16,
FALSE, TRUE, TRUE
},
{
"/dimensions/100% width and height",
"dimensions/bug612951.svg",
NULL,
0, 0, 47, 47,
FALSE, TRUE
0, 0, 47, 47.14, 44.546, 45.44,
FALSE, TRUE, TRUE
},
{
"/dimensions/viewbox only",
"dimensions/bug614018.svg",
NULL,
0, 0, 972, 546,
0, 0, 972, 546, 0, 0,
FALSE, TRUE
},
{
"/dimensions/sub/rect no unit",
"dimensions/sub-rect-no-unit.svg",
"#rect-no-unit",
0, 0, 44, 45,
0, 0, 44, 45, 0, 0,
FALSE, TRUE
},
{
"/dimensions/sub/text_position",
"dimensions/347-wrapper.svg",
"#LabelA",
80, 48, 0, 0,
80, 48.90, 0, 0, 0, 0,
TRUE, FALSE
}
},
/* FIXME: The wilber test fails, the ink_rect has the wrong size */
/*{
"/dimensions/sub/bug760112-wilber",
"dimensions/bug760112-wilber.svg",
"#g39819",
0, 0, 16, 16, 16, 16,
FALSE, TRUE, TRUE
},
*/
/* {"/dimensions/sub/rect with transform", "dimensions/bug564527.svg", "#back", 0, 0, 144, 203} */
};
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment