[librsvg/librsvg-2.44] handle::image_surface_new_from_href() - Port to Rust



commit ebed5198dc4d37eb7926e023a6655619512d04ff
Author: Federico Mena Quintero <federico gnome org>
Date:   Mon Oct 1 13:31:29 2018 -0500

    handle::image_surface_new_from_href() - Port to Rust

 librsvg/rsvg-handle.c               | 96 +++----------------------------------
 librsvg/rsvg-private.h              |  6 +--
 rsvg_internals/src/error.rs         |  9 ++++
 rsvg_internals/src/filters/image.rs | 36 ++------------
 rsvg_internals/src/handle.rs        | 83 ++++++++++++++++++++++++++++++++
 rsvg_internals/src/image.rs         | 35 +++-----------
 6 files changed, 112 insertions(+), 153 deletions(-)
---
diff --git a/librsvg/rsvg-handle.c b/librsvg/rsvg-handle.c
index 7de1e400..c469d6cc 100644
--- a/librsvg/rsvg-handle.c
+++ b/librsvg/rsvg-handle.c
@@ -1031,6 +1031,12 @@ rsvg_handle_load_extern (RsvgHandle *handle, const char *uri)
     return res;
 }
 
+gboolean
+rsvg_handle_keep_image_data (RsvgHandle *handle)
+{
+    return (handle->priv->flags & RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA) != 0;
+}
+
 static RsvgDrawingCtx *
 rsvg_handle_create_drawing_ctx(RsvgHandle *handle,
                                cairo_t *cr,
@@ -1719,96 +1725,6 @@ _rsvg_handle_acquire_stream (RsvgHandle *handle,
     return stream;
 }
 
-cairo_surface_t *
-rsvg_cairo_surface_new_from_href (RsvgHandle *handle,
-                                  const char *href,
-                                  GError **error)
-{
-    char *data;
-    gsize data_len;
-    char *mime_type = NULL;
-    GdkPixbufLoader *loader = NULL;
-    GdkPixbuf *pixbuf = NULL;
-    cairo_surface_t *surface = NULL;
-
-    g_assert (error != NULL && *error == NULL);
-
-    data = _rsvg_handle_acquire_data (handle, href, &mime_type, &data_len, error);
-    if (data == NULL) {
-        if (*error == NULL && data_len == 0) {
-            g_set_error (error,
-                         RSVG_ERROR,
-                         RSVG_ERROR_FAILED,
-                         "empty image data");
-        }
-
-        return NULL;
-    }
-
-    if (mime_type) {
-        loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, error);
-    } else {
-        loader = gdk_pixbuf_loader_new ();
-    }
-
-    if (loader == NULL)
-        goto out;
-
-    if (!gdk_pixbuf_loader_write (loader, (guchar *) data, data_len, error)) {
-        gdk_pixbuf_loader_close (loader, NULL);
-        goto out;
-    }
-
-    if (!gdk_pixbuf_loader_close (loader, error))
-        goto out;
-
-    pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
-
-    if (!pixbuf) {
-        g_set_error (error,
-                     GDK_PIXBUF_ERROR,
-                     GDK_PIXBUF_ERROR_FAILED,
-                      _("Failed to load image '%s': reason not known, probably a corrupt image file"),
-                      href);
-        goto out;
-    }
-
-    surface = rsvg_cairo_surface_from_pixbuf (pixbuf);
-    if (!surface) {
-        g_set_error (error, RSVG_ERROR, RSVG_ERROR_FAILED, "could not convert pixbuf to cairo surface");
-        goto out;
-    }
-
-    if (mime_type == NULL) {
-        /* Try to get the information from the loader */
-        GdkPixbufFormat *format;
-        char **mime_types;
-
-        if ((format = gdk_pixbuf_loader_get_format (loader)) != NULL) {
-            mime_types = gdk_pixbuf_format_get_mime_types (format);
-
-            if (mime_types != NULL)
-                mime_type = g_strdup (mime_types[0]);
-            g_strfreev (mime_types);
-        }
-    }
-
-    if ((handle->priv->flags & RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA) != 0 &&
-        mime_type != NULL &&
-        cairo_surface_set_mime_data (surface, mime_type, (guchar *) data,
-                                     data_len, g_free, data) == CAIRO_STATUS_SUCCESS) {
-        data = NULL; /* transferred to the surface */
-    }
-
-  out:
-    if (loader)
-        g_object_unref (loader);
-    g_free (mime_type);
-    g_free (data);
-
-    return surface;
-}
-
 #ifdef HAVE_PANGOFT2
 
 static void
diff --git a/librsvg/rsvg-private.h b/librsvg/rsvg-private.h
index e5c94c4d..a8bdb3f0 100644
--- a/librsvg/rsvg-private.h
+++ b/librsvg/rsvg-private.h
@@ -260,9 +260,6 @@ cairo_surface_t *rsvg_cairo_surface_from_pixbuf (const GdkPixbuf *pixbuf);
 G_GNUC_INTERNAL
 GdkPixbuf *rsvg_cairo_surface_to_pixbuf (cairo_surface_t *surface);
 
-G_GNUC_INTERNAL
-cairo_surface_t *rsvg_cairo_surface_new_from_href (RsvgHandle *handle, const char *href, GError ** error);
-
 /* Defined in rsvg_internals/src/drawing_ctx.rs */
 G_GNUC_INTERNAL
 RsvgDrawingCtx *rsvg_drawing_ctx_new (cairo_t *cr,
@@ -329,6 +326,9 @@ G_GNUC_INTERNAL
 RsvgHandle *rsvg_handle_load_extern (RsvgHandle *handle,
                                      const char *uri);
 
+G_GNUC_INTERNAL
+gboolean rsvg_handle_keep_image_data (RsvgHandle *handle);
+
 G_GNUC_INTERNAL
 char *_rsvg_handle_acquire_data (RsvgHandle *handle,
                                  const char *uri,
diff --git a/rsvg_internals/src/error.rs b/rsvg_internals/src/error.rs
index db5a824e..4ced1898 100644
--- a/rsvg_internals/src/error.rs
+++ b/rsvg_internals/src/error.rs
@@ -3,6 +3,7 @@ use std::fmt;
 
 use cairo;
 use cssparser::BasicParseError;
+use glib;
 
 use attributes::Attribute;
 use parsers::ParseError;
@@ -104,6 +105,8 @@ impl From<cairo::Status> for RenderingError {
 pub enum LoadingError {
     Cairo(cairo::Status),
     EmptyData,
+    Glib(glib::Error),
+    Unknown,
 }
 
 impl From<cairo::Status> for LoadingError {
@@ -114,6 +117,12 @@ impl From<cairo::Status> for LoadingError {
     }
 }
 
+impl From<glib::Error> for LoadingError {
+    fn from(e: glib::Error) -> LoadingError {
+        LoadingError::Glib(e)
+    }
+}
+
 #[cfg(test)]
 pub fn is_parse_error<T>(r: &Result<T, ValueErrorKind>) -> bool {
     match *r {
diff --git a/rsvg_internals/src/filters/image.rs b/rsvg_internals/src/filters/image.rs
index 6d7e103a..4420bdc3 100644
--- a/rsvg_internals/src/filters/image.rs
+++ b/rsvg_internals/src/filters/image.rs
@@ -2,17 +2,12 @@ use std::cell::{Cell, RefCell};
 use std::ptr;
 
 use cairo::{self, ImageSurface, MatrixTrait, Pattern};
-use cairo_sys;
-use glib;
-use glib::translate::{from_glib_full, ToGlibPtr};
-use glib_sys;
-use libc;
 
 use aspect_ratio::AspectRatio;
 use attributes::Attribute;
 use drawing_ctx::DrawingCtx;
 use error::RenderingError;
-use handle::RsvgHandle;
+use handle::{self, RsvgHandle};
 use node::{CascadedValues, NodeResult, NodeTrait, RsvgNode};
 use parsers::parse;
 use property_bag::PropertyBag;
@@ -119,32 +114,9 @@ impl Image {
         bounds_builder: BoundsBuilder<'_>,
         href: &str,
     ) -> Result<ImageSurface, FilterError> {
-        let surface = {
-            extern "C" {
-                fn rsvg_cairo_surface_new_from_href(
-                    handle: *const RsvgHandle,
-                    href: *const libc::c_char,
-                    error: *mut *mut glib_sys::GError,
-                ) -> *mut cairo_sys::cairo_surface_t;
-            }
-
-            let mut error = ptr::null_mut();
-
-            let raw_surface = unsafe {
-                rsvg_cairo_surface_new_from_href(
-                    self.handle.get(),
-                    href.to_glib_none().0,
-                    &mut error,
-                )
-            };
-            if !raw_surface.is_null() {
-                unsafe { cairo::ImageSurface::from_raw_full(raw_surface).unwrap() }
-            } else {
-                // TODO: pass the error through?
-                let _: glib::Error = unsafe { from_glib_full(error) };
-                return Err(FilterError::InvalidInput);
-            }
-        };
+        // FIXME: translate the error better here
+        let surface = handle::image_surface_new_from_href(self.handle.get() as *mut _, href)
+            .map_err(|_| FilterError::InvalidInput)?;
 
         let output_surface = ImageSurface::create(
             cairo::Format::ARgb32,
diff --git a/rsvg_internals/src/handle.rs b/rsvg_internals/src/handle.rs
index 30333634..e3506ae2 100644
--- a/rsvg_internals/src/handle.rs
+++ b/rsvg_internals/src/handle.rs
@@ -1,5 +1,8 @@
 use std::ptr;
 
+use cairo::{ImageSurface, Status};
+use cairo_sys;
+use gdk_pixbuf::{PixbufLoader, PixbufLoaderExt};
 use glib;
 use glib::translate::*;
 use glib_sys;
@@ -7,6 +10,8 @@ use libc;
 
 use css::{CssStyles, RsvgCssStyles};
 use defs::{Defs, RsvgDefs};
+use error::LoadingError;
+use surface_utils::shared_surface::SharedImageSurface;
 
 pub enum RsvgHandle {}
 
@@ -33,6 +38,8 @@ extern "C" {
         out_len: *mut usize,
         error: *mut *mut glib_sys::GError,
     ) -> *mut u8;
+
+    fn rsvg_handle_keep_image_data(handle: *const RsvgHandle) -> glib_sys::gboolean;
 }
 
 pub fn get_defs<'a>(handle: *const RsvgHandle) -> &'a Defs {
@@ -101,3 +108,79 @@ pub fn acquire_data(handle: *mut RsvgHandle, url: &str) -> Result<BinaryData, gl
         }
     }
 }
+
+fn keep_image_data(handle: *const RsvgHandle) -> bool {
+    unsafe { from_glib(rsvg_handle_keep_image_data(handle)) }
+}
+
+pub fn image_surface_new_from_href(
+    handle: *mut RsvgHandle,
+    href: &str,
+) -> Result<ImageSurface, LoadingError> {
+    let data = acquire_data(handle, href)?;
+
+    if data.data.len() == 0 {
+        return Err(LoadingError::EmptyData);
+    }
+
+    let loader = if let Some(ref content_type) = data.content_type {
+        PixbufLoader::new_with_mime_type(content_type)?
+    } else {
+        PixbufLoader::new()
+    };
+
+    loader.write(&data.data)?;
+    loader.close()?;
+
+    let pixbuf = loader.get_pixbuf().ok_or(LoadingError::Unknown)?;
+
+    let surface = SharedImageSurface::from_pixbuf(&pixbuf)?.into_image_surface()?;
+
+    if keep_image_data(handle) {
+        let mime_type = data.content_type.or_else(|| {
+            // Try to get the content type from the loader
+
+            loader.get_format().and_then(|format| {
+                let content_types = format.get_mime_types();
+
+                if content_types.len() != 0 {
+                    Some(content_types[0].clone())
+                } else {
+                    None
+                }
+            })
+        });
+
+        if let Some(mime_type) = mime_type {
+            extern "C" {
+                fn cairo_surface_set_mime_data(
+                    surface: *mut cairo_sys::cairo_surface_t,
+                    mime_type: *const libc::c_char,
+                    data: *mut libc::c_char,
+                    length: libc::c_ulong,
+                    destroy: cairo_sys::cairo_destroy_func_t,
+                    closure: *mut libc::c_void,
+                ) -> Status;
+            }
+
+            let data_ptr = ToGlibContainerFromSlice::to_glib_full_from_slice(&data.data);
+
+            unsafe {
+                let status = cairo_surface_set_mime_data(
+                    surface.to_glib_none().0,
+                    mime_type.to_glib_none().0,
+                    data_ptr as *mut _,
+                    data.data.len() as libc::c_ulong,
+                    Some(glib_sys::g_free),
+                    data_ptr as *mut _,
+                );
+
+                if status != Status::Success {
+                    return Err(LoadingError::Cairo(status));
+                }
+            }
+        }
+    }
+
+    Ok(surface)
+}
diff --git a/rsvg_internals/src/image.rs b/rsvg_internals/src/image.rs
index b1c6bc01..dc4bddb8 100644
--- a/rsvg_internals/src/image.rs
+++ b/rsvg_internals/src/image.rs
@@ -1,20 +1,14 @@
 use cairo;
 use cairo::{MatrixTrait, Pattern};
-use cairo_sys;
-use glib;
-use glib::translate::*;
-use glib_sys;
-use libc;
 use std::cell::{Cell, RefCell};
-use std::ptr;
 
 use aspect_ratio::AspectRatio;
 use attributes::Attribute;
 use bbox::BoundingBox;
 use drawing_ctx::DrawingCtx;
-use error::RenderingError;
+use error::{NodeError, RenderingError};
 use float_eq_cairo::ApproxEqCairo;
-use handle::RsvgHandle;
+use handle::{self, RsvgHandle};
 use length::*;
 use node::*;
 use parsers::{parse, parse_and_validate};
@@ -77,26 +71,11 @@ impl NodeTrait for NodeImage {
                 Attribute::XlinkHref | Attribute::Path => {
                     // "path" is used by some older Adobe Illustrator versions
 
-                    extern "C" {
-                        fn rsvg_cairo_surface_new_from_href(
-                            handle: *const RsvgHandle,
-                            href: *const libc::c_char,
-                            error: *mut *mut glib_sys::GError,
-                        ) -> *mut cairo_sys::cairo_surface_t;
-                    }
-
-                    let mut error = ptr::null_mut();
-
-                    let raw_surface = unsafe {
-                        rsvg_cairo_surface_new_from_href(handle, value.to_glib_none().0, &mut error)
-                    };
-                    if !raw_surface.is_null() {
-                        *self.surface.borrow_mut() = Some(unsafe {
-                            cairo::ImageSurface::from_raw_full(raw_surface).unwrap()
-                        });
-                    } else {
-                        let _: glib::Error = unsafe { from_glib_full(error) }; // FIXME: we should note that 
the image couldn't be loaded
-                    }
+                    *self.surface.borrow_mut() = Some(
+                        // FIXME: translate the error better here
+                        handle::image_surface_new_from_href(handle as *mut _, value)
+                            .map_err(|_| NodeError::value_error(attr, "could not load image"))?,
+                    );
                 }
 
                 _ => (),


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