[librsvg/wip/aruiz/rust-pixbuf-loader] pixbuf: initial stop_load implementation



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]