summaryrefslogtreecommitdiff
path: root/rsvg_internals
diff options
context:
space:
mode:
authorFederico Mena Quintero <federico@gnome.org>2019-01-11 19:11:12 -0600
committerFederico Mena Quintero <federico@gnome.org>2019-01-11 19:11:12 -0600
commitd7ed7b51ff4d4589d71d28f368ad53ead8c86c80 (patch)
tree40a31ed4820d3ff657bc9bf526677576bc33e560 /rsvg_internals
parent8c79496d13004a553314a729a47b2b1156788e4a (diff)
downloadlibrsvg-d7ed7b51ff4d4589d71d28f368ad53ead8c86c80.tar.gz
rsvg-pixbuf.c: Port all the functions here to Rust
Diffstat (limited to 'rsvg_internals')
-rw-r--r--rsvg_internals/src/handle.rs18
-rw-r--r--rsvg_internals/src/lib.rs7
-rw-r--r--rsvg_internals/src/pixbuf_utils.rs236
3 files changed, 246 insertions, 15 deletions
diff --git a/rsvg_internals/src/handle.rs b/rsvg_internals/src/handle.rs
index 999c8833..0af787b3 100644
--- a/rsvg_internals/src/handle.rs
+++ b/rsvg_internals/src/handle.rs
@@ -42,17 +42,17 @@ pub struct RsvgHandle {
// Keep in sync with rsvg.h:RsvgDimensionData
#[repr(C)]
pub struct RsvgDimensionData {
- width: libc::c_int,
- height: libc::c_int,
- em: f64,
- ex: f64,
+ pub width: libc::c_int,
+ pub height: libc::c_int,
+ pub em: f64,
+ pub ex: f64,
}
// Keep in sync with rsvg.h:RsvgPositionData
#[repr(C)]
pub struct RsvgPositionData {
- x: libc::c_int,
- y: libc::c_int,
+ pub x: libc::c_int,
+ pub y: libc::c_int,
}
/// Flags used during loading
@@ -319,7 +319,7 @@ impl Handle {
draw_ctx
}
- fn get_dimensions(&mut self) -> Result<RsvgDimensionData, RenderingError> {
+ pub fn get_dimensions(&mut self) -> Result<RsvgDimensionData, RenderingError> {
// This function is probably called from the cairo_render functions,
// or is being erroneously called within the size_func.
// To prevent an infinite loop we are saving the state, and
@@ -499,7 +499,7 @@ impl Handle {
self.lookup_node(name).is_ok()
}
- fn render_cairo_sub(
+ pub fn render_cairo_sub(
&mut self,
cr: &cairo::Context,
id: Option<&str>,
@@ -717,7 +717,7 @@ pub unsafe extern "C" fn rsvg_handle_rust_free(raw_handle: *mut Handle) {
Box::from_raw(raw_handle);
}
-fn get_rust_handle<'a>(handle: *const RsvgHandle) -> &'a mut Handle {
+pub fn get_rust_handle<'a>(handle: *const RsvgHandle) -> &'a mut Handle {
unsafe { &mut *(rsvg_handle_get_rust(handle) as *mut Handle) }
}
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index ed906bb4..be39ff8d 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -69,6 +69,13 @@ pub use handle::{
rsvg_handle_rust_write,
};
+pub use pixbuf_utils::{
+ rsvg_rust_pixbuf_from_file_at_max_size,
+ rsvg_rust_pixbuf_from_file_at_size,
+ rsvg_rust_pixbuf_from_file_at_zoom,
+ rsvg_rust_pixbuf_from_file_at_zoom_with_max,
+};
+
pub use xml::rsvg_xml_state_error;
#[macro_use]
diff --git a/rsvg_internals/src/pixbuf_utils.rs b/rsvg_internals/src/pixbuf_utils.rs
index a809518a..bfdd6dbf 100644
--- a/rsvg_internals/src/pixbuf_utils.rs
+++ b/rsvg_internals/src/pixbuf_utils.rs
@@ -1,17 +1,32 @@
-use glib::translate::*;
+use std::ptr;
-use error::RenderingError;
+use cairo::{self, ImageSurface};
use gdk_pixbuf::{Colorspace, Pixbuf};
-use gdk_pixbuf_sys as ffi;
+use gdk_pixbuf_sys;
+use glib::translate::*;
+use glib_sys;
+use libc;
+
+use error::{set_gerror, RenderingError};
+use handle::{get_rust_handle, rsvg_handle_rust_new_from_gfile_sync, Handle, RsvgDimensionData};
use rect::IRect;
-use surface_utils::{iterators::Pixels, shared_surface::SharedImageSurface};
+use surface_utils::{
+ iterators::Pixels,
+ shared_surface::SharedImageSurface,
+ shared_surface::SurfaceType,
+};
// Pixbuf::new() doesn't return out-of-memory errors properly
// See https://github.com/gtk-rs/gdk-pixbuf/issues/96
fn pixbuf_new(width: i32, height: i32) -> Result<Pixbuf, RenderingError> {
unsafe {
- let raw_pixbuf =
- ffi::gdk_pixbuf_new(Colorspace::Rgb.to_glib(), true.to_glib(), 8, width, height);
+ let raw_pixbuf = gdk_pixbuf_sys::gdk_pixbuf_new(
+ Colorspace::Rgb.to_glib(),
+ true.to_glib(),
+ 8,
+ width,
+ height,
+ );
if raw_pixbuf.is_null() {
return Err(RenderingError::OutOfMemory);
@@ -47,3 +62,212 @@ pub fn pixbuf_from_surface(surface: &SharedImageSurface) -> Result<Pixbuf, Rende
Ok(pixbuf)
}
+
+enum SizeKind {
+ Zoom,
+ WidthHeight,
+ WidthHeightMax,
+ ZoomMax,
+}
+
+struct SizeMode {
+ kind: SizeKind,
+ x_zoom: f64,
+ y_zoom: f64,
+ width: i32,
+ height: i32,
+}
+
+fn get_final_size(dimensions: &RsvgDimensionData, size_mode: &SizeMode) -> (i32, i32) {
+ let in_width = dimensions.width;
+ let in_height = dimensions.height;
+
+ let mut out_width;
+ let mut out_height;
+
+ match size_mode.kind {
+ SizeKind::Zoom => {
+ out_width = (size_mode.x_zoom * f64::from(in_width) + 0.5).floor() as i32;
+ out_height = (size_mode.y_zoom * f64::from(in_height) + 0.5).floor() as i32;
+ }
+
+ SizeKind::ZoomMax => {
+ out_width = (size_mode.x_zoom * f64::from(in_width) + 0.5).floor() as i32;
+ out_height = (size_mode.y_zoom * f64::from(in_height) + 0.5).floor() as i32;
+
+ if out_width > size_mode.width || out_height > size_mode.height {
+ let zoom_x = f64::from(size_mode.width) / f64::from(out_width);
+ let zoom_y = f64::from(size_mode.height) / f64::from(out_height);
+ let zoom = zoom_x.min(zoom_y);
+
+ out_width = (zoom * f64::from(out_width) + 0.5) as i32;
+ out_height = (zoom * f64::from(out_height) + 0.5) as i32;
+ }
+ }
+
+ SizeKind::WidthHeightMax => {
+ let zoom_x = f64::from(size_mode.width) / f64::from(in_width);
+ let zoom_y = f64::from(size_mode.height) / f64::from(in_height);
+
+ let zoom = zoom_x.min(zoom_y);
+
+ out_width = (zoom * f64::from(in_width) + 0.5) as i32;
+ out_height = (zoom * f64::from(in_height) + 0.5) as i32;
+ }
+
+ SizeKind::WidthHeight => {
+ if size_mode.width != -1 {
+ out_width = size_mode.width;
+ } else {
+ out_width = in_width;
+ }
+
+ if size_mode.height != -1 {
+ out_height = size_mode.height;
+ } else {
+ out_height = in_height;
+ }
+ }
+ }
+
+ (out_width, out_height)
+}
+
+fn render_to_pixbuf_at_size(
+ handle: &mut Handle,
+ dimensions: &RsvgDimensionData,
+ width: i32,
+ height: i32,
+) -> Result<Pixbuf, RenderingError> {
+ let surface = ImageSurface::create(cairo::Format::ARgb32, width, height)?;
+
+ {
+ let cr = cairo::Context::new(&surface);
+ cr.scale(
+ f64::from(width) / f64::from(dimensions.width),
+ f64::from(height) / f64::from(dimensions.height),
+ );
+ handle.render_cairo_sub(&cr, None)?;
+ }
+
+ let shared_surface = SharedImageSurface::new(surface, SurfaceType::SRgb)?;
+
+ pixbuf_from_surface(&shared_surface)
+}
+
+fn pixbuf_from_file_with_size_mode(
+ filename: *const libc::c_char,
+ size_mode: &SizeMode,
+ error: *mut *mut glib_sys::GError,
+) -> *mut gdk_pixbuf_sys::GdkPixbuf {
+ unsafe {
+ let file = gio_sys::g_file_new_for_path(filename);
+
+ let handle = rsvg_handle_rust_new_from_gfile_sync(file, 0, ptr::null_mut(), error);
+
+ gobject_sys::g_object_unref(file as *mut _);
+
+ if handle.is_null() {
+ return ptr::null_mut();
+ }
+
+ let rhandle = get_rust_handle(handle);
+
+ let raw_pixbuf = rhandle
+ .get_dimensions()
+ .and_then(|dimensions| {
+ let (width, height) = get_final_size(&dimensions, size_mode);
+
+ render_to_pixbuf_at_size(rhandle, &dimensions, width, height)
+ })
+ .and_then(|pixbuf| Ok(pixbuf.to_glib_full()))
+ .map_err(|e| set_gerror(error, 0, &format!("{}", e)))
+ .unwrap_or(ptr::null_mut());
+
+ gobject_sys::g_object_unref(handle as *mut _);
+
+ raw_pixbuf
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_rust_pixbuf_from_file_at_size(
+ filename: *const libc::c_char,
+ width: i32,
+ height: i32,
+ error: *mut *mut glib_sys::GError,
+) -> *mut gdk_pixbuf_sys::GdkPixbuf {
+ pixbuf_from_file_with_size_mode(
+ filename,
+ &SizeMode {
+ kind: SizeKind::WidthHeight,
+ x_zoom: 0.0,
+ y_zoom: 0.0,
+ width,
+ height,
+ },
+ error,
+ )
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_rust_pixbuf_from_file_at_zoom(
+ filename: *const libc::c_char,
+ x_zoom: f64,
+ y_zoom: f64,
+ error: *mut *mut glib_sys::GError,
+) -> *mut gdk_pixbuf_sys::GdkPixbuf {
+ pixbuf_from_file_with_size_mode(
+ filename,
+ &SizeMode {
+ kind: SizeKind::Zoom,
+ x_zoom,
+ y_zoom,
+ width: 0,
+ height: 0,
+ },
+ error,
+ )
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_rust_pixbuf_from_file_at_zoom_with_max(
+ filename: *const libc::c_char,
+ x_zoom: f64,
+ y_zoom: f64,
+ width: i32,
+ height: i32,
+ error: *mut *mut glib_sys::GError,
+) -> *mut gdk_pixbuf_sys::GdkPixbuf {
+ pixbuf_from_file_with_size_mode(
+ filename,
+ &SizeMode {
+ kind: SizeKind::ZoomMax,
+ x_zoom,
+ y_zoom,
+ width,
+ height,
+ },
+ error,
+ )
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_rust_pixbuf_from_file_at_max_size(
+ filename: *const libc::c_char,
+ width: i32,
+ height: i32,
+ error: *mut *mut glib_sys::GError,
+) -> *mut gdk_pixbuf_sys::GdkPixbuf {
+ pixbuf_from_file_with_size_mode(
+ filename,
+ &SizeMode {
+ kind: SizeKind::WidthHeightMax,
+ x_zoom: 0.0,
+ y_zoom: 0.0,
+ width,
+ height,
+ },
+ error,
+ )
+}