[lasem] svg_filter: implement subregion for blur filter.
- From: Emmanuel Pacaud <emmanuel src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [lasem] svg_filter: implement subregion for blur filter.
- Date: Sun, 21 Oct 2012 14:02:20 +0000 (UTC)
commit 3881b9383ea390784913fb305b075512994d7619
Author: Emmanuel Pacaud <emmanuel gnome org>
Date: Sun Oct 21 16:00:03 2012 +0200
svg_filter: implement subregion for blur filter.
src/lsmcairo.c | 98 ++++++++++++++++++++++++++++++++-------------
src/lsmcairo.h | 3 +-
src/lsmsvgfilterelement.c | 10 +++-
src/lsmsvgview.c | 2 +-
4 files changed, 79 insertions(+), 34 deletions(-)
---
diff --git a/src/lsmcairo.c b/src/lsmcairo.c
index 12e0348..bfe2ee6 100644
--- a/src/lsmcairo.c
+++ b/src/lsmcairo.c
@@ -142,28 +142,20 @@ lsm_filter_surface_unref (LsmFilterSurface *filter_surface)
G_DEFINE_BOXED_TYPE (LsmFilterSurface, lsm_filter_surface, lsm_filter_surface_ref, lsm_filter_surface_unref)
static void
-box_blur (LsmFilterSurface *input,
- LsmFilterSurface *output,
+box_blur (unsigned char *input_pixels,
+ unsigned char *output_pixels,
guchar * intermediate,
- gint kw, gint kh)
+ gint kw, gint kh,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ int rowstride)
{
gint ch;
gint x, y;
- gint rowstride;
- gint x1, y1, x2, y2;
- guchar *in_pixels;
- guchar *output_pixels;
gint sum;
- in_pixels = cairo_image_surface_get_data (input->surface);
- output_pixels = cairo_image_surface_get_data (output->surface);
-
- rowstride = cairo_image_surface_get_stride (input->surface);
-
- x1 = 0; y1 = 0;
- x2 = cairo_image_surface_get_width (input->surface);
- y2 = cairo_image_surface_get_height (input->surface);
-
if (kw > x2 - x1)
kw = x2 - x1;
@@ -176,14 +168,14 @@ box_blur (LsmFilterSurface *input,
for (y = y1; y < y2; y++) {
sum = 0;
for (x = x1; x < x1 + kw; x++) {
- sum += (intermediate[x % kw] = in_pixels[4 * x + y * rowstride + ch]);
+ sum += (intermediate[x % kw] = input_pixels[4 * x + y * rowstride + ch]);
if (x - kw / 2 >= 0 && x - kw / 2 < x2)
output_pixels[4 * (x - kw / 2) + y * rowstride + ch] = sum / kw;
}
for (x = x1 + kw; x < x2; x++) {
sum -= intermediate[x % kw];
- sum += (intermediate[x % kw] = in_pixels[4 * x + y * rowstride + ch]);
+ sum += (intermediate[x % kw] = input_pixels[4 * x + y * rowstride + ch]);
output_pixels[4 * (x - kw / 2) + y * rowstride + ch] = sum / kw;
}
for (x = x2; x < x2 + kw; x++) {
@@ -194,7 +186,7 @@ box_blur (LsmFilterSurface *input,
}
}
}
- in_pixels = output_pixels;
+ input_pixels = output_pixels;
}
if (kh >= 1) {
@@ -203,14 +195,14 @@ box_blur (LsmFilterSurface *input,
sum = 0;
for (y = y1; y < y1 + kh; y++) {
- sum += (intermediate[y % kh] = in_pixels[4 * x + y * rowstride + ch]);
+ sum += (intermediate[y % kh] = input_pixels[4 * x + y * rowstride + ch]);
if (y - kh / 2 >= 0 && y - kh / 2 < y2)
output_pixels[4 * x + (y - kh / 2) * rowstride + ch] = sum / kh;
}
for (; y < y2; y++) {
sum -= intermediate[y % kh];
- sum += (intermediate[y % kh] = in_pixels[4 * x + y * rowstride + ch]);
+ sum += (intermediate[y % kh] = input_pixels[4 * x + y * rowstride + ch]);
output_pixels[4 * x + (y - kh / 2) * rowstride + ch] = sum / kh;
}
for (; y < y2 + kh; y++) {
@@ -227,11 +219,17 @@ box_blur (LsmFilterSurface *input,
void
lsm_filter_surface_fast_blur (LsmFilterSurface *input,
LsmFilterSurface *output,
- const LsmBox *subregion,
double sx, double sy)
{
- gint kx, ky;
- guchar *intermediate;
+ int kx, ky;
+ unsigned char *intermediate;
+ int rowstride;
+ int x1, y1, x2, y2;
+ unsigned char *input_pixels;
+ unsigned char *output_pixels;
+ int width, height;
+ cairo_surface_t *blur_surface;
+ gboolean do_clip = FALSE;
g_return_if_fail (input != NULL);
g_return_if_fail (output != NULL);
@@ -256,15 +254,59 @@ lsm_filter_surface_fast_blur (LsmFilterSurface *input,
if (kx < 1 && ky < 1)
return;
+ rowstride = cairo_image_surface_get_stride (input->surface);
+
+ width = cairo_image_surface_get_width (input->surface);
+ height = cairo_image_surface_get_height (input->surface);
+
+ if (input->subregion.x < output->subregion.x ||
+ input->subregion.y < output->subregion.y ||
+ input->subregion.width > output->subregion.width ||
+ input->subregion.height > output->subregion.height) {
+ do_clip = TRUE;
+ blur_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ } else
+ blur_surface = output->surface;
+
+ if (width != cairo_image_surface_get_width (output->surface) ||
+ height != cairo_image_surface_get_height (output->surface))
+ return;
+
+ x1 = output->subregion.x - kx;
+ y1 = output->subregion.y - ky;
+ x2 = output->subregion.width + output->subregion.x + kx;
+ y2 = output->subregion.height + output->subregion.y + ky;
+ x1 = CLAMP (x1, 0, width);
+ y1 = CLAMP (y1, 0, height);
+ x2 = CLAMP (x2, x1, width);
+ y2 = CLAMP (y2, y1, height);
+
intermediate = g_new (guchar, MAX (kx, ky));
- box_blur (input, output, intermediate, kx, ky);
- box_blur (output, output, intermediate, kx, ky);
- box_blur (output, output, intermediate, kx, ky);
+ input_pixels = cairo_image_surface_get_data (input->surface);
+ output_pixels = cairo_image_surface_get_data (blur_surface);
+
+ box_blur (input_pixels, output_pixels, intermediate, kx, ky, x1, y1, x2, y2, rowstride);
+ box_blur (output_pixels, output_pixels, intermediate, kx, ky, x1, y1, x2, y2, rowstride);
+ box_blur (output_pixels, output_pixels, intermediate, kx, ky, x1, y1, x2, y2, rowstride);
g_free (intermediate);
- cairo_surface_mark_dirty (output->surface);
+ cairo_surface_mark_dirty (blur_surface);
+
+ if (do_clip) {
+ cairo_t *cairo;
+
+ cairo = cairo_create (output->surface);
+ cairo_rectangle (cairo,
+ output->subregion.x, output->subregion.y,
+ output->subregion.width, output->subregion.height);
+ cairo_clip (cairo);
+ cairo_set_source_surface (cairo, blur_surface, 0, 0);
+ cairo_paint (cairo);
+ cairo_surface_destroy (blur_surface);
+ cairo_destroy (cairo);
+ }
}
void
diff --git a/src/lsmcairo.h b/src/lsmcairo.h
index 4068f37..d3533a1 100644
--- a/src/lsmcairo.h
+++ b/src/lsmcairo.h
@@ -54,8 +54,7 @@ void lsm_filter_surface_blend (LsmFilterSurface *input_1,
LsmFilterSurface *output,
const LsmBox *subregion,
int blending_mode);
-void lsm_filter_surface_fast_blur (LsmFilterSurface *input, LsmFilterSurface *output,
- const LsmBox *subregion, double sx, double sy);
+void lsm_filter_surface_fast_blur (LsmFilterSurface *input, LsmFilterSurface *output, double sx, double sy);
void lsm_filter_surface_flood (LsmFilterSurface *surface, const LsmBox *subregion,
double red, double green, double blue, double opacity);
void lsm_filter_surface_offset (LsmFilterSurface *input, LsmFilterSurface *output,
diff --git a/src/lsmsvgfilterelement.c b/src/lsmsvgfilterelement.c
index 4515dca..9d10210 100644
--- a/src/lsmsvgfilterelement.c
+++ b/src/lsmsvgfilterelement.c
@@ -105,14 +105,18 @@ lsm_svg_filter_element_render (LsmSvgElement *self, LsmSvgView *view)
is_object_bounding_box = (filter->primitive_units.value == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX);
- lsm_svg_view_push_viewport (view, object_extents,
- is_object_bounding_box ? &viewbox : NULL, NULL, LSM_SVG_OVERFLOW_VISIBLE);
+ if (is_object_bounding_box) {
+ lsm_svg_view_push_viewport (view, object_extents,
+ is_object_bounding_box ? &viewbox : NULL, NULL, LSM_SVG_OVERFLOW_VISIBLE);
+ }
for (node = LSM_DOM_NODE (filter)->first_child; node != NULL; node = node->next_sibling)
if (LSM_IS_SVG_FILTER_PRIMITIVE (node))
lsm_svg_filter_primitive_apply (LSM_SVG_FILTER_PRIMITIVE (node), view);
- lsm_svg_view_pop_viewport (view);
+ if (is_object_bounding_box) {
+ lsm_svg_view_pop_viewport (view);
+ }
}
static void
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index e63c4e0..e5adfdf 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -2188,7 +2188,7 @@ lsm_svg_view_apply_gaussian_blur (LsmSvgView *view, const char *input, const cha
lsm_log_render ("[SvgView::apply_gaussian_blur] %g px,%g px",
std_x, std_y);
- lsm_filter_surface_fast_blur (input_surface, output_surface, &subregion_px, std_x, std_y);
+ lsm_filter_surface_fast_blur (input_surface, output_surface, std_x, std_y);
}
void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]