From 108b1c7825116ed3f93aa57384bbd3290cdc9181 Mon Sep 17 00:00:00 2001
From: Karl Tomlinson <karlt+@karlt.net>
Date: Sat, 17 Jul 2010 01:08:53 +0000
Subject: 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>
---
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 77d8214..d5a2fab 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -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 (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);
-	    }
+    if (!clip->path)
+	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);
+    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 (! _cairo_clip_int_rect_to_user (gstate,
-						    &clip_rect,
-						    &rectangles[i]))
-		{
-		    free (rectangles);
-		    return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
-		}
-	    }
+    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);
 	}
-    } else {
-        cairo_rectangle_int_t extents;
 
-	if (! _cairo_surface_get_extents (_cairo_gstate_get_target (gstate),
-					  &extents))
-	{
-	    /* unbounded surface -> unclipped */
-	    goto DONE;
-	}
+	for (i = 0; i < n_rects; ++i) {
+	    cairo_rectangle_int_t clip_rect;
 
-	n_rects = 1;
-	rectangles = malloc(sizeof (cairo_rectangle_t));
-	if (unlikely (rectangles == NULL))
-	    return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
+	    cairo_region_get_rectangle (region, i, &clip_rect);
 
-	if (! _cairo_clip_int_rect_to_user (gstate, &extents, rectangles)) {
-	    free (rectangles);
-	    return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
+	    if (! _cairo_clip_int_rect_to_user (gstate,
+						&clip_rect,
+						&rectangles[i]))
+	    {
+		free (rectangles);
+		return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
+	    }
 	}
     }
 
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index baf6145..7caf624 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -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
diff --git a/test/get-clip.c b/test/get-clip.c
index f0477a1..f97db3f 100644
--- a/test/get-clip.c
+++ b/test/get-clip.c
@@ -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);
--
cgit v0.8.3-6-g21f6
