...
 
Commits (16)
......@@ -32,7 +32,7 @@ minimum version is listed here; you may use a newer version instead.
**Compilers:**
* a C compiler and `make` tool; we recommend GNU `make`.
* rust 1.27 or later
* rust 1.30 or later
* cargo
**Mandatory dependencies:**
......
This diff is collapsed.
......@@ -9,3 +9,18 @@ debug = true
[profile.bench]
lto = true
[patch.crates-io]
cairo-rs = { git = "https://github.com/gtk-rs/cairo" }
cairo-sys-rs = { git = "https://github.com/gtk-rs/cairo" }
gdk-pixbuf = { git = "https://github.com/gtk-rs/gdk-pixbuf" }
gdk-pixbuf-sys = { git = "https://github.com/gtk-rs/sys" }
gio = { git = "https://github.com/gtk-rs/gio" }
gio-sys = { git = "https://github.com/gtk-rs/sys" }
glib = { git = "https://github.com/gtk-rs/glib" }
glib-sys = { git = "https://github.com/gtk-rs/sys" }
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
pango = { git = "https://github.com/gtk-rs/pango" }
pango-sys = { git = "https://github.com/gtk-rs/sys" }
pangocairo = { git = "https://github.com/gtk-rs/pangocairo" }
......@@ -14,14 +14,7 @@ headers = \
librsvg/rsvg.h \
librsvg/rsvg-cairo.h
enum_sources = \
librsvg/librsvg-enum-types.h \
librsvg/librsvg-enum-types.c
BUILT_SOURCES += $(enum_sources)
librsvg_@RSVG_API_MAJOR_VERSION@_la_SOURCES = \
librsvg/librsvg-enum-types.c \
librsvg/librsvg-enum-types.h \
librsvg/librsvg-features.c \
librsvg/librsvg-features.h \
librsvg/rsvg-base.c \
......@@ -208,8 +201,7 @@ librsvg_@RSVG_API_MAJOR_VERSION@_la_LIBADD = \
librsvgincdir = $(includedir)/librsvg-$(RSVG_API_VERSION)/librsvg
librsvginc_HEADERS = \
$(headers) \
librsvg/librsvg-features.h \
librsvg/librsvg-enum-types.h
librsvg/librsvg-features.h
dist_man_MANS = rsvg-convert.1
......@@ -286,45 +278,12 @@ EXTRA_DIST = \
tap-driver.sh \
tap-test
CLEANFILES = \
$(enum_sources) \
librsvg/s-enum-types-h librsvg/s-enum-types-c
## Put `exec' in the name because this should be installed by
## `install-exec', not `install-data'.
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = librsvg-$(RSVG_API_VERSION).pc
librsvg/librsvg-enum-types.h: librsvg/s-enum-types-h
@true
librsvg/s-enum-types-h: $(headers) Makefile
$(AM_V_GEN) ( cd $(srcdir) && $(GLIB_MKENUMS) \
--fhead "#if !defined (__RSVG_RSVG_H_INSIDE__) && !defined (RSVG_COMPILATION)\n#warning \"Including <librsvg/librsvg-enum-types.h> directly is deprecated.\"\n#endif\n\n#ifndef __LIBRSVG_ENUM_TYPES_H__\n#define __LIBRSVG_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
--fprod "/* enumerations from \"@filename@\" */\n" \
--vhead "GType @enum_name@_get_type (void);\n#define RSVG_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \
--ftail "G_END_DECLS\n\n#endif /* __LIBRSVG_ENUM_TYPES_H__ */" \
$(headers) ) > librsvg/tmp-librsvg-enum-types.h \
&& (cmp -s librsvg/tmp-librsvg-enum-types.h librsvg/librsvg-enum-types.h || cp librsvg/tmp-librsvg-enum-types.h librsvg/librsvg-enum-types.h ) \
&& rm -f librsvg/tmp-librsvg-enum-types.h \
&& echo timestamp > $@
librsvg/librsvg-enum-types.c: librsvg/s-enum-types-c librsvg/librsvg-enum-types.h
@true
librsvg/s-enum-types-c: $(headers) Makefile
$(AM_V_GEN) ( cd $(srcdir) && $(GLIB_MKENUMS) \
--fhead "#include \"librsvg/rsvg.h\"" \
--fprod "\n/* enumerations from \"@filename@\" */" \
--vhead "GType\n@enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G@Type@Value values[] = {" \
--vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
--vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (\"@EnumName@\", values);\n }\n return etype;\n}\n" \
$(headers) ) > librsvg/tmp-librsvg-enum-types.c \
&& (cmp -s librsvg/tmp-librsvg-enum-types.c librsvg/librsvg-enum-types.c || cp librsvg/tmp-librsvg-enum-types.c librsvg/librsvg-enum-types.c ) \
&& rm -f librsvg/tmp-librsvg-enum-types.c \
&& echo timestamp > $@
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc
if HAVE_INTROSPECTION
......@@ -363,7 +322,7 @@ nodist_gir_DATA = $(INTROSPECTION_GIRS)
typelibsdir = $(libdir)/girepository-1.0
nodist_typelibs_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
CLEANFILES += $(nodist_gir_DATA) $(nodist_typelibs_DATA)
CLEANFILES = $(nodist_gir_DATA) $(nodist_typelibs_DATA)
if ENABLE_VAPIGEN
include $(VAPIGEN_MAKEFILE)
......
......@@ -113,7 +113,7 @@ AS_IF(test x$RUSTC = xno,
dnl Minimum version of rustc that we support
dnl If you change this, please update COMPILING.md
MINIMUM_RUST_MAJOR=1
MINIMUM_RUST_MINOR=27
MINIMUM_RUST_MINOR=30
rust_version=`$RUSTC --version`
version=`echo "$rust_version" | sed -e 's/^rustc //g'`
......
......@@ -54,12 +54,10 @@ FIXXREF_OPTIONS = \
# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
HFILE_GLOB = \
$(top_srcdir)/librsvg/*.h \
$(top_builddir)/librsvg/*.h
$(top_srcdir)/librsvg/*.h
CFILE_GLOB = \
$(top_srcdir)/librsvg/*.c \
$(top_builddir)/librsvg/*.c
$(top_srcdir)/librsvg/*.c
# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
......
......@@ -131,9 +131,6 @@
/* Implemented in rsvg_internals/src/xml.rs */
typedef struct RsvgXmlState RsvgXmlState;
/* Implemented in rsvg_internals/src/xml.rs */
extern void rsvg_xml_state_error(RsvgXmlState *xml, const char *msg);
/* Implemented in rsvg_internals/src/handle.rs */
extern double rsvg_handle_rust_get_dpi_x (RsvgHandle *raw_handle);
extern double rsvg_handle_rust_get_dpi_y (RsvgHandle *raw_handle);
......@@ -191,6 +188,8 @@ extern RsvgHandle *rsvg_handle_rust_new_from_data (const guint8 *data,
/* Implemented in rsvg_internals/src/c_api.rs */
extern GType rsvg_handle_rust_get_type (void);
extern GType rsvg_rust_error_get_type (void);
extern GType rsvg_rust_handle_flags_get_type (void);
GType
rsvg_handle_get_type (void)
......@@ -872,23 +871,14 @@ rsvg_handle_internal_set_testing (RsvgHandle *handle, gboolean testing)
rsvg_handle_rust_set_testing (handle, testing);
}
/* This one is defined in the C code, because the prototype has varargs
* and we can't handle those from Rust :(
*/
G_GNUC_INTERNAL void rsvg_sax_error_cb (void *data, const char *msg, ...);
void
rsvg_sax_error_cb (void *data, const char *msg, ...)
GType
rsvg_error_get_type(void)
{
RsvgXmlState *xml = data;
va_list args;
char *buf;
va_start (args, msg);
g_vasprintf (&buf, msg, args);
va_end (args);
rsvg_xml_state_error (xml, buf);
return rsvg_rust_error_get_type();
}
g_free (buf);
GType
rsvg_handle_flags_get_type(void)
{
return rsvg_rust_handle_flags_get_type();
}
......@@ -66,6 +66,9 @@ typedef enum {
#define RSVG_ERROR (rsvg_error_quark ())
GQuark rsvg_error_quark (void) G_GNUC_CONST;
GType rsvg_error_get_type (void);
#define RSVG_TYPE_ERROR (rsvg_error_get_type())
typedef struct _RsvgHandle RsvgHandle;
typedef struct _RsvgHandleClass RsvgHandleClass;
typedef struct _RsvgDimensionData RsvgDimensionData;
......@@ -206,6 +209,10 @@ typedef enum /*< flags >*/
RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA = 1 << 1
} RsvgHandleFlags;
GType rsvg_handle_flags_get_type (void);
#define RSVG_TYPE_HANDLE_FLAGS (rsvg_handle_flags_get_type())
RsvgHandle *rsvg_handle_new_with_flags (RsvgHandleFlags flags);
void rsvg_handle_set_base_gfile (RsvgHandle *handle,
......@@ -294,7 +301,6 @@ const char *rsvg_handle_get_metadata (RsvgHandle * handle);
G_END_DECLS
#include "librsvg-enum-types.h"
#include "librsvg-features.h"
#include "rsvg-cairo.h"
......
......@@ -21,31 +21,31 @@ phf_codegen = "0.7.21"
[dependencies]
bitflags = "1.0"
cairo-rs = { git="https://github.com/gtk-rs/cairo", branch="master" }
cairo-sys-rs = { git="https://github.com/gtk-rs/cairo", branch="master" }
cairo-rs = "0.5.0"
cairo-sys-rs = "0.7.0"
cssparser = "0.25.1"
data-url = "0.1"
downcast-rs = "^1.0.0"
encoding = "0.2.33"
float-cmp = "0.4.0"
gdk-pixbuf = { git="https://github.com/gtk-rs/gdk-pixbuf", branch="master" }
gdk-pixbuf-sys = { git="https://github.com/gtk-rs/sys", branch="master" }
gio = { git="https://github.com/gtk-rs/gio", branch="master", features=["v2_48"] } # per configure.ac
gio-sys = { git="https://github.com/gtk-rs/sys", branch="master" }
glib = { git="https://github.com/gtk-rs/glib", branch="master", features=["subclassing"] }
glib-sys = { git="https://github.com/gtk-rs/sys", branch="master" }
gobject-sys = { git="https://github.com/gtk-rs/sys", branch="master" }
itertools = "0.7.4"
gdk-pixbuf = "0.5.0"
gdk-pixbuf-sys = "0.7.0"
gio = { version="0.5.1", features=["v2_48"] } # per configure.ac
gio-sys = "0.7.0"
glib = { version = "0.6.0", features=["subclassing"] }
glib-sys = "0.7.0"
gobject-sys = "0.7.0"
itertools = "0.8"
language-tags = "0.2.2"
lazy_static = "1.0.0"
libc = "0.2"
locale_config = "*" # recommended explicitly by locale_config's README.md
nalgebra = "0.16"
nalgebra = "0.17"
num-traits = "0.2"
owning_ref = "0.4.0"
pango = { git="https://github.com/gtk-rs/pango", branch="master" }
pango-sys = { git="https://github.com/gtk-rs/sys", branch="master" }
pangocairo = { git="https://github.com/gtk-rs/pangocairo", branch="master" }
pango = "0.5.0"
pango-sys = "0.7.0"
pangocairo = "0.6.0"
phf = "0.7.21"
rayon = "1"
regex = "1"
......
use std::ops;
use std::sync::Once;
use std::{f64, i32};
use libc;
......@@ -12,14 +13,11 @@ use glib::value::{FromValue, FromValueOptional, SetValue};
use glib::{ParamFlags, ParamSpec, StaticType, ToValue, Type, Value};
use glib_sys;
use gobject_sys;
use gobject_sys::{self, GEnumValue, GFlagsValue};
use error::RSVG_ERROR_FAILED;
use handle::Handle;
extern "C" {
fn rsvg_handle_flags_get_type() -> glib_sys::GType;
}
mod handle_flags {
// The following is entirely stolen from the auto-generated code
// for GBindingFlags, from gtk-rs/glib/src/gobject/auto/flags.rs
......@@ -54,7 +52,7 @@ mod handle_flags {
impl StaticType for HandleFlags {
fn static_type() -> Type {
unsafe { from_glib(rsvg_handle_flags_get_type()) }
unsafe { from_glib(rsvg_rust_handle_flags_get_type()) }
}
}
......@@ -300,3 +298,85 @@ pub fn get_rust_handle<'a>(handle: *const RsvgHandle) -> &'a Handle {
pub unsafe extern "C" fn rsvg_handle_rust_get_type() -> glib_sys::GType {
Handle::get_type().to_glib()
}
#[no_mangle]
pub unsafe extern "C" fn rsvg_rust_error_get_type() -> glib_sys::GType {
static ONCE: Once = Once::new();
static mut ETYPE: glib_sys::GType = gobject_sys::G_TYPE_INVALID;
// We have to store the GEnumValue in a static variable but
// that requires it to be Sync. It is not Sync by default
// because it contains pointers, so we have define a custom
// wrapper type here on which we can implement Sync.
#[repr(transparent)]
struct GEnumValueWrapper(GEnumValue);
unsafe impl Sync for GEnumValueWrapper {}
static VALUES: [GEnumValueWrapper; 2] = [
GEnumValueWrapper(GEnumValue {
value: RSVG_ERROR_FAILED,
value_name: b"RSVG_ERROR_FAILED\0" as *const u8 as *const _,
value_nick: b"failed\0" as *const u8 as *const _,
}),
GEnumValueWrapper(GEnumValue {
value: 0,
value_name: 0 as *const _,
value_nick: 0 as *const _,
}),
];
ONCE.call_once(|| {
ETYPE = gobject_sys::g_enum_register_static(
b"RsvgError\0" as *const u8 as *const _,
&VALUES as *const GEnumValueWrapper as *const GEnumValue,
);
});
ETYPE
}
#[no_mangle]
pub unsafe extern "C" fn rsvg_rust_handle_flags_get_type() -> glib_sys::GType {
static ONCE: Once = Once::new();
static mut FTYPE: glib_sys::GType = gobject_sys::G_TYPE_INVALID;
// We have to store the GFlagsValue in a static variable but
// that requires it to be Sync. It is not Sync by default
// because it contains pointers, so we have define a custom
// wrapper type here on which we can implement Sync.
#[repr(transparent)]
struct GFlagsValueWrapper(GFlagsValue);
unsafe impl Sync for GFlagsValueWrapper {}
static VALUES: [GFlagsValueWrapper; 4] = [
GFlagsValueWrapper(GFlagsValue {
value: 0, // handle_flags::HandleFlags::NONE.bits(),
value_name: b"RSVG_HANDLE_FLAGS_NONE\0" as *const u8 as *const _,
value_nick: b"flags-none\0" as *const u8 as *const _,
}),
GFlagsValueWrapper(GFlagsValue {
value: 1 << 0, // HandleFlags::UNLIMITED.to_glib(),
value_name: b"RSVG_HANDLE_FLAG_UNLIMITED\0" as *const u8 as *const _,
value_nick: b"flag-unlimited\0" as *const u8 as *const _,
}),
GFlagsValueWrapper(GFlagsValue {
value: 1 << 1, // HandleFlags::KEEP_IMAGE_DATA.to_glib(),
value_name: b"RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA\0" as *const u8 as *const _,
value_nick: b"flag-keep-image-data\0" as *const u8 as *const _,
}),
GFlagsValueWrapper(GFlagsValue {
value: 0,
value_name: 0 as *const _,
value_nick: 0 as *const _,
}),
];
ONCE.call_once(|| {
FTYPE = gobject_sys::g_flags_register_static(
b"RsvgHandleFlags\0" as *const u8 as *const _,
&VALUES as *const GFlagsValueWrapper as *const GFlagsValue,
);
});
FTYPE
}
......@@ -4,7 +4,6 @@ use std::ascii::AsciiExt;
use std::str::FromStr;
use glib;
use itertools::{FoldWhile, Itertools};
use language_tags::LanguageTag;
use locale_config::{LanguageRange, Locale};
......@@ -87,30 +86,27 @@ impl SystemLanguage {
/// [`systemLanguage`]: https://www.w3.org/TR/SVG/struct.html#ConditionalProcessingSystemLanguageAttribute
/// [BCP47]: http://www.ietf.org/rfc/bcp/bcp47.txt
pub fn from_attribute(s: &str, locale: &Locale) -> Result<SystemLanguage, ValueErrorKind> {
s.split(',')
.map(LanguageTag::from_str)
.fold_while(
// start with no match
Ok(SystemLanguage(false)),
// The accumulator is Result<SystemLanguage, ValueErrorKind>
|acc, tag_result| match tag_result {
Ok(language_tag) => {
let have_match = acc.unwrap().0;
if have_match {
FoldWhile::Continue(Ok(SystemLanguage(have_match)))
} else {
locale_accepts_language_tag(locale, &language_tag)
.map(|matches| FoldWhile::Continue(Ok(SystemLanguage(matches))))
.unwrap_or_else(|e| FoldWhile::Done(Err(e)))
}
s.split(',').map(LanguageTag::from_str).try_fold(
// start with no match
SystemLanguage(false),
// The accumulator is Result<SystemLanguage, ValueErrorKind>
|acc, tag_result| match tag_result {
Ok(language_tag) => {
let have_match = acc.0;
if have_match {
Ok(SystemLanguage(have_match))
} else {
locale_accepts_language_tag(locale, &language_tag)
.map(|matches| SystemLanguage(matches))
}
Err(e) => FoldWhile::Done(Err(ValueErrorKind::Parse(ParseError::new(
&format!("invalid language tag: \"{}\"", e),
)))),
},
)
.into_inner()
}
Err(e) => Err(ValueErrorKind::Parse(ParseError::new(&format!(
"invalid language tag: \"{}\"",
e
)))),
},
)
}
}
......
......@@ -324,7 +324,7 @@ pub fn is_value_error<T>(r: &Result<T, ValueErrorKind>) -> bool {
pub struct RsvgError;
// Keep in sync with rsvg.h:RsvgError
const RSVG_ERROR_FAILED: i32 = 0;
pub const RSVG_ERROR_FAILED: i32 = 0;
impl ErrorDomain for RsvgError {
fn domain() -> glib::Quark {
......
use std::cell::{Cell, RefCell};
use cairo::{self, ImageSurface, MatrixTrait};
use nalgebra::{DMatrix, Dynamic, MatrixVec};
use nalgebra::{DMatrix, Dynamic, VecStorage};
use attributes::Attribute;
use drawing_ctx::DrawingCtx;
......@@ -193,7 +193,7 @@ impl NodeTrait for ConvolveMatrix {
));
}
DMatrix::from_data(MatrixVec::new(
DMatrix::from_data(VecStorage::new(
Dynamic::new(self.order.get().1 as usize),
Dynamic::new(self.order.get().0 as usize),
v,
......
......@@ -3,7 +3,7 @@ use std::cmp::min;
use std::f64;
use cairo::MatrixTrait;
use nalgebra::{DMatrix, Dynamic, MatrixVec};
use nalgebra::{DMatrix, Dynamic, VecStorage};
use attributes::Attribute;
use drawing_ctx::DrawingCtx;
......@@ -182,7 +182,7 @@ fn gaussian_blur(
} else {
(1, kernel.len())
};
let kernel = DMatrix::from_data(MatrixVec::new(
let kernel = DMatrix::from_data(VecStorage::new(
Dynamic::new(rows),
Dynamic::new(cols),
kernel,
......
......@@ -113,7 +113,7 @@ pub fn acquire_data(
Ok(BinaryData {
data: contents,
content_type: mime_type,
content_type: mime_type.map(From::from),
})
}
}
......@@ -40,6 +40,12 @@ extern crate bitflags;
#[macro_use]
extern crate glib;
pub use c_api::{
rsvg_handle_rust_get_type,
rsvg_rust_error_get_type,
rsvg_rust_handle_flags_get_type,
};
pub use color::{rsvg_css_parse_color, ColorKind, ColorSpec};
pub use dpi::rsvg_rust_set_default_dpi_x_y;
......@@ -83,8 +89,6 @@ pub use pixbuf_utils::{
rsvg_rust_pixbuf_from_file_at_zoom_with_max,
};
pub use xml::rsvg_xml_state_error;
#[macro_use]
mod log;
......
......@@ -34,11 +34,11 @@ fn normalize_default(elements: NormalizeDefault, s: &str) -> String {
let mut s = s;
if !elements.has_element_before {
s = s.trim_left();
s = s.trim_start();
}
if !elements.has_element_after {
s = s.trim_right();
s = s.trim_end();
}
s.chars()
......
......@@ -6,11 +6,12 @@ use std::ptr::NonNull;
use cairo::prelude::SurfaceExt;
use cairo::{self, ImageSurface};
use cairo_sys;
use gdk_pixbuf::{Colorspace, Pixbuf, PixbufExt};
use gdk_pixbuf::{Colorspace, Pixbuf};
use glib::translate::{Stash, ToGlibPtr};
use nalgebra::{storage::Storage, Dim, Matrix};
use rayon;
use io::BinaryData;
use rect::IRect;
use srgb;
use util::clamp;
......@@ -167,7 +168,12 @@ impl SharedImageSurface {
}
}
pub fn from_pixbuf(pixbuf: &Pixbuf) -> Result<SharedImageSurface, cairo::Status> {
/// Creates a surface from the pixbuf, and optionally attaches the
/// original MIME data to the Cairo surface.
pub fn from_pixbuf(
pixbuf: &Pixbuf,
data: Option<BinaryData>,
) -> Result<SharedImageSurface, cairo::Status> {
assert!(pixbuf.get_colorspace() == Colorspace::Rgb);
let n_channels = pixbuf.get_n_channels();
......@@ -231,6 +237,17 @@ impl SharedImageSurface {
}
}
if let Some(data) = data {
let BinaryData {
data: bytes,
content_type,
} = data;
if let Some(mime_type) = content_type {
surf.set_mime_data(&mime_type, bytes)?;
}
}
Self::new(surf, SurfaceType::SRgb)
}
......
use gdk_pixbuf::{PixbufLoader, PixbufLoaderExt};
use gio;
use glib::translate::*;
use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
......@@ -189,39 +188,13 @@ fn load_image(
let pixbuf = loader.get_pixbuf().ok_or(LoadingError::Unknown)?;
let surface = SharedImageSurface::from_pixbuf(&pixbuf)?;
if load_options.flags.keep_image_data {
if let Some(mime_type) = data.content_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,
) -> cairo_sys::cairo_status_t;
}
let data = if load_options.flags.keep_image_data {
Some(data)
} else {
None
};
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 != cairo_sys::STATUS_SUCCESS {
return Err(LoadingError::Cairo(status.into()));
}
}
}
}
let surface = SharedImageSurface::from_pixbuf(&pixbuf, data)?;
Ok(surface)
}
use libc;
use std::borrow::Cow;
use std::ffi::CStr;
use std::str;
......@@ -17,6 +18,14 @@ pub unsafe fn utf8_cstr<'a>(s: *const libc::c_char) -> &'a str {
str::from_utf8_unchecked(CStr::from_ptr(s).to_bytes())
}
/// Error-tolerant C string import
pub unsafe fn cstr<'a>(s: *const libc::c_char) -> Cow<'a, str> {
if s.is_null() {
return Cow::Borrowed("(null)");
}
CStr::from_ptr(s).to_string_lossy()
}
pub fn clamp<T: PartialOrd>(val: T, low: T, high: T) -> T {
if val < low {
low
......
......@@ -542,19 +542,6 @@ fn parse_xml_stylesheet_processing_instruction(data: &str) -> Result<Vec<(String
unreachable!();
}
#[no_mangle]
pub unsafe extern "C" fn rsvg_xml_state_error(xml: *mut XmlState, msg: *const libc::c_char) {
assert!(!xml.is_null());
let xml = &mut *xml;
assert!(!msg.is_null());
// Unlike the functions that take UTF-8 validated strings from
// libxml2, I don't trust error messages to be validated.
let msg: String = from_glib_none(msg);
xml.error(&msg);
}
#[cfg(test)]
mod tests {
use super::*;
......
......@@ -107,7 +107,7 @@ pub struct xmlSAXHandler {
pub _private: gpointer,
pub startElementNs: gpointer,
pub endElementNs: gpointer,
pub serror: gpointer,
pub serror: Option<unsafe extern "C" fn(user_data: *mut libc::c_void, error: xmlErrorPtr)>,
}
pub type xmlSAXHandlerPtr = *mut xmlSAXHandler;
......
......@@ -3,6 +3,7 @@
use gio;
use gio::prelude::*;
use std::borrow::Cow;
use std::cell::RefCell;
use std::mem;
use std::ptr;
......@@ -16,14 +17,11 @@ use error::LoadingError;
use handle::LoadFlags;
use io::get_input_stream_for_loading;
use property_bag::PropertyBag;
use util::cstr;
use util::utf8_cstr;
use xml::XmlState;
use xml2::*;
extern "C" {
fn rsvg_sax_error_cb(data: *mut libc::c_void);
}
fn get_xml2_sax_handler() -> xmlSAXHandler {
let mut h: xmlSAXHandler = unsafe { mem::zeroed() };
......@@ -36,14 +34,42 @@ fn get_xml2_sax_handler() -> xmlSAXHandler {
h.startElement = Some(sax_start_element_cb);
h.endElement = Some(sax_end_element_cb);
h.processingInstruction = Some(sax_processing_instruction_cb);
// This one is defined in the C code, because the prototype has varargs
// and we can't handle those from Rust :(
h.error = rsvg_sax_error_cb as *mut _;
h.serror = Some(rsvg_sax_serror_cb);
h
}
unsafe extern "C" fn rsvg_sax_serror_cb(user_data: *mut libc::c_void, error: xmlErrorPtr) {
let state = (user_data as *mut XmlState).as_mut().unwrap();
let error = error.as_ref().unwrap();
let level_name = match error.level {
1 => "warning",
2 => "error",
3 => "fatal error",
_ => "unknown error",
};
// "int2" is the column number
let column = if error.int2 > 0 {
Cow::Owned(format!(":{}", error.int2))
} else {
Cow::Borrowed("")
};
let full_error_message = format!(
"{} code={} ({}) in {}:{}{}: {}",
level_name,
error.code,
error.domain,
cstr(error.file),
error.line,
column,
cstr(error.message)
);
state.error(&full_error_message);
}
fn free_xml_parser_and_doc(parser: xmlParserCtxtPtr) {
// Free the ctxt and its ctxt->myDoc - libxml2 doesn't free them together
// http://xmlsoft.org/html/libxml-parser.html#xmlFreeParserCtxt
......
......@@ -12,7 +12,8 @@
#include "test-utils.h"
/*
rsvg_handle_internal_set_testing
Untested:
rsvg_handle_internal_set_testing
*/
static void
......@@ -25,6 +26,104 @@ handle_has_gtype (void)
g_object_unref (handle);
}
static gboolean
flags_value_matches (GFlagsValue *v,
guint value,
const char *value_name,
const char *value_nick)
{
return (v->value == value
&& strcmp (v->value_name, value_name) == 0
&& strcmp (v->value_nick, value_nick) == 0);
}
static void
flags_registration (void)
{
GType ty;
GTypeQuery q;
GTypeClass *type_class;
GFlagsClass *flags_class;
ty = RSVG_TYPE_HANDLE_FLAGS;
g_assert (ty != G_TYPE_INVALID);
g_type_query (RSVG_TYPE_HANDLE_FLAGS, &q);
g_assert (q.type == ty);
g_assert (G_TYPE_IS_FLAGS (q.type));
g_assert_cmpstr (q.type_name, ==, "RsvgHandleFlags");
type_class = g_type_class_ref (ty);
g_assert (G_IS_FLAGS_CLASS (type_class));
g_assert (G_FLAGS_CLASS_TYPE (type_class) == ty);
flags_class = G_FLAGS_CLASS (type_class);
g_assert (flags_class->n_values == 3);
g_assert (flags_value_matches(&flags_class->values[0],
RSVG_HANDLE_FLAGS_NONE,
"RSVG_HANDLE_FLAGS_NONE",
"flags-none"));
g_assert (flags_value_matches(&flags_class->values[1],
RSVG_HANDLE_FLAG_UNLIMITED,
"RSVG_HANDLE_FLAG_UNLIMITED",
"flag-unlimited"));
g_assert (flags_value_matches(&flags_class->values[2],
RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA,
"RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA",
"flag-keep-image-data"));
g_type_class_unref (type_class);
}
static gboolean
enum_value_matches (GEnumValue *v,
gint value,
const char *value_name,
const char *value_nick)
{
return (v->value == value
&& strcmp (v->value_name, value_name) == 0
&& strcmp (v->value_nick, value_nick) == 0);
}
static void
error_registration (void)
{
GType ty;
GTypeQuery q;
GTypeClass *type_class;
GEnumClass *enum_class;
g_assert_cmpint (RSVG_ERROR, !=, 0);
ty = RSVG_TYPE_ERROR;
g_assert (ty != G_TYPE_INVALID);
g_type_query (ty, &q);
g_assert (q.type == ty);
g_assert (G_TYPE_IS_ENUM (q.type));
g_assert_cmpstr (q.type_name, ==, "RsvgError");
type_class = g_type_class_ref (ty);
g_assert (G_IS_ENUM_CLASS (type_class));
g_assert (G_ENUM_CLASS_TYPE (type_class) == ty);
enum_class = G_ENUM_CLASS (type_class);
g_assert (enum_class->n_values == 1);
g_assert (enum_value_matches (&enum_class->values[0],
RSVG_ERROR_FAILED,
"RSVG_ERROR_FAILED",
"failed"));
g_type_class_unref (type_class);
}
static char *
get_test_filename (const char *basename) {
return g_build_filename (test_utils_get_test_data_path (),
......@@ -204,26 +303,6 @@ set_dpi (void)
g_free (filename);
}
static void
error_quark (void)
{
g_assert_cmpint (rsvg_error_quark(), !=, 0);
}
static void
auto_generated (void)
{
GTypeQuery q;
g_type_query (RSVG_TYPE_ERROR, &q);
g_assert (G_TYPE_IS_ENUM (q.type));
g_assert_cmpstr (q.type_name, ==, "RsvgError");
g_type_query (RSVG_TYPE_HANDLE_FLAGS, &q);
g_assert (G_TYPE_IS_FLAGS (q.type));
g_assert_cmpstr (q.type_name, ==, "RsvgHandleFlags");
}
static void
base_uri (void)
{
......@@ -944,10 +1023,10 @@ main (int argc, char **argv)
}
g_test_add_func ("/api/handle_has_gtype", handle_has_gtype);
g_test_add_func ("/api/flags_registration", flags_registration);
g_test_add_func ("/api/error_registration", error_registration);
g_test_add_func ("/api/noops", noops);
g_test_add_func ("/api/set_dpi", set_dpi);
g_test_add_func ("/api/error_quark", error_quark);
g_test_add_func ("/api/auto_generated", auto_generated);
g_test_add_func ("/api/base_uri", base_uri);
g_test_add_func ("/api/base_gfile", base_gfile);
g_test_add_func ("/api/handle_write_close_free", handle_write_close_free);
......