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
This commit is contained in:
parent
9c2a16fb3b
commit
967cb56275
@ -173,27 +173,34 @@ flip_buffer (guchar *dst_buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_boxblur (guchar *buffer,
|
_boxblur (guchar *buffer,
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
int radius)
|
int radius,
|
||||||
|
GtkBlurFlags flags)
|
||||||
{
|
{
|
||||||
guchar *flipped_buffer;
|
guchar *flipped_buffer;
|
||||||
int d = get_box_filter_size (radius);
|
int d = get_box_filter_size (radius);
|
||||||
|
|
||||||
flipped_buffer = g_malloc (width * height);
|
flipped_buffer = g_malloc (width * height);
|
||||||
|
|
||||||
/* Step 1: swap rows and columns */
|
if (flags & GTK_BLUR_Y)
|
||||||
flip_buffer (flipped_buffer, buffer, width, height);
|
{
|
||||||
|
/* Step 1: swap rows and columns */
|
||||||
|
flip_buffer (flipped_buffer, buffer, width, height);
|
||||||
|
|
||||||
/* Step 2: blur rows (really columns) */
|
/* Step 2: blur rows (really columns) */
|
||||||
blur_rows (flipped_buffer, buffer, height, width, d);
|
blur_rows (flipped_buffer, buffer, height, width, d);
|
||||||
|
|
||||||
/* Step 3: swap rows and columns */
|
/* Step 3: swap rows and columns */
|
||||||
flip_buffer (buffer, flipped_buffer, height, width);
|
flip_buffer (buffer, flipped_buffer, height, width);
|
||||||
|
}
|
||||||
|
|
||||||
/* Step 4: blur rows */
|
if (flags & GTK_BLUR_X)
|
||||||
blur_rows (buffer, flipped_buffer, width, height, d);
|
{
|
||||||
|
/* Step 4: blur rows */
|
||||||
|
blur_rows (buffer, flipped_buffer, width, height, d);
|
||||||
|
}
|
||||||
|
|
||||||
g_free (flipped_buffer);
|
g_free (flipped_buffer);
|
||||||
}
|
}
|
||||||
@ -207,7 +214,8 @@ _boxblur (guchar *buffer,
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
_gtk_cairo_blur_surface (cairo_surface_t* surface,
|
_gtk_cairo_blur_surface (cairo_surface_t* surface,
|
||||||
double radius_d)
|
double radius_d,
|
||||||
|
GtkBlurFlags flags)
|
||||||
{
|
{
|
||||||
int radius = radius_d;
|
int radius = radius_d;
|
||||||
|
|
||||||
@ -220,13 +228,16 @@ _gtk_cairo_blur_surface (cairo_surface_t* surface,
|
|||||||
if (radius <= 1)
|
if (radius <= 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if ((flags & (GTK_BLUR_X|GTK_BLUR_Y)) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
/* Before we mess with the surface, execute any pending drawing. */
|
/* Before we mess with the surface, execute any pending drawing. */
|
||||||
cairo_surface_flush (surface);
|
cairo_surface_flush (surface);
|
||||||
|
|
||||||
_boxblur (cairo_image_surface_get_data (surface),
|
_boxblur (cairo_image_surface_get_data (surface),
|
||||||
cairo_image_surface_get_stride (surface),
|
cairo_image_surface_get_stride (surface),
|
||||||
cairo_image_surface_get_height (surface),
|
cairo_image_surface_get_height (surface),
|
||||||
radius);
|
radius, flags);
|
||||||
|
|
||||||
/* Inform cairo we altered the surface contents. */
|
/* Inform cairo we altered the surface contents. */
|
||||||
cairo_surface_mark_dirty (surface);
|
cairo_surface_mark_dirty (surface);
|
||||||
|
@ -29,8 +29,15 @@
|
|||||||
|
|
||||||
G_BEGIN_DECLS
|
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,
|
void _gtk_cairo_blur_surface (cairo_surface_t *surface,
|
||||||
double radius);
|
double radius,
|
||||||
|
GtkBlurFlags flags);;
|
||||||
int _gtk_cairo_blur_compute_pixels (double radius);
|
int _gtk_cairo_blur_compute_pixels (double radius);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -310,12 +310,15 @@ static const cairo_user_data_key_t original_cr_key;
|
|||||||
|
|
||||||
static cairo_t *
|
static cairo_t *
|
||||||
gtk_css_shadow_value_start_drawing (const GtkCssValue *shadow,
|
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_rectangle_int_t clip_rect;
|
||||||
cairo_surface_t *surface;
|
cairo_surface_t *surface;
|
||||||
cairo_t *blur_cr;
|
cairo_t *blur_cr;
|
||||||
gdouble radius, clip_radius;
|
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))
|
if (!needs_blur (shadow))
|
||||||
return cr;
|
return cr;
|
||||||
@ -328,9 +331,11 @@ gtk_css_shadow_value_start_drawing (const GtkCssValue *shadow,
|
|||||||
/* Create a larger surface to center the blur. */
|
/* Create a larger surface to center the blur. */
|
||||||
surface = cairo_surface_create_similar_image (cairo_get_target (cr),
|
surface = cairo_surface_create_similar_image (cairo_get_target (cr),
|
||||||
CAIRO_FORMAT_A8,
|
CAIRO_FORMAT_A8,
|
||||||
clip_rect.width + 2 * clip_radius,
|
clip_rect.width + (blur_x ? 2 * clip_radius : 0),
|
||||||
clip_rect.height + 2 * clip_radius);
|
clip_rect.height + (blur_y ? 2 * clip_radius : 0));
|
||||||
cairo_surface_set_device_offset (surface, clip_radius - clip_rect.x, clip_radius - clip_rect.y);
|
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);
|
blur_cr = cairo_create (surface);
|
||||||
cairo_set_user_data (blur_cr, &original_cr_key, cairo_reference (cr), (cairo_destroy_func_t) cairo_destroy);
|
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 *
|
static cairo_t *
|
||||||
gtk_css_shadow_value_finish_drawing (const GtkCssValue *shadow,
|
gtk_css_shadow_value_finish_drawing (const GtkCssValue *shadow,
|
||||||
cairo_t *cr)
|
cairo_t *cr,
|
||||||
|
GtkBlurFlags blur_flags)
|
||||||
{
|
{
|
||||||
gdouble radius;
|
gdouble radius;
|
||||||
cairo_t *original_cr;
|
cairo_t *original_cr;
|
||||||
@ -361,12 +367,13 @@ gtk_css_shadow_value_finish_drawing (const GtkCssValue *shadow,
|
|||||||
/* Blur the surface. */
|
/* Blur the surface. */
|
||||||
surface = cairo_get_target (cr);
|
surface = cairo_get_target (cr);
|
||||||
radius = _gtk_css_number_value_get (shadow->radius, 0);
|
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));
|
gdk_cairo_set_source_rgba (original_cr, _gtk_css_rgba_value_get_rgba (shadow->color));
|
||||||
cairo_mask_surface (original_cr, surface, 0, 0);
|
cairo_mask_surface (original_cr, surface, 0, 0);
|
||||||
|
|
||||||
cairo_destroy (cr);
|
cairo_destroy (cr);
|
||||||
|
|
||||||
cairo_surface_destroy (surface);
|
cairo_surface_destroy (surface);
|
||||||
|
|
||||||
return original_cr;
|
return original_cr;
|
||||||
@ -428,7 +435,7 @@ make_blurred_pango_surface (cairo_t *existing_cr,
|
|||||||
cr = cairo_create (surface);
|
cr = cairo_create (surface);
|
||||||
cairo_move_to (cr, 0, 0);
|
cairo_move_to (cr, 0, 0);
|
||||||
_gtk_pango_fill_layout (cr, layout);
|
_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);
|
cairo_destroy (cr);
|
||||||
|
|
||||||
@ -515,14 +522,14 @@ _gtk_css_shadow_value_paint_icon (const GtkCssValue *shadow,
|
|||||||
pattern = cairo_pattern_reference (cairo_get_source (cr));
|
pattern = cairo_pattern_reference (cairo_get_source (cr));
|
||||||
|
|
||||||
gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color));
|
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,
|
cairo_translate (cr,
|
||||||
_gtk_css_number_value_get (shadow->hoffset, 0),
|
_gtk_css_number_value_get (shadow->hoffset, 0),
|
||||||
_gtk_css_number_value_get (shadow->voffset, 0));
|
_gtk_css_number_value_get (shadow->voffset, 0));
|
||||||
cairo_mask (cr, pattern);
|
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_restore (cr);
|
||||||
cairo_pattern_destroy (pattern);
|
cairo_pattern_destroy (pattern);
|
||||||
@ -570,16 +577,18 @@ draw_shadow (const GtkCssValue *shadow,
|
|||||||
cairo_t *cr,
|
cairo_t *cr,
|
||||||
GtkRoundedBox *box,
|
GtkRoundedBox *box,
|
||||||
GtkRoundedBox *clip_box,
|
GtkRoundedBox *clip_box,
|
||||||
gboolean blur)
|
GtkBlurFlags blur_flags)
|
||||||
{
|
{
|
||||||
cairo_t *shadow_cr;
|
cairo_t *shadow_cr;
|
||||||
|
gboolean do_blur;
|
||||||
|
|
||||||
if (has_empty_clip (cr))
|
if (has_empty_clip (cr))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color));
|
gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color));
|
||||||
if (blur)
|
do_blur = (blur_flags & (GTK_BLUR_X | GTK_BLUR_Y)) != 0;
|
||||||
shadow_cr = gtk_css_shadow_value_start_drawing (shadow, cr);
|
if (do_blur)
|
||||||
|
shadow_cr = gtk_css_shadow_value_start_drawing (shadow, cr, blur_flags);
|
||||||
else
|
else
|
||||||
shadow_cr = cr;
|
shadow_cr = cr;
|
||||||
|
|
||||||
@ -590,8 +599,8 @@ draw_shadow (const GtkCssValue *shadow,
|
|||||||
|
|
||||||
cairo_fill (shadow_cr);
|
cairo_fill (shadow_cr);
|
||||||
|
|
||||||
if (blur)
|
if (do_blur)
|
||||||
gtk_css_shadow_value_finish_drawing (shadow, shadow_cr);
|
gtk_css_shadow_value_finish_drawing (shadow, shadow_cr, blur_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
_gtk_rounded_box_shrink (&clip_box, -clip_radius, -clip_radius, -clip_radius, -clip_radius);
|
||||||
|
|
||||||
if (!needs_blur (shadow))
|
if (!needs_blur (shadow))
|
||||||
draw_shadow (shadow, cr, &box, &clip_box, FALSE);
|
draw_shadow (shadow, cr, &box, &clip_box, GTK_BLUR_NONE);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int i, x1, x2, y1, y2;
|
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 */
|
/* Also clip with remaining to ensure we never draw any area twice */
|
||||||
gdk_cairo_region (cr, remaining);
|
gdk_cairo_region (cr, remaining);
|
||||||
cairo_clip (cr);
|
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);
|
cairo_restore (cr);
|
||||||
|
|
||||||
/* We drew the region, remove it from remaining */
|
/* We drew the region, remove it from remaining */
|
||||||
@ -731,8 +740,11 @@ _gtk_css_shadow_value_paint_box (const GtkCssValue *shadow,
|
|||||||
/* Then the sides */
|
/* Then the sides */
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
|
GtkBlurFlags blur_flags = 0;
|
||||||
|
|
||||||
if (i == GTK_CSS_TOP || i == GTK_CSS_BOTTOM)
|
if (i == GTK_CSS_TOP || i == GTK_CSS_BOTTOM)
|
||||||
{
|
{
|
||||||
|
blur_flags |= GTK_BLUR_Y;
|
||||||
x1 = floor (box.box.x - clip_radius);
|
x1 = floor (box.box.x - clip_radius);
|
||||||
x2 = ceil (box.box.x + box.box.width + 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)
|
if (i == GTK_CSS_LEFT || i == GTK_CSS_RIGHT)
|
||||||
{
|
{
|
||||||
|
blur_flags |= GTK_BLUR_X;
|
||||||
y1 = floor (box.box.y - clip_radius);
|
y1 = floor (box.box.y - clip_radius);
|
||||||
y2 = ceil (box.box.y + box.box.height + 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 */
|
/* Also clip with remaining to ensure we never draw any area twice */
|
||||||
gdk_cairo_region (cr, remaining);
|
gdk_cairo_region (cr, remaining);
|
||||||
cairo_clip (cr);
|
cairo_clip (cr);
|
||||||
draw_shadow (shadow, cr, &box, &clip_box, TRUE);
|
draw_shadow (shadow, cr, &box, &clip_box, blur_flags);
|
||||||
cairo_restore (cr);
|
cairo_restore (cr);
|
||||||
|
|
||||||
/* We drew the region, remove it from remaining */
|
/* We drew the region, remove it from remaining */
|
||||||
@ -785,7 +798,7 @@ _gtk_css_shadow_value_paint_box (const GtkCssValue *shadow,
|
|||||||
cairo_save (cr);
|
cairo_save (cr);
|
||||||
gdk_cairo_region (cr, remaining);
|
gdk_cairo_region (cr, remaining);
|
||||||
cairo_clip (cr);
|
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_restore (cr);
|
||||||
|
|
||||||
cairo_region_destroy (remaining);
|
cairo_region_destroy (remaining);
|
||||||
|
@ -41,7 +41,7 @@ main (int argc, char **argv)
|
|||||||
{
|
{
|
||||||
init_surface (cr);
|
init_surface (cr);
|
||||||
g_timer_start (timer);
|
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;
|
msec = g_timer_elapsed (timer, NULL) * 1000;
|
||||||
if (j == 1)
|
if (j == 1)
|
||||||
g_print ("Radius %2d: %.2f msec, %.2f kpixels/msec:\n", i, msec, size*size/(msec*1000));
|
g_print ("Radius %2d: %.2f msec, %.2f kpixels/msec:\n", i, msec, size*size/(msec*1000));
|
||||||
|
Loading…
Reference in New Issue
Block a user