diff options
author | Alexander Larsson <alexl@redhat.com> | 2015-03-20 14:34:44 +0100 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2015-03-21 21:31:49 +0100 |
commit | 967cb56275a139942c9df78f46134d3a4e4dd1eb (patch) | |
tree | 4c4bd9a60060d935be1b8544d774796557868452 | |
parent | 9c2a16fb3be9bfe1a4e0e30bc7aa6de298541867 (diff) | |
download | gtk+-967cb56275a139942c9df78f46134d3a4e4dd1eb.tar.gz |
shadow-box: Blur only horizontally/vertically for the non-corner parts
There is no need to e.g. blur in the x-direction for the top part
of a box shadow. Also, there is no need to extend the mask in the
non-blurred direction.
https://bugzilla.gnome.org/show_bug.cgi?id=746468
-rw-r--r-- | gtk/gtkcairoblur.c | 39 | ||||
-rw-r--r-- | gtk/gtkcairoblurprivate.h | 9 | ||||
-rw-r--r-- | gtk/gtkcssshadowvalue.c | 49 | ||||
-rw-r--r-- | tests/blur-performance.c | 2 |
4 files changed, 65 insertions, 34 deletions
diff --git a/gtk/gtkcairoblur.c b/gtk/gtkcairoblur.c index 8d67c8c04b..9c10480fbb 100644 --- a/gtk/gtkcairoblur.c +++ b/gtk/gtkcairoblur.c @@ -173,27 +173,34 @@ flip_buffer (guchar *dst_buffer, } static void -_boxblur (guchar *buffer, - int width, - int height, - int radius) +_boxblur (guchar *buffer, + int width, + int height, + int radius, + GtkBlurFlags flags) { guchar *flipped_buffer; int d = get_box_filter_size (radius); flipped_buffer = g_malloc (width * height); - /* Step 1: swap rows and columns */ - flip_buffer (flipped_buffer, buffer, width, height); + if (flags & GTK_BLUR_Y) + { + /* Step 1: swap rows and columns */ + flip_buffer (flipped_buffer, buffer, width, height); - /* Step 2: blur rows (really columns) */ - blur_rows (flipped_buffer, buffer, height, width, d); + /* Step 2: blur rows (really columns) */ + blur_rows (flipped_buffer, buffer, height, width, d); - /* Step 3: swap rows and columns */ - flip_buffer (buffer, flipped_buffer, height, width); + /* Step 3: swap rows and columns */ + flip_buffer (buffer, flipped_buffer, height, width); + } - /* Step 4: blur rows */ - blur_rows (buffer, flipped_buffer, width, height, d); + if (flags & GTK_BLUR_X) + { + /* Step 4: blur rows */ + blur_rows (buffer, flipped_buffer, width, height, d); + } g_free (flipped_buffer); } @@ -207,7 +214,8 @@ _boxblur (guchar *buffer, */ void _gtk_cairo_blur_surface (cairo_surface_t* surface, - double radius_d) + double radius_d, + GtkBlurFlags flags) { int radius = radius_d; @@ -220,13 +228,16 @@ _gtk_cairo_blur_surface (cairo_surface_t* surface, if (radius <= 1) return; + if ((flags & (GTK_BLUR_X|GTK_BLUR_Y)) == 0) + return; + /* Before we mess with the surface, execute any pending drawing. */ cairo_surface_flush (surface); _boxblur (cairo_image_surface_get_data (surface), cairo_image_surface_get_stride (surface), cairo_image_surface_get_height (surface), - radius); + radius, flags); /* Inform cairo we altered the surface contents. */ cairo_surface_mark_dirty (surface); diff --git a/gtk/gtkcairoblurprivate.h b/gtk/gtkcairoblurprivate.h index d3e2f9ac46..970c0826d8 100644 --- a/gtk/gtkcairoblurprivate.h +++ b/gtk/gtkcairoblurprivate.h @@ -29,8 +29,15 @@ G_BEGIN_DECLS +typedef enum { + GTK_BLUR_NONE = 0, + GTK_BLUR_X = 1<<0, + GTK_BLUR_Y = 1<<1 +} GtkBlurFlags; + void _gtk_cairo_blur_surface (cairo_surface_t *surface, - double radius); + double radius, + GtkBlurFlags flags);; int _gtk_cairo_blur_compute_pixels (double radius); G_END_DECLS diff --git a/gtk/gtkcssshadowvalue.c b/gtk/gtkcssshadowvalue.c index 0a307b31a8..341844f751 100644 --- a/gtk/gtkcssshadowvalue.c +++ b/gtk/gtkcssshadowvalue.c @@ -310,12 +310,15 @@ static const cairo_user_data_key_t original_cr_key; static cairo_t * gtk_css_shadow_value_start_drawing (const GtkCssValue *shadow, - cairo_t *cr) + cairo_t *cr, + GtkBlurFlags blur_flags) { cairo_rectangle_int_t clip_rect; cairo_surface_t *surface; cairo_t *blur_cr; gdouble radius, clip_radius; + gboolean blur_x = (blur_flags & GTK_BLUR_X) != 0; + gboolean blur_y = (blur_flags & GTK_BLUR_Y) != 0; if (!needs_blur (shadow)) return cr; @@ -328,9 +331,11 @@ gtk_css_shadow_value_start_drawing (const GtkCssValue *shadow, /* Create a larger surface to center the blur. */ surface = cairo_surface_create_similar_image (cairo_get_target (cr), CAIRO_FORMAT_A8, - clip_rect.width + 2 * clip_radius, - clip_rect.height + 2 * clip_radius); - cairo_surface_set_device_offset (surface, clip_radius - clip_rect.x, clip_radius - clip_rect.y); + clip_rect.width + (blur_x ? 2 * clip_radius : 0), + clip_rect.height + (blur_y ? 2 * clip_radius : 0)); + cairo_surface_set_device_offset (surface, + (blur_x ? clip_radius : 0) - clip_rect.x, + (blur_y ? clip_radius : 0) - clip_rect.y); blur_cr = cairo_create (surface); cairo_set_user_data (blur_cr, &original_cr_key, cairo_reference (cr), (cairo_destroy_func_t) cairo_destroy); @@ -347,7 +352,8 @@ gtk_css_shadow_value_start_drawing (const GtkCssValue *shadow, static cairo_t * gtk_css_shadow_value_finish_drawing (const GtkCssValue *shadow, - cairo_t *cr) + cairo_t *cr, + GtkBlurFlags blur_flags) { gdouble radius; cairo_t *original_cr; @@ -361,12 +367,13 @@ gtk_css_shadow_value_finish_drawing (const GtkCssValue *shadow, /* Blur the surface. */ surface = cairo_get_target (cr); radius = _gtk_css_number_value_get (shadow->radius, 0); - _gtk_cairo_blur_surface (surface, radius); + _gtk_cairo_blur_surface (surface, radius, blur_flags); gdk_cairo_set_source_rgba (original_cr, _gtk_css_rgba_value_get_rgba (shadow->color)); cairo_mask_surface (original_cr, surface, 0, 0); cairo_destroy (cr); + cairo_surface_destroy (surface); return original_cr; @@ -428,7 +435,7 @@ make_blurred_pango_surface (cairo_t *existing_cr, cr = cairo_create (surface); cairo_move_to (cr, 0, 0); _gtk_pango_fill_layout (cr, layout); - _gtk_cairo_blur_surface (surface, radius * x_scale); + _gtk_cairo_blur_surface (surface, radius * x_scale, GTK_BLUR_X | GTK_BLUR_Y); cairo_destroy (cr); @@ -515,14 +522,14 @@ _gtk_css_shadow_value_paint_icon (const GtkCssValue *shadow, pattern = cairo_pattern_reference (cairo_get_source (cr)); gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color)); - cr = gtk_css_shadow_value_start_drawing (shadow, cr); + cr = gtk_css_shadow_value_start_drawing (shadow, cr, GTK_BLUR_X | GTK_BLUR_Y); cairo_translate (cr, _gtk_css_number_value_get (shadow->hoffset, 0), _gtk_css_number_value_get (shadow->voffset, 0)); cairo_mask (cr, pattern); - cr = gtk_css_shadow_value_finish_drawing (shadow, cr); + cr = gtk_css_shadow_value_finish_drawing (shadow, cr, GTK_BLUR_X | GTK_BLUR_Y); cairo_restore (cr); cairo_pattern_destroy (pattern); @@ -570,16 +577,18 @@ draw_shadow (const GtkCssValue *shadow, cairo_t *cr, GtkRoundedBox *box, GtkRoundedBox *clip_box, - gboolean blur) + GtkBlurFlags blur_flags) { cairo_t *shadow_cr; + gboolean do_blur; if (has_empty_clip (cr)) return; gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color)); - if (blur) - shadow_cr = gtk_css_shadow_value_start_drawing (shadow, cr); + do_blur = (blur_flags & (GTK_BLUR_X | GTK_BLUR_Y)) != 0; + if (do_blur) + shadow_cr = gtk_css_shadow_value_start_drawing (shadow, cr, blur_flags); else shadow_cr = cr; @@ -590,8 +599,8 @@ draw_shadow (const GtkCssValue *shadow, cairo_fill (shadow_cr); - if (blur) - gtk_css_shadow_value_finish_drawing (shadow, shadow_cr); + if (do_blur) + gtk_css_shadow_value_finish_drawing (shadow, shadow_cr, blur_flags); } void @@ -647,7 +656,7 @@ _gtk_css_shadow_value_paint_box (const GtkCssValue *shadow, _gtk_rounded_box_shrink (&clip_box, -clip_radius, -clip_radius, -clip_radius, -clip_radius); if (!needs_blur (shadow)) - draw_shadow (shadow, cr, &box, &clip_box, FALSE); + draw_shadow (shadow, cr, &box, &clip_box, GTK_BLUR_NONE); else { int i, x1, x2, y1, y2; @@ -717,7 +726,7 @@ _gtk_css_shadow_value_paint_box (const GtkCssValue *shadow, /* Also clip with remaining to ensure we never draw any area twice */ gdk_cairo_region (cr, remaining); cairo_clip (cr); - draw_shadow (shadow, cr, &box, &clip_box, TRUE); + draw_shadow (shadow, cr, &box, &clip_box, GTK_BLUR_X | GTK_BLUR_Y); cairo_restore (cr); /* We drew the region, remove it from remaining */ @@ -731,8 +740,11 @@ _gtk_css_shadow_value_paint_box (const GtkCssValue *shadow, /* Then the sides */ for (i = 0; i < 4; i++) { + GtkBlurFlags blur_flags = 0; + if (i == GTK_CSS_TOP || i == GTK_CSS_BOTTOM) { + blur_flags |= GTK_BLUR_Y; x1 = floor (box.box.x - clip_radius); x2 = ceil (box.box.x + box.box.width + clip_radius); } @@ -749,6 +761,7 @@ _gtk_css_shadow_value_paint_box (const GtkCssValue *shadow, if (i == GTK_CSS_LEFT || i == GTK_CSS_RIGHT) { + blur_flags |= GTK_BLUR_X; y1 = floor (box.box.y - clip_radius); y2 = ceil (box.box.y + box.box.height + clip_radius); } @@ -769,7 +782,7 @@ _gtk_css_shadow_value_paint_box (const GtkCssValue *shadow, /* Also clip with remaining to ensure we never draw any area twice */ gdk_cairo_region (cr, remaining); cairo_clip (cr); - draw_shadow (shadow, cr, &box, &clip_box, TRUE); + draw_shadow (shadow, cr, &box, &clip_box, blur_flags); cairo_restore (cr); /* We drew the region, remove it from remaining */ @@ -785,7 +798,7 @@ _gtk_css_shadow_value_paint_box (const GtkCssValue *shadow, cairo_save (cr); gdk_cairo_region (cr, remaining); cairo_clip (cr); - draw_shadow (shadow, cr, &box, &clip_box, FALSE); + draw_shadow (shadow, cr, &box, &clip_box, GTK_BLUR_NONE); cairo_restore (cr); cairo_region_destroy (remaining); diff --git a/tests/blur-performance.c b/tests/blur-performance.c index c4381f9208..a99e5cd00d 100644 --- a/tests/blur-performance.c +++ b/tests/blur-performance.c @@ -41,7 +41,7 @@ main (int argc, char **argv) { init_surface (cr); g_timer_start (timer); - _gtk_cairo_blur_surface (surface, i); + _gtk_cairo_blur_surface (surface, i, GTK_BLUR_X | GTK_BLUR_Y); msec = g_timer_elapsed (timer, NULL) * 1000; if (j == 1) g_print ("Radius %2d: %.2f msec, %.2f kpixels/msec:\n", i, msec, size*size/(msec*1000)); |