diff options
Diffstat (limited to 'rsvg-rs')
-rw-r--r-- | rsvg-rs/.gitignore | 5 | ||||
-rw-r--r-- | rsvg-rs/CHANGELOG.md | 15 | ||||
-rw-r--r-- | rsvg-rs/Cargo.toml | 34 | ||||
-rw-r--r-- | rsvg-rs/Gir.toml | 38 | ||||
-rw-r--r-- | rsvg-rs/Makefile | 32 | ||||
-rw-r--r-- | rsvg-rs/README.md | 17 | ||||
-rw-r--r-- | rsvg-rs/rsvg-sys/Cargo.toml | 30 | ||||
-rw-r--r-- | rsvg-rs/rsvg-sys/Gir.toml | 12 | ||||
-rw-r--r-- | rsvg-rs/rsvg-sys/build.rs | 61 | ||||
-rw-r--r-- | rsvg-rs/rsvg-sys/src/lib.rs | 160 | ||||
-rw-r--r-- | rsvg-rs/src/auto/enums.rs | 6 | ||||
-rw-r--r-- | rsvg-rs/src/auto/flags.rs | 58 | ||||
-rw-r--r-- | rsvg-rs/src/auto/handle.rs | 574 | ||||
-rw-r--r-- | rsvg-rs/src/auto/mod.rs | 14 | ||||
-rw-r--r-- | rsvg-rs/src/dimension_data.rs | 67 | ||||
-rw-r--r-- | rsvg-rs/src/handle.rs | 16 | ||||
-rw-r--r-- | rsvg-rs/src/lib.rs | 125 | ||||
-rw-r--r-- | rsvg-rs/src/position_data.rs | 67 |
18 files changed, 1331 insertions, 0 deletions
diff --git a/rsvg-rs/.gitignore b/rsvg-rs/.gitignore new file mode 100644 index 00000000..5141448e --- /dev/null +++ b/rsvg-rs/.gitignore @@ -0,0 +1,5 @@ +.idea +target/ +**/*.rs.bk +Cargo.lock +vendor.md
\ No newline at end of file diff --git a/rsvg-rs/CHANGELOG.md b/rsvg-rs/CHANGELOG.md new file mode 100644 index 00000000..bcc0e694 --- /dev/null +++ b/rsvg-rs/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog + +### 0.3.0 + +- Works with `gtk = "0.3.0"` + +### 0.2.0 + +- Works with `gtk = "0.2.0"` +- Regenerated API (`HandleExt` trait introduced) + +### 0.1.3 + +- Initial commit +- Works with `gtk = "0.1.3"` diff --git a/rsvg-rs/Cargo.toml b/rsvg-rs/Cargo.toml new file mode 100644 index 00000000..24cf5d96 --- /dev/null +++ b/rsvg-rs/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "rsvg" +version = "0.3.0" +authors = ["selaux"] +description = "Rust bindings for the Rsvg library" +repository = "https://github.com/selaux/rsvg-rs" +license = "MIT" + +keywords = ["rsvg", "svg", "gtk-rs"] +include = ["src/**/*", "Cargo.toml"] + +[lib] +name = "rsvg" + +[dependencies] +libc = "0.2" +bitflags = "0.9" +glib = "0.4.0" +glib-sys = "0.5.0" +gobject-sys = "0.5.0" +gdk-pixbuf = "0.3.0" + +[dev-dependencies] +# image = "0.13.0" +# imageproc = "0.8.0" +gtk = "0.3.0" + +[dependencies.cairo-rs] +version = "0.3.0" +features = ["png"] + +[dependencies.rsvg-sys] +version = "0.5.0" +path = "./rsvg-sys" diff --git a/rsvg-rs/Gir.toml b/rsvg-rs/Gir.toml new file mode 100644 index 00000000..d71fafa2 --- /dev/null +++ b/rsvg-rs/Gir.toml @@ -0,0 +1,38 @@ +[options] +girs_dir = "gir-files" +library = "Rsvg" +version = "2.0" +min_cfg_version = "2.36" +target_path = "." +work_mode = "normal" +generate_safety_asserts = false +deprecate_by_min_version = true + +generate = [ + "Rsvg.HandleFlags" +] + +manual = [ + "Rsvg.DimensionData", + "Rsvg.PositionData", + "cairo.Context", + "GdkPixbuf.Pixbuf", + "GLib.Error" +] + +[[object]] +name = "Rsvg.Handle" +status = "generate" + [[object.function]] + pattern = "render_cairo(_sub)?" + [[object.function.parameter]] + name = "cr" + const = true + + [[object.function]] + name = "get_base_uri" + ignore = true + + [[object.property]] + name = "base-uri" + ignore = true
\ No newline at end of file diff --git a/rsvg-rs/Makefile b/rsvg-rs/Makefile new file mode 100644 index 00000000..56558613 --- /dev/null +++ b/rsvg-rs/Makefile @@ -0,0 +1,32 @@ +RUSTDOC_STRIPPER = target/rustdoc-stripper/bin/rustdoc-stripper +GIR = target/gir/bin/gir +GIR_FILES = $(shell pkg-config --variable girdir gobject-introspection-1.0) +SYS_FILES = rsvg-sys/src/lib.rs +DOCS = vendor.md + +src/auto/mod.rs : Gir.toml $(GIR) $(RUSTDOC_STRIPPER) $(GIR_FILES) $(SYS_FILES) $(DOCS) + $(GIR) -c Gir.toml -d $(GIR_FILES) + $(RUSTDOC_STRIPPER) -g -o $(DOCS) -d src/auto + +$(DOCS): Gir.toml $(GIR) $(GIR_FILES) + $(GIR) -c $< -d $(GIR_FILES) -m doc + +.PHONY: clean +clean: + rm -rf src/auto $(SYS_FILES) $(DOCS) + +$(SYS_FILES): rsvg-sys/Gir.toml $(GIR) $(GIR_FILES) + $(GIR) -c $< -o $(abspath rsvg-sys) -d $(GIR_FILES) + +$(RUSTDOC_STRIPPER) : + cargo install --root target/rustdoc-stripper rustdoc-stripper --version "0.1.5" + +$(GIR) : + cargo install --root target/gir --git https://github.com/gtk-rs/gir --rev d50d839ceaed9cc5eabac729dbc161c295306270 gir + +.PHONY: gir +gir : src/auto/mod.rs + +.PHONY: gir-sys +gir-sys : $(SYS_FILES) + diff --git a/rsvg-rs/README.md b/rsvg-rs/README.md new file mode 100644 index 00000000..ae9f76e4 --- /dev/null +++ b/rsvg-rs/README.md @@ -0,0 +1,17 @@ +# rsvg-rs + +[](https://crates.io/crates/rsvg) +[](https://docs.rs/crate/rsvg) +[](https://travis-ci.org/selaux/rsvg-rs) + +[libRSVG](https://wiki.gnome.org/action/show/Projects/LibRsvg?action=show&redirect=LibRsvg) bindings for Rust. + +Based on [Gtk-rs project](http://gtk-rs.org/) bindings. + +## Example + +See [examples folder](/examples) + +## License + +MIT diff --git a/rsvg-rs/rsvg-sys/Cargo.toml b/rsvg-rs/rsvg-sys/Cargo.toml new file mode 100644 index 00000000..b0d01985 --- /dev/null +++ b/rsvg-rs/rsvg-sys/Cargo.toml @@ -0,0 +1,30 @@ +[build-dependencies] +pkg-config = "0.3.7" + +[dependencies] +atk-sys = "0.5.0" +bitflags = "1.0" +cairo-sys-rs = "0.5.0" +gdk-pixbuf-sys = "0.5.0" +gdk-sys = "0.5.0" +gio-sys = "0.5.0" +glib-sys = "0.5.0" +gobject-sys = "0.5.0" +libc = "0.2" +pango-sys = "0.5.0" + +[features] +dox = [] + +[lib] +name = "rsvg_sys" + +[package] +authors = ["selaux"] +build = "build.rs" +description = "Rust bindings for the Rsvg library (ffi)" +license = "MIT" +links = "rsvg" +name = "rsvg-sys" +repository = "https://github.com/selaux/rsvg-rs" +version = "0.5.0" diff --git a/rsvg-rs/rsvg-sys/Gir.toml b/rsvg-rs/rsvg-sys/Gir.toml new file mode 100644 index 00000000..980c87a8 --- /dev/null +++ b/rsvg-rs/rsvg-sys/Gir.toml @@ -0,0 +1,12 @@ +[options] +work_mode = "sys" +library = "Rsvg" +version = "2.0" +min_cfg_version = "2.36" +external_libraries = [ + "GLib", + "GObject", + "Gio", + "GdkPixbuf", + "Cairo", +] diff --git a/rsvg-rs/rsvg-sys/build.rs b/rsvg-rs/rsvg-sys/build.rs new file mode 100644 index 00000000..405c80f8 --- /dev/null +++ b/rsvg-rs/rsvg-sys/build.rs @@ -0,0 +1,61 @@ +extern crate pkg_config; + +use pkg_config::{Config, Error}; +use std::env; +use std::io::prelude::*; +use std::io; +use std::process; + +fn main() { + if let Err(s) = find() { + let _ = writeln!(io::stderr(), "{}", s); + process::exit(1); + } +} + +fn find() -> Result<(), Error> { + let package_name = "librsvg-2.0"; + let shared_libs = ["rsvg-2"]; + let version = { + "2.36" + }; + + if let Ok(lib_dir) = env::var("GTK_LIB_DIR") { + for lib_ in shared_libs.iter() { + println!("cargo:rustc-link-lib=dylib={}", lib_); + } + println!("cargo:rustc-link-search=native={}", lib_dir); + return Ok(()) + } + + let target = env::var("TARGET").expect("TARGET environment variable doesn't exist"); + let hardcode_shared_libs = target.contains("windows"); + + let mut config = Config::new(); + config.atleast_version(version); + if hardcode_shared_libs { + config.cargo_metadata(false); + } + match config.probe(package_name) { + Ok(library) => { + if hardcode_shared_libs { + for lib_ in shared_libs.iter() { + println!("cargo:rustc-link-lib=dylib={}", lib_); + } + for path in library.link_paths.iter() { + println!("cargo:rustc-link-search=native={}", + path.to_str().expect("library path doesn't exist")); + } + } + Ok(()) + } + Err(Error::EnvNoPkgConfig(_)) | Err(Error::Command { .. }) => { + for lib_ in shared_libs.iter() { + println!("cargo:rustc-link-lib=dylib={}", lib_); + } + Ok(()) + } + Err(err) => Err(err), + } +} + diff --git a/rsvg-rs/rsvg-sys/src/lib.rs b/rsvg-rs/rsvg-sys/src/lib.rs new file mode 100644 index 00000000..7fe0ea91 --- /dev/null +++ b/rsvg-rs/rsvg-sys/src/lib.rs @@ -0,0 +1,160 @@ +// This file was generated by gir (d50d839) from gir-files (???) +// DO NOT EDIT + +#![allow(non_camel_case_types, non_upper_case_globals)] + +extern crate libc; +#[macro_use] extern crate bitflags; +extern crate glib_sys as glib; +extern crate gobject_sys as gobject; +extern crate gio_sys as gio; +extern crate gdk_pixbuf_sys as gdk_pixbuf; +extern crate cairo_sys as cairo; + +#[allow(unused_imports)] +use libc::{c_int, c_char, c_uchar, c_float, c_uint, c_double, + c_short, c_ushort, c_long, c_ulong, + c_void, size_t, ssize_t, intptr_t, uintptr_t, time_t, FILE}; + +#[allow(unused_imports)] +use glib::{gboolean, gconstpointer, gpointer, GType, Volatile}; + +// Enums +pub type Error = c_int; +pub const RSVG_ERROR_FAILED: Error = 0; +pub type RsvgError = Error; + +// Constants +pub const LIBRSVG_MAJOR_VERSION: c_int = 2; +pub const LIBRSVG_MICRO_VERSION: c_int = 2; +pub const LIBRSVG_MINOR_VERSION: c_int = 42; +pub const LIBRSVG_VERSION: *const c_char = b"2.42.2\0" as *const u8 as *const c_char; + +// Flags +bitflags! { + #[repr(C)] + pub struct RsvgHandleFlags: c_uint { + const FLAGS_NONE = 0; + const FLAG_UNLIMITED = 1; + const FLAG_KEEP_IMAGE_DATA = 2; + } +} +pub const RSVG_HANDLE_FLAGS_NONE: RsvgHandleFlags = RsvgHandleFlags::FLAGS_NONE; +pub const RSVG_HANDLE_FLAG_UNLIMITED: RsvgHandleFlags = RsvgHandleFlags::FLAG_UNLIMITED; +pub const RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA: RsvgHandleFlags = RsvgHandleFlags::FLAG_KEEP_IMAGE_DATA; + +// Records +#[repr(C)] +pub struct RsvgDimensionData { + pub width: c_int, + pub height: c_int, + pub em: c_double, + pub ex: c_double, +} + +impl ::std::fmt::Debug for RsvgDimensionData { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "RsvgDimensionData @ {:?}", self as *const _) + } +} + +#[repr(C)] +pub struct RsvgHandleClass { + pub parent: gobject::GObjectClass, + pub _abi_padding: [gpointer; 15], +} + +impl ::std::fmt::Debug for RsvgHandleClass { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "RsvgHandleClass @ {:?}", self as *const _) + } +} + +#[repr(C)] +pub struct RsvgHandlePrivate(c_void); + +impl ::std::fmt::Debug for RsvgHandlePrivate { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "RsvgHandlePrivate @ {:?}", self as *const _) + } +} + +#[repr(C)] +pub struct RsvgPositionData { + pub x: c_int, + pub y: c_int, +} + +impl ::std::fmt::Debug for RsvgPositionData { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "RsvgPositionData @ {:?}", self as *const _) + } +} + +// Classes +#[repr(C)] +pub struct RsvgHandle { + pub parent: gobject::GObject, + pub priv_: *mut RsvgHandlePrivate, + pub _abi_padding: [gpointer; 15], +} + +impl ::std::fmt::Debug for RsvgHandle { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("RsvgHandle @ {:?}", self as *const _)) + .field("parent", &self.parent) + .field("priv_", &self.priv_) + .field("_abi_padding", &self._abi_padding) + .finish() + } +} + +extern "C" { + + //========================================================================= + // RsvgError + //========================================================================= + pub fn rsvg_error_get_type() -> GType; + pub fn rsvg_error_quark() -> glib::GQuark; + + //========================================================================= + // RsvgHandleFlags + //========================================================================= + pub fn rsvg_handle_flags_get_type() -> GType; + + //========================================================================= + // RsvgHandle + //========================================================================= + pub fn rsvg_handle_get_type() -> GType; + pub fn rsvg_handle_new() -> *mut RsvgHandle; + pub fn rsvg_handle_new_from_data(data: *mut u8, data_len: size_t, error: *mut *mut glib::GError) -> *mut RsvgHandle; + pub fn rsvg_handle_new_from_file(file_name: *const c_char, error: *mut *mut glib::GError) -> *mut RsvgHandle; + pub fn rsvg_handle_new_from_gfile_sync(file: *mut gio::GFile, flags: RsvgHandleFlags, cancellable: *mut gio::GCancellable, error: *mut *mut glib::GError) -> *mut RsvgHandle; + pub fn rsvg_handle_new_from_stream_sync(input_stream: *mut gio::GInputStream, base_file: *mut gio::GFile, flags: RsvgHandleFlags, cancellable: *mut gio::GCancellable, error: *mut *mut glib::GError) -> *mut RsvgHandle; + pub fn rsvg_handle_new_with_flags(flags: RsvgHandleFlags) -> *mut RsvgHandle; + pub fn rsvg_handle_close(handle: *mut RsvgHandle, error: *mut *mut glib::GError) -> gboolean; + pub fn rsvg_handle_get_base_uri(handle: *mut RsvgHandle) -> *const c_char; + pub fn rsvg_handle_get_dimensions(handle: *mut RsvgHandle, dimension_data: *mut RsvgDimensionData); + pub fn rsvg_handle_get_dimensions_sub(handle: *mut RsvgHandle, dimension_data: *mut RsvgDimensionData, id: *const c_char) -> gboolean; + pub fn rsvg_handle_get_pixbuf(handle: *mut RsvgHandle) -> *mut gdk_pixbuf::GdkPixbuf; + pub fn rsvg_handle_get_pixbuf_sub(handle: *mut RsvgHandle, id: *const c_char) -> *mut gdk_pixbuf::GdkPixbuf; + pub fn rsvg_handle_get_position_sub(handle: *mut RsvgHandle, position_data: *mut RsvgPositionData, id: *const c_char) -> gboolean; + pub fn rsvg_handle_has_sub(handle: *mut RsvgHandle, id: *const c_char) -> gboolean; + pub fn rsvg_handle_internal_set_testing(handle: *mut RsvgHandle, testing: gboolean); + pub fn rsvg_handle_read_stream_sync(handle: *mut RsvgHandle, stream: *mut gio::GInputStream, cancellable: *mut gio::GCancellable, error: *mut *mut glib::GError) -> gboolean; + pub fn rsvg_handle_render_cairo(handle: *mut RsvgHandle, cr: *mut cairo::cairo_t) -> gboolean; + pub fn rsvg_handle_render_cairo_sub(handle: *mut RsvgHandle, cr: *mut cairo::cairo_t, id: *const c_char) -> gboolean; + pub fn rsvg_handle_set_base_gfile(handle: *mut RsvgHandle, base_file: *mut gio::GFile); + pub fn rsvg_handle_set_base_uri(handle: *mut RsvgHandle, base_uri: *const c_char); + pub fn rsvg_handle_set_dpi(handle: *mut RsvgHandle, dpi: c_double); + pub fn rsvg_handle_set_dpi_x_y(handle: *mut RsvgHandle, dpi_x: c_double, dpi_y: c_double); + pub fn rsvg_handle_write(handle: *mut RsvgHandle, buf: *mut u8, count: size_t, error: *mut *mut glib::GError) -> gboolean; + + //========================================================================= + // Other functions + //========================================================================= + pub fn rsvg_cleanup(); + pub fn rsvg_set_default_dpi(dpi: c_double); + pub fn rsvg_set_default_dpi_x_y(dpi_x: c_double, dpi_y: c_double); + +} diff --git a/rsvg-rs/src/auto/enums.rs b/rsvg-rs/src/auto/enums.rs new file mode 100644 index 00000000..956a81a1 --- /dev/null +++ b/rsvg-rs/src/auto/enums.rs @@ -0,0 +1,6 @@ +// This file was generated by gir (d50d839) from gir-files (???) +// DO NOT EDIT + +use ffi; +use glib::translate::*; + diff --git a/rsvg-rs/src/auto/flags.rs b/rsvg-rs/src/auto/flags.rs new file mode 100644 index 00000000..b53bd76b --- /dev/null +++ b/rsvg-rs/src/auto/flags.rs @@ -0,0 +1,58 @@ +// This file was generated by gir (d50d839) from gir-files (???) +// DO NOT EDIT + +use ffi; +use glib::Type; +use glib::StaticType; +use glib::value::{Value, SetValue, FromValue, FromValueOptional}; +use gobject_ffi; +use glib::translate::*; + +bitflags! { + pub struct HandleFlags: u32 { + const FLAGS_NONE = 0; + const FLAG_UNLIMITED = 1; + const FLAG_KEEP_IMAGE_DATA = 2; + } +} + +#[doc(hidden)] +impl ToGlib for HandleFlags { + type GlibType = ffi::RsvgHandleFlags; + + fn to_glib(&self) -> ffi::RsvgHandleFlags { + ffi::RsvgHandleFlags::from_bits_truncate(self.bits()) + } +} + +#[doc(hidden)] +impl FromGlib<ffi::RsvgHandleFlags> for HandleFlags { + fn from_glib(value: ffi::RsvgHandleFlags) -> HandleFlags { + HandleFlags::from_bits_truncate(value.bits()) + } +} + +impl StaticType for HandleFlags { + fn static_type() -> Type { + unsafe { from_glib(ffi::rsvg_handle_flags_get_type()) } + } +} + +impl<'a> FromValueOptional<'a> for HandleFlags { + unsafe fn from_value_optional(value: &Value) -> Option<Self> { + Some(FromValue::from_value(value)) + } +} + +impl<'a> FromValue<'a> for HandleFlags { + unsafe fn from_value(value: &Value) -> Self { + from_glib(ffi::RsvgHandleFlags::from_bits_truncate(gobject_ffi::g_value_get_flags(value.to_glib_none().0))) + } +} + +impl SetValue for HandleFlags { + unsafe fn set_value(value: &mut Value, this: &Self) { + gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, this.to_glib().bits()) + } +} + diff --git a/rsvg-rs/src/auto/handle.rs b/rsvg-rs/src/auto/handle.rs new file mode 100644 index 00000000..9f7a342c --- /dev/null +++ b/rsvg-rs/src/auto/handle.rs @@ -0,0 +1,574 @@ +// This file was generated by gir (d50d839) from gir-files (???) +// DO NOT EDIT + +use DimensionData; +use Error; +use HandleFlags; +use PositionData; +use cairo; +use ffi; +use gdk_pixbuf; +use glib; +use glib::StaticType; +use glib::Value; +use glib::object::Downcast; +use glib::object::IsA; +use glib::signal::SignalHandlerId; +use glib::signal::connect; +use glib::translate::*; +use glib_ffi; +use gobject_ffi; +use std::boxed::Box as Box_; +use std::mem; +use std::mem::transmute; +use std::ptr; + +glib_wrapper! { + pub struct Handle(Object<ffi::RsvgHandle, ffi::RsvgHandleClass>); + + match fn { + get_type => || ffi::rsvg_handle_get_type(), + } +} + +impl Handle { + /// Returns a new rsvg handle. Must be freed with `gobject::Object::unref`. This + /// handle can be used for dynamically loading an image. You need to feed it + /// data using `HandleExt::write`, then call `HandleExt::close` when done. + /// Afterwords, you can render it using Cairo or get a `gdk_pixbuf::Pixbuf` from it. When + /// finished, free with `gobject::Object::unref`. No more than one image can be loaded + /// with one handle. + /// + /// # Returns + /// + /// A new `Handle` + pub fn new() -> Handle { + unsafe { + from_glib_full(ffi::rsvg_handle_new()) + } + } + + /// Loads the SVG specified by `data`. + /// ## `data` + /// The SVG data + /// ## `data_len` + /// The length of `data`, in bytes + /// + /// # Returns + /// + /// A `Handle` or `None` if an error occurs. + pub fn new_from_data(data: &[u8]) -> Result<Handle, Error> { + let data_len = data.len() as usize; + unsafe { + let mut error = ptr::null_mut(); + let ret = ffi::rsvg_handle_new_from_data(data.to_glib_none().0, data_len, &mut error); + if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } + } + } + + /// Loads the SVG specified by `file_name`. + /// ## `file_name` + /// The file name to load. If built with gnome-vfs, can be a URI. + /// + /// # Returns + /// + /// A `Handle` or `None` if an error occurs. + pub fn new_from_file(file_name: &str) -> Result<Handle, Error> { + unsafe { + let mut error = ptr::null_mut(); + let ret = ffi::rsvg_handle_new_from_file(file_name.to_glib_none().0, &mut error); + if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } + } + } + + //pub fn new_from_gfile_sync<'a, P: IsA</*Ignored*/gio::File>, Q: Into<Option<&'a /*Ignored*/gio::Cancellable>>>(file: &P, flags: HandleFlags, cancellable: Q) -> Result<Handle, Error> { + // unsafe { TODO: call ffi::rsvg_handle_new_from_gfile_sync() } + //} + + //pub fn new_from_stream_sync<'a, 'b, P: IsA</*Ignored*/gio::InputStream>, Q: IsA</*Ignored*/gio::File> + 'a, R: Into<Option<&'a Q>>, S: Into<Option<&'b /*Ignored*/gio::Cancellable>>>(input_stream: &P, base_file: R, flags: HandleFlags, cancellable: S) -> Result<Handle, Error> { + // unsafe { TODO: call ffi::rsvg_handle_new_from_stream_sync() } + //} + + /// Creates a new `Handle` with flags `flags`. + /// ## `flags` + /// flags from `HandleFlags` + /// + /// # Returns + /// + /// a new `Handle` + pub fn new_with_flags(flags: HandleFlags) -> Handle { + unsafe { + from_glib_full(ffi::rsvg_handle_new_with_flags(flags.to_glib())) + } + } +} + +impl Default for Handle { + fn default() -> Self { + Self::new() + } +} + +/// Trait containing all `Handle` methods. +/// +/// # Implementors +/// +/// [`Handle`](struct.Handle.html) +pub trait HandleExt { + /// Closes `self`, to indicate that loading the image is complete. This will + /// return `true` if the loader closed successfully. Note that `self` isn't + /// freed until `gobject::Object::unref` is called. + /// + /// # Returns + /// + /// `true` on success, or `false` on error + fn close(&self) -> Result<(), Error>; + + /// Get the SVG's size. Do not call from within the size_func callback, because an infinite loop will occur. + /// ## `dimension_data` + /// A place to store the SVG's size + fn get_dimensions(&self) -> DimensionData; + + /// Get the size of a subelement of the SVG file. Do not call from within the + /// size_func callback, because an infinite loop will occur. + /// ## `dimension_data` + /// A place to store the SVG's size + /// ## `id` + /// An element's id within the SVG, starting with "##", for + /// example, "#`layer1`"; or `None` to use the whole SVG. + fn get_dimensions_sub<'a, P: Into<Option<&'a str>>>(&self, id: P) -> Option<DimensionData>; + + /// Returns the pixbuf loaded by `self`. The pixbuf returned will be reffed, so + /// the caller of this function must assume that ref. If insufficient data has + /// been read to create the pixbuf, or an error occurred in loading, then `None` + /// will be returned. Note that the pixbuf may not be complete until + /// `HandleExt::close` has been called. + /// + /// # Returns + /// + /// the pixbuf loaded by `self`, or `None`. + fn get_pixbuf(&self) -> Option<gdk_pixbuf::Pixbuf>; + + /// Returns the pixbuf loaded by `self`. The pixbuf returned will be reffed, so + /// the caller of this function must assume that ref. If insufficient data has + /// been read to create the pixbuf, or an error occurred in loading, then `None` + /// will be returned. Note that the pixbuf may not be complete until + /// `HandleExt::close` has been called. + /// ## `id` + /// An element's id within the SVG, starting with "##", for + /// example, "#`layer1`"; or `None` to use the whole SVG. + /// + /// # Returns + /// + /// the pixbuf loaded by `self`, or `None`. + fn get_pixbuf_sub<'a, P: Into<Option<&'a str>>>(&self, id: P) -> Option<gdk_pixbuf::Pixbuf>; + + /// Get the position of a subelement of the SVG file. Do not call from within + /// the size_func callback, because an infinite loop will occur. + /// ## `position_data` + /// A place to store the SVG fragment's position. + /// ## `id` + /// An element's id within the SVG, starting with "##", for + /// example, "#`layer1`"; or `None` to use the whole SVG. + fn get_position_sub<'a, P: Into<Option<&'a str>>>(&self, id: P) -> Option<PositionData>; + + /// Checks whether the element `id` exists in the SVG document. + /// ## `id` + /// an element's id within the SVG, starting with "##", for example, "#`layer1`". + /// + /// # Returns + /// + /// `true` if `id` exists in the SVG document + fn has_sub(&self, id: &str) -> bool; + + fn internal_set_testing(&self, testing: bool); + + //fn read_stream_sync<'a, P: IsA</*Ignored*/gio::InputStream>, Q: Into<Option<&'a /*Ignored*/gio::Cancellable>>>(&self, stream: &P, cancellable: Q) -> Result<(), Error>; + + /// Draws a SVG to a Cairo surface + /// ## `cr` + /// A Cairo renderer + /// + /// # Returns + /// + /// `true` if drawing succeeded. + fn render_cairo(&self, cr: &cairo::Context) -> bool; + + /// Draws a subset of a SVG to a Cairo surface + /// ## `cr` + /// A Cairo renderer + /// ## `id` + /// An element's id within the SVG, or `None` to render + /// the whole SVG. For example, if you have a layer called "layer1" + /// that you wish to render, pass "#`layer1`" as the id. + /// + /// # Returns + /// + /// `true` if drawing succeeded. + fn render_cairo_sub<'a, P: Into<Option<&'a str>>>(&self, cr: &cairo::Context, id: P) -> bool; + + //fn set_base_gfile<P: IsA</*Ignored*/gio::File>>(&self, base_file: &P); + + /// Set the base URI for this SVG. This can only be called before `HandleExt::write` + /// has been called. + /// ## `base_uri` + /// The base uri + fn set_base_uri(&self, base_uri: &str); + + /// Sets the DPI for the outgoing pixbuf. Common values are + /// 75, 90, and 300 DPI. Passing a number <= 0 to `dpi` will + /// reset the DPI to whatever the default value happens to be. + /// ## `dpi` + /// Dots Per Inch (aka Pixels Per Inch) + fn set_dpi(&self, dpi: f64); + + /// Sets the DPI for the outgoing pixbuf. Common values are + /// 75, 90, and 300 DPI. Passing a number <= 0 to `dpi_x` or `dpi_y` will + /// reset the DPI to whatever the default value happens to be. + /// ## `dpi_x` + /// Dots Per Inch (aka Pixels Per Inch) + /// ## `dpi_y` + /// Dots Per Inch (aka Pixels Per Inch) + fn set_dpi_x_y(&self, dpi_x: f64, dpi_y: f64); + + /// Loads the next `count` bytes of the image. This will return `true` if the data + /// was loaded successful, and `false` if an error occurred. In the latter case, + /// the loader will be closed, and will not accept further writes. If `false` is + /// returned, `error` will be set to an error from the `Error` domain. Errors + /// from `gio::IOErrorEnum` are also possible. + /// ## `buf` + /// pointer to svg data + /// ## `count` + /// length of the `buf` buffer in bytes + /// + /// # Returns + /// + /// `true` on success, or `false` on error + fn write(&self, buf: &[u8]) -> Result<(), Error>; + + fn get_property_dpi_x(&self) -> f64; + + fn set_property_dpi_x(&self, dpi_x: f64); + + fn get_property_dpi_y(&self) -> f64; + + fn set_property_dpi_y(&self, dpi_y: f64); + + fn get_property_em(&self) -> f64; + + fn get_property_ex(&self) -> f64; + + /// Flags from `HandleFlags`. + fn get_property_flags(&self) -> HandleFlags; + + fn get_property_height(&self) -> i32; + + fn get_property_width(&self) -> i32; + + fn connect_property_dpi_x_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId; + + fn connect_property_dpi_y_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId; + + fn connect_property_em_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId; + + fn connect_property_ex_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId; + + fn connect_property_flags_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId; + + fn connect_property_height_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId; + + fn connect_property_width_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId; +} + +impl<O: IsA<Handle> + IsA<glib::object::Object>> HandleExt for O { + fn close(&self) -> Result<(), Error> { + unsafe { + let mut error = ptr::null_mut(); + let _ = ffi::rsvg_handle_close(self.to_glib_none().0, &mut error); + if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } + } + } + + fn get_dimensions(&self) -> DimensionData { + unsafe { + let mut dimension_data = DimensionData::uninitialized(); + ffi::rsvg_handle_get_dimensions(self.to_glib_none().0, dimension_data.to_glib_none_mut().0); + dimension_data + } + } + + fn get_dimensions_sub<'a, P: Into<Option<&'a str>>>(&self, id: P) -> Option<DimensionData> { + let id = id.into(); + let id = id.to_glib_none(); + unsafe { + let mut dimension_data = DimensionData::uninitialized(); + let ret = from_glib(ffi::rsvg_handle_get_dimensions_sub(self.to_glib_none().0, dimension_data.to_glib_none_mut().0, id.0)); + if ret { Some(dimension_data) } else { None } + } + } + + fn get_pixbuf(&self) -> Option<gdk_pixbuf::Pixbuf> { + unsafe { + from_glib_full(ffi::rsvg_handle_get_pixbuf(self.to_glib_none().0)) + } + } + + fn get_pixbuf_sub<'a, P: Into<Option<&'a str>>>(&self, id: P) -> Option<gdk_pixbuf::Pixbuf> { + let id = id.into(); + let id = id.to_glib_none(); + unsafe { + from_glib_full(ffi::rsvg_handle_get_pixbuf_sub(self.to_glib_none().0, id.0)) + } + } + + fn get_position_sub<'a, P: Into<Option<&'a str>>>(&self, id: P) -> Option<PositionData> { + let id = id.into(); + let id = id.to_glib_none(); + unsafe { + let mut position_data = PositionData::uninitialized(); + let ret = from_glib(ffi::rsvg_handle_get_position_sub(self.to_glib_none().0, position_data.to_glib_none_mut().0, id.0)); + if ret { Some(position_data) } else { None } + } + } + + fn has_sub(&self, id: &str) -> bool { + unsafe { + from_glib(ffi::rsvg_handle_has_sub(self.to_glib_none().0, id.to_glib_none().0)) + } + } + + fn internal_set_testing(&self, testing: bool) { + unsafe { + ffi::rsvg_handle_internal_set_testing(self.to_glib_none().0, testing.to_glib()); + } + } + + //fn read_stream_sync<'a, P: IsA</*Ignored*/gio::InputStream>, Q: Into<Option<&'a /*Ignored*/gio::Cancellable>>>(&self, stream: &P, cancellable: Q) -> Result<(), Error> { + // unsafe { TODO: call ffi::rsvg_handle_read_stream_sync() } + //} + + fn render_cairo(&self, cr: &cairo::Context) -> bool { + unsafe { + from_glib(ffi::rsvg_handle_render_cairo(self.to_glib_none().0, mut_override(cr.to_glib_none().0))) + } + } + + fn render_cairo_sub<'a, P: Into<Option<&'a str>>>(&self, cr: &cairo::Context, id: P) -> bool { + let id = id.into(); + let id = id.to_glib_none(); + unsafe { + from_glib(ffi::rsvg_handle_render_cairo_sub(self.to_glib_none().0, mut_override(cr.to_glib_none().0), id.0)) + } + } + + //fn set_base_gfile<P: IsA</*Ignored*/gio::File>>(&self, base_file: &P) { + // unsafe { TODO: call ffi::rsvg_handle_set_base_gfile() } + //} + + fn set_base_uri(&self, base_uri: &str) { + unsafe { + ffi::rsvg_handle_set_base_uri(self.to_glib_none().0, base_uri.to_glib_none().0); + } + } + + fn set_dpi(&self, dpi: f64) { + unsafe { + ffi::rsvg_handle_set_dpi(self.to_glib_none().0, dpi); + } + } + + fn set_dpi_x_y(&self, dpi_x: f64, dpi_y: f64) { + unsafe { + ffi::rsvg_handle_set_dpi_x_y(self.to_glib_none().0, dpi_x, dpi_y); + } + } + + fn write(&self, buf: &[u8]) -> Result<(), Error> { + let count = buf.len() as usize; + unsafe { + let mut error = ptr::null_mut(); + let _ = ffi::rsvg_handle_write(self.to_glib_none().0, buf.to_glib_none().0, count, &mut error); + if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } + } + } + + fn get_property_dpi_x(&self) -> f64 { + unsafe { + let mut value = Value::uninitialized(); + gobject_ffi::g_value_init(value.to_glib_none_mut().0, <f64 as StaticType>::static_type().to_glib()); + gobject_ffi::g_object_get_property(self.to_glib_none().0, "dpi-x".to_glib_none().0, value.to_glib_none_mut().0); + value.get().unwrap() + } + } + + fn set_property_dpi_x(&self, dpi_x: f64) { + unsafe { + gobject_ffi::g_object_set_property(self.to_glib_none().0, "dpi-x".to_glib_none().0, Value::from(&dpi_x).to_glib_none().0); + } + } + + fn get_property_dpi_y(&self) -> f64 { + unsafe { + let mut value = Value::uninitialized(); + gobject_ffi::g_value_init(value.to_glib_none_mut().0, <f64 as StaticType>::static_type().to_glib()); + gobject_ffi::g_object_get_property(self.to_glib_none().0, "dpi-y".to_glib_none().0, value.to_glib_none_mut().0); + value.get().unwrap() + } + } + + fn set_property_dpi_y(&self, dpi_y: f64) { + unsafe { + gobject_ffi::g_object_set_property(self.to_glib_none().0, "dpi-y".to_glib_none().0, Value::from(&dpi_y).to_glib_none().0); + } + } + + fn get_property_em(&self) -> f64 { + unsafe { + let mut value = Value::uninitialized(); + gobject_ffi::g_value_init(value.to_glib_none_mut().0, <f64 as StaticType>::static_type().to_glib()); + gobject_ffi::g_object_get_property(self.to_glib_none().0, "em".to_glib_none().0, value.to_glib_none_mut().0); + value.get().unwrap() + } + } + + fn get_property_ex(&self) -> f64 { + unsafe { + let mut value = Value::uninitialized(); + gobject_ffi::g_value_init(value.to_glib_none_mut().0, <f64 as StaticType>::static_type().to_glib()); + gobject_ffi::g_object_get_property(self.to_glib_none().0, "ex".to_glib_none().0, value.to_glib_none_mut().0); + value.get().unwrap() + } + } + + fn get_property_flags(&self) -> HandleFlags { + unsafe { + let mut value = Value::uninitialized(); + gobject_ffi::g_value_init(value.to_glib_none_mut().0, <HandleFlags as StaticType>::static_type().to_glib()); + gobject_ffi::g_object_get_property(self.to_glib_none().0, "flags".to_glib_none().0, value.to_glib_none_mut().0); + value.get().unwrap() + } + } + + fn get_property_height(&self) -> i32 { + unsafe { + let mut value = Value::uninitialized(); + gobject_ffi::g_value_init(value.to_glib_none_mut().0, <i32 as StaticType>::static_type().to_glib()); + gobject_ffi::g_object_get_property(self.to_glib_none().0, "height".to_glib_none().0, value.to_glib_none_mut().0); + value.get().unwrap() + } + } + + fn get_property_width(&self) -> i32 { + unsafe { + let mut value = Value::uninitialized(); + gobject_ffi::g_value_init(value.to_glib_none_mut().0, <i32 as StaticType>::static_type().to_glib()); + gobject_ffi::g_object_get_property(self.to_glib_none().0, "width".to_glib_none().0, value.to_glib_none_mut().0); + value.get().unwrap() + } + } + + fn connect_property_dpi_x_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId { + unsafe { + let f: Box_<Box_<Fn(&Self) + 'static>> = Box_::new(Box_::new(f)); + connect(self.to_glib_none().0, "notify::dpi-x", + transmute(notify_dpi_x_trampoline::<Self> as usize), Box_::into_raw(f) as *mut _) + } + } + + fn connect_property_dpi_y_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId { + unsafe { + let f: Box_<Box_<Fn(&Self) + 'static>> = Box_::new(Box_::new(f)); + connect(self.to_glib_none().0, "notify::dpi-y", + transmute(notify_dpi_y_trampoline::<Self> as usize), Box_::into_raw(f) as *mut _) + } + } + + fn connect_property_em_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId { + unsafe { + let f: Box_<Box_<Fn(&Self) + 'static>> = Box_::new(Box_::new(f)); + connect(self.to_glib_none().0, "notify::em", + transmute(notify_em_trampoline::<Self> as usize), Box_::into_raw(f) as *mut _) + } + } + + fn connect_property_ex_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId { + unsafe { + let f: Box_<Box_<Fn(&Self) + 'static>> = Box_::new(Box_::new(f)); + connect(self.to_glib_none().0, "notify::ex", + transmute(notify_ex_trampoline::<Self> as usize), Box_::into_raw(f) as *mut _) + } + } + + fn connect_property_flags_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId { + unsafe { + let f: Box_<Box_<Fn(&Self) + 'static>> = Box_::new(Box_::new(f)); + connect(self.to_glib_none().0, "notify::flags", + transmute(notify_flags_trampoline::<Self> as usize), Box_::into_raw(f) as *mut _) + } + } + + fn connect_property_height_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId { + unsafe { + let f: Box_<Box_<Fn(&Self) + 'static>> = Box_::new(Box_::new(f)); + connect(self.to_glib_none().0, "notify::height", + transmute(notify_height_trampoline::<Self> as usize), Box_::into_raw(f) as *mut _) + } + } + + fn connect_property_width_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId { + unsafe { + let f: Box_<Box_<Fn(&Self) + 'static>> = Box_::new(Box_::new(f)); + connect(self.to_glib_none().0, "notify::width", + transmute(notify_width_trampoline::<Self> as usize), Box_::into_raw(f) as *mut _) + } + } +} + +unsafe extern "C" fn notify_dpi_x_trampoline<P>(this: *mut ffi::RsvgHandle, _param_spec: glib_ffi::gpointer, f: glib_ffi::gpointer) +where P: IsA<Handle> { + callback_guard!(); + let f: &&(Fn(&P) + 'static) = transmute(f); + f(&Handle::from_glib_borrow(this).downcast_unchecked()) +} + +unsafe extern "C" fn notify_dpi_y_trampoline<P>(this: *mut ffi::RsvgHandle, _param_spec: glib_ffi::gpointer, f: glib_ffi::gpointer) +where P: IsA<Handle> { + callback_guard!(); + let f: &&(Fn(&P) + 'static) = transmute(f); + f(&Handle::from_glib_borrow(this).downcast_unchecked()) +} + +unsafe extern "C" fn notify_em_trampoline<P>(this: *mut ffi::RsvgHandle, _param_spec: glib_ffi::gpointer, f: glib_ffi::gpointer) +where P: IsA<Handle> { + callback_guard!(); + let f: &&(Fn(&P) + 'static) = transmute(f); + f(&Handle::from_glib_borrow(this).downcast_unchecked()) +} + +unsafe extern "C" fn notify_ex_trampoline<P>(this: *mut ffi::RsvgHandle, _param_spec: glib_ffi::gpointer, f: glib_ffi::gpointer) +where P: IsA<Handle> { + callback_guard!(); + let f: &&(Fn(&P) + 'static) = transmute(f); + f(&Handle::from_glib_borrow(this).downcast_unchecked()) +} + +unsafe extern "C" fn notify_flags_trampoline<P>(this: *mut ffi::RsvgHandle, _param_spec: glib_ffi::gpointer, f: glib_ffi::gpointer) +where P: IsA<Handle> { + callback_guard!(); + let f: &&(Fn(&P) + 'static) = transmute(f); + f(&Handle::from_glib_borrow(this).downcast_unchecked()) +} + +unsafe extern "C" fn notify_height_trampoline<P>(this: *mut ffi::RsvgHandle, _param_spec: glib_ffi::gpointer, f: glib_ffi::gpointer) +where P: IsA<Handle> { + callback_guard!(); + let f: &&(Fn(&P) + 'static) = transmute(f); + f(&Handle::from_glib_borrow(this).downcast_unchecked()) +} + +unsafe extern "C" fn notify_width_trampoline<P>(this: *mut ffi::RsvgHandle, _param_spec: glib_ffi::gpointer, f: glib_ffi::gpointer) +where P: IsA<Handle> { + callback_guard!(); + let f: &&(Fn(&P) + 'static) = transmute(f); + f(&Handle::from_glib_borrow(this).downcast_unchecked()) +} diff --git a/rsvg-rs/src/auto/mod.rs b/rsvg-rs/src/auto/mod.rs new file mode 100644 index 00000000..4ddf345a --- /dev/null +++ b/rsvg-rs/src/auto/mod.rs @@ -0,0 +1,14 @@ +// This file was generated by gir (d50d839) from gir-files (???) +// DO NOT EDIT + +mod handle; +pub use self::handle::Handle; +pub use self::handle::HandleExt; + +mod flags; +pub use self::flags::HandleFlags; + +#[doc(hidden)] +pub mod traits { + pub use super::HandleExt; +} diff --git a/rsvg-rs/src/dimension_data.rs b/rsvg-rs/src/dimension_data.rs new file mode 100644 index 00000000..37dc22c4 --- /dev/null +++ b/rsvg-rs/src/dimension_data.rs @@ -0,0 +1,67 @@ +use std::mem; +use glib::translate::*; +use ffi; + +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(C)] +pub struct DimensionData { + pub width: i32, + pub height: i32, + pub em: f64, + pub ex: f64, +} + +impl DimensionData { + pub fn new(width: i32, height: i32, em: f64, ex: f64) -> DimensionData { + DimensionData { + width: width, + height: height, + em: em, + ex: ex, + } + } +} + +#[doc(hidden)] +impl Uninitialized for DimensionData { + #[inline] + unsafe fn uninitialized() -> Self { + mem::uninitialized() + } +} + +#[doc(hidden)] +impl<'a> ToGlibPtr<'a, *const ffi::RsvgDimensionData> for DimensionData { + type Storage = &'a Self; + + #[inline] + fn to_glib_none(&'a self) -> Stash<'a, *const ffi::RsvgDimensionData, Self> { + let ptr: *const DimensionData = &*self; + Stash(ptr as *const ffi::RsvgDimensionData, self) + } +} + +#[doc(hidden)] +impl<'a> ToGlibPtrMut<'a, *mut ffi::RsvgDimensionData> for DimensionData { + type Storage = &'a mut Self; + + #[inline] + fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::RsvgDimensionData, Self> { + let ptr: *mut DimensionData = &mut *self; + StashMut(ptr as *mut ffi::RsvgDimensionData, self) + } +} + +#[doc(hidden)] +impl FromGlibPtrNone<*const ffi::RsvgDimensionData> for DimensionData { + unsafe fn from_glib_none(ptr: *const ffi::RsvgDimensionData) -> Self { + *(ptr as *const DimensionData) + } +} + +#[doc(hidden)] +impl FromGlibPtrNone<*mut ffi::RsvgDimensionData> for DimensionData { + unsafe fn from_glib_none(ptr: *mut ffi::RsvgDimensionData) -> Self { + *(ptr as *mut DimensionData) + } +}
\ No newline at end of file diff --git a/rsvg-rs/src/handle.rs b/rsvg-rs/src/handle.rs new file mode 100644 index 00000000..0e02e472 --- /dev/null +++ b/rsvg-rs/src/handle.rs @@ -0,0 +1,16 @@ +use ffi; +use std::ptr; + +use glib::Error; +use glib::translate::*; +use auto::Handle; + +impl Handle { + pub fn new_from_str(data: &str) -> Result<Handle, Error> { + unsafe { + let mut error = ptr::null_mut(); + let handle = ffi::rsvg_handle_new_from_data(data.as_ptr() as *mut _, data.len() as _, &mut error); + if error.is_null() { Ok(from_glib_full(handle)) } else { Err(from_glib_full(error)) } + } + } +}
\ No newline at end of file diff --git a/rsvg-rs/src/lib.rs b/rsvg-rs/src/lib.rs new file mode 100644 index 00000000..158eef54 --- /dev/null +++ b/rsvg-rs/src/lib.rs @@ -0,0 +1,125 @@ +extern crate rsvg_sys as ffi; +extern crate glib_sys as glib_ffi; +extern crate gobject_sys as gobject_ffi; + +#[macro_use] +extern crate glib; +extern crate cairo; +extern crate gdk_pixbuf; +#[macro_use] +extern crate bitflags; +extern crate libc; + +macro_rules! callback_guard { + () => () +} + +pub use glib::Error; + +mod auto; +pub use auto::*; + +mod handle; +mod position_data; +mod dimension_data; +pub use position_data::PositionData; +pub use dimension_data::DimensionData; + +#[cfg(test)] +#[macro_use] +extern crate imageproc; + +#[cfg(test)] +mod tests { + extern crate image; + + use super::HandleExt; + use self::image::GenericImage; + + fn get_fixture_path(fixture: &str) -> String { + return format!("./test-fixtures/{}", fixture); + } + + #[test] + fn it_should_be_possible_to_create_new_handle_and_write_manually_to_it() { + let handle = super::Handle::new(); + + handle.write(r#"<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="50" height="50"></svg>"#.as_bytes()).unwrap(); + handle.close().unwrap(); + + assert_eq!(handle.get_dimensions(), super::DimensionData { width: 50, height: 50, em: 50.0, ex: 50.0 }); + assert_eq!(handle.get_position_sub("#unknownid"), None); + } + + #[test] + fn it_should_be_possible_to_load_svg_from_string() { + let svg = r#"<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="50" height="50"></svg>"#; + let handle = super::Handle::new_from_str(svg).unwrap(); + + assert_eq!(handle.get_dimensions(), super::DimensionData { width: 50, height: 50, em: 50.0, ex: 50.0 }); + assert_eq!(handle.get_position_sub("#unknownid"), None); + } + + #[test] + fn it_should_be_possible_to_load_svg_from_slice() { + let svg = r#"<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="50" height="50"></svg>"#; + let handle = super::Handle::new_from_data(svg.as_bytes()).unwrap(); + + assert_eq!(handle.get_dimensions(), super::DimensionData { width: 50, height: 50, em: 50.0, ex: 50.0 }); + assert_eq!(handle.get_position_sub("#unknownid"), None); + } + + #[test] + #[ignore] + fn it_should_be_possible_to_load_svg_from_file() { + let svg_path = get_fixture_path("mysvg.svg"); + let handle = super::Handle::new_from_file(&svg_path).unwrap(); + + assert_eq!(handle.get_dimensions(), super::DimensionData { width: 100, height: 100, em: 100.0, ex: 100.0 }); + assert_eq!(handle.get_position_sub("#unknownid"), None); + } + + #[test] + #[ignore] + fn it_should_be_possible_to_render_to_cairo_context() { + let svg_path = get_fixture_path("mysvg.svg"); + let expected = image::open(get_fixture_path("mysvg.svg.png")).unwrap(); + let handle = super::Handle::new_from_file(&svg_path).unwrap(); + let dimensions = handle.get_dimensions(); + let surface = super::cairo::ImageSurface::create(super::cairo::Format::ARgb32, dimensions.width, dimensions.height).unwrap(); + let context = super::cairo::Context::new(&surface); + let mut png_data: Vec<u8> = vec!(); + + context.paint_with_alpha(0.0); + handle.render_cairo(&context); + surface.write_to_png(&mut png_data).unwrap(); + + let result = image::load_from_memory_with_format(&png_data, image::ImageFormat::PNG).unwrap(); + assert_dimensions_match!(result, expected); + assert_pixels_eq!(result, expected); + } + + #[test] + #[ignore] + fn it_should_be_possible_to_render_to_gdk_pixbuf_without_throwing() { + let svg_path = get_fixture_path("mysvg.svg"); + let expected = image::open(get_fixture_path("mysvg.svg.png")).unwrap(); + let handle = super::Handle::new_from_file(&svg_path).unwrap(); + let pixbuf = handle.get_pixbuf().unwrap(); + let pixels = (unsafe { pixbuf.get_pixels() }).to_vec(); + let dimensions = handle.get_dimensions(); + let result = image::ImageBuffer::from_raw(dimensions.width as u32, dimensions.height as u32, pixels) + .map(|v| image::DynamicImage::ImageRgba8(v)) + .unwrap(); + + assert_dimensions_match!(result, expected); + assert_pixels_eq!(result, expected); + } + + #[test] + fn it_should_return_an_error_when_loading_non_existing_file() { + let handle = super::Handle::new_from_file("unknown.svg"); + + assert!(handle.is_err()); + } +} diff --git a/rsvg-rs/src/position_data.rs b/rsvg-rs/src/position_data.rs new file mode 100644 index 00000000..10837ddd --- /dev/null +++ b/rsvg-rs/src/position_data.rs @@ -0,0 +1,67 @@ +use std::mem; +use glib::translate::*; +use ffi; + +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(C)] +pub struct PositionData { + pub x: i32, + pub y: i32, + pub em: f64, + pub ex: f64, +} + +impl PositionData { + pub fn new(x: i32, y: i32, em: f64, ex: f64) -> PositionData { + PositionData { + x: x, + y: y, + em: em, + ex: ex, + } + } +} + +#[doc(hidden)] +impl Uninitialized for PositionData { + #[inline] + unsafe fn uninitialized() -> Self { + mem::uninitialized() + } +} + +#[doc(hidden)] +impl<'a> ToGlibPtr<'a, *const ffi::RsvgPositionData> for PositionData { + type Storage = &'a Self; + + #[inline] + fn to_glib_none(&'a self) -> Stash<'a, *const ffi::RsvgPositionData, Self> { + let ptr: *const PositionData = &*self; + Stash(ptr as *const ffi::RsvgPositionData, self) + } +} + +#[doc(hidden)] +impl<'a> ToGlibPtrMut<'a, *mut ffi::RsvgPositionData> for PositionData { + type Storage = &'a mut Self; + + #[inline] + fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::RsvgPositionData, Self> { + let ptr: *mut PositionData = &mut *self; + StashMut(ptr as *mut ffi::RsvgPositionData, self) + } +} + +#[doc(hidden)] +impl FromGlibPtrNone<*const ffi::RsvgPositionData> for PositionData { + unsafe fn from_glib_none(ptr: *const ffi::RsvgPositionData) -> Self { + *(ptr as *const PositionData) + } +} + +#[doc(hidden)] +impl FromGlibPtrNone<*mut ffi::RsvgPositionData> for PositionData { + unsafe fn from_glib_none(ptr: *mut ffi::RsvgPositionData) -> Self { + *(ptr as *mut PositionData) + } +}
\ No newline at end of file |