[librsvg] rsvg_handle_render_cairo_sub(): Port to Rust



commit b930b1a77c400390ae3a189aaf67aa861fe5f067
Author: Federico Mena Quintero <federico gnome org>
Date:   Thu Dec 20 16:17:23 2018 -0600

    rsvg_handle_render_cairo_sub(): Port to Rust
    
    This adds a couple of new error cases to RenderingError.

 librsvg/rsvg-handle.c        | 46 +++--------------------
 rsvg_internals/src/defs.rs   |  2 +-
 rsvg_internals/src/error.rs  | 10 +++++
 rsvg_internals/src/handle.rs | 89 ++++++++++++++++++++++++++++++++++++++++----
 rsvg_internals/src/lib.rs    |  1 +
 5 files changed, 100 insertions(+), 48 deletions(-)
---
diff --git a/librsvg/rsvg-handle.c b/librsvg/rsvg-handle.c
index 6242f2d0..c79cda0e 100644
--- a/librsvg/rsvg-handle.c
+++ b/librsvg/rsvg-handle.c
@@ -178,7 +178,10 @@ extern gboolean rsvg_handle_rust_get_geometry_sub (RsvgHandle *handle,
                                                    RsvgRectangle *out_ink_rect,
                                                    RsvgRectangle *out_logical_rect,
                                                    const char *id);
-extern gboolean rsvg_handle_rust_has_sub(RsvgHandle *handle, const char *id);
+extern gboolean rsvg_handle_rust_has_sub (RsvgHandle *handle, const char *id);
+extern gboolean rsvg_handle_rust_render_cairo_sub (RsvgHandle *handle,
+                                                   cairo_t *cr,
+                                                   const char *id);
 
 /* Implemented in rust/src/node.rs */
 /* Call this as node = rsvg_node_unref (node);  Then node will be NULL and you don't own it anymore! */
@@ -1024,51 +1027,14 @@ is_loaded (RsvgHandle *handle)
 gboolean
 rsvg_handle_render_cairo_sub (RsvgHandle * handle, cairo_t * cr, const char *id)
 {
-    RsvgDimensionData dimensions;
-    RsvgDrawingCtx *draw;
-    RsvgNode *drawsub = NULL;
-    cairo_status_t status;
-    gboolean res;
-
     g_return_val_if_fail (RSVG_IS_HANDLE (handle), FALSE);
+    g_return_val_if_fail (cr != NULL, FALSE);
 
     if (!is_loaded (handle)) {
         return FALSE;
     }
 
-    status = cairo_status (cr);
-
-    if (status != CAIRO_STATUS_SUCCESS) {
-        g_warning ("cannot render on a cairo_t with a failure status (status=%d, %s)",
-                   (int) status,
-                   cairo_status_to_string (status));
-        return FALSE;
-    }
-
-    if (id && *id)
-        drawsub = rsvg_handle_defs_lookup (handle, id);
-
-    if (drawsub == NULL && id != NULL) {
-        g_warning ("element id=\"%s\" does not exist", id);
-        /* todo: there's no way to signal that @id doesn't exist */
-        return FALSE;
-    }
-
-    rsvg_handle_get_dimensions (handle, &dimensions);
-    if (dimensions.width == 0 || dimensions.height == 0)
-        return FALSE;
-
-    cairo_save (cr);
-
-    draw = rsvg_handle_create_drawing_ctx_for_node (handle, cr, &dimensions, drawsub, 
handle->priv->is_testing);
-    res = rsvg_drawing_ctx_draw_node_from_stack (draw);
-
-    rsvg_drawing_ctx_free (draw);
-    drawsub = rsvg_node_unref (drawsub);
-
-    cairo_restore (cr);
-
-    return res;
+    return rsvg_handle_rust_render_cairo_sub (handle, cr, id);
 }
 
 /**
diff --git a/rsvg_internals/src/defs.rs b/rsvg_internals/src/defs.rs
index 373e8e22..91591297 100644
--- a/rsvg_internals/src/defs.rs
+++ b/rsvg_internals/src/defs.rs
@@ -122,7 +122,7 @@ impl fmt::Display for Fragment {
 }
 
 /// Errors returned when creating an `Href` out of a string
-#[derive(Debug, PartialEq)]
+#[derive(Debug, Clone, PartialEq)]
 pub enum HrefError {
     /// The href is an invalid URI or has empty components.
     ParseError,
diff --git a/rsvg_internals/src/error.rs b/rsvg_internals/src/error.rs
index 5d6856cc..5c82c96f 100644
--- a/rsvg_internals/src/error.rs
+++ b/rsvg_internals/src/error.rs
@@ -10,6 +10,7 @@ use glib_sys;
 use libc;
 
 use attributes::Attribute;
+use defs::HrefError;
 use parsers::ParseError;
 
 /// A simple error which refers to an attribute's value
@@ -90,11 +91,20 @@ impl<'a> From<BasicParseError<'a>> for ValueErrorKind {
     }
 }
 
+#[derive(Clone)]
+pub enum DefsLookupErrorKind {
+    HrefError(HrefError),
+    CannotLookupExternalReferences,
+    NotFound,
+}
+
 #[derive(Clone)]
 pub enum RenderingError {
     Cairo(cairo::Status),
     CircularReference,
     InstancingLimit,
+    InvalidId(DefsLookupErrorKind),
+    SvgHasNoSize,
 }
 
 impl From<cairo::Status> for RenderingError {
diff --git a/rsvg_internals/src/handle.rs b/rsvg_internals/src/handle.rs
index 5b7c47f6..e9bc584a 100644
--- a/rsvg_internals/src/handle.rs
+++ b/rsvg_internals/src/handle.rs
@@ -16,10 +16,10 @@ use url::Url;
 
 use allowed_url::AllowedUrl;
 use css::{self, CssStyles};
-use defs::{Fragment, Href, HrefError};
+use defs::{Fragment, Href};
 use dpi::Dpi;
 use drawing_ctx::{DrawingCtx, RsvgRectangle};
-use error::{set_gerror, LoadingError};
+use error::{set_gerror, DefsLookupErrorKind, LoadingError, RenderingError};
 use io;
 use load::LoadContext;
 use node::{box_node, Node, RsvgNode};
@@ -228,6 +228,7 @@ impl Handle {
         draw_ctx
     }
 
+    // FIXME: return proper errors
     fn get_node_geometry(
         &mut self,
         handle: *mut RsvgHandle,
@@ -278,6 +279,7 @@ impl Handle {
         Ok((ink_rect, logical_rect))
     }
 
+    // FIXME: return proper errors
     fn get_geometry_sub(
         &mut self,
         handle: *mut RsvgHandle,
@@ -365,14 +367,67 @@ impl Handle {
     }
 
     fn has_sub(&mut self, handle: *const RsvgHandle, name: &str) -> bool {
+        // FIXME: return a proper error; only NotFound should map to false
         self.defs_lookup(handle, name).is_ok()
     }
-}
 
-enum DefsLookupErrorKind {
-    HrefError(HrefError),
-    CannotLookupExternalReferences,
-    NotFound,
+    fn render_cairo_sub(
+        &mut self,
+        handle: *mut RsvgHandle,
+        cr: &cairo::Context,
+        id: Option<&str>,
+    ) -> Result<(), RenderingError> {
+        let status = cr.status();
+        if status != Status::Success {
+            let msg = format!(
+                "cannot render on a cairo_t with a failure status (status={:?})",
+                status,
+            );
+
+            rsvg_g_warning(&msg);
+            return Err(RenderingError::Cairo(status));
+        }
+
+        let node = if let Some(id) = id {
+            Some(
+                self.defs_lookup(handle, id)
+                    .map_err(|e| RenderingError::InvalidId(e))?,
+            )
+        } else {
+            None
+        };
+
+        let mut dimensions = unsafe { mem::zeroed() };
+
+        unsafe {
+            rsvg_handle_get_dimensions(handle, &mut dimensions);
+        }
+
+        if dimensions.width == 0 || dimensions.height == 0 {
+            return Err(RenderingError::SvgHasNoSize);
+        }
+
+        cr.save();
+
+        let mut draw_ctx = self.create_drawing_ctx_for_node(
+            handle,
+            cr,
+            &dimensions,
+            node.as_ref(),
+            is_testing(handle),
+        );
+
+        let svg_ref = self.svg.borrow();
+        let svg = svg_ref.as_ref().unwrap();
+
+        let root = svg.tree.root();
+
+        let res = draw_ctx.draw_node_from_stack(&root.get_cascaded_values(), &root, false);
+
+        cr.restore();
+
+        res
+    }
 }
 
 // Keep these in sync with rsvg.h:RsvgHandleFlags
@@ -878,3 +933,23 @@ pub unsafe extern "C" fn rsvg_handle_rust_has_sub(
         rhandle.has_sub(handle, &id).to_glib()
     }
 }
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_handle_rust_render_cairo_sub(
+    handle: *mut RsvgHandle,
+    cr: *mut cairo_sys::cairo_t,
+    id: *const libc::c_char,
+) -> 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_cairo_sub(handle, &cr, id.as_ref().map(String::as_str)) {
+        Ok(()) => true.to_glib(),
+
+        Err(_) => {
+            // FIXME: return a proper error code to the public API
+            false.to_glib()
+        }
+    }
+}
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index e55b35a7..f3416f63 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -51,6 +51,7 @@ pub use handle::{
     rsvg_handle_rust_has_sub,
     rsvg_handle_rust_new,
     rsvg_handle_rust_read_stream_sync,
+    rsvg_handle_rust_render_cairo_sub,
     rsvg_handle_rust_set_base_url,
     rsvg_handle_rust_set_dpi_x,
     rsvg_handle_rust_set_dpi_y,


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