[gtk+] css: Fix computation of pixels occupied by blur radius



commit e9fb8ad1f7606deb4ae35773351e67281d56aa9f
Author: Benjamin Otte <otte redhat com>
Date:   Mon Feb 3 15:56:59 2014 +0100

    css: Fix computation of pixels occupied by blur radius
    
    These computations were done randomly in lots of places and more often
    than not, they were also wrong.
    This function was copied (with docs) from Firefox:
      http://lxr.mozilla.org/mozilla-central/source/gfx/2d/Blur.cpp
    
    https://bugzilla.gnome.org/show_bug.cgi?id=723159

 gtk/gtkcairoblur.c        |   26 ++++++++++++++++++++++++++
 gtk/gtkcairoblurprivate.h |    5 +++--
 gtk/gtkcssshadowsvalue.c  |   12 +++++++-----
 gtk/gtkcssshadowvalue.c   |    8 ++------
 4 files changed, 38 insertions(+), 13 deletions(-)
---
diff --git a/gtk/gtkcairoblur.c b/gtk/gtkcairoblur.c
index 3f944e2..df98989 100644
--- a/gtk/gtkcairoblur.c
+++ b/gtk/gtkcairoblur.c
@@ -251,3 +251,29 @@ _gtk_cairo_blur_surface (cairo_surface_t* surface,
   /* Inform cairo we altered the surfaces contents. */
   cairo_surface_mark_dirty (surface);
 }
+
+/**
+ * _gtk_cairo_blur_compute_pixels:
+ * @radius: the radius to compute the pixels for
+ *
+ * Computes the number of pixels necessary to extend an image in one
+ * direction to hold the image with shadow.
+ *
+ * This is just the number of pixels added by the blur radius, shadow
+ * offset and spread are not included.
+ * 
+ * Much of this, the 3 * sqrt(2 * pi) / 4, is the known value for
+ * approximating a Gaussian using box blurs.  This yields quite a good
+ * approximation for a Gaussian.  Then we multiply this by 1.5 since our
+ * code wants the radius of the entire triple-box-blur kernel instead of
+ * the diameter of an individual box blur.  For more details, see:
+ * http://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=590039#c19
+ */
+#define GAUSSIAN_SCALE_FACTOR ((3.0 * sqrt(2 * G_PI) / 4) * 1.5)
+
+int
+_gtk_cairo_blur_compute_pixels (double radius)
+{
+  return floor (radius * GAUSSIAN_SCALE_FACTOR + 0.5);
+}
diff --git a/gtk/gtkcairoblurprivate.h b/gtk/gtkcairoblurprivate.h
index e048bac..d3e2f9a 100644
--- a/gtk/gtkcairoblurprivate.h
+++ b/gtk/gtkcairoblurprivate.h
@@ -29,8 +29,9 @@
 
 G_BEGIN_DECLS
 
-void            _gtk_cairo_blur_surface (cairo_surface_t *surface,
-                                         double           radius);
+void            _gtk_cairo_blur_surface         (cairo_surface_t *surface,
+                                                 double           radius);
+int             _gtk_cairo_blur_compute_pixels  (double           radius);
 
 G_END_DECLS
 
diff --git a/gtk/gtkcssshadowsvalue.c b/gtk/gtkcssshadowsvalue.c
index b688594..eb32471 100644
--- a/gtk/gtkcssshadowsvalue.c
+++ b/gtk/gtkcssshadowsvalue.c
@@ -21,6 +21,7 @@
 
 #include "gtkcssshadowsvalueprivate.h"
 
+#include "gtkcairoblurprivate.h"
 #include "gtkcssshadowvalueprivate.h"
 
 #include <string.h>
@@ -309,7 +310,7 @@ _gtk_css_shadows_value_get_extents (const GtkCssValue *shadows,
   guint i;
   GtkBorder b = { 0 };
   const GtkCssValue *shadow;
-  gdouble hoffset, voffset, spread, radius;
+  gdouble hoffset, voffset, spread, radius, clip_radius;
 
   g_return_if_fail (shadows->class == &GTK_CSS_VALUE_SHADOWS);
 
@@ -323,11 +324,12 @@ _gtk_css_shadows_value_get_extents (const GtkCssValue *shadows,
       _gtk_css_shadow_value_get_geometry (shadow,
                                           &hoffset, &voffset,
                                           &radius, &spread);
+      clip_radius = _gtk_cairo_blur_compute_pixels (radius);
 
-      b.top = MAX (0, radius + spread - voffset);
-      b.right = MAX (0, radius + spread + hoffset);
-      b.bottom = MAX (0, radius + spread + voffset);
-      b.left = MAX (0, radius + spread - hoffset);
+      b.top = MAX (0, clip_radius + spread - voffset);
+      b.right = MAX (0, clip_radius + spread + hoffset);
+      b.bottom = MAX (0, clip_radius + spread + voffset);
+      b.left = MAX (0, clip_radius + spread - hoffset);
 
       border->top = MAX (border->top, b.top);
       border->right = MAX (border->right, b.right);
diff --git a/gtk/gtkcssshadowvalue.c b/gtk/gtkcssshadowvalue.c
index cdfd852..6dcd2dd 100644
--- a/gtk/gtkcssshadowvalue.c
+++ b/gtk/gtkcssshadowvalue.c
@@ -31,10 +31,6 @@
 
 #include <math.h>
 
-/* The blur of _gtk_cairo_blur_surface only approximately ends at radius,
-   so we add an extra pixel to make the clips less dramatic */
-#define CLIP_RADIUS_EXTRA 4
-
 struct _GtkCssValue {
   GTK_CSS_VALUE_BASE
   guint inset :1;
@@ -327,7 +323,7 @@ gtk_css_shadow_value_start_drawing (const GtkCssValue *shadow,
 
   gdk_cairo_get_clip_rectangle (cr, &clip_rect);
 
-  clip_radius = radius + CLIP_RADIUS_EXTRA;
+  clip_radius = _gtk_cairo_blur_compute_pixels (radius);
 
   /* Create a larger surface to center the blur. */
   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
@@ -534,7 +530,7 @@ _gtk_css_shadow_value_paint_box (const GtkCssValue   *shadow,
 
   spread = _gtk_css_number_value_get (shadow->spread, 0);
   radius = _gtk_css_number_value_get (shadow->radius, 0);
-  clip_radius = radius + CLIP_RADIUS_EXTRA;
+  clip_radius = _gtk_cairo_blur_compute_pixels (radius);
   x = _gtk_css_number_value_get (shadow->hoffset, 0);
   y = _gtk_css_number_value_get (shadow->voffset, 0);
 


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