[librsvg] handle: port get_pixbuf_sub to rust



commit 24096468be30c139582793920c2e472d9f825643
Author: Paolo Borelli <pborelli gnome org>
Date:   Wed Dec 26 11:56:30 2018 +0100

    handle: port get_pixbuf_sub to rust

 Cargo.lock                   |  1 +
 librsvg/rsvg-handle.c        | 32 ++----------------
 librsvg/rsvg-pixbuf.c        | 76 ------------------------------------------
 librsvg/rsvg-private.h       |  3 --
 rsvg_internals/Cargo.toml    |  1 +
 rsvg_internals/src/handle.rs | 79 ++++++++++++++++++++++++++++++++++++++++++--
 rsvg_internals/src/lib.rs    |  2 ++
 7 files changed, 83 insertions(+), 111 deletions(-)
---
diff --git a/Cargo.lock b/Cargo.lock
index 8dcf781b..2757a749 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -957,6 +957,7 @@ dependencies = [
  "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
  "float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gdk-pixbuf 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gdk-pixbuf-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "gio-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/librsvg/rsvg-handle.c b/librsvg/rsvg-handle.c
index 15b1bdf2..ee790c8c 100644
--- a/librsvg/rsvg-handle.c
+++ b/librsvg/rsvg-handle.c
@@ -176,6 +176,7 @@ extern gboolean rsvg_handle_rust_has_sub (RsvgHandle *handle, const char *id);
 extern gboolean rsvg_handle_rust_render_cairo_sub (RsvgHandle *handle,
                                                    cairo_t *cr,
                                                    const char *id);
+extern GdkPixbuf *rsvg_handle_rust_get_pixbuf_sub (RsvgHandle *handle, const char *id);
 
 struct RsvgHandlePrivate {
     RsvgSizeFunc size_func;
@@ -1241,42 +1242,13 @@ rsvg_handle_has_sub (RsvgHandle *handle,
 GdkPixbuf *
 rsvg_handle_get_pixbuf_sub (RsvgHandle * handle, const char *id)
 {
-    RsvgDimensionData dimensions;
-    GdkPixbuf *output = NULL;
-    cairo_surface_t *surface;
-    cairo_t *cr;
-
     g_return_val_if_fail (RSVG_IS_HANDLE (handle), NULL);
 
     if (!is_loaded (handle)) {
         return NULL;
     }
 
-    rsvg_handle_get_dimensions (handle, &dimensions);
-    if (!(dimensions.width && dimensions.height))
-        return NULL;
-
-    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-                                          dimensions.width, dimensions.height);
-    if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
-        cairo_surface_destroy (surface);
-        return NULL;
-    }
-
-    cr = cairo_create (surface);
-
-    if (!rsvg_handle_render_cairo_sub (handle, cr, id)) {
-        cairo_destroy (cr);
-        cairo_surface_destroy (surface);
-        return NULL;
-    }
-
-    cairo_destroy (cr);
-
-    output = rsvg_cairo_surface_to_pixbuf (surface);
-    cairo_surface_destroy (surface);
-
-    return output;
+    return rsvg_handle_rust_get_pixbuf_sub (handle, id);
 }
 
 /**
diff --git a/librsvg/rsvg-pixbuf.c b/librsvg/rsvg-pixbuf.c
index 57877c32..1687cf42 100644
--- a/librsvg/rsvg-pixbuf.c
+++ b/librsvg/rsvg-pixbuf.c
@@ -223,79 +223,3 @@ rsvg_pixbuf_from_file_at_max_size (const gchar * file_name,
 
     return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
 }
-
-/* Copied from gtk+/gdk/gdkpixbuf-drawable.c, LGPL 2+.
- *
- * Copyright (C) 1999 Michael Zucchi
- *
- * Authors: Michael Zucchi <zucchi zedzone mmc com au>
- *          Cody Russell <bratsche dfw net>
- *          Federico Mena-Quintero <federico gimp org>
- */
-
-static void
-convert_alpha (guchar *dest_data,
-               int     dest_stride,
-               guchar *src_data,
-               int     src_stride,
-               int     src_x,
-               int     src_y,
-               int     width,
-               int     height)
-{
-    int x, y;
-
-    src_data += src_stride * src_y + src_x * 4;
-
-    for (y = 0; y < height; y++) {
-        guint32 *src = (guint32 *) src_data;
-
-        for (x = 0; x < width; x++) {
-          guint alpha = src[x] >> 24;
-
-          if (alpha == 0) {
-              dest_data[x * 4 + 0] = 0;
-              dest_data[x * 4 + 1] = 0;
-              dest_data[x * 4 + 2] = 0;
-          } else {
-              dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
-              dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >>  8) * 255 + alpha / 2) / alpha;
-              dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >>  0) * 255 + alpha / 2) / alpha;
-          }
-          dest_data[x * 4 + 3] = alpha;
-      }
-
-      src_data += src_stride;
-      dest_data += dest_stride;
-    }
-}
-
-GdkPixbuf *
-rsvg_cairo_surface_to_pixbuf (cairo_surface_t *surface)
-{
-    GdkPixbuf *dest;
-    int width, height;
-
-    /* General sanity checks */
-    g_assert (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE);
-    g_assert (cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32);
-
-    width = cairo_image_surface_get_width (surface);
-    height = cairo_image_surface_get_height (surface);
-    if (width == 0 || height == 0)
-        return NULL;
-
-    dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
-                           TRUE,
-                           8,
-                           width, height);
-
-    convert_alpha (gdk_pixbuf_get_pixels (dest),
-                   gdk_pixbuf_get_rowstride (dest),
-                   cairo_image_surface_get_data (surface),
-                   cairo_image_surface_get_stride (surface),
-                   0, 0,
-                   width, height);
-
-    return dest;
-}
diff --git a/librsvg/rsvg-private.h b/librsvg/rsvg-private.h
index 22911e2f..05c5cca7 100644
--- a/librsvg/rsvg-private.h
+++ b/librsvg/rsvg-private.h
@@ -66,9 +66,6 @@ double rsvg_get_default_dpi_x (void);
 G_GNUC_INTERNAL
 double rsvg_get_default_dpi_y (void);
 
-G_GNUC_INTERNAL
-GdkPixbuf *rsvg_cairo_surface_to_pixbuf (cairo_surface_t *surface);
-
 G_GNUC_INTERNAL
 void rsvg_return_if_fail_warning (const char *pretty_function,
                                   const char *expression, GError ** error);
diff --git a/rsvg_internals/Cargo.toml b/rsvg_internals/Cargo.toml
index bf89d050..c9f077c2 100644
--- a/rsvg_internals/Cargo.toml
+++ b/rsvg_internals/Cargo.toml
@@ -28,6 +28,7 @@ downcast-rs = "^1.0.0"
 encoding = "0.2.33"
 float-cmp = "0.4.0"
 gdk-pixbuf = "0.5.0"
+gdk-pixbuf-sys = "0.7.0"
 gio = { version="0.5.1", features=["v2_48"] } # per configure.ac
 gio-sys = "0.7.0"
 glib = "0.6.0"
diff --git a/rsvg_internals/src/handle.rs b/rsvg_internals/src/handle.rs
index 60a80898..1e52fe53 100644
--- a/rsvg_internals/src/handle.rs
+++ b/rsvg_internals/src/handle.rs
@@ -6,7 +6,8 @@ use std::slice;
 
 use cairo::{self, ImageSurface, Status};
 use cairo_sys;
-use gdk_pixbuf::{PixbufLoader, PixbufLoaderExt};
+use gdk_pixbuf::{Colorspace, Pixbuf, PixbufLoader, PixbufLoaderExt};
+use gdk_pixbuf_sys;
 use gio::{File as GFile, InputStream};
 use gio_sys;
 use glib::translate::*;
@@ -20,11 +21,16 @@ use defs::{Fragment, Href};
 use dpi::Dpi;
 use drawing_ctx::{DrawingCtx, RsvgRectangle};
 use error::{set_gerror, DefsLookupErrorKind, LoadingError, RenderingError};
+use filters::context::IRect;
 use io;
 use load::LoadContext;
 use node::{Node, RsvgNode};
 use structure::NodeSvg;
-use surface_utils::shared_surface::SharedImageSurface;
+use surface_utils::{
+    iterators::Pixels,
+    shared_surface::SharedImageSurface,
+    shared_surface::SurfaceType,
+};
 use svg::Svg;
 use util::rsvg_g_warning;
 use xml::XmlState;
@@ -428,6 +434,60 @@ impl Handle {
 
         res
     }
+
+    fn get_pixbuf_sub(
+        &mut self,
+        handle: *mut RsvgHandle,
+        id: Option<&str>,
+    ) -> Result<Pixbuf, RenderingError> {
+        let mut dimensions = unsafe { mem::zeroed() };
+
+        unsafe {
+            rsvg_handle_get_dimensions(handle, &mut dimensions);
+        }
+
+        if dimensions.width == 0 || dimensions.height == 0 {
+            return Err(RenderingError::SvgHasNoSize);
+        }
+
+        let surface =
+            ImageSurface::create(cairo::Format::ARgb32, dimensions.width, dimensions.height)?;
+
+        {
+            let cr = cairo::Context::new(&surface);
+            self.render_cairo_sub(handle, &cr, id)?;
+        }
+
+        let surface = SharedImageSurface::new(surface, SurfaceType::SRgb)?;
+
+        let bounds = IRect {
+            x0: 0,
+            y0: 0,
+            x1: dimensions.width,
+            y1: dimensions.height,
+        };
+
+        let pixbuf = Pixbuf::new(
+            Colorspace::Rgb,
+            true,
+            8,
+            dimensions.width,
+            dimensions.height,
+        );
+
+        for (x, y, pixel) in Pixels::new(&surface, bounds) {
+            let (r, g, b, a) = if pixel.a == 0 {
+                (0, 0, 0, 0)
+            } else {
+                let pixel = pixel.unpremultiply();
+                (pixel.r, pixel.g, pixel.b, pixel.a)
+            };
+
+            pixbuf.put_pixel(x as i32, y as i32, r, g, b, a);
+        }
+
+        Ok(pixbuf)
+    }
 }
 
 // Keep these in sync with rsvg.h:RsvgHandleFlags
@@ -910,3 +970,18 @@ pub unsafe extern "C" fn rsvg_handle_rust_render_cairo_sub(
         }
     }
 }
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_handle_rust_get_pixbuf_sub(
+    handle: *mut RsvgHandle,
+    id: *const libc::c_char,
+) -> *mut gdk_pixbuf_sys::GdkPixbuf {
+    let rhandle = get_rust_handle(handle);
+
+    let id: Option<String> = from_glib_none(id);
+
+    match rhandle.get_pixbuf_sub(handle, id.as_ref().map(String::as_str)) {
+        Ok(pixbuf) => pixbuf.to_glib_full(),
+        Err(_) => ptr::null_mut(),
+    }
+}
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index 7fb70e79..771c6dd5 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -11,6 +11,7 @@ extern crate downcast_rs;
 extern crate encoding;
 extern crate float_cmp;
 extern crate gdk_pixbuf;
+extern crate gdk_pixbuf_sys;
 extern crate gio;
 extern crate gio_sys;
 extern crate glib;
@@ -44,6 +45,7 @@ pub use handle::{
     rsvg_handle_rust_get_flags,
     rsvg_handle_rust_get_geometry_sub,
     rsvg_handle_rust_get_load_state,
+    rsvg_handle_rust_get_pixbuf_sub,
     rsvg_handle_rust_has_sub,
     rsvg_handle_rust_new,
     rsvg_handle_rust_read_stream_sync,


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