handle::image_surface_new_from_href() - Port to Rust

parent c6eb91d2
......@@ -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
......
......@@ -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,
......
......@@ -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 {
......
......@@ -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,
......
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)
}
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"))?,
);
}
_ => (),
......
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