b=562574 fixes for cairo_copy_clip_rectangle_list and empty cairo_clip_extents r=jrmuizel
authorKarl Tomlinson <karlt+@karlt.net>
Fri, 23 Jul 2010 10:22:51 +1200
changeset 48106 bdfeac0b9d4a7aacd751d38d049fd3434409cfe9
parent 48105 9b1bc16c0b8271b7b9d36a40dfb34491fec49e50
child 48107 a171b4faa517e9bda444757ee7c153b9438a3daf
push id14574
push userktomlinson@mozilla.com
push dateThu, 22 Jul 2010 23:01:26 +0000
treeherdermozilla-central@02d92df7381d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs562574
milestone2.0b3pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
b=562574 fixes for cairo_copy_clip_rectangle_list and empty cairo_clip_extents r=jrmuizel
gfx/cairo/README
gfx/cairo/cairo/src/cairo-clip.c
gfx/cairo/cairo/src/cairo-gstate.c
gfx/cairo/clip-rects-surface-extents.patch
gfx/cairo/empty-clip-extents.patch
gfx/cairo/empty-clip-rectangles.patch
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -123,16 +123,22 @@ ensure-text-flushed.patch: PDF-operators
 fix-xcopyarea-with-clips.patch: 5d07307b691afccccbb15f773d5231669ba44f5a
 
 cairo-x-visual.patch: make valid visua for cairo_xlib_surface_create_with_xrender_format (55037bfb2454a671332d961e061c712ab5471580)
 
 win32-transparent-surface.patch: add API so we can create a win32 surface for an HDC and indicate the surface has an alpha channel
 
 cairo_qt_glyphs.patch: Drop X surface from Qt surface, add support for new qt glyphs api
 
+empty-clip-rectangles.patch: f2fa15680ec3ac95cb68d4957557f06561a7dc55
+
+empty-clip-extents.patch: b79ea8a6cab8bd28aebecf6e1e8229d5ac017264
+
+clip-rects-surface-extents.patch: 108b1c7825116ed3f93aa57384bbd3290cdc9181
+
 ==== pixman patches ====
 
 pixman-android-cpu-detect.patch: Add CPU detection support for Android, where we can't reliably access /proc/self/auxv.
 
 pixman-rename-and-endian.patch: include cairo-platform.h for renaming of external symbols and endian macros
 
 NOTE: we previously supported ARM assembler on MSVC, this has been removed because of the maintenance burden
 
--- a/gfx/cairo/cairo/src/cairo-clip.c
+++ b/gfx/cairo/cairo/src/cairo-clip.c
@@ -1306,19 +1306,24 @@ cairo_status_t
 
 	if (unlikely (status))
 	    return status;
     } while ((clip_path = clip_path->prev) != NULL);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
+static const cairo_rectangle_int_t _cairo_empty_rectangle_int = { 0, 0, 0, 0 };
+
 const cairo_rectangle_int_t *
 _cairo_clip_get_extents (const cairo_clip_t *clip)
 {
+    if (clip->all_clipped)
+	return &_cairo_empty_rectangle_int;
+
     if (clip->path == NULL)
 	return NULL;
 
     return &clip->path->extents;
 }
 
 void
 _cairo_clip_drop_cache (cairo_clip_t  *clip)
@@ -1448,76 +1453,59 @@ static cairo_rectangle_list_t *
     list->num_rectangles = 0;
 
     return list;
 }
 
 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;
     cairo_region_t *region = NULL;
     cairo_int_status_t status;
     int n_rects = 0;
     int i;
 
-    if (clip != NULL && 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->all_clipped)
+	goto DONE;
+
+    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 = 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);
 	}
 
-	n_rects = 1;
-	rectangles = malloc(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, &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);
+	    }
 	}
     }
 
  DONE:
     list = malloc (sizeof (cairo_rectangle_list_t));
     if (unlikely (list == NULL)) {
         free (rectangles);
 	return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
--- a/gfx/cairo/cairo/src/cairo-gstate.c
+++ b/gfx/cairo/cairo/src/cairo-gstate.c
@@ -1438,17 +1438,29 @@ cairo_bool_t
 	*y2 = py2;
 
     return TRUE;
 }
 
 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
 _cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate)
 {
     if (gstate->scaled_font == NULL)
 	return;
 
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/clip-rects-surface-extents.patch
@@ -0,0 +1,163 @@
+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
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/empty-clip-extents.patch
@@ -0,0 +1,59 @@
+From b79ea8a6cab8bd28aebecf6e1e8229d5ac017264 Mon Sep 17 00:00:00 2001
+From: Karl Tomlinson <karlt+@karlt.net>
+Date: Fri, 16 Jul 2010 23:46:25 +0000
+Subject: clip: consider all_clipped in _cairo_clip_get_extents
+
+If the gstate clip in _cairo_gstate_int_clip_extents() has all_clipped
+set (and path NULL), then it returns the gstate target extents instead of
+an empty rectangle.  If the target is infinite, then it says the clip is
+unbounded.
+
+Fixes https://bugs.freedesktop.org/show_bug.cgi?id=29124
+Tested-by test/get-clip
+
+Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
+---
+diff --git a/src/cairo-clip.c b/src/cairo-clip.c
+index f6173c6..77d8214 100644
+--- a/src/cairo-clip.c
++++ b/src/cairo-clip.c
+@@ -1264,9 +1264,14 @@ _cairo_clip_combine_with_surface (cairo_clip_t *clip,
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
++static const cairo_rectangle_int_t _cairo_empty_rectangle_int = { 0, 0, 0, 0 };
++
+ const cairo_rectangle_int_t *
+ _cairo_clip_get_extents (const cairo_clip_t *clip)
+ {
++    if (clip->all_clipped)
++	return &_cairo_empty_rectangle_int;
++
+     if (clip->path == NULL)
+ 	return NULL;
+ 
+diff --git a/test/get-clip.c b/test/get-clip.c
+index 9d6e796..f0477a1 100644
+--- a/test/get-clip.c
++++ b/test/get-clip.c
+@@ -83,6 +83,8 @@ check_clip_extents (const cairo_test_context_t *ctx,
+     cairo_clip_extents (cr, &ext_x1, &ext_y1, &ext_x2, &ext_y2);
+     if (ext_x1 == x && ext_y1 == y && ext_x2 == x + width && ext_y2 == y + height)
+         return 1;
++    if (width == 0.0 && height == 0.0 && ext_x1 == ext_x2 && ext_y1 == ext_y2)
++        return 1;
+     cairo_test_log (ctx, "Error: %s; clip extents %f,%f,%f,%f should be %f,%f,%f,%f\n",
+                     message, ext_x1, ext_y1, ext_x2 - ext_x1, ext_y2 - ext_y1,
+                     x, y, width, height);
+@@ -138,7 +140,8 @@ preamble (cairo_test_context_t *ctx)
+     cairo_save (cr);
+     cairo_clip (cr);
+     rectangle_list = cairo_copy_clip_rectangle_list (cr);
+-    if (! check_count (ctx, phase, rectangle_list, 0))
++    if (! check_count (ctx, phase, rectangle_list, 0) ||
++        ! check_clip_extents (ctx, phase, cr, 0, 0, 0, 0))
+     {
+ 	goto FAIL;
+     }
+--
+cgit v0.8.3-6-g21f6
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/empty-clip-rectangles.patch
@@ -0,0 +1,28 @@
+From f2fa15680ec3ac95cb68d4957557f06561a7dc55 Mon Sep 17 00:00:00 2001
+From: Karl Tomlinson <karlt+@karlt.net>
+Date: Fri, 16 Jul 2010 22:39:50 +0000
+Subject: clip: return empty clip from _cairo_clip_copy_rectangle_list when all_clipped
+
+Fixes https://bugs.freedesktop.org/show_bug.cgi?id=29122
+Tested by test/get-clip
+
+Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
+---
+diff --git a/src/cairo-clip.c b/src/cairo-clip.c
+index 12dc04d..f6173c6 100644
+--- a/src/cairo-clip.c
++++ b/src/cairo-clip.c
+@@ -1499,7 +1499,10 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
+     int n_rects = 0;
+     int i;
+ 
+-    if (clip != NULL && clip->path != NULL) {
++    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;
+--
+cgit v0.8.3-6-g21f6