From f2cb8f12705ab3a36767df3430f8868ed7b29536 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Thu, 20 Sep 2012 02:39:35 +0200 Subject: [PATCH] blur: Use recording surface for capturing things to blur This gets around clipping issues quite nicely and provides us with a (mostly theoretical) performance boost. --- gtk/gtkcssshadowvalue.c | 43 ++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/gtk/gtkcssshadowvalue.c b/gtk/gtkcssshadowvalue.c index 56ebe3af1b..7d4acbca1d 100644 --- a/gtk/gtkcssshadowvalue.c +++ b/gtk/gtkcssshadowvalue.c @@ -21,6 +21,8 @@ #include "gtkcssshadowvalueprivate.h" +#include + #include "gtkcairoblurprivate.h" #include "gtkcssnumbervalueprivate.h" #include "gtkcssrgbavalueprivate.h" @@ -309,7 +311,7 @@ static cairo_t * gtk_css_shadow_value_start_drawing (const GtkCssValue *shadow, cairo_t *cr) { - cairo_rectangle_int_t clip_rect; + cairo_rectangle_t clip; cairo_surface_t *surface; cairo_t *blur_cr; gdouble radius; @@ -318,13 +320,16 @@ gtk_css_shadow_value_start_drawing (const GtkCssValue *shadow, if (radius == 0.0) return cr; - gdk_cairo_get_clip_rectangle (cr, &clip_rect); + radius = ceil (radius); + cairo_clip_extents (cr, &clip.x, &clip.y, &clip.width, &clip.height); + clip.x -= radius; + clip.y -= radius; + clip.width += 2 * radius; + clip.height += 2 * radius; /* Create a larger surface to center the blur. */ - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - clip_rect.width + 2 * radius, - clip_rect.height + 2 * radius); - cairo_surface_set_device_offset (surface, radius - clip_rect.x, radius - clip_rect.y); + surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, &clip); + cairo_surface_set_device_offset (surface, - clip.x, - clip.y); blur_cr = cairo_create (surface); cairo_set_user_data (blur_cr, &shadow_key, cairo_reference (cr), (cairo_destroy_func_t) cairo_destroy); @@ -344,23 +349,39 @@ gtk_css_shadow_value_finish_drawing (const GtkCssValue *shadow, cairo_t *cr) { gdouble radius; - cairo_t *original_cr; - cairo_surface_t *surface; + cairo_t *original_cr, *image_cr; + cairo_surface_t *recording_surface, *image_surface; + cairo_rectangle_t ink; radius = _gtk_css_number_value_get (shadow->radius, 0); if (radius == 0.0) return cr; - surface = cairo_get_target (cr); + recording_surface = cairo_get_target (cr); original_cr = cairo_get_user_data (cr, &shadow_key); /* Blur the surface. */ - _gtk_cairo_blur_surface (surface, radius); + cairo_recording_surface_ink_extents (recording_surface, &ink.x, &ink.y, &ink.width, &ink.height); + ink.width = ceil (ink.width + ink.x - floor (ink.x)) + 2 * ceil (radius); + ink.height = ceil (ink.height + ink.y - floor (ink.y)) + 2 * ceil (radius); + ink.x = floor (ink.x) + ceil (radius); + ink.y = floor (ink.y) + ceil (radius); - cairo_set_source_surface (original_cr, surface, 0, 0); + image_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ink.width, ink.height); + cairo_surface_set_device_offset (image_surface, - ink.x, - ink.y); + + image_cr = cairo_create (image_surface); + cairo_set_source_surface (image_cr, recording_surface, 0, 0); + cairo_paint (image_cr); + cairo_destroy (image_cr); + + _gtk_cairo_blur_surface (image_surface, radius); + + cairo_set_source_surface (original_cr, image_surface, 0, 0); cairo_paint (original_cr); cairo_destroy (cr); + cairo_surface_destroy (image_surface); return original_cr; }