[librsvg] rsvg-pixbuf.c: Port all the functions here to Rust
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] rsvg-pixbuf.c: Port all the functions here to Rust
- Date: Sat, 12 Jan 2019 01:12:20 +0000 (UTC)
commit d7ed7b51ff4d4589d71d28f368ad53ead8c86c80
Author: Federico Mena Quintero <federico gnome org>
Date: Fri Jan 11 19:11:12 2019 -0600
rsvg-pixbuf.c: Port all the functions here to Rust
Makefile.am | 2 -
librsvg/rsvg-pixbuf.c | 132 +++++++++------------
rsvg_internals/src/handle.rs | 18 +--
rsvg_internals/src/lib.rs | 7 ++
rsvg_internals/src/pixbuf_utils.rs | 236 ++++++++++++++++++++++++++++++++++++-
5 files changed, 302 insertions(+), 93 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index d83aaaeb..7412c9a6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -29,8 +29,6 @@ librsvg_@RSVG_API_MAJOR_VERSION@_la_SOURCES = \
librsvg/rsvg-css.h \
librsvg/rsvg-handle.c \
librsvg/rsvg-pixbuf.c \
- librsvg/rsvg-size-callback.c \
- librsvg/rsvg-size-callback.h \
librsvg/rsvg.h \
$(NULL)
diff --git a/librsvg/rsvg-pixbuf.c b/librsvg/rsvg-pixbuf.c
index adafe3ba..65cf388f 100644
--- a/librsvg/rsvg-pixbuf.c
+++ b/librsvg/rsvg-pixbuf.c
@@ -40,37 +40,33 @@
#include <stdlib.h>
#include "rsvg.h"
-#include "rsvg-size-callback.h"
-static GdkPixbuf *
-rsvg_pixbuf_from_file_with_size_data (const gchar * file_name,
- struct RsvgSizeCallbackData *cb_data,
- GError ** error)
-{
- GFile *file;
- RsvgHandle *handle;
- GdkPixbuf *pixbuf = NULL;
-
- file = g_file_new_for_path (file_name);
- handle = rsvg_handle_new_from_gfile_sync (file, 0, NULL, error);
-
- if (handle) {
- rsvg_handle_set_size_callback (handle, _rsvg_size_callback, cb_data, NULL);
- pixbuf = rsvg_handle_get_pixbuf (handle);
- }
-
- g_object_unref (handle);
- g_object_unref (file);
-
- return pixbuf;
-}
+/* Defined in rsvg_internals/src/pixbuf_utils.rs */
+extern GdkPixbuf *rsvg_rust_pixbuf_from_file_at_size (const char *filename,
+ int width,
+ int height,
+ GError **error);
+extern GdkPixbuf *rsvg_rust_pixbuf_from_file_at_zoom (const char *filename,
+ double x_zoom,
+ double y_zoom,
+ GError **error);
+extern GdkPixbuf *rsvg_rust_pixbuf_from_file_at_zoom_with_max (const char *filename,
+ double x_zoom,
+ double y_zoom,
+ int width,
+ int height,
+ GError **error);
+extern GdkPixbuf *rsvg_rust_pixbuf_from_file_at_max_size (const char *filename,
+ int width,
+ int height,
+ GError **error);
/**
* rsvg_pixbuf_from_file:
- * @file_name: A file name
+ * @filename: A file name
* @error: return location for errors
*
- * Loads a new #GdkPixbuf from @file_name and returns it. The caller must
+ * Loads a new #GdkPixbuf from @filename and returns it. The caller must
* assume the reference to the reurned pixbuf. If an error occurred, @error is
* set and %NULL is returned.
*
@@ -78,19 +74,22 @@ rsvg_pixbuf_from_file_with_size_data (const gchar * file_name,
* Deprecated: Set up a cairo matrix and use rsvg_handle_new_from_file() + rsvg_handle_render_cairo()
instead.
**/
GdkPixbuf *
-rsvg_pixbuf_from_file (const gchar * file_name, GError ** error)
+rsvg_pixbuf_from_file (const gchar *filename, GError **error)
{
- return rsvg_pixbuf_from_file_at_size (file_name, -1, -1, error);
+ g_return_val_if_fail (filename != NULL, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ return rsvg_rust_pixbuf_from_file_at_size (filename, -1, -1, error);
}
/**
* rsvg_pixbuf_from_file_at_zoom:
- * @file_name: A file name
+ * @filename: A file name
* @x_zoom: The horizontal zoom factor
* @y_zoom: The vertical zoom factor
* @error: return location for errors
*
- * Loads a new #GdkPixbuf from @file_name and returns it. This pixbuf is scaled
+ * Loads a new #GdkPixbuf from @filename and returns it. This pixbuf is scaled
* from the size indicated by the file by a factor of @x_zoom and @y_zoom. The
* caller must assume the reference to the returned pixbuf. If an error
* occurred, @error is set and %NULL is returned.
@@ -99,32 +98,26 @@ rsvg_pixbuf_from_file (const gchar * file_name, GError ** error)
* Deprecated: Set up a cairo matrix and use rsvg_handle_new_from_file() + rsvg_handle_render_cairo()
instead.
**/
GdkPixbuf *
-rsvg_pixbuf_from_file_at_zoom (const gchar * file_name,
- double x_zoom, double y_zoom, GError ** error)
+rsvg_pixbuf_from_file_at_zoom (const gchar *filename,
+ double x_zoom, double y_zoom, GError **error)
{
- struct RsvgSizeCallbackData data;
-
- g_return_val_if_fail (file_name != NULL, NULL);
+ g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (x_zoom > 0.0 && y_zoom > 0.0, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- data.type = RSVG_SIZE_ZOOM;
- data.x_zoom = x_zoom;
- data.y_zoom = y_zoom;
- data.keep_aspect_ratio = FALSE;
-
- return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
+ return rsvg_rust_pixbuf_from_file_at_zoom (filename, x_zoom, y_zoom, error);
}
/**
* rsvg_pixbuf_from_file_at_zoom_with_max:
- * @file_name: A file name
+ * @filename: A file name
* @x_zoom: The horizontal zoom factor
* @y_zoom: The vertical zoom factor
* @max_width: The requested max width
* @max_height: The requested max heigh
* @error: return location for errors
*
- * Loads a new #GdkPixbuf from @file_name and returns it. This pixbuf is scaled
+ * Loads a new #GdkPixbuf from @filename and returns it. This pixbuf is scaled
* from the size indicated by the file by a factor of @x_zoom and @y_zoom. If the
* resulting pixbuf would be larger than max_width/max_heigh it is uniformly scaled
* down to fit in that rectangle. The caller must assume the reference to the
@@ -134,34 +127,27 @@ rsvg_pixbuf_from_file_at_zoom (const gchar * file_name,
* Deprecated: Set up a cairo matrix and use rsvg_handle_new_from_file() + rsvg_handle_render_cairo()
instead.
**/
GdkPixbuf *
-rsvg_pixbuf_from_file_at_zoom_with_max (const gchar * file_name,
+rsvg_pixbuf_from_file_at_zoom_with_max (const gchar *filename,
double x_zoom,
double y_zoom,
- gint max_width, gint max_height, GError ** error)
+ gint max_width, gint max_height, GError **error)
{
- struct RsvgSizeCallbackData data;
-
- g_return_val_if_fail (file_name != NULL, NULL);
+ g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (x_zoom > 0.0 && y_zoom > 0.0, NULL);
+ g_return_val_if_fail (max_width >= 1 && max_height >= 1, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- data.type = RSVG_SIZE_ZOOM_MAX;
- data.x_zoom = x_zoom;
- data.y_zoom = y_zoom;
- data.width = max_width;
- data.height = max_height;
- data.keep_aspect_ratio = FALSE;
-
- return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
+ return rsvg_rust_pixbuf_from_file_at_zoom_with_max (filename, x_zoom, y_zoom, max_width, max_height,
error);
}
/**
* rsvg_pixbuf_from_file_at_size:
- * @file_name: A file name
+ * @filename: A file name
* @width: The new width, or -1
* @height: The new height, or -1
* @error: return location for errors
*
- * Loads a new #GdkPixbuf from @file_name and returns it. This pixbuf is scaled
+ * Loads a new #GdkPixbuf from @filename and returns it. This pixbuf is scaled
* from the size indicated to the new size indicated by @width and @height. If
* either of these are -1, then the default size of the image being loaded is
* used. The caller must assume the reference to the returned pixbuf. If an
@@ -171,26 +157,23 @@ rsvg_pixbuf_from_file_at_zoom_with_max (const gchar * file_name,
* Deprecated: Set up a cairo matrix and use rsvg_handle_new_from_file() + rsvg_handle_render_cairo()
instead.
**/
GdkPixbuf *
-rsvg_pixbuf_from_file_at_size (const gchar * file_name, gint width, gint height, GError ** error)
+rsvg_pixbuf_from_file_at_size (const gchar *filename, gint width, gint height, GError **error)
{
- struct RsvgSizeCallbackData data;
-
- data.type = RSVG_SIZE_WH;
- data.width = width;
- data.height = height;
- data.keep_aspect_ratio = FALSE;
+ g_return_val_if_fail (filename != NULL, NULL);
+ g_return_val_if_fail ((width >= 1 && height >= 1) || (width == -1 && height == -1), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
+ return rsvg_rust_pixbuf_from_file_at_size (filename, width, height, error);
}
/**
* rsvg_pixbuf_from_file_at_max_size:
- * @file_name: A file name
+ * @filename: A file name
* @max_width: The requested max width
* @max_height: The requested max heigh
* @error: return location for errors
*
- * Loads a new #GdkPixbuf from @file_name and returns it. This pixbuf is uniformly
+ * Loads a new #GdkPixbuf from @filename and returns it. This pixbuf is uniformly
* scaled so that the it fits into a rectangle of size max_width * max_height. The
* caller must assume the reference to the returned pixbuf. If an error occurred,
* @error is set and %NULL is returned.
@@ -199,15 +182,12 @@ rsvg_pixbuf_from_file_at_size (const gchar * file_name, gint width, gint height,
* Deprecated: Set up a cairo matrix and use rsvg_handle_new_from_file() + rsvg_handle_render_cairo()
instead.
**/
GdkPixbuf *
-rsvg_pixbuf_from_file_at_max_size (const gchar * file_name,
- gint max_width, gint max_height, GError ** error)
+rsvg_pixbuf_from_file_at_max_size (const gchar *filename,
+ gint max_width, gint max_height, GError **error)
{
- struct RsvgSizeCallbackData data;
-
- data.type = RSVG_SIZE_WH_MAX;
- data.width = max_width;
- data.height = max_height;
- data.keep_aspect_ratio = FALSE;
+ g_return_val_if_fail (filename != NULL, NULL);
+ g_return_val_if_fail (max_width >= 1 && max_height >= 1, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
+ return rsvg_rust_pixbuf_from_file_at_max_size(filename, max_width, max_height, error);
}
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,
+ )
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]