]> Pileus Git - ~andy/gtk/blob - gtk/gtkcairoblur.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkcairoblur.c
1 /*
2  * Copyright (C) 2012 Canonical Ltd
3  *
4  * This  library is free  software; you can  redistribute it and/or
5  * modify it  under  the terms  of the  GNU Lesser  General  Public
6  * License  as published  by the Free  Software  Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed  in the hope that it will be useful,
10  * but  WITHOUT ANY WARRANTY; without even  the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License  along  with  this library;  if not,  write to  the Free
16  * Software Foundation, Inc., 51  Franklin St, Fifth Floor, Boston,
17  * MA 02110-1301, USA.
18  *
19  * Authored by Andrea Cimitan <andrea.cimitan@canonical.com>
20  * Original code from Mirco Mueller <mirco.mueller@canonical.com>
21  *
22  */
23
24 #include "gtkcairoblurprivate.h"
25
26 #include <math.h>
27
28 /*
29  * Notes:
30  *   based on exponential-blur algorithm by Jani Huhtanen
31  */
32 static inline void
33 _blurinner (guchar* pixel,
34             gint   *zR,
35             gint   *zG,
36             gint   *zB,
37             gint   *zA,
38             gint    alpha,
39             gint    aprec,
40             gint    zprec)
41 {
42   gint R;
43   gint G;
44   gint B;
45   guchar A;
46
47   R = *pixel;
48   G = *(pixel + 1);
49   B = *(pixel + 2);
50   A = *(pixel + 3);
51
52   *zR += (alpha * ((R << zprec) - *zR)) >> aprec;
53   *zG += (alpha * ((G << zprec) - *zG)) >> aprec;
54   *zB += (alpha * ((B << zprec) - *zB)) >> aprec;
55   *zA += (alpha * ((A << zprec) - *zA)) >> aprec;
56
57   *pixel       = *zR >> zprec;
58   *(pixel + 1) = *zG >> zprec;
59   *(pixel + 2) = *zB >> zprec;
60   *(pixel + 3) = *zA >> zprec;
61
62
63 static inline void
64 _blurrow (guchar* pixels,
65           gint    width,
66           gint    height,
67           gint    rowstride,
68           gint    channels,
69           gint    line,
70           gint    alpha,
71           gint    aprec,
72           gint    zprec)
73 {
74   gint    zR;
75   gint    zG;
76   gint    zB;
77   gint    zA;
78   gint    index;
79   guchar* scanline;
80
81   scanline = &pixels[line * rowstride];
82
83   zR = *scanline << zprec;
84   zG = *(scanline + 1) << zprec;
85   zB = *(scanline + 2) << zprec;
86   zA = *(scanline + 3) << zprec;
87
88   for (index = 0; index < width; index ++)
89     _blurinner (&scanline[index * channels],
90                 &zR,
91                 &zG,
92                 &zB,
93                 &zA,
94                 alpha,
95                 aprec,
96                 zprec);
97
98   for (index = width - 2; index >= 0; index--)
99     _blurinner (&scanline[index * channels],
100                 &zR,
101                 &zG,
102                 &zB,
103                 &zA,
104                 alpha,
105                 aprec,
106                 zprec);
107 }
108
109 static inline void
110 _blurcol (guchar* pixels,
111           gint    width,
112           gint    height,
113           gint    rowstride,
114           gint    channels,
115           gint    x,
116           gint    alpha,
117           gint    aprec,
118           gint    zprec)
119 {
120   gint zR;
121   gint zG;
122   gint zB;
123   gint zA;
124   gint index;
125   guchar* ptr;
126
127   ptr = pixels;
128   
129   ptr += x * channels;
130
131   zR = *((guchar*) ptr    ) << zprec;
132   zG = *((guchar*) ptr + 1) << zprec;
133   zB = *((guchar*) ptr + 2) << zprec;
134   zA = *((guchar*) ptr + 3) << zprec;
135
136   for (index = 0; index < height; index++)
137     _blurinner (&ptr[index * rowstride],
138                 &zR,
139                 &zG,
140                 &zB,
141                 &zA,
142                 alpha,
143                 aprec,
144                 zprec);
145
146   for (index = height - 2; index >= 0; index--)
147     _blurinner (&ptr[index * rowstride],
148                 &zR,
149                 &zG,
150                 &zB,
151                 &zA,
152                 alpha,
153                 aprec,
154                 zprec);
155 }
156
157 /*
158  * _expblur:
159  * @pixels: image data
160  * @width: image width
161  * @height: image height
162  * @rowstride: image rowstride
163  * @channels: image channels
164  * @radius: kernel radius
165  * @aprec: precision of alpha parameter in fixed-point format 0.aprec
166  * @zprec: precision of state parameters zR,zG,zB and zA in fp format 8.zprec
167  *
168  * Performs an in-place blur of image data 'pixels'
169  * with kernel of approximate radius 'radius'.
170  *
171  * Blurs with two sided exponential impulse response.
172  *
173  */
174 static void
175 _expblur (guchar* pixels,
176           gint    width,
177           gint    height,
178           gint    rowstride,
179           gint    channels,
180           double  radius,
181           gint    aprec,
182           gint    zprec)
183 {
184   gint alpha;
185   int row, col;
186
187   /* Calculate the alpha such that 90% of 
188    * the kernel is within the radius.
189    * (Kernel extends to infinity) */
190   alpha = (gint) ((1 << aprec) * (1.0f - expf (-2.3f / (radius + 1.f))));
191
192   for (row = 0; row < height; row++)
193     _blurrow (pixels,
194               width,
195               height,
196               rowstride,
197               channels,
198               row,
199               alpha,
200               aprec,
201               zprec);
202
203   for(col = 0; col < width; col++)
204     _blurcol (pixels,
205               width,
206               height,
207               rowstride,
208               channels,
209               col,
210               alpha,
211               aprec,
212               zprec);
213 }
214
215
216 /*
217  * _gtk_cairo_blur_surface:
218  * @surface: a cairo image surface.
219  * @radius: the blur radius.
220  *
221  * Blurs the cairo image surface at the given radius.
222  */
223 void
224 _gtk_cairo_blur_surface (cairo_surface_t* surface,
225                          double           radius)
226 {
227   cairo_format_t format;
228
229   g_return_if_fail (surface != NULL);
230   g_return_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE);
231
232   format = cairo_image_surface_get_format (surface);
233   g_return_if_fail (format == CAIRO_FORMAT_RGB24 ||
234                     format == CAIRO_FORMAT_ARGB32);
235
236   if (radius == 0)
237     return;
238
239   /* Before we mess with the surface execute any pending drawing. */
240   cairo_surface_flush (surface);
241
242   _expblur (cairo_image_surface_get_data (surface),
243             cairo_image_surface_get_width (surface),
244             cairo_image_surface_get_height (surface),
245             cairo_image_surface_get_stride (surface),
246             4,
247             radius,
248             16,
249             7);
250
251   /* Inform cairo we altered the surfaces contents. */
252   cairo_surface_mark_dirty (surface);
253 }