[gtk+] shadow-box: Blur only horizontally/vertically for the non-corner parts



commit 967cb56275a139942c9df78f46134d3a4e4dd1eb
Author: Alexander Larsson <alexl redhat com>
Date:   Fri Mar 20 14:34:44 2015 +0100

    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

 gtk/gtkcairoblur.c        |   39 +++++++++++++++++++++++------------
 gtk/gtkcairoblurprivate.h |    9 +++++++-
 gtk/gtkcssshadowvalue.c   |   49 ++++++++++++++++++++++++++++----------------
 tests/blur-performance.c  |    2 +-
 4 files changed, 65 insertions(+), 34 deletions(-)
---
diff --git a/gtk/gtkcairoblur.c b/gtk/gtkcairoblur.c
index 8d67c8c..9c10480 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 d3e2f9a..970c082 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 0a307b3..341844f 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 c4381f9..a99e5cd 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));


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]