[librsvg: 12/15] Add new API rsvg_handle_get_geometry_for_element()



commit f0880719741517a3a4b0dea968858c8b2262ea60
Author: Federico Mena Quintero <federico gnome org>
Date:   Mon Jul 29 14:25:31 2019 -0500

    Add new API rsvg_handle_get_geometry_for_element()

 doc/rsvg-sections.txt                   |  1 +
 librsvg/rsvg-cairo.h                    |  6 +++
 librsvg/rsvg-handle.c                   | 69 +++++++++++++++++++++++++++++++++
 rsvg_internals/src/c_api.rs             | 40 +++++++++++++++++++
 rsvg_internals/src/lib.rs               |  1 +
 tests/api.c                             | 40 +++++++++++++++++++
 tests/fixtures/api/geometry-element.svg |  6 +++
 7 files changed, 163 insertions(+)
---
diff --git a/doc/rsvg-sections.txt b/doc/rsvg-sections.txt
index ad395bff..82c4dcc9 100644
--- a/doc/rsvg-sections.txt
+++ b/doc/rsvg-sections.txt
@@ -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>
diff --git a/librsvg/rsvg-cairo.h b/librsvg/rsvg-cairo.h
index 408c77f8..ba6de5e0 100644
--- a/librsvg/rsvg-cairo.h
+++ b/librsvg/rsvg-cairo.h
@@ -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
 
diff --git a/librsvg/rsvg-handle.c b/librsvg/rsvg-handle.c
index 7b5333cc..b13950c3 100644
--- a/librsvg/rsvg-handle.c
+++ b/librsvg/rsvg-handle.c
@@ -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
diff --git a/rsvg_internals/src/c_api.rs b/rsvg_internals/src/c_api.rs
index bc66eabb..24de9dfd 100644
--- a/rsvg_internals/src/c_api.rs
+++ b/rsvg_internals/src/c_api.rs
@@ -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
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index 149bf1d6..c8441b63 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -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,
diff --git a/tests/api.c b/tests/api.c
index d8a8d7b7..48849af3 100644
--- a/tests/api.c
+++ b/tests/api.c
@@ -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);
diff --git a/tests/fixtures/api/geometry-element.svg b/tests/fixtures/api/geometry-element.svg
new file mode 100644
index 00000000..3d707cdc
--- /dev/null
+++ b/tests/fixtures/api/geometry-element.svg
@@ -0,0 +1,6 @@
+<?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>


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