2 * Copyright (C) 2008 Benjamin Otte <otte@gnome.org>
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.1 of the License, or (at your option) any later version.
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.
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 Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
24 #include "swfdec_blur_filter.h"
28 #include "swfdec_debug.h"
30 G_DEFINE_TYPE (SwfdecBlurFilter
, swfdec_blur_filter
, SWFDEC_TYPE_FILTER
)
33 swfdec_blur_filter_clone (SwfdecFilter
*dfilter
, SwfdecFilter
*sfilter
)
35 SwfdecBlurFilter
*dest
= SWFDEC_BLUR_FILTER (dfilter
);
36 SwfdecBlurFilter
*source
= SWFDEC_BLUR_FILTER (sfilter
);
40 dest
->quality
= source
->quality
;
44 swfdec_blur_filter_create_convolution_matrix (SwfdecBlurFilter
*blur
,
45 double xscale
, double yscale
)
48 double div
, blurx
, blury
;
50 if (blur
->matrix
&& xscale
== blur
->xscale
&& yscale
== blur
->yscale
)
53 blurx
= MAX (blur
->x
* xscale
, 1);
54 blury
= MAX (blur
->y
* yscale
, 1);
55 w
= ceil ((blurx
- 1) / 2);
57 h
= ceil ((blury
- 1) / 2);
60 blur
->matrix
= swfdec_convolution_matrix_new (w
, h
);
61 blur
->xscale
= xscale
;
62 blur
->yscale
= yscale
;
64 div
= 1.0 / (blurx
* blury
);
65 for (y
= 0; y
< h
; y
++) {
67 if (y
== 0 || y
== w
- 1) {
68 val
*= (1 - (h
- MAX (blury
, 1)) / 2);
70 for (x
= 0; x
< w
; x
++) {
71 if (x
== 0 || x
== w
- 1) {
72 swfdec_convolution_matrix_set (blur
->matrix
, x
, y
,
73 val
* (1 - (w
- MAX (blurx
, 1)) / 2));
75 swfdec_convolution_matrix_set (blur
->matrix
, x
, y
, val
);
82 swfdec_blur_filter_get_rectangle (SwfdecFilter
*filter
, SwfdecRectangle
*dest
,
83 double xscale
, double yscale
, const SwfdecRectangle
*source
)
85 SwfdecBlurFilter
*blur
= SWFDEC_BLUR_FILTER (filter
);
89 blurx
= MAX (blur
->x
* xscale
, 1);
90 blury
= MAX (blur
->y
* yscale
, 1);
91 w
= ceil ((blurx
- 1) / 2);
93 h
= ceil ((blury
- 1) / 2);
96 dest
->x
= source
->x
- w
;
97 dest
->y
= source
->y
- h
;
98 dest
->width
= source
->width
+ 2 * w
;
99 dest
->height
= source
->height
+ 2 * h
;
102 static cairo_pattern_t
*
103 swfdec_blur_filter_apply (SwfdecFilter
*filter
, cairo_pattern_t
*pattern
,
104 double xscale
, double yscale
, const SwfdecRectangle
*rect
)
106 SwfdecBlurFilter
*blur
= SWFDEC_BLUR_FILTER (filter
);
107 cairo_surface_t
*a
, *b
;
109 guint8
*adata
, *bdata
;
110 guint astride
, bstride
;
113 if (blur
->x
<= 1.0 && blur
->y
<= 1.0)
114 return cairo_pattern_reference (pattern
);
116 swfdec_blur_filter_create_convolution_matrix (blur
, xscale
, yscale
);
117 x
= swfdec_convolution_matrix_get_width (blur
->matrix
) / 2;
118 y
= swfdec_convolution_matrix_get_height (blur
->matrix
) / 2;
120 /* FIXME: make this work in a single pass (requires smarter matrix construction) */
121 a
= cairo_image_surface_create (CAIRO_FORMAT_ARGB32
,
122 rect
->width
+ 2 * x
* blur
->quality
,
123 rect
->height
+ 2 * y
* blur
->quality
);
124 cairo_surface_set_device_offset (a
,
125 - (double) rect
->x
+ x
* blur
->quality
, - (double) rect
->y
+ y
* blur
->quality
);
126 b
= cairo_image_surface_create (CAIRO_FORMAT_ARGB32
,
127 rect
->width
+ 2 * x
* blur
->quality
,
128 rect
->height
+ 2 * y
* blur
->quality
);
129 cairo_surface_set_device_offset (b
,
130 - (double) rect
->x
+ x
* blur
->quality
, - (double) rect
->y
+ y
* blur
->quality
);
132 cr
= cairo_create (b
);
133 cairo_set_source (cr
, pattern
);
134 cairo_rectangle (cr
, rect
->x
, rect
->y
, rect
->width
, rect
->height
);
137 cairo_surface_flush (b
);
139 adata
= cairo_image_surface_get_data (a
);
140 astride
= cairo_image_surface_get_stride (a
);
141 bdata
= cairo_image_surface_get_data (b
);
142 bstride
= cairo_image_surface_get_stride (b
);
143 for (i
= 1, j
= blur
->quality
- 1; i
<= blur
->quality
; i
++, j
--) {
144 swfdec_convolution_matrix_apply (blur
->matrix
,
145 rect
->width
+ 2 * x
* i
, rect
->height
+ 2 * y
* i
,
146 adata
+ 4 * x
* j
+ astride
* y
* j
, astride
,
147 bdata
+ 4 * x
* j
+ bstride
* y
* j
, bstride
);
150 if (i
> blur
->quality
) {
151 cairo_surface_destroy (b
);
154 swfdec_convolution_matrix_apply (blur
->matrix
,
155 rect
->width
+ 2 * x
* i
, rect
->height
+ 2 * y
* i
,
156 bdata
+ 4 * x
* j
+ bstride
* y
* j
, bstride
,
157 adata
+ 4 * x
* j
+ astride
* y
* j
, astride
);
160 cairo_surface_destroy (a
);
163 cairo_surface_mark_dirty (a
);
164 pattern
= cairo_pattern_create_for_surface (a
);
165 cairo_surface_destroy (a
);
171 swfdec_blur_filter_dispose (GObject
*object
)
173 SwfdecBlurFilter
*blur
= SWFDEC_BLUR_FILTER (object
);
176 swfdec_convolution_matrix_free (blur
->matrix
);
180 G_OBJECT_CLASS (swfdec_blur_filter_parent_class
)->dispose (object
);
184 swfdec_blur_filter_class_init (SwfdecBlurFilterClass
*klass
)
186 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
187 SwfdecFilterClass
*filter_class
= SWFDEC_FILTER_CLASS (klass
);
189 object_class
->dispose
= swfdec_blur_filter_dispose
;
191 filter_class
->clone
= swfdec_blur_filter_clone
;
192 filter_class
->get_rectangle
= swfdec_blur_filter_get_rectangle
;
193 filter_class
->apply
= swfdec_blur_filter_apply
;
197 swfdec_blur_filter_init (SwfdecBlurFilter
*filter
)
205 swfdec_blur_filter_invalidate (SwfdecBlurFilter
*blur
)
207 g_return_if_fail (SWFDEC_IS_BLUR_FILTER (blur
));
210 swfdec_convolution_matrix_free (blur
->matrix
);