clip: consider gstate target extents in _cairo_gstate_copy_clip_rectangle_list

Fixes https://bugs.freedesktop.org/show_bug.cgi?id=29125

To be consistent with _cairo_gstate_clip_extents, the context's clip
should be intersected with the target surface extents (instead of only
using them when there is no clip).

Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Karl Tomlinson 2010-07-17 13:08:53 +12:00 committed by Chris Wilson
parent b79ea8a6ca
commit 108b1c7825
3 changed files with 57 additions and 49 deletions

View file

@ -1495,7 +1495,7 @@ _cairo_rectangle_list_create_in_error (cairo_status_t status)
cairo_rectangle_list_t *
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
{
#define ERROR_LIST(S) _cairo_rectangle_list_create_in_error (_cairo_error (S));
#define ERROR_LIST(S) _cairo_rectangle_list_create_in_error (_cairo_error (S))
cairo_rectangle_list_t *list;
cairo_rectangle_t *rectangles = NULL;
@ -1507,57 +1507,37 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
if (clip->all_clipped)
goto DONE;
if (clip->path != NULL) {
status = _cairo_clip_get_region (clip, &region);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
goto DONE;
} else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
} else if (unlikely (status)) {
return ERROR_LIST (status);
}
if (!clip->path)
return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
status = _cairo_clip_get_region (clip, &region);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
goto DONE;
} else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
} else if (unlikely (status)) {
return ERROR_LIST (status);
}
if (region != NULL) {
n_rects = cairo_region_num_rectangles (region);
if (n_rects) {
rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t));
if (unlikely (rectangles == NULL)) {
return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
}
for (i = 0; i < n_rects; ++i) {
cairo_rectangle_int_t clip_rect;
cairo_region_get_rectangle (region, i, &clip_rect);
if (! _cairo_clip_int_rect_to_user (gstate,
&clip_rect,
&rectangles[i]))
{
free (rectangles);
return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
}
}
}
} else {
cairo_rectangle_int_t extents;
if (! _cairo_surface_get_extents (_cairo_gstate_get_target (gstate),
&extents))
{
/* unbounded surface -> unclipped */
goto DONE;
}
n_rects = 1;
rectangles = malloc(sizeof (cairo_rectangle_t));
if (unlikely (rectangles == NULL))
n_rects = cairo_region_num_rectangles (region);
if (n_rects) {
rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t));
if (unlikely (rectangles == NULL)) {
return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
}
if (! _cairo_clip_int_rect_to_user (gstate, &extents, rectangles)) {
free (rectangles);
return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
for (i = 0; i < n_rects; ++i) {
cairo_rectangle_int_t clip_rect;
cairo_region_get_rectangle (region, i, &clip_rect);
if (! _cairo_clip_int_rect_to_user (gstate,
&clip_rect,
&rectangles[i]))
{
free (rectangles);
return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
}
}
}

View file

@ -1555,7 +1555,19 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate,
cairo_rectangle_list_t*
_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate)
{
return _cairo_clip_copy_rectangle_list (&gstate->clip, gstate);
cairo_clip_t clip;
cairo_rectangle_int_t extents;
cairo_rectangle_list_t *list;
_cairo_clip_init_copy (&clip, &gstate->clip);
if (_cairo_surface_get_extents (gstate->target, &extents))
_cairo_clip_rectangle (&clip, &extents);
list = _cairo_clip_copy_rectangle_list (&clip, gstate);
_cairo_clip_fini (&clip);
return list;
}
static void

View file

@ -120,6 +120,22 @@ preamble (cairo_test_context_t *ctx)
}
cairo_rectangle_list_destroy (rectangle_list);
/* We should get the same results after applying a clip that contains the
existing clip. */
phase = "Clip beyond surface extents";
cairo_save (cr);
cairo_rectangle (cr, -10, -10, SIZE + 20 , SIZE + 20);
cairo_clip (cr);
rectangle_list = cairo_copy_clip_rectangle_list (cr);
if (! check_count (ctx, phase, rectangle_list, 1) ||
! check_clip_extents (ctx, phase, cr, 0, 0, SIZE, SIZE) ||
! check_rectangles_contain (ctx, phase, rectangle_list, 0, 0, SIZE, SIZE))
{
goto FAIL;
}
cairo_rectangle_list_destroy (rectangle_list);
cairo_restore (cr);
/* Test simple clip rect. */
phase = "Simple clip rect";
cairo_save (cr);