[murrine] Added blur capabilities and menustyle = 2.



commit fd9b854f14ea45c8efaca016e802d2d80ab83c0c
Author: Andrea Cimitan <andrea cimitan gmail com>
Date:   Thu Aug 5 18:21:11 2010 +0100

    Added blur capabilities and menustyle = 2.

 CREDITS                 |    2 +
 Makefile.am             |   10 ++-
 NEWS                    |    1 +
 src/exponential-blur.c  |  299 ++++++++++++++++++++++++++++++++++++++++
 src/exponential-blur.h  |   42 ++++++
 src/gaussian-blur.c     |  172 +++++++++++++++++++++++
 src/gaussian-blur.h     |   42 ++++++
 src/murrine_draw.c      |   29 ++++-
 src/murrine_draw_rgba.c |   27 ++++-
 src/raico-blur.c        |  184 +++++++++++++++++++++++++
 src/raico-blur.h        |   73 ++++++++++
 src/stack-blur.c        |  346 +++++++++++++++++++++++++++++++++++++++++++++++
 src/stack-blur.h        |   42 ++++++
 13 files changed, 1266 insertions(+), 3 deletions(-)
---
diff --git a/CREDITS b/CREDITS
index a80111f..ceb3b64 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1,5 +1,7 @@
 Cimi's thanks:
 
+Mirco Mueller  - for his amazing blur functions :)
+
 Doug Whitely   - for the permission to edit his theme and for the little help.
 
 Oliver Tobin   - for his support to refine my theme.
diff --git a/Makefile.am b/Makefile.am
index 9b58109..cd7162d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -24,7 +24,15 @@ libmurrine_la_SOURCES = \
 	./src/murrine_draw.c \
 	./src/murrine_draw_rgba.c \
 	./src/murrine_draw.h \
-	./src/murrine_types.h
+	./src/murrine_types.h \
+	./src/exponential-blur.c \
+	./src/exponential-blur.h \
+	./src/gaussian-blur.c \
+	./src/gaussian-blur.h \
+	./src/raico-blur.c \
+	./src/raico-blur.h \
+	./src/stack-blur.c \
+	./src/stack-blur.h
 
 libmurrine_la_LDFLAGS = -module -avoid-version -no-undefined
 libmurrine_la_LIBADD =  $(GTK_LIBS)
diff --git a/NEWS b/NEWS
index e6e8eaa..a0b459c 100644
--- a/NEWS
+++ b/NEWS
@@ -45,6 +45,7 @@ Changes in this release:
 - New option: trough_shades = { 1.0, 1.0 } to draw a gradient on
               the trough of GtkScrollbar and GtkProgressBar.
 - Changed option: listviewstyle = 2 for a solid line.
+- Changed option: menustyle = 2 for glow on the sides of the menu.
 - Changed option: reliefstyle = 3 for a gradient on shadow.
                   reliefstyle = 4 for a stronger shadow.
 - Changed option: stepperstyle = 2 for squared steppers with a rounded slider.
diff --git a/src/exponential-blur.c b/src/exponential-blur.c
new file mode 100644
index 0000000..ea6b085
--- /dev/null
+++ b/src/exponential-blur.c
@@ -0,0 +1,299 @@
+////////////////////////////////////////////////////////////////////////////////
+//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
+//      10        20        30        40        50        60        70        80
+//
+// raico-blur
+//
+// exponential-blur.c - implements exponential-blur function
+//
+// Copyright 2009 Canonical Ltd.
+//
+// Authors:
+//    Mirco "MacSlow" Mueller <mirco mueller canonical com>
+//    Jason Smith <jason smith canonical com>
+//
+// Notes:
+//    based on exponential-blur algorithm by Jani Huhtanen
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 3, as published
+// by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranties of
+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+// PURPOSE.  See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// FIXME: not working yet, unfinished
+
+#include <math.h>
+
+#include "exponential-blur.h"
+
+static inline void
+_blurinner (guchar* pixel,
+	    gint   *zR,
+	    gint   *zG,
+	    gint   *zB,
+	    gint   *zA,
+	    gint    alpha,
+	    gint    aprec,
+	    gint    zprec);
+
+static inline void
+_blurrow (guchar* pixels,
+	  gint    width,
+	  gint    height,
+	  gint    channels,
+	  gint    line,
+	  gint    alpha,
+	  gint    aprec,
+	  gint    zprec);
+
+static inline void
+_blurcol (guchar* pixels,
+	  gint    width,
+	  gint    height,
+	  gint    channels,
+	  gint    col,
+	  gint    alpha,
+	  gint    aprec,
+	  gint    zprec);
+
+void
+_expblur (guchar* pixels,
+	  gint    width,
+	  gint    height,
+	  gint    channels,
+	  gint    radius,
+	  gint    aprec,
+	  gint    zprec);
+
+void
+surface_exponential_blur (cairo_surface_t* surface,
+			  guint            radius)
+{
+	guchar*        pixels;
+	guint          width;
+	guint          height;
+	cairo_format_t format;
+
+	// sanity checks are done in raico-blur.c
+
+	// before we mess with the surface execute any pending drawing
+	cairo_surface_flush (surface);
+
+	pixels = cairo_image_surface_get_data (surface);
+	width  = cairo_image_surface_get_width (surface);
+	height = cairo_image_surface_get_height (surface);
+	format = cairo_image_surface_get_format (surface);
+
+	switch (format)
+	{
+		case CAIRO_FORMAT_ARGB32:
+			_expblur (pixels, width, height, 4, radius, 16, 7);
+		break;
+
+		case CAIRO_FORMAT_RGB24:
+			_expblur (pixels, width, height, 3, radius, 16, 7);
+		break;
+
+		case CAIRO_FORMAT_A8:
+			_expblur (pixels, width, height, 1, radius, 16, 7);
+		break;
+
+		default :
+			// do nothing
+		break;
+	}
+
+	// inform cairo we altered the surfaces contents
+	cairo_surface_mark_dirty (surface);	
+}
+
+//
+// pixels   image-data
+// width    image-width
+// height   image-height
+// channels image-channels
+//
+// in-place blur of image 'img' with kernel of approximate radius 'radius'
+//
+// blurs with two sided exponential impulse response
+//
+// aprec = precision of alpha parameter in fixed-point format 0.aprec
+//
+// zprec = precision of state parameters zR,zG,zB and zA in fp format 8.zprec
+//
+void
+_expblur (guchar* pixels,
+	  gint    width,
+	  gint    height,
+	  gint    channels,
+	  gint    radius,
+	  gint    aprec,
+	  gint    zprec)
+{
+	gint alpha;
+	gint row = 0;
+	gint col = 0;
+
+	if (radius < 1)
+		return;
+
+	// calculate the alpha such that 90% of 
+	// the kernel is within the radius.
+	// (Kernel extends to infinity)
+	alpha = (gint) ((1 << aprec) * (1.0f - expf (-2.3f / (radius + 1.f))));
+
+	for (; row < height; row++)
+		_blurrow (pixels,
+			  width,
+			  height,
+			  channels,
+			  row,
+			  alpha,
+			  aprec,
+			  zprec);
+
+	for(; col < width; col++)
+		_blurcol (pixels,
+			  width,
+			  height,
+			  channels,
+			  col,
+			  alpha,
+			  aprec,
+			  zprec);
+
+	return;
+}
+
+static inline void
+_blurinner (guchar* pixel,
+	    gint   *zR,
+	    gint   *zG,
+	    gint   *zB,
+	    gint   *zA,
+	    gint    alpha,
+	    gint    aprec,
+	    gint    zprec)
+{
+	gint R;
+	gint G;
+	gint B;
+	guchar A;
+
+	R = *pixel;
+	G = *(pixel + 1);
+	B = *(pixel + 2);
+	A = *(pixel + 3);
+
+	*zR += (alpha * ((R << zprec) - *zR)) >> aprec;
+	*zG += (alpha * ((G << zprec) - *zG)) >> aprec;
+	*zB += (alpha * ((B << zprec) - *zB)) >> aprec;
+	*zA += (alpha * ((A << zprec) - *zA)) >> aprec;
+
+	*pixel       = *zR >> zprec;
+	*(pixel + 1) = *zG >> zprec;
+	*(pixel + 2) = *zB >> zprec;
+	*(pixel + 3) = *zA >> zprec;
+} 
+
+static inline void
+_blurrow (guchar* pixels,
+	  gint    width,
+	  gint    height,
+	  gint    channels,
+	  gint    line,
+	  gint    alpha,
+	  gint    aprec,
+	  gint    zprec)
+{
+	gint    zR;
+	gint    zG;
+	gint    zB;
+	gint    zA;
+	gint    index;
+	guchar* scanline;
+
+	scanline = &(pixels[line * width * channels]);
+
+	zR = *scanline << zprec;
+	zG = *(scanline + 1) << zprec;
+	zB = *(scanline + 2) << zprec;
+	zA = *(scanline + 3) << zprec;
+
+	for (index = 0; index < width; index ++)
+		_blurinner (&scanline[index * channels],
+			    &zR,
+			    &zG,
+			    &zB,
+			    &zA,
+			    alpha,
+			    aprec,
+			    zprec);
+
+	for (index = width - 2; index >= 0; index--)
+		_blurinner (&scanline[index * channels],
+			    &zR,
+			    &zG,
+			    &zB,
+			    &zA,
+			    alpha,
+			    aprec,
+			    zprec);
+}
+
+static inline void
+_blurcol (guchar* pixels,
+	  gint    width,
+	  gint    height,
+	  gint    channels,
+	  gint    x,
+	  gint    alpha,
+	  gint    aprec,
+	  gint    zprec)
+{
+	gint zR;
+	gint zG;
+	gint zB;
+	gint zA;
+	gint index;
+	guchar* ptr;
+
+	ptr = pixels;
+	
+	ptr += x * channels;
+
+	zR = *((guchar*) ptr    ) << zprec;
+	zG = *((guchar*) ptr + 1) << zprec;
+	zB = *((guchar*) ptr + 2) << zprec;
+	zA = *((guchar*) ptr + 3) << zprec;
+
+	for (index = width; index < (height - 1) * width; index += width)
+		_blurinner ((guchar*) &ptr[index * channels],
+			    &zR,
+			    &zG,
+			    &zB,
+			    &zA,
+			    alpha,
+			    aprec,
+			    zprec);
+
+	for (index = (height - 2) * width; index >= 0; index -= width)
+		_blurinner ((guchar*) &ptr[index * channels],
+			    &zR,
+			    &zG,
+			    &zB,
+			    &zA,
+			    alpha,
+			    aprec,
+			    zprec);
+}
+
diff --git a/src/exponential-blur.h b/src/exponential-blur.h
new file mode 100644
index 0000000..203fd0a
--- /dev/null
+++ b/src/exponential-blur.h
@@ -0,0 +1,42 @@
+////////////////////////////////////////////////////////////////////////////////
+//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
+//      10        20        30        40        50        60        70        80
+//
+// raico-blur
+//
+// exponential-blur.h - implements exponential-blur function
+//
+// Copyright 2009 Canonical Ltd.
+//
+// Authors:
+//    Mirco "MacSlow" Mueller <mirco mueller canonical com>
+//
+// Notes:
+//    based on exponential-blur algorithm by Jani Huhtanen
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 3, as published
+// by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranties of
+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+// PURPOSE.  See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _EXPONENTIAL_BLUR_H
+#define _EXPONENTIAL_BLUR_H
+
+#include <glib.h>
+#include <cairo.h>
+
+void
+surface_exponential_blur (cairo_surface_t* surface,
+			  guint            radius);
+
+#endif // _EXPONENTIAL_BLUR_H
+
diff --git a/src/gaussian-blur.c b/src/gaussian-blur.c
new file mode 100644
index 0000000..7694ebc
--- /dev/null
+++ b/src/gaussian-blur.c
@@ -0,0 +1,172 @@
+////////////////////////////////////////////////////////////////////////////////
+//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
+//      10        20        30        40        50        60        70        80
+//
+// raico-blur
+//
+// gaussian-blur.c - implements gaussian-blur function
+//
+// Copyright 2009 Canonical Ltd.
+//
+// Authors:
+//    Mirco "MacSlow" Mueller <mirco mueller canonical com>
+//
+// Notes:
+//    based on filters in libpixman
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 3, as published
+// by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranties of
+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+// PURPOSE.  See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <math.h>
+#include <pixman.h>
+
+#include "gaussian-blur.h"
+
+pixman_fixed_t*
+create_gaussian_blur_kernel (gint    radius,
+                             gdouble sigma,
+                             gint*   length)
+{
+	const gdouble   scale2 = 2.0f * sigma * sigma;
+	const gdouble   scale1 = 1.0f / (G_PI * scale2);
+	const gint      size = 2 * radius + 1;
+	const gint      n_params = size * size;
+	pixman_fixed_t* params;
+	gdouble*        tmp;
+	gdouble         sum;
+	gint            x;
+	gint            y;
+	gint            i;
+
+        tmp = g_newa (double, n_params);
+
+        // caluclate gaussian kernel in floating point format
+        for (i = 0, sum = 0, x = -radius; x <= radius; ++x) {
+                for (y = -radius; y <= radius; ++y, ++i) {
+                        const gdouble u = x * x;
+                        const gdouble v = y * y;
+
+                        tmp[i] = scale1 * exp (-(u+v)/scale2);
+
+                        sum += tmp[i];
+                }
+        }
+
+        // normalize gaussian kernel and convert to fixed point format
+        params = g_new (pixman_fixed_t, n_params + 2);
+
+        params[0] = pixman_int_to_fixed (size);
+        params[1] = pixman_int_to_fixed (size);
+
+        for (i = 0; i < n_params; ++i)
+                params[2 + i] = pixman_double_to_fixed (tmp[i] / sum);
+
+        if (length)
+                *length = n_params + 2;
+
+        return params;
+}
+
+void
+_blur_image_surface (cairo_surface_t* surface,
+		     gint             radius,
+		     gdouble          sigma /* pass 0.0f for auto-calculation */)
+{
+        pixman_fixed_t* params = NULL;
+        gint            n_params;
+        pixman_image_t* src;
+        gint            w;
+        gint            h;
+        gint            s;
+        gpointer        p;
+	gdouble         radiusf;
+
+	radiusf = fabs (radius) + 1.0f;
+	if (sigma == 0.0f)
+		sigma = sqrt (-(radiusf * radiusf) / (2.0f * log (1.0f / 255.0f)));
+
+        w = cairo_image_surface_get_width (surface);
+        h = cairo_image_surface_get_height (surface);
+        s = cairo_image_surface_get_stride (surface);
+
+	// create pixman image for cairo image surface
+	p = cairo_image_surface_get_data (surface);
+	src = pixman_image_create_bits (PIXMAN_a8r8g8b8, w, h, p, s);
+
+	// attach gaussian kernel to pixman image
+	params = create_gaussian_blur_kernel (radius, sigma, &n_params);
+	pixman_image_set_filter (src,
+				 PIXMAN_FILTER_CONVOLUTION,
+				 params,
+				 n_params);
+	g_free (params);
+
+        // render blured image to new pixman image
+        pixman_image_composite (PIXMAN_OP_SRC,
+				src,
+				NULL,
+				src,
+				0,
+				0,
+				0,
+				0,
+				0,
+				0,
+				w,
+				h);
+	pixman_image_unref (src);
+}
+
+void
+surface_gaussian_blur (cairo_surface_t* surface,
+		       guint            radius)
+{
+	guchar*        pixels;
+	guint          width;
+	guint          height;
+	cairo_format_t format;
+
+	// sanity checks are done in raico-blur.c
+
+	// before we mess with the surface execute any pending drawing
+	cairo_surface_flush (surface);
+
+	pixels = cairo_image_surface_get_data (surface);
+	width  = cairo_image_surface_get_width (surface);
+	height = cairo_image_surface_get_height (surface);
+	format = cairo_image_surface_get_format (surface);
+
+	switch (format)
+	{
+		case CAIRO_FORMAT_ARGB32:
+			_blur_image_surface (surface, radius, 0.0f);
+		break;
+
+		case CAIRO_FORMAT_RGB24:
+			// do nothing, for now
+		break;
+
+		case CAIRO_FORMAT_A8:
+			// do nothing, for now
+		break;
+
+		default :
+			// do nothing
+		break;
+	}
+
+	// inform cairo we altered the surfaces contents
+	cairo_surface_mark_dirty (surface);	
+}
+
diff --git a/src/gaussian-blur.h b/src/gaussian-blur.h
new file mode 100644
index 0000000..e06f352
--- /dev/null
+++ b/src/gaussian-blur.h
@@ -0,0 +1,42 @@
+////////////////////////////////////////////////////////////////////////////////
+//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
+//      10        20        30        40        50        60        70        80
+//
+// notify-osd
+//
+// gaussian-blur.h - implements gaussian-blur function
+//
+// Copyright 2009 Canonical Ltd.
+//
+// Authors:
+//    Mirco "MacSlow" Mueller <mirco mueller canonical com>
+//
+// Notes:
+//    based on filters in libpixman
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 3, as published
+// by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranties of
+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+// PURPOSE.  See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _GAUSSIAN_BLUR_H
+#define _GAUSSIAN_BLUR_H
+
+#include <glib.h>
+#include <cairo.h>
+
+void
+surface_gaussian_blur (cairo_surface_t* surface,
+		       guint            radius);
+
+#endif // _GAUSSIAN_BLUR_H
+
diff --git a/src/murrine_draw.c b/src/murrine_draw.c
index bac84e3..b4a62e6 100644
--- a/src/murrine_draw.c
+++ b/src/murrine_draw.c
@@ -25,6 +25,7 @@
 #include "murrine_types.h"
 #include "support.h"
 #include "cairo-support.h"
+#include "raico-blur.h"
 
 static void
 murrine_draw_inset (cairo_t *cr,
@@ -2272,7 +2273,7 @@ murrine_draw_menu_frame (cairo_t *cr,
                          int x, int y, int width, int height,
                          int menustyle)
 {
-	const MurrineRGB *border = &colors->shade[5];
+	const MurrineRGB *border = &colors->shade[menustyle == 2 ? 2 : 5];
 
 	cairo_translate       (cr, x, y);
 
@@ -2280,6 +2281,7 @@ murrine_draw_menu_frame (cairo_t *cr,
 	cairo_rectangle       (cr, 0.5, 0.5, width-1, height-1);
 	cairo_stroke          (cr);
 
+
 	if (menustyle == 1)
 	{
 		MurrineRGB *fill = (MurrineRGB*)&colors->spot[1];
@@ -2293,6 +2295,31 @@ murrine_draw_menu_frame (cairo_t *cr,
 		murrine_set_color_rgb (cr, fill);
 		cairo_fill (cr);
 	}
+
+	if (menustyle == 2)
+	{
+		raico_blur_t* blur = NULL;
+		cairo_t *cr_surface; 
+		cairo_surface_t *surface; 
+
+		MurrineRGB fill;
+		murrine_shade (&colors->bg[0], 0.1, &fill);
+
+		/* draw glow */
+		surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width+40, height+40);
+		cr_surface = cairo_create (surface); 
+		blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW);
+		raico_blur_set_radius (blur, 20);
+		cairo_set_line_width (cr_surface, 4.0);
+		cairo_rectangle (cr_surface, 20, 15, width, height+5);
+		murrine_set_color_rgb (cr_surface, &fill);
+		cairo_stroke (cr_surface);
+		raico_blur_apply (blur, surface);
+		cairo_set_source_surface (cr, surface, -20, -20); 
+		cairo_paint (cr);
+		cairo_surface_destroy (surface); 
+		cairo_destroy (cr_surface); 
+	}
 }
 
 static void
diff --git a/src/murrine_draw_rgba.c b/src/murrine_draw_rgba.c
index 04e20dc..c283247 100644
--- a/src/murrine_draw_rgba.c
+++ b/src/murrine_draw_rgba.c
@@ -2225,7 +2225,7 @@ murrine_rgba_draw_menu_frame (cairo_t *cr,
                               int x, int y, int width, int height,
                               int menustyle)
 {
-	const MurrineRGB *border = &colors->shade[5];
+	const MurrineRGB *border = &colors->shade[menustyle == 2 ? 2 : 5];
 	uint8 corners = (menustyle == 1 ? MRN_CORNER_BOTTOMRIGHT :
 	                                  MRN_CORNER_BOTTOMLEFT | MRN_CORNER_BOTTOMRIGHT);
 
@@ -2256,6 +2256,31 @@ murrine_rgba_draw_menu_frame (cairo_t *cr,
 		murrine_set_color_rgb (cr, fill);
 		cairo_fill (cr);
 	}
+
+	if (menustyle == 2)
+	{
+		raico_blur_t* blur = NULL;
+		cairo_t *cr_surface; 
+		cairo_surface_t *surface; 
+
+		MurrineRGB fill;
+		murrine_shade (&colors->bg[0], 0.1, &fill);
+
+		/* draw glow */
+		surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width+40, height+40);
+		cr_surface = cairo_create (surface); 
+		blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW);
+		raico_blur_set_radius (blur, 20);
+		cairo_set_line_width (cr_surface, 4.0);
+		cairo_rectangle (cr_surface, 20, 15, width, height+5);
+		murrine_set_color_rgb (cr_surface, &fill);
+		cairo_stroke (cr_surface);
+		raico_blur_apply (blur, surface);
+		cairo_set_source_surface (cr, surface, -20, -20); 
+		cairo_paint (cr);
+		cairo_surface_destroy (surface); 
+		cairo_destroy (cr_surface); 
+	}
 }
 
 static void
diff --git a/src/raico-blur.c b/src/raico-blur.c
new file mode 100644
index 0000000..2fdc08f
--- /dev/null
+++ b/src/raico-blur.c
@@ -0,0 +1,184 @@
+////////////////////////////////////////////////////////////////////////////////
+//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
+//      10        20        30        40        50        60        70        80
+//
+// notify-osd
+//
+// raico-blur.c - implements public API for blurring cairo image-surfaces
+//
+// Copyright 2009 Canonical Ltd.
+//
+// Authors:
+//    Mirco "MacSlow" Mueller <mirco mueller canonical com>
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 3, as published
+// by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranties of
+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+// PURPOSE.  See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include "raico-blur.h"
+#include "exponential-blur.h"
+#include "stack-blur.h"
+#include "gaussian-blur.h"
+
+struct _raico_blur_private_t
+{
+	raico_blur_quality_t quality; // low, medium, high
+	guint                radius;  // blur-radius
+};
+
+raico_blur_t*
+raico_blur_create (raico_blur_quality_t quality)
+{
+	raico_blur_t*         blur = NULL;
+	raico_blur_private_t* priv = NULL;
+
+	blur = g_new0 (raico_blur_t, 1);
+	if (!blur)
+	{
+		g_debug ("raico_blur_create(): could not allocate blur struct");
+		return NULL;
+	}
+
+	priv = g_new0 (raico_blur_private_t, 1);
+	if (!priv)
+	{
+		g_debug ("raico_blur_create(): could not allocate priv struct");
+		g_free ((gpointer) blur);
+		return NULL;
+	}
+
+	priv->quality = quality;
+	priv->radius  = 0;
+
+	blur->priv = priv;
+
+	return blur;
+}
+
+raico_blur_quality_t
+raico_blur_get_quality (raico_blur_t* blur)
+{
+	g_assert (blur != NULL);
+
+	return blur->priv->quality;
+}
+
+void
+raico_blur_set_quality (raico_blur_t*        blur,
+			raico_blur_quality_t quality)
+{
+	if (!blur)
+	{
+		g_debug ("raico_blur_set_quality(): NULL blur-pointer passed");
+		return;
+	}
+
+	blur->priv->quality = quality;
+}
+
+guint
+raico_blur_get_radius (raico_blur_t* blur)
+{
+	g_assert (blur != NULL);
+
+	return blur->priv->radius;
+}
+
+void
+raico_blur_set_radius (raico_blur_t* blur,
+		       guint         radius)
+{
+	if (!blur)
+	{
+		g_debug ("raico_blur_set_radius(): NULL blur-pointer passed");
+		return;
+	}
+
+	blur->priv->radius = radius;
+}
+
+void
+raico_blur_apply (raico_blur_t*    blur,
+		  cairo_surface_t* surface)
+{
+	cairo_format_t format;
+
+	// sanity checks
+	if (!blur)
+	{
+		g_debug ("raico_blur_apply(): NULL blur-pointer passed");
+		return;
+	}
+
+	if (!surface)
+	{
+		g_debug ("raico_blur_apply(): NULL surface-pointer passed");
+		return;
+	}
+
+	if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
+	{
+		g_debug ("raico_blur_apply(): invalid surface status");
+		return;
+	}
+
+	if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_IMAGE)
+	{
+		g_debug ("raico_blur_apply(): non-image surface passed");
+		return;
+	}
+
+	format = cairo_image_surface_get_format (surface);
+	if (format != CAIRO_FORMAT_A8 &&
+	    format != CAIRO_FORMAT_RGB24 &&
+	    format != CAIRO_FORMAT_ARGB32)
+	{
+		g_debug ("raico_blur_apply(): unsupported image-format");
+		return;
+	}
+
+	// stupid, but you never know
+	if (blur->priv->radius == 0)
+		return;
+
+	// now do the real work
+	switch (blur->priv->quality)
+	{
+		case RAICO_BLUR_QUALITY_LOW:
+			surface_exponential_blur (surface, blur->priv->radius);
+		break;
+
+		case RAICO_BLUR_QUALITY_MEDIUM:
+			//surface_stack_blur (surface, blur->priv->radius);
+			surface_gaussian_blur (surface, blur->priv->radius);
+		break;
+
+		case RAICO_BLUR_QUALITY_HIGH:
+			surface_gaussian_blur (surface, blur->priv->radius);
+		break;
+	}
+}
+
+void
+raico_blur_destroy (raico_blur_t* blur)
+{
+	if (!blur)
+	{
+		g_debug ("raico_blur_destroy(): invalid blur-pointer passed");
+		return;
+	}
+
+	g_free ((gpointer) blur->priv);
+	g_free ((gpointer) blur);
+}
+
diff --git a/src/raico-blur.h b/src/raico-blur.h
new file mode 100644
index 0000000..c1d743e
--- /dev/null
+++ b/src/raico-blur.h
@@ -0,0 +1,73 @@
+////////////////////////////////////////////////////////////////////////////////
+//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
+//      10        20        30        40        50        60        70        80
+//
+// notify-osd
+//
+// raico-blur.h - implements public API for blurring cairo image-surfaces
+//
+// Copyright 2009 Canonical Ltd.
+//
+// Authors:
+//    Mirco "MacSlow" Mueller <mirco mueller canonical com>
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 3, as published
+// by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranties of
+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+// PURPOSE.  See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _RAICO_BLUR_H
+#define _RAICO_BLUR_H
+
+#include <glib.h>
+#include <cairo.h>
+
+typedef enum _raico_blur_quality_t
+{
+	RAICO_BLUR_QUALITY_LOW = 0, // low quality, but fast, maybe interactive
+	RAICO_BLUR_QUALITY_MEDIUM,  // compromise between speed and quality
+	RAICO_BLUR_QUALITY_HIGH     // quality before speed
+} raico_blur_quality_t;
+
+typedef struct _raico_blur_private_t raico_blur_private_t;
+
+typedef struct _raico_blur_t
+{
+	raico_blur_private_t* priv;
+} raico_blur_t;
+
+raico_blur_t*
+raico_blur_create (raico_blur_quality_t quality);
+
+raico_blur_quality_t
+raico_blur_get_quality (raico_blur_t* blur);
+
+void
+raico_blur_set_quality (raico_blur_t*        blur,
+			raico_blur_quality_t quality);
+
+guint
+raico_blur_get_radius (raico_blur_t* blur);
+
+void
+raico_blur_set_radius (raico_blur_t* blur,
+		       guint         radius);
+
+void
+raico_blur_apply (raico_blur_t*    blur,
+		  cairo_surface_t* surface);
+
+void
+raico_blur_destroy (raico_blur_t* blur);
+
+#endif // _RAICO_BLUR_H
+
diff --git a/src/stack-blur.c b/src/stack-blur.c
new file mode 100644
index 0000000..fe3bce3
--- /dev/null
+++ b/src/stack-blur.c
@@ -0,0 +1,346 @@
+////////////////////////////////////////////////////////////////////////////////
+//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
+//      10        20        30        40        50        60        70        80
+//
+// raico-blur
+//
+// stack-blur.c - implements stack-blur function
+//
+// Copyright 2009 Canonical Ltd.
+//
+// Authors:
+//    Mirco "MacSlow" Mueller <mirco mueller canonical com>
+//
+// Notes:
+//    based on stack-blur algorithm by Mario Klingemann <mario quasimondo com>
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 3, as published
+// by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranties of
+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+// PURPOSE.  See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// FIXME: not working yet, unfinished
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "stack-blur.h"
+
+void
+surface_stack_blur (cairo_surface_t* surface,
+		    guint            radius)
+{
+	guchar*        pixels;
+	guint          width;
+	guint          height;
+	cairo_format_t format;
+
+	// sanity checks are done in raico-blur.c
+
+	// before we mess with the surface execute any pending drawing
+	cairo_surface_flush (surface);
+
+	pixels = cairo_image_surface_get_data (surface);
+	width  = cairo_image_surface_get_width (surface);
+	height = cairo_image_surface_get_height (surface);
+	format = cairo_image_surface_get_format (surface);
+
+	switch (format)
+	{
+		case CAIRO_FORMAT_ARGB32:{
+
+	gint w   = width;
+	gint h   = height;
+	gint wm  = w - 1;
+	gint hm  = h - 1;
+	gint wh  = w * h;
+	gint div = radius + radius + 1;
+
+	if (radius < 1)
+		break;
+
+	gint* r = (gint*) g_malloc0 (wh);
+	gint* g = (gint*) g_malloc0 (wh);
+	gint* b = (gint*) g_malloc0 (wh);
+	gint* a = (gint*) g_malloc0 (wh);
+
+	gint rsum;
+	gint gsum;
+	gint bsum;
+	gint asum;
+	gint x;
+	gint y;
+	gint i;
+	gint yp;
+	gint yi;
+	gint yw;
+	gint* dv = NULL;
+
+	gint* vmin = (gint*) g_malloc0 (MAX (w, h));
+
+	gint divsum = (div + 1) >> 1;
+	divsum *= divsum;
+	dv = (gint*) g_malloc0 (256 * divsum);
+	g_assert (dv != NULL);
+
+	for (i = 0; i < 256 * divsum; ++i)
+		dv[i] = (i / divsum);
+
+	yw = yi = 0;
+
+	gint** stack =  (gint**) g_malloc0 (div);
+
+	for (i = 0; i < div; ++i)
+		stack[i] = (gint*) g_malloc0 (4);
+
+	gint  stackpointer;
+	gint  stackstart;
+	gint* sir;
+	gint  rbs;
+	gint  r1 = radius + 1;
+	gint  routsum;
+	gint  goutsum;
+	gint  boutsum;
+	gint  aoutsum;
+	gint  rinsum;
+	gint  ginsum;
+	gint  binsum;
+	gint  ainsum;
+
+	for (y = 0; y < h; ++y)
+	{
+		rinsum = ginsum = binsum = ainsum = routsum = goutsum = boutsum = aoutsum = rsum = gsum = bsum = asum = 0;
+
+		for(i =- radius; i <= radius; ++i)
+		{
+			sir = stack[i + radius];
+			sir[0] = pixels[yi + MIN (wm, MAX (i, 0)) + 0];
+			sir[1] = pixels[yi + MIN (wm, MAX (i, 0)) + 1];
+			sir[2] = pixels[yi + MIN (wm, MAX (i, 0)) + 2];
+			sir[3] = pixels[yi + MIN (wm, MAX (i, 0)) + 3];
+            
+			rbs = r1 - abs (i);
+			rsum += sir[0] * rbs;
+			gsum += sir[1] * rbs;
+			bsum += sir[2] * rbs;
+			asum += sir[3] * rbs;
+            
+			if (i > 0)
+			{
+				rinsum += sir[0];
+				ginsum += sir[1];
+				binsum += sir[2];
+				ainsum += sir[3];
+			}
+			else
+			{
+				routsum += sir[0];
+				goutsum += sir[1];
+				boutsum += sir[2];
+				aoutsum += sir[3];
+			}
+		}
+
+		stackpointer = radius;
+
+		for (x = 0; x < w; ++x)
+		{
+			r[yi] = dv[rsum];
+			g[yi] = dv[gsum];
+			b[yi] = dv[bsum];
+			a[yi] = dv[asum];
+
+			rsum -= routsum;
+			gsum -= goutsum;
+			bsum -= boutsum;
+			asum -= aoutsum;
+
+			stackstart = stackpointer - radius + div;
+			sir = stack[stackstart % div];
+
+			routsum -= sir[0];
+			goutsum -= sir[1];
+			boutsum -= sir[2];
+			aoutsum -= sir[3];
+
+			if (y == 0)
+				vmin[x] = MIN (x + radius + 1, wm);
+
+			sir[0] = pixels[yw + vmin[x] + 0];
+			sir[1] = pixels[yw + vmin[x] + 1];
+			sir[2] = pixels[yw + vmin[x] + 2];
+			sir[3] = pixels[yw + vmin[x] + 3];
+
+			rinsum += sir[0];
+			ginsum += sir[1];
+			binsum += sir[2];
+			ainsum += sir[3];
+
+			rsum += rinsum;
+			gsum += ginsum;
+			bsum += binsum;
+			asum += ainsum;
+
+			stackpointer = (stackpointer + 1) % div;
+			sir = stack[(stackpointer) % div];
+
+			routsum += sir[0];
+			goutsum += sir[1];
+			boutsum += sir[2];
+			aoutsum += sir[3];
+
+			rinsum -= sir[0];
+			ginsum -= sir[1];
+			binsum -= sir[2];
+			ainsum -= sir[3];
+
+			++yi;
+		}
+
+		yw += w;
+
+	}
+
+	for (x = 0; x < w; ++x)
+	{
+		rinsum = ginsum = binsum = ainsum = routsum = goutsum = boutsum = aoutsum = rsum = gsum = bsum = asum = 0;
+
+		yp =- radius * w;
+        
+		for (i =- radius; i <= radius; ++i)
+		{
+			yi = MAX (0, yp) + x;
+
+			sir = stack[i + radius];
+
+			sir[0] = r[yi];
+			sir[1] = g[yi];
+			sir[2] = b[yi];
+			sir[3] = a[yi];
+
+			rbs = r1 - abs (i);
+
+			rsum += r[yi] * rbs;
+			gsum += g[yi] * rbs;
+			bsum += b[yi] * rbs;
+			asum += a[yi] * rbs;
+
+			if (i > 0)
+			{
+				rinsum += sir[0];
+				ginsum += sir[1];
+				binsum += sir[2];
+				ainsum += sir[3];
+			}
+			else
+			{
+				routsum += sir[0];
+				goutsum += sir[1];
+				boutsum += sir[2];
+				aoutsum += sir[3];
+			}
+
+			if (i < hm)
+				yp += w;
+		}
+
+		yi = x;
+		stackpointer = radius;
+
+		for (y = 0; y < h; ++y)
+		{
+			pixels[yi + 0] = dv[rsum];
+			pixels[yi + 1] = dv[gsum];
+			pixels[yi + 2] = dv[bsum];
+			pixels[yi + 3] = dv[asum];
+
+			rsum -= routsum;
+			gsum -= goutsum;
+			bsum -= boutsum;
+			asum -= aoutsum;
+
+			stackstart = stackpointer - radius + div;
+			sir = stack[stackstart % div];
+
+			routsum -= sir[0];
+			goutsum -= sir[1];
+			boutsum -= sir[2];
+			aoutsum -= sir[3];
+
+			if (x == 0)
+				vmin[y] = MIN (y + r1, hm) * w;
+
+			gint pixel = x + vmin[y];
+
+			sir[0] = r[pixel];
+			sir[1] = g[pixel];
+			sir[2] = b[pixel];
+			sir[3] = a[pixel];
+
+			rinsum += sir[0];
+			ginsum += sir[1];
+			binsum += sir[2];
+			ainsum += sir[3];
+
+			rsum += rinsum;
+			gsum += ginsum;
+			bsum += binsum;
+			asum += ainsum;
+
+			stackpointer = (stackpointer + 1) % div;
+			sir = stack[stackpointer];
+
+			routsum += sir[0];
+			goutsum += sir[1];
+			boutsum += sir[2];
+			aoutsum += sir[3];
+
+			rinsum -= sir[0];
+			ginsum -= sir[1];
+			binsum -= sir[2];
+			ainsum -= sir[3];
+
+			yi += w;
+		}
+	}
+
+	g_free ((gpointer) r);
+	g_free ((gpointer) g);
+	g_free ((gpointer) b);
+	g_free ((gpointer) a);
+	g_free ((gpointer) vmin);
+	g_free ((gpointer) dv);
+
+	for (i = 0; i < div; ++i)
+		g_free ((gpointer) stack[i]);
+
+	g_free ((gpointer) stack);
+	}
+		break;
+
+		case CAIRO_FORMAT_RGB24:
+			// do nothing, for the moment
+		break;
+
+		case CAIRO_FORMAT_A8:
+			// do nothing, for the moment
+		break;
+
+		default :
+			// really do nothing
+		break;
+	}
+
+	// inform cairo we altered the surfaces contents
+	cairo_surface_mark_dirty (surface);	
+}
+
diff --git a/src/stack-blur.h b/src/stack-blur.h
new file mode 100644
index 0000000..2cb12b3
--- /dev/null
+++ b/src/stack-blur.h
@@ -0,0 +1,42 @@
+////////////////////////////////////////////////////////////////////////////////
+//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
+//      10        20        30        40        50        60        70        80
+//
+// notify-osd
+//
+// stack-blur.h - implements stack-blur function
+//
+// Copyright 2009 Canonical Ltd.
+//
+// Authors:
+//    Mirco "MacSlow" Mueller <mirco mueller canonical com>
+//
+// Notes:
+//    based on stack-blur algorithm by Mario Klingemann <mario quasimondo com>
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 3, as published
+// by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranties of
+// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+// PURPOSE.  See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _STACK_BLUR_H
+#define _STACK_BLUR_H
+
+#include <glib.h>
+#include <cairo.h>
+
+void
+surface_stack_blur (cairo_surface_t* surface,
+		    guint            radius);
+
+#endif // _STACK_BLUR_H
+



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