diff --git a/gtk/gtkcairoblur.c b/gtk/gtkcairoblur.c index 3f944e2429..df989898b2 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 e048bac8cd..d3e2f9ac46 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 b688594cc1..eb32471cec 100644 --- a/gtk/gtkcssshadowsvalue.c +++ b/gtk/gtkcssshadowsvalue.c @@ -21,6 +21,7 @@ #include "gtkcssshadowsvalueprivate.h" +#include "gtkcairoblurprivate.h" #include "gtkcssshadowvalueprivate.h" #include @@ -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 == >K_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 cdfd852612..6dcd2dd798 100644 --- a/gtk/gtkcssshadowvalue.c +++ b/gtk/gtkcssshadowvalue.c @@ -31,10 +31,6 @@ #include -/* 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);