Commit e9fb8ad1 authored by Benjamin Otte's avatar Benjamin Otte

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
parent 43baa213
......@@ -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);
}
......@@ -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
......
......@@ -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);
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment