[librsvg/wip/aruiz/rust-pixbuf-loader] eureka!



commit 9563553cd971fcace83b07a3908140086f58f37e
Author: Alberto Ruiz <aruiz redhat com>
Date:   Wed Jul 27 17:58:21 2022 +0100

    eureka!

 gdk-pixbuf-loader/src/lib.rs | 92 ++++++++++++++++++++++++++------------------
 1 file changed, 55 insertions(+), 37 deletions(-)
---
diff --git a/gdk-pixbuf-loader/src/lib.rs b/gdk-pixbuf-loader/src/lib.rs
index ad3f8ae91..06e433ef6 100644
--- a/gdk-pixbuf-loader/src/lib.rs
+++ b/gdk-pixbuf-loader/src/lib.rs
@@ -12,7 +12,7 @@ use libc::{c_char, c_int, c_uint, c_void};
 use gio::prelude::MemoryInputStreamExt;
 use gio::MemoryInputStream;
 use glib::Bytes;
-use librsvg::{Loader, SvgHandle};
+use librsvg::Loader;
 
 #[allow(non_camel_case_types)]
 type c_bool = c_int;
@@ -23,7 +23,6 @@ struct SvgContext {
     update_func: GdkPixbufModuleUpdatedFunc,
     user_data: *mut c_void,
     stream: MemoryInputStream,
-    handle: SvgHandle,
 }
 
 #[no_mangle]
@@ -39,24 +38,15 @@ unsafe extern "C" fn begin_load(
     }
 
     let stream = MemoryInputStream::new();
+    let ctx = Box::new(SvgContext {
+        size_func,
+        prep_func,
+        update_func,
+        user_data,
+        stream,
+    });
 
-    match Loader::new().read_stream::<_, gio::File, gio::Cancellable>(&stream, None, None) {
-        Ok(handle) => {
-            let ctx = SvgContext {
-                size_func,
-                prep_func,
-                update_func,
-                user_data,
-                stream,
-                handle,
-            };
-            Box::into_raw(Box::new(ctx)) as *mut c_void
-        }
-        Err(e) => {
-            //TODO> Set error
-            null_mut()
-        }
-    }
+    Box::into_raw(ctx) as *mut c_void
 }
 
 #[no_mangle]
@@ -78,16 +68,16 @@ 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);
+fn argb_to_rgba(data: &mut Vec<u8>, width: usize, height: usize, stride: usize) {
+    assert!((width * 4) >= stride);
+    assert!((stride * height) <= data.len());
+    for i in 0..height {
+        let row_index = i * stride;
         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;
+            let pixel_index = row_index + (j * 4);
+            let tmp = data[pixel_index + 2];
+            data[pixel_index + 2] = data[pixel_index];
+            data[pixel_index] = tmp;
         }
     }
 }
@@ -99,23 +89,41 @@ unsafe extern "C" fn stop_load(user_data: *mut c_void, error: *mut *mut GError)
         *error = null_mut();
     }
 
-    let renderer = librsvg::CairoRenderer::new(&ctx.handle);
+    let handle = match Loader::new().read_stream::<_, gio::File, gio::Cancellable>(
+        &ctx.stream,
+        None,
+        None,
+    ) {
+        Ok(handle) => handle,
+        Err(e) => {
+            let gerr = glib::Error::new(gdk_pixbuf::PixbufError::Failed, &e.to_string());
+            *error = gerr.into_raw();
+            return 0;
+        }
+    };
+
+    let renderer = librsvg::CairoRenderer::new(&handle);
     let (w, h) = match renderer.intrinsic_size_in_pixels() {
         Some((w, h)) => (w, h),
         None => {
-            //TODO: Set Error
+            let gerr = glib::Error::new(
+                gdk_pixbuf::PixbufError::Failed,
+                "Could not get intrinsic size in pixel of Cairo memory surface",
+            );
+            *error = gerr.into_raw();
             return 0;
         }
     };
 
-    let mut surface = match cairo::ImageSurface::create(
+    let surface = match cairo::ImageSurface::create(
         cairo::Format::ARgb32,
         w.ceil() as i32,
         h.ceil() as i32,
     ) {
         Ok(sfc) => sfc,
         Err(e) => {
-            //TODO: Set Error
+            let gerr = glib::Error::new(gdk_pixbuf::PixbufError::Failed, &e.to_string());
+            *error = gerr.into_raw();
             return 0;
         }
     };
@@ -123,7 +131,8 @@ unsafe extern "C" fn stop_load(user_data: *mut c_void, error: *mut *mut GError)
     let cr = match cairo::Context::new(&surface) {
         Ok(cr) => cr,
         Err(e) => {
-            //TODO: Set Error
+            let gerr = glib::Error::new(gdk_pixbuf::PixbufError::Failed, &e.to_string());
+            *error = gerr.into_raw();
             return 0;
         }
     };
@@ -138,7 +147,8 @@ unsafe extern "C" fn stop_load(user_data: *mut c_void, error: *mut *mut GError)
         },
     ) {
         Err(e) => {
-            //TODO: Set Error
+            let gerr = glib::Error::new(gdk_pixbuf::PixbufError::Failed, &e.to_string());
+            *error = gerr.into_raw();
             return 0;
         }
         _ => {}
@@ -147,16 +157,24 @@ unsafe extern "C" fn stop_load(user_data: *mut c_void, error: *mut *mut GError)
     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();
+    // The cairo::Context holds a reference to the surface which needs to be dropped to access the data
+    std::mem::drop(cr);
+    let sfc_data = match surface.take_data() {
+        Ok(data) => data,
+        Err(e) => {
+            let gerr = glib::Error::new(gdk_pixbuf::PixbufError::Failed, &e.to_string());
+            *error = gerr.into_raw();
+            return 0;
+        }
+    };
     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);
+    argb_to_rgba(&mut pb_data, w as usize, h as usize, stride as usize);
 
     // Vector length and capacity to rebuild and destroy the vector in destroy_fn
     let cb_data = Box::new((pb_data.len(), pb_data.capacity()));


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]