Add new API rsvg_handle_get_geometry_for_element()

parent e943136e
......@@ -72,6 +72,7 @@ RSVG_TYPE_HANDLE_FLAGS
rsvg_handle_render_document
rsvg_handle_get_geometry_for_layer
rsvg_handle_render_layer
rsvg_handle_get_geometry_for_element
rsvg_handle_render_cairo
rsvg_handle_render_cairo_sub
</SECTION>
......
......@@ -60,6 +60,12 @@ gboolean rsvg_handle_render_layer (RsvgHandle *handle,
const RsvgRectangle *viewport,
GError **error);
RSVG_API
gboolean rsvg_handle_get_geometry_for_element (RsvgHandle *handle,
const char *id,
RsvgRectangle *out_ink_rect,
RsvgRectangle *out_logical_rect,
GError **error);
G_END_DECLS
......
......@@ -397,6 +397,11 @@ extern gboolean rsvg_rust_handle_render_layer (RsvgHandle *handle,
const char *id,
const RsvgRectangle *viewport,
GError **error);
extern gboolean rsvg_rust_handle_get_geometry_for_element (RsvgHandle *handle,
const char *id,
RsvgRectangle *out_ink_rect,
RsvgRectangle *out_logical_rect,
GError **error);
......@@ -1380,6 +1385,70 @@ rsvg_handle_render_layer (RsvgHandle *handle,
return rsvg_rust_handle_render_layer (handle, cr, id, viewport, error);
}
/**
* rsvg_handle_get_geometry_for_element:
* @handle: An #RsvgHandle
* @id: (nullable): An element's id within the SVG, starting with "##" (a single
* hash character), for example, "##layer1". This notation corresponds to a
* URL's fragment ID. Alternatively, pass %NULL to compute the geometry for the
* whole SVG.
* @out_ink_rect: (out)(optional): Place to store the ink rectangle of the element.
* @out_logical_rect: (out)(optional): Place to store the logical rectangle of the element.
* @error: (allow-none): a location to store a #GError, or %NULL
*
* Computes the ink rectangle and logical rectangle of a singe SVG element.
*
* While `rsvg_handle_get_geometry_for_layer` computes the geometry of an SVG element subtree with
* its transformation matrix, this other function will compute the element's geometry
* as if it were being rendered under an identity transformation by itself. That is,
* the resulting geometry is as if the element got extracted by itself from the SVG.
*
* This function is the counterpart to `rsvg_handle_render_element`.
*
* Element IDs should look like an URL fragment identifier; for example, pass
* "##foo" (hash <literal>foo</literal>) to get the geometry of the element that
* has an <literal>id="foo"</literal> attribute.
*
* The "ink rectangle" is the bounding box that would be painted
* for fully- stroked and filled elements.
*
* The "logical rectangle" just takes into account the unstroked
* paths and text outlines.
*
* Note that these bounds are not minimum bounds; for example,
* clipping paths are not taken into account.
*
* You can pass #NULL for the @id if you want to measure all
* the elements in the SVG, i.e. to measure everything from the
* root element.
*
* This operation is not constant-time, as it involves going through all
* the child elements.
*
* API ordering: This function must be called on a fully-loaded @handle. See
* the section <link href="#API-ordering">API ordering</link> for details.
*
* Panics: this function will panic if the @handle is not fully-loaded.
*
* Since: 2.46
*/
gboolean
rsvg_handle_get_geometry_for_element (RsvgHandle *handle,
const char *id,
RsvgRectangle *out_ink_rect,
RsvgRectangle *out_logical_rect,
GError **error)
{
g_return_val_if_fail (RSVG_IS_HANDLE (handle), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
return rsvg_rust_handle_get_geometry_for_element (handle,
id,
out_ink_rect,
out_logical_rect,
error);
}
/**
* rsvg_handle_internal_set_testing:
* @handle: a #RsvgHandle
......
......@@ -730,6 +730,14 @@ impl CHandle {
handle.render_layer(cr, id, viewport, self.dpi.get(), self.is_testing.get())
}
fn get_geometry_for_element(
&self,
id: Option<&str>,
) -> Result<(RsvgRectangle, RsvgRectangle), RenderingError> {
let handle = self.get_handle_ref()?;
handle.get_geometry_for_element(id, self.dpi.get(), self.is_testing.get())
}
fn get_intrinsic_dimensions(&self) -> Result<IntrinsicDimensions, RenderingError> {
let handle = self.get_handle_ref()?;
Ok(handle.get_intrinsic_dimensions())
......@@ -1343,6 +1351,38 @@ pub unsafe extern "C" fn rsvg_rust_handle_render_layer(
}
}
#[no_mangle]
pub unsafe extern "C" fn rsvg_rust_handle_get_geometry_for_element(
handle: *mut RsvgHandle,
id: *const libc::c_char,
out_ink_rect: *mut RsvgRectangle,
out_logical_rect: *mut RsvgRectangle,
error: *mut *mut glib_sys::GError,
) -> glib_sys::gboolean {
let rhandle = get_rust_handle(handle);
let id: Option<String> = from_glib_none(id);
match rhandle.get_geometry_for_element(id.as_ref().map(String::as_str)) {
Ok((ink_rect, logical_rect)) => {
if !out_ink_rect.is_null() {
*out_ink_rect = ink_rect;
}
if !out_logical_rect.is_null() {
*out_logical_rect = logical_rect;
}
true.to_glib()
}
Err(e) => {
set_gerror(error, 0, &format!("{}", e));
false.to_glib()
}
}
}
/// Detects whether a `*const libc::c_char` is a path or a URI
///
/// `rsvg_handle_new_from_file()` takes a `filename` argument, and advertises
......
......@@ -15,6 +15,7 @@ pub use crate::c_api::{
rsvg_rust_handle_get_dpi_x,
rsvg_rust_handle_get_dpi_y,
rsvg_rust_handle_get_flags,
rsvg_rust_handle_get_geometry_for_element,
rsvg_rust_handle_get_geometry_for_layer,
rsvg_rust_handle_get_intrinsic_dimensions,
rsvg_rust_handle_get_pixbuf_sub,
......
......@@ -1075,6 +1075,45 @@ render_layer (void)
g_object_unref (handle);
}
static void
get_geometry_for_element (void)
{
char *filename = get_test_filename ("geometry-element.svg");
GError *error = NULL;
RsvgHandle *handle = rsvg_handle_new_from_file (filename, &error);
g_free (filename);
g_assert (handle != NULL);
g_assert (error == NULL);
RsvgRectangle ink_rect;
RsvgRectangle logical_rect;
g_assert (!rsvg_handle_get_geometry_for_element (handle, "#nonexistent",
&ink_rect, &logical_rect, &error));
g_assert (error != NULL);
g_error_free (error);
error = NULL;
g_assert (rsvg_handle_get_geometry_for_element (handle, "#foo",
&ink_rect, &logical_rect, &error));
g_assert (error == NULL);
g_assert_cmpfloat (ink_rect.x, ==, 0.0);
g_assert_cmpfloat (ink_rect.y, ==, 0.0);
g_assert_cmpfloat (ink_rect.width, ==, 40.0);
g_assert_cmpfloat (ink_rect.height, ==, 50.0);
g_assert_cmpfloat (logical_rect.x, ==, 5.0);
g_assert_cmpfloat (logical_rect.y, ==, 5.0);
g_assert_cmpfloat (logical_rect.width, ==, 30.0);
g_assert_cmpfloat (logical_rect.height, ==, 40.0);
g_object_unref (handle);
}
/* https://gitlab.gnome.org/GNOME/librsvg/issues/385 */
static void
no_write_before_close (void)
......@@ -1300,6 +1339,7 @@ main (int argc, char **argv)
g_test_add_func ("/api/render_document", render_document);
g_test_add_func ("/api/get_geometry_for_layer", get_geometry_for_layer);
g_test_add_func ("/api/render_layer", render_layer);
g_test_add_func ("/api/get_geometry_for_element", get_geometry_for_element);
g_test_add_func ("/api/no_write_before_close", no_write_before_close);
g_test_add_func ("/api/empty_write_close", empty_write_close);
g_test_add_func ("/api/cannot_request_external_elements", cannot_request_external_elements);
......
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<g transform="rotate(45)" stroke-width="10" stroke="#000000">
<rect id="foo" x="10" y="20" width="30" height="40" fill="#0000ff"/>
</g>
</svg>
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