[librsvg/librsvg-2.44] handle::image_surface_new_from_href() - Port to Rust
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg/librsvg-2.44] handle::image_surface_new_from_href() - Port to Rust
- Date: Tue, 9 Oct 2018 14:17:58 +0000 (UTC)
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]