Add C version of rsvg_handle_render_layer()

parent 2bbb1fd1
......@@ -26,7 +26,6 @@ rsvg_handle_get_dimensions
rsvg_handle_get_dimensions_sub
rsvg_handle_get_position_sub
rsvg_handle_get_intrinsic_dimensions
rsvg_handle_get_geometry_for_element
rsvg_handle_has_sub
rsvg_handle_get_title
rsvg_handle_get_desc
......@@ -70,6 +69,8 @@ RSVG_TYPE_HANDLE_FLAGS
<SECTION>
<FILE>rsvg-cairo</FILE>
<TITLE>Using RSVG with cairo</TITLE>
rsvg_handle_get_geometry_for_layer
rsvg_handle_render_layer
rsvg_handle_render_cairo
rsvg_handle_render_cairo_sub
</SECTION>
......
......@@ -39,6 +39,22 @@ gboolean rsvg_handle_render_cairo (RsvgHandle *handle, cairo_t *cr);
RSVG_API
gboolean rsvg_handle_render_cairo_sub (RsvgHandle *handle, cairo_t *cr, const char *id);
RSVG_API
gboolean rsvg_handle_get_geometry_for_layer (RsvgHandle *handle,
const char *id,
const RsvgRectangle *viewport,
RsvgRectangle *out_ink_rect,
RsvgRectangle *out_logical_rect,
GError **error);
RSVG_API
gboolean rsvg_handle_render_layer (RsvgHandle *handle,
cairo_t *cr,
const char *id,
const RsvgRectangle *viewport,
GError **error);
G_END_DECLS
#endif
......@@ -388,6 +388,12 @@ extern gboolean rsvg_rust_handle_get_geometry_for_layer (RsvgHandle *handle,
RsvgRectangle *out_ink_rect,
RsvgRectangle *out_logical_rect,
GError **error);
extern gboolean rsvg_rust_handle_render_layer (RsvgHandle *handle,
cairo_t *cr,
const char *id,
const RsvgRectangle *viewport,
GError **error);
/* Implemented in rsvg_internals/src/c_api.rs */
......@@ -1285,6 +1291,21 @@ rsvg_handle_get_geometry_for_layer (RsvgHandle *handle,
error);
}
gboolean
rsvg_handle_render_layer (RsvgHandle *handle,
cairo_t *cr,
const char *id,
const RsvgRectangle *viewport,
GError **error)
{
g_return_val_if_fail (RSVG_IS_HANDLE (handle), FALSE);
g_return_val_if_fail (cr != NULL, FALSE);
g_return_val_if_fail (viewport != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
return rsvg_rust_handle_render_layer (handle, cr, id, viewport, error);
}
/**
* rsvg_handle_internal_set_testing:
* @handle: a #RsvgHandle
......
......@@ -280,14 +280,6 @@ void rsvg_handle_get_intrinsic_dimensions (RsvgHandle *handle,
gboolean *out_has_viewbox,
RsvgRectangle *out_viewbox);
RSVG_API
gboolean rsvg_handle_get_geometry_for_layer (RsvgHandle *handle,
const char *id,
const RsvgRectangle *viewport,
RsvgRectangle *out_ink_rect,
RsvgRectangle *out_logical_rect,
GError **error);
/* GIO APIs */
/**
......
......@@ -455,6 +455,36 @@ impl<'a> CairoRenderer<'a> {
.render_layer(cr, id, viewport, self.dpi, false)
}
/// Computes the (ink_rect, logical_rect) of a single SVG element
///
/// While `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 `render_element`.
///
/// Element IDs should look like an URL fragment identifier; for
/// example, pass `Some("#foo")` to get the geometry of the
/// element that has an `id="foo"` 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 `None` 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.
///
/// FIXME: example
pub fn geometry_for_element(
&self,
id: Option<&str>,
......
......@@ -711,6 +711,16 @@ impl CHandle {
handle.get_geometry_for_layer(id, viewport, self.dpi.get(), self.is_testing.get())
}
fn render_layer(
&self,
cr: &cairo::Context,
id: Option<&str>,
viewport: &cairo::Rectangle,
) -> Result<(), RenderingError> {
let handle = self.get_handle_ref()?;
handle.render_layer(cr, id, viewport, 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())
......@@ -1282,6 +1292,28 @@ pub unsafe extern "C" fn rsvg_rust_handle_get_geometry_for_layer(
}
}
#[no_mangle]
pub unsafe extern "C" fn rsvg_rust_handle_render_layer(
handle: *mut RsvgHandle,
cr: *mut cairo_sys::cairo_t,
id: *const libc::c_char,
viewport: *const RsvgRectangle,
error: *mut *mut glib_sys::GError,
) -> glib_sys::gboolean {
let rhandle = get_rust_handle(handle);
let cr = from_glib_none(cr);
let id: Option<String> = from_glib_none(id);
match rhandle.render_layer(&cr, id.as_ref().map(String::as_str), &(*viewport).into()) {
Ok(()) => 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
......
......@@ -983,6 +983,52 @@ get_geometry_for_layer (void)
g_object_unref (handle);
}
static void
render_layer (void)
{
char *filename = get_test_filename ("layers.svg");
GError *error = NULL;
RsvgHandle *handle = rsvg_handle_new_from_file (filename, &error);
g_free (filename);
g_assert (handle != NULL);
g_assert (error == NULL);
cairo_surface_t *output = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 300, 300);
cairo_t *cr = cairo_create (output);
RsvgRectangle viewport = { 100.0, 100.0, 100.0, 100.0 };
g_assert (rsvg_handle_render_layer (handle, cr, "#bar", &viewport, &error));
g_assert (error == NULL);
cairo_destroy (cr);
cairo_surface_t *expected = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 300, 300);
cr = cairo_create (expected);
cairo_translate (cr, 100.0, 100.0);
cairo_rectangle (cr, 20.0, 20.0, 30.0, 30.0);
cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 1.0);
cairo_fill (cr);
cairo_destroy (cr);
cairo_surface_t *diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 300, 300);
TestUtilsBufferDiffResult result = {0, 0};
test_utils_compare_surfaces (output, expected, diff, &result);
if (result.pixels_changed && result.max_diff > 0) {
g_test_fail ();
}
cairo_surface_destroy (diff);
cairo_surface_destroy (expected);
cairo_surface_destroy (output);
g_object_unref (handle);
}
/* https://gitlab.gnome.org/GNOME/librsvg/issues/385 */
static void
no_write_before_close (void)
......@@ -1206,6 +1252,7 @@ main (int argc, char **argv)
g_test_add_func ("/api/render_cairo_sub", render_cairo_sub);
g_test_add_func ("/api/get_intrinsic_dimensions", get_intrinsic_dimensions);
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/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">
<rect id="foo" x="10" y="10" width="30" height="30" fill="#00ff00"/>
<rect id="bar" x="20" y="20" width="30" height="30" fill="#0000ff"/>
</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