Commit 056d7712 authored by Federico Mena Quintero's avatar Federico Mena Quintero

Merge branch 'surface-from-href' into 'master'

#349 - Don't panic if we get a data: URI with empty data

Closes #349

See merge request !134
parents 081300d2 c3c9759c
Pipeline #33393 failed with stages
in 22 minutes and 20 seconds
......@@ -345,6 +345,33 @@ name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gdk-pixbuf"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gdk-pixbuf-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gdk-pixbuf-sys"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "generic-array"
version = "0.11.1"
......@@ -353,6 +380,32 @@ dependencies = [
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gio"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gio-sys"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "glib"
version = "0.5.0"
......@@ -767,6 +820,7 @@ dependencies = [
"cssparser 0.24.0 (registry+https://github.com/rust-lang/crates.io-index)",
"downcast-rs 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -1048,7 +1102,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "134a8fa843d80a51a5b77d36d42bc2def9edcb0262c914861d08129fd1926600"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum gdk-pixbuf 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c2d2199eba47ebcb9977ce28179649bdd59305ef465c4e6f9b65aaa41c24e6b5"
"checksum gdk-pixbuf-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df6a3b73e04fafc07f5ebc083f1096a773412e627828e1103a55e921f81187d8"
"checksum generic-array 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8107dafa78c80c848b71b60133954b4a58609a3a1a5f9af037ecc7f67280f369"
"checksum gio 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2db9fad8f1b0d4c7338a210a6cbdf081dcc1a3c223718c698c4f313f6c288acb"
"checksum gio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2a57872499171d279f8577ce83837da4cae62b08dd32892236ed67ab7ea61030"
"checksum glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e0be1b1432e227bcd1a9b28db9dc1474a7e7fd4227e08e16f35304f32d09b61"
"checksum glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615bef979b5838526aee99241afc80cfb2e34a8735d4bcb8ec6072598c18a408"
"checksum gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70409d6405db8b1591602fcd0cbe8af52cd9976dd39194442b4c149ba343f86d"
......
......@@ -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,86 +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;
data = _rsvg_handle_acquire_data (handle, href, &mime_type, &data_len, error);
if (data == NULL)
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,97 +260,6 @@ rsvg_pixbuf_from_file_at_max_size (const gchar * file_name,
return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
}
cairo_surface_t *
rsvg_cairo_surface_from_pixbuf (const GdkPixbuf *pixbuf)
{
gint width, height, gdk_rowstride, n_channels, cairo_rowstride;
guchar *gdk_pixels, *cairo_pixels;
cairo_format_t format;
cairo_surface_t *surface;
int j;
if (pixbuf == NULL)
return NULL;
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
n_channels = gdk_pixbuf_get_n_channels (pixbuf);
if (n_channels == 3)
format = CAIRO_FORMAT_RGB24;
else
format = CAIRO_FORMAT_ARGB32;
surface = cairo_image_surface_create (format, width, height);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
cairo_surface_destroy (surface);
return NULL;
}
cairo_pixels = cairo_image_surface_get_data (surface);
cairo_rowstride = cairo_image_surface_get_stride (surface);
if (n_channels == 3) {
for (j = height; j; j--) {
guchar *p = gdk_pixels;
guchar *q = cairo_pixels;
guchar *end = p + 3 * width;
while (p < end) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
q[0] = p[2];
q[1] = p[1];
q[2] = p[0];
#else
q[1] = p[0];
q[2] = p[1];
q[3] = p[2];
#endif
p += 3;
q += 4;
}
gdk_pixels += gdk_rowstride;
cairo_pixels += cairo_rowstride;
}
} else {
for (j = height; j; j--) {
guchar *p = gdk_pixels;
guchar *q = cairo_pixels;
guchar *end = p + 4 * width;
guint t1, t2, t3;
#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
while (p < end) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
MULT (q[0], p[2], p[3], t1);
MULT (q[1], p[1], p[3], t2);
MULT (q[2], p[0], p[3], t3);
q[3] = p[3];
#else
q[0] = p[3];
MULT (q[1], p[0], p[3], t1);
MULT (q[2], p[1], p[3], t2);
MULT (q[3], p[2], p[3], t3);
#endif
p += 4;
q += 4;
}
#undef MULT
gdk_pixels += gdk_rowstride;
cairo_pixels += cairo_rowstride;
}
}
cairo_surface_mark_dirty (surface);
return surface;
}
/* Copied from gtk+/gdk/gdkpixbuf-drawable.c, LGPL 2+.
*
* Copyright (C) 1999 Michael Zucchi
......
......@@ -255,14 +255,9 @@ gboolean rsvg_cond_check_required_extensions (const char *value);
G_GNUC_INTERNAL
gboolean rsvg_cond_check_system_language (const char *value);
G_GNUC_INTERNAL
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 +324,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,
......
......@@ -63,6 +63,9 @@ version = "0.6"
#git = "https://github.com/gtk-rs/sys"
#branch = "master"
[dependencies.gdk-pixbuf]
version = "0.4"
[dev-dependencies]
criterion = "0.2"
......
......@@ -172,7 +172,8 @@ fn generate_phf_of_svg_attributes() {
writeln!(
&mut file,
"#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]"
).unwrap();
)
.unwrap();
writeln!(&mut file, "pub enum Attribute {{").unwrap();
for &(_, valname) in attribute_defs.iter() {
......@@ -184,7 +185,8 @@ fn generate_phf_of_svg_attributes() {
writeln!(
&mut file,
"static ATTRIBUTES: phf::Map<&'static str, Attribute> = "
).unwrap();
)
.unwrap();
let mut map = phf_codegen::Map::new();
map.phf_path("phf");
......
......@@ -200,7 +200,8 @@ impl Parse for AspectRatio {
p.expect_ident()
.map_err(|_| ValueErrorKind::Parse(ParseError::new("expected identifier")))
.and_then(|ident| parse_fit_mode(ident))
}).unwrap_or(FitMode::default());
})
.unwrap_or(FitMode::default());
parser
.expect_exhausted()
......
......@@ -32,7 +32,8 @@ impl Parse for CoordUnits {
cow.as_ref().to_string(),
))),
),
}).map_err(|_| {
})
.map_err(|_| {
ValueErrorKind::Parse(ParseError::new(
"expected 'userSpaceOnUse' or 'objectBoundingBox'",
))
......
......@@ -152,7 +152,8 @@ impl<'a> DrawingCtx<'a> {
y: 0.0,
width,
height,
}.transform(&affine)
}
.transform(&affine)
.outer();
// scale according to size set by size_func callback
......@@ -597,7 +598,8 @@ impl<'a> DrawingCtx<'a> {
fill_opacity,
&bbox,
current_color,
).and_then(|had_paint_server| {
)
.and_then(|had_paint_server| {
if had_paint_server {
pangocairo::functions::update_layout(&cr, layout);
pangocairo::functions::show_layout(&cr, layout);
......@@ -620,7 +622,8 @@ impl<'a> DrawingCtx<'a> {
stroke_opacity,
&bbox,
&current_color,
).and_then(|had_paint_server| {
)
.and_then(|had_paint_server| {
if had_paint_server {
need_layout_path = true;
}
......@@ -700,7 +703,8 @@ impl<'a> DrawingCtx<'a> {
fill_opacity,
&bbox,
current_color,
).and_then(|had_paint_server| {
)
.and_then(|had_paint_server| {
if had_paint_server {
if values.stroke.0 == PaintServer::None {
cr.fill();
......@@ -710,7 +714,8 @@ impl<'a> DrawingCtx<'a> {
}
Ok(())
}).and_then(|_| {
})
.and_then(|_| {
let stroke_opacity = values.stroke_opacity.0;
paint_server::set_source_paint_server(
......@@ -719,7 +724,8 @@ impl<'a> DrawingCtx<'a> {
&stroke_opacity,
&bbox,
&current_color,
).and_then(|had_paint_server| {
)
.and_then(|had_paint_server| {
if had_paint_server {
cr.stroke();
}
......
......@@ -3,6 +3,7 @@ use std::fmt;
use cairo;
use cssparser::BasicParseError;
use glib;
use attributes::Attribute;
use parsers::ParseError;
......@@ -100,6 +101,28 @@ impl From<cairo::Status> for RenderingError {
}
}
#[derive(Clone)]
pub enum LoadingError {
Cairo(cairo::Status),
EmptyData,
Glib(glib::Error),
Unknown,
}
impl From<cairo::Status> for LoadingError {
fn from(e: cairo::Status) -> LoadingError {
assert!(e != cairo::Status::Success);
LoadingError::Cairo(e)
}
}
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 {
......
......@@ -256,7 +256,8 @@ impl Parse for Operator {
cow.as_ref().to_string(),
))),
),
}).map_err(|_| ValueErrorKind::Value("invalid operator value".to_string()))
})
.map_err(|_| ValueErrorKind::Value("invalid operator value".to_string()))
}
}
......
......@@ -472,7 +472,8 @@ impl FilterContext {
&opacity,
&bbox,
&self.computed_from_node_being_filtered.color.0,
).and_then(|had_paint_server| {
)
.and_then(|had_paint_server| {
if had_paint_server {
cr.paint();
}
......@@ -523,14 +524,16 @@ impl FilterContext {
.and_then(|surface| {
SharedImageSurface::new(surface, SurfaceType::SRgb)
.map_err(FilterError::CairoError)
}).map(FilterInput::StandardInput),
})
.map(FilterInput::StandardInput),
Input::StrokePaint => self
.get_paint_server_surface(draw_ctx, &values.stroke.0, values.stroke_opacity.0)
.map_err(FilterError::CairoError)
.and_then(|surface| {
SharedImageSurface::new(surface, SurfaceType::SRgb)
.map_err(FilterError::CairoError)
}).map(FilterInput::StandardInput),
})
.map(FilterInput::StandardInput),
Input::FilterOutput(ref name) => self
.filter_output(name)
......
......@@ -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;
......@@ -80,7 +75,8 @@ impl Image {
&surface,
f64::from(ctx.source_graphic().width()),
f64::from(ctx.source_graphic().height()),
).map_err(|e| {
)
.map_err(|e| {
if let RenderingError::Cairo(status) = e {
FilterError::CairoError(status)
} else {
......@@ -119,32 +115,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,
......
......@@ -126,7 +126,8 @@ impl NodeTrait for Primitive {
} else {
None
}
}).unwrap_or(CoordUnits::UserSpaceOnUse);
})
.unwrap_or(CoordUnits::UserSpaceOnUse);
let no_units_allowed = primitiveunits == CoordUnits::ObjectBoundingBox;
let check_units = |length: Length| {
......@@ -292,7 +293,8 @@ pub fn render(
};
(c, linear_rgb)
}).filter_map(|(c, linear_rgb)| {
})
.filter_map(|(c, linear_rgb)| {
let rr = RcRef::new(c)
.try_map(|c| {
// Go through the filter primitives and see if the node is one of them.
......@@ -333,7 +335,8 @@ pub fn render(
turbulence::Turbulence,
);
filter.ok_or(())
}).ok();
})
.ok();
rr.map(|rr| (rr, linear_rgb))
});
......
......@@ -94,7 +94,8 @@ impl NodeTrait for Turbulence {
f64::from(i32::min_value()),
f64::from(i32::max_value()),
) as i32
}).map_err(|err| NodeError::attribute_error(attr, err))?,
})
.map_err(|err| NodeError::attribute_error(attr, err))?,
),
Attribute::StitchTiles => self.stitch_tiles.set(StitchTiles::parse(attr, value)?),
Attribute::Type => self.type_.set(NoiseType::parse(attr, value)?),
......@@ -398,7 +399,8 @@ impl Filter for Turbulence {
g: generate(1),
b: generate(2),
a: generate(3),
}.premultiply();
}
.premultiply();
output_data.set_pixel(output_stride, pixel, x as u32, y as u32);
}
......
......@@ -53,7 +53,8 @@ impl Parse for SpreadMethod {
cow.as_ref().to_string(),
))),
),
}).map_err(|_| {
})
.map_err(|_| {
ValueErrorKind::Parse(ParseError::new("expected 'pad' | 'reflect' | 'repeat'"))
})
}
......@@ -379,7 +380,8 @@ impl Gradient {
}
!in_error
}).for_each(|child| {
})
.for_each(|child| {
child.with_impl(|stop: &NodeStop| {
let cascaded = child.get_cascaded_values();
let values = cascaded.get();
......@@ -444,7 +446,8 @@ fn resolve_gradient(gradient: &Gradient, draw_ctx: &mut DrawingCtx<'_>) -> Gradi
result.resolve_from_fallback(&fallback_grad)
});
Some(())
}).or_else(|| {
})
.or_else(|| {
result.resolve_from_defaults();
Some(())
});
......
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 {
......@@ -85,7 +92,14 @@ pub fn acquire_data(handle: *mut RsvgHandle, url: &str) -> Result<BinaryData, gl
);
if buf.is_null() {
if error.is_null() && len == 0 {
Ok(BinaryData {
data: Vec::new(),
content_type: None,
})
} else {
Err(from_glib_full(error))
}
} else {
Ok(BinaryData {
data: FromGlibContainer::from_glib_full_num(buf as *mut u8, len),
......@@ -94,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 {