[librsvg/wip/aruiz/rust-pixbuf-loader] pixbuf: initial stop_load implementation
- From: Alberto Ruiz <aruiz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg/wip/aruiz/rust-pixbuf-loader] pixbuf: initial stop_load implementation
- Date: Mon, 25 Jul 2022 21:22:13 +0000 (UTC)
commit bc273467e358392db4033fbaa49e63eaf363e900
Author: Alberto Ruiz <aruiz redhat com>
Date: Mon Jul 25 22:22:04 2022 +0100
pixbuf: initial stop_load implementation
gdk-pixbuf-loader/Cargo.toml | 8 +-
gdk-pixbuf-loader/src/lib.rs | 197 +++++++++++++++++++++++++++++++++----------
2 files changed, 157 insertions(+), 48 deletions(-)
---
diff --git a/gdk-pixbuf-loader/Cargo.toml b/gdk-pixbuf-loader/Cargo.toml
index 180157635..be69b0508 100644
--- a/gdk-pixbuf-loader/Cargo.toml
+++ b/gdk-pixbuf-loader/Cargo.toml
@@ -1,13 +1,17 @@
[package]
-name = "gdk-pixbuf-loader"
+name = "pixbufloader-svg"
version = "0.0.1"
authors = ["Alberto Ruiz <aruiz gnome org>"]
edition = "2021"
+[lib]
+crate-type = ["cdylib"]
+
[dependencies]
librsvg = { path = ".." }
gdk-pixbuf-sys = "0.15"
libc = "0.2"
glib-sys = "0.15"
glib = "0.15"
-gio = "0.15"
\ No newline at end of file
+gio = "0.15"
+cairo-rs = "0.15"
\ No newline at end of file
diff --git a/gdk-pixbuf-loader/src/lib.rs b/gdk-pixbuf-loader/src/lib.rs
index 9749d1eba..ad3f8ae91 100644
--- a/gdk-pixbuf-loader/src/lib.rs
+++ b/gdk-pixbuf-loader/src/lib.rs
@@ -1,4 +1,4 @@
-use std::ptr::{null_mut, null};
+use std::ptr::null_mut;
use gdk_pixbuf_sys::{
GdkPixbufFormat, GdkPixbufModule, GdkPixbufModulePattern, GdkPixbufModulePreparedFunc,
@@ -7,7 +7,7 @@ use gdk_pixbuf_sys::{
};
use glib_sys::GError;
-use libc::{c_int, c_uint, c_void};
+use libc::{c_char, c_int, c_uint, c_void};
use gio::prelude::MemoryInputStreamExt;
use gio::MemoryInputStream;
@@ -42,8 +42,8 @@ unsafe extern "C" fn begin_load(
match Loader::new().read_stream::<_, gio::File, gio::Cancellable>(&stream, None, None) {
Ok(handle) => {
- let mut ctx = SvgContext {
- size_func: size_func,
+ let ctx = SvgContext {
+ size_func,
prep_func,
update_func,
user_data,
@@ -78,13 +78,118 @@ unsafe extern "C" fn load_increment(
1
}
+fn argb_to_rgba(data: &mut Vec<u8>, width: i32, height: i32, stride: i32) {
+ for i in 0..height as usize {
+ let row_index = i * (width as usize * 4) + i * (stride as usize);
+ for j in 0..width {
+ let pixel_index = row_index + (j as usize * 4);
+ let tmp = data[pixel_index];
+ data[pixel_index] = data[pixel_index + 1];
+ data[pixel_index + 1] = data[pixel_index + 2];
+ data[pixel_index + 2] = data[pixel_index + 3];
+ data[pixel_index + 3] = tmp;
+ }
+ }
+}
+
#[no_mangle]
unsafe extern "C" fn stop_load(user_data: *mut c_void, error: *mut *mut GError) -> c_int {
+ let ctx = Box::from_raw(user_data as *mut SvgContext);
if error != null_mut() {
*error = null_mut();
}
- Box::from_raw(user_data as *mut SvgContext);
+ let renderer = librsvg::CairoRenderer::new(&ctx.handle);
+ let (w, h) = match renderer.intrinsic_size_in_pixels() {
+ Some((w, h)) => (w, h),
+ None => {
+ //TODO: Set Error
+ return 0;
+ }
+ };
+
+ let mut surface = match cairo::ImageSurface::create(
+ cairo::Format::ARgb32,
+ w.ceil() as i32,
+ h.ceil() as i32,
+ ) {
+ Ok(sfc) => sfc,
+ Err(e) => {
+ //TODO: Set Error
+ return 0;
+ }
+ };
+
+ let cr = match cairo::Context::new(&surface) {
+ Ok(cr) => cr,
+ Err(e) => {
+ //TODO: Set Error
+ return 0;
+ }
+ };
+
+ match renderer.render_document(
+ &cr,
+ &cairo::Rectangle {
+ x: 0.0,
+ y: 0.0,
+ width: w,
+ height: h,
+ },
+ ) {
+ Err(e) => {
+ //TODO: Set Error
+ return 0;
+ }
+ _ => {}
+ };
+
+ let mut w = w.ceil() as i32;
+ let mut h = h.ceil() as i32;
+
+ surface.flush();
+ let stride = surface.stride();
+ let sfc_data = surface.data().unwrap();
+ let sfc_data = std::slice::from_raw_parts(sfc_data.as_ptr(), sfc_data.len()); // This is just a slice to
the canonical data
+
+ // We need it as a mutable vector to move the alpha channel around
+ let mut pb_data = sfc_data.to_vec();
+
+ // GDK Pixbuf only support RGBA and Cairo only ARGB32, we swap channels around
+ argb_to_rgba(&mut pb_data, w, h, stride);
+
+ // Vector length and capacity to rebuild and destroy the vector in destroy_fn
+ let cb_data = Box::new((pb_data.len(), pb_data.capacity()));
+
+ // Function to free the pixel data by rebuilding the Vec object
+ #[no_mangle]
+ unsafe extern "C" fn destroy_fn(pixels: *mut u8, user_data: *mut c_void) {
+ let data = Box::<(usize, usize)>::from_raw(user_data as *mut (usize, usize));
+ Vec::from_raw_parts(pixels, data.0, data.1);
+ }
+
+ let pb_data = pb_data.leak::<'static>(); // Allocator stops tracking vector data
+ let pixbuf = gdk_pixbuf_sys::gdk_pixbuf_new_from_data(
+ pb_data.as_mut_ptr(),
+ gdk_pixbuf_sys::GDK_COLORSPACE_RGB,
+ 1,
+ 8,
+ w,
+ h,
+ stride,
+ Some(destroy_fn),
+ Box::into_raw(cb_data) as *mut c_void,
+ );
+ if let Some(size_func) = ctx.size_func {
+ size_func(&mut w as *mut i32, &mut h as *mut i32, ctx.user_data);
+ }
+ if let Some(update_func) = ctx.update_func {
+ update_func(pixbuf, 0, 0, w, h, ctx.user_data);
+ }
+ if let Some(prep_func) = ctx.prep_func {
+ prep_func(pixbuf, null_mut(), ctx.user_data);
+ }
+
1
}
@@ -95,48 +200,48 @@ extern "C" fn fill_vtable(module: &mut GdkPixbufModule) {
module.load_increment = Some(load_increment);
}
+const SIGNATURE: [GdkPixbufModulePattern; 3] = [
+ GdkPixbufModulePattern {
+ prefix: " <svg\0".as_ptr() as *mut c_char,
+ mask: "* \0".as_ptr() as *mut c_char,
+ relevance: 100,
+ },
+ GdkPixbufModulePattern {
+ prefix: " <!DOCTYPE svg\0".as_ptr() as *mut c_char,
+ mask: "* \0".as_ptr() as *mut c_char,
+ relevance: 100,
+ },
+ GdkPixbufModulePattern {
+ prefix: std::ptr::null_mut(),
+ mask: std::ptr::null_mut(),
+ relevance: 0,
+ },
+];
+
+const MIME_TYPES: [*const u8; 7] = [
+ "image/svg+xml\0".as_ptr(),
+ "image/svg\0".as_ptr(),
+ "image/svg-xml\0".as_ptr(),
+ "image/vnd.adobe.svg+xml\0".as_ptr(),
+ "text/xml-svg\0".as_ptr(),
+ "image/svg+xml-compressed\0".as_ptr(),
+ std::ptr::null(),
+];
+
+const EXTENSIONS: [*const u8; 4] = [
+ "svg\0".as_ptr(),
+ "svgz\0".as_ptr(),
+ "svg.gz\0".as_ptr(),
+ std::ptr::null(),
+];
+
#[no_mangle]
extern "C" fn fill_info(info: &mut GdkPixbufFormat) {
- let signature = vec![
- GdkPixbufModulePattern {
- mask: " <svg\0".as_ptr() as *mut i8,
- prefix: "* \0".as_ptr() as *mut i8,
- relevance: 100,
- },
- GdkPixbufModulePattern {
- mask: " <!DOCTYPE svg\0".as_ptr() as *mut i8,
- prefix: "* \0".as_ptr() as *mut i8,
- relevance: 100,
- },
- GdkPixbufModulePattern {
- mask: std::ptr::null_mut(),
- prefix: std::ptr::null_mut(),
- relevance: 0,
- },
- ];
-
- let mime_types = [
- "image/svg+xml\0".as_ptr(),
- "image/svg\0".as_ptr(),
- "image/svg-xml\0".as_ptr(),
- "image/vnd.adobe.svg+xml\0".as_ptr(),
- "text/xml-svg\0".as_ptr(),
- "image/svg+xml-compressed\0".as_ptr(),
- std::ptr::null(),
- ];
-
- let extensions = [
- "svg\0".as_ptr(),
- "svgz\0".as_ptr(),
- "svg.gz\0".as_ptr(),
- std::ptr::null(),
- ];
-
- info.name = "svg\0".as_ptr() as *mut i8;
- info.signature = signature.as_ptr() as *mut GdkPixbufModulePattern;
- info.description = "Scalable Vector Graphics\0".as_ptr() as *mut i8; //TODO: Gettext this
- info.mime_types = mime_types.as_ptr() as *mut *mut i8;
- info.extensions = extensions.as_ptr() as *mut *mut i8;
+ info.name = "svg\0".as_ptr() as *mut c_char;
+ info.signature = SIGNATURE.as_ptr() as *mut GdkPixbufModulePattern;
+ info.description = "Scalable Vector Graphics\0".as_ptr() as *mut c_char; //TODO: Gettext this
+ info.mime_types = MIME_TYPES.as_ptr() as *mut *mut c_char;
+ info.extensions = EXTENSIONS.as_ptr() as *mut *mut c_char;
info.flags = GDK_PIXBUF_FORMAT_SCALABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
- info.license = "LGPL\0".as_ptr() as *mut i8;
+ info.license = "LGPL\0".as_ptr() as *mut c_char;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]