cairo: Handle clipped blur content
This is the result of experimenting with corner cases when blurring. The result is a test that tests when the child of a blur node is clipped out but the blurred child is not, the blurred parts are still visible. This immediately broke the cairo renderer, so the fix is included.
This commit is contained in:
@@ -5901,35 +5901,42 @@ gsk_blur_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GskBlurNode *self = (GskBlurNode *) node;
|
||||
cairo_pattern_t *pattern;
|
||||
cairo_surface_t *surface;
|
||||
cairo_surface_t *image_surface;
|
||||
cairo_t *cr2;
|
||||
graphene_rect_t blur_bounds;
|
||||
double clip_radius;
|
||||
|
||||
cairo_save (cr);
|
||||
clip_radius = gsk_cairo_blur_compute_pixels (0.5 * self->radius);
|
||||
|
||||
/* clip so the push_group() creates a smaller surface */
|
||||
gsk_cairo_rectangle (cr, &node->bounds);
|
||||
cairo_clip (cr);
|
||||
/* We need to extend the clip by the blur radius
|
||||
* so we can blur pixels in that region */
|
||||
_graphene_rect_init_from_clip_extents (&blur_bounds, cr);
|
||||
graphene_rect_inset (&blur_bounds, - clip_radius, - clip_radius);
|
||||
if (!gsk_rect_intersection (&blur_bounds, &node->bounds, &blur_bounds))
|
||||
return;
|
||||
|
||||
cairo_push_group (cr);
|
||||
surface = cairo_surface_create_similar_image (cairo_get_target (cr),
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
ceil (blur_bounds.size.width),
|
||||
ceil (blur_bounds.size.height));
|
||||
cairo_surface_set_device_offset (surface,
|
||||
- blur_bounds.origin.x,
|
||||
- blur_bounds.origin.y);
|
||||
|
||||
gsk_render_node_draw (self->child, cr);
|
||||
cr2 = cairo_create (surface);
|
||||
gsk_render_node_draw (self->child, cr2);
|
||||
cairo_destroy (cr2);
|
||||
|
||||
pattern = cairo_pop_group (cr);
|
||||
cairo_pattern_get_surface (pattern, &surface);
|
||||
image_surface = cairo_surface_map_to_image (surface, NULL);
|
||||
blur_image_surface (image_surface, (int)self->radius, 3);
|
||||
blur_image_surface (surface, (int) ceil (0.5 * self->radius), 3);
|
||||
cairo_surface_mark_dirty (surface);
|
||||
cairo_surface_unmap_image (surface, image_surface);
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_set_source_surface (cr, surface, 0, 0);
|
||||
cairo_rectangle (cr,
|
||||
node->bounds.origin.x, node->bounds.origin.y,
|
||||
node->bounds.size.width, node->bounds.size.height);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
40
testsuite/gsk/compare/blur-contents-outside-of-clip.node
Normal file
40
testsuite/gsk/compare/blur-contents-outside-of-clip.node
Normal file
@@ -0,0 +1,40 @@
|
||||
color-matrix {
|
||||
matrix: matrix3d(256, 0, 0, 0, 0, 256, 0, 0, 0, 0, 256, 0, 0, 0, 0, 256);
|
||||
child: clip {
|
||||
clip: -37 59 50 50;
|
||||
child: container {
|
||||
blur {
|
||||
blur: 17;
|
||||
child: color {
|
||||
bounds: -87 59 50 50;
|
||||
color: rgb(255,0,0);
|
||||
}
|
||||
}
|
||||
blur {
|
||||
blur: 17;
|
||||
child: color {
|
||||
bounds: 13 59 50 50;
|
||||
color: rgb(255,0,0);
|
||||
}
|
||||
}
|
||||
blur {
|
||||
blur: 17;
|
||||
child: color {
|
||||
bounds: -37 9 50 50;
|
||||
color: rgb(255,0,0);
|
||||
}
|
||||
}
|
||||
blur {
|
||||
blur: 17;
|
||||
child: color {
|
||||
bounds: -37 109 50 50;
|
||||
color: rgb(255,0,0);
|
||||
}
|
||||
}
|
||||
color {
|
||||
bounds: -22 74 20 20;
|
||||
color: rgb(0,0,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
testsuite/gsk/compare/blur-contents-outside-of-clip.png
Normal file
BIN
testsuite/gsk/compare/blur-contents-outside-of-clip.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 168 B |
@@ -20,6 +20,7 @@ compare_render_tests = [
|
||||
'blend-in-rotate',
|
||||
'blend-normal',
|
||||
'blurred-lines',
|
||||
'blur-contents-outside-of-clip',
|
||||
'border-bottom-right',
|
||||
'border-one-rounded',
|
||||
'borders-rotated',
|
||||
|
||||
Reference in New Issue
Block a user