[cairo-commit] src/cairo.h src/cairoint.h src/cairo-region.c src/cairo-traps.c

Søren Sandmann Pedersen sandmann at kemper.freedesktop.org
Mon Jun 15 02:47:55 PDT 2009


 src/cairo-region.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 src/cairo-traps.c  |   47 ++++++++++++++++++++++++++++-------------------
 src/cairo.h        |    4 ++++
 src/cairoint.h     |    1 +
 4 files changed, 77 insertions(+), 19 deletions(-)

New commits:
commit 5d57aeaa23566739ba01a0fac1c3b90ce27b28cd
Author: Søren Sandmann Pedersen <sandmann at redhat.com>
Date:   Tue May 26 17:53:37 2009 -0400

    Reinstate cairo_region_create_rectangles()
    
    cairo_region_union_rectangle() is linear in the number of rectangles
    in the region. There is no way to make it significantly faster without
    losing the ability to return errors synchronously, so a
    cairo_region_create_rectangles() is needed to avoid a large
    performance regression.

diff --git a/src/cairo-region.c b/src/cairo-region.c
index c355b4a..aeb2ef2 100644
--- a/src/cairo-region.c
+++ b/src/cairo-region.c
@@ -134,6 +134,50 @@ cairo_region_create (void)
 }
 slim_hidden_def (cairo_region_create);
 
+cairo_region_t *
+cairo_region_create_rectangles (cairo_rectangle_int_t *rects,
+				int count)
+{
+    pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
+    pixman_box32_t *pboxes = stack_pboxes;
+    cairo_region_t *region;
+    int i;
+
+    region = _cairo_malloc (sizeof (cairo_region_t));
+
+    if (!region)
+	return (cairo_region_t *)&_cairo_region_nil;
+
+    region->status = CAIRO_STATUS_SUCCESS;
+    
+    if (count > ARRAY_LENGTH (stack_pboxes)) {
+	pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
+
+	if (unlikely (pboxes == NULL)) {
+	    free (region);
+	    return (cairo_region_t *)&_cairo_region_nil;
+	}
+    }
+
+    for (i = 0; i < count; i++) {
+	pboxes[i].x1 = rects[i].x;
+	pboxes[i].y1 = rects[i].y;
+	pboxes[i].x2 = rects[i].x + rects[i].width;
+	pboxes[i].y2 = rects[i].y + rects[i].height;
+    }
+
+    if (! pixman_region32_init_rects (&region->rgn, pboxes, count)) {
+	free (region);
+
+	region = (cairo_region_t *)&_cairo_region_nil;
+    }
+    
+    if (pboxes != stack_pboxes)
+	free (pboxes);
+
+    return region;
+}
+
 /**
  * cairo_region_create_rectangle:
  * @rectangle: a #cairo_rectangle_int_t
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index 092bd9d..d8464cc 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -619,9 +619,10 @@ cairo_int_status_t
 _cairo_traps_extract_region (const cairo_traps_t  *traps,
 			     cairo_region_t      **region)
 {
+    cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
+    cairo_rectangle_int_t *rects = stack_rects;
     cairo_int_status_t status;
-    cairo_region_t *r;
-    int i;
+    int i, rect_count;
 
     for (i = 0; i < traps->num_traps; i++) {
 	if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x   ||
@@ -635,13 +636,15 @@ _cairo_traps_extract_region (const cairo_traps_t  *traps,
 	}
     }
 
-    r = cairo_region_create ();
-    if (unlikely (r->status))
-	return r->status;
+    if (traps->num_traps > ARRAY_LENGTH (stack_rects)) {
+	rects = _cairo_malloc_ab (traps->num_traps, sizeof (cairo_rectangle_int_t));
 
-    for (i = 0; i < traps->num_traps; i++) {
-	cairo_rectangle_int_t rect;
+	if (unlikely (rects == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
 
+    rect_count = 0;
+    for (i = 0; i < traps->num_traps; i++) {
 	int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
 	int y1 = _cairo_fixed_integer_part (traps->traps[i].top);
 	int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
@@ -652,21 +655,27 @@ _cairo_traps_extract_region (const cairo_traps_t  *traps,
 	 */
 	if (x1 == x2 || y1 == y2)
 	    continue;
+	
+	rects[rect_count].x = x1;
+	rects[rect_count].y = y1;
+	rects[rect_count].width = x2 - x1;
+	rects[rect_count].height = y2 - y1;
 
-	rect.x = x1;
-	rect.y = y1;
-	rect.width = x2 - x1;
-	rect.height = y2 - y1;
-
-	status = cairo_region_union_rectangle (r, &rect);
-	if (unlikely (status)) {
-	    cairo_region_destroy (r);
-	    return status;
-	}
+	rect_count++;
     }
+ 
+    *region = cairo_region_create_rectangles (rects, rect_count);
+    status = cairo_region_status (*region);
 
-    *region = r;
-    return CAIRO_STATUS_SUCCESS;
+    if (rects != stack_rects)
+	free (rects);
+
+    if (unlikely (status)) {
+	cairo_region_destroy (*region);
+	*region = NULL;
+    }
+    
+    return status;
 }
 
 /* moves trap points such that they become the actual corners of the trapezoid */
diff --git a/src/cairo.h b/src/cairo.h
index 2fef37c..e21cc8a 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -2374,6 +2374,10 @@ cairo_public cairo_region_t *
 cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle);
 
 cairo_public cairo_region_t *
+cairo_region_create_rectangles (cairo_rectangle_int_t *rects,
+				int count);
+
+cairo_public cairo_region_t *
 cairo_region_copy (cairo_region_t *original);
 
 cairo_public void
diff --git a/src/cairoint.h b/src/cairoint.h
index 9021ebf..0bb4d02 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2742,6 +2742,7 @@ slim_hidden_proto (cairo_user_to_device_distance);
 slim_hidden_proto (cairo_version_string);
 slim_hidden_proto (cairo_region_create);
 slim_hidden_proto (cairo_region_create_rectangle);
+slim_hidden_proto (cairo_region_create_rectangles);
 slim_hidden_proto (cairo_region_copy);
 slim_hidden_proto (cairo_region_destroy);
 slim_hidden_proto (cairo_region_status);


More information about the cairo-commit mailing list