diff options
author | Søren Sandmann Pedersen <sandmann@redhat.com> | 2009-05-26 17:53:37 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <sandmann@redhat.com> | 2009-06-15 05:48:51 -0400 |
commit | 5d57aeaa23566739ba01a0fac1c3b90ce27b28cd (patch) | |
tree | d60e06bb812f0e1652a67a5c96701011cb5160f6 | |
parent | 216a2e24c7375e48677ce30f9fe8fb3d8bbdd10d (diff) |
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.
-rw-r--r-- | src/cairo-region.c | 44 | ||||
-rw-r--r-- | src/cairo-traps.c | 47 | ||||
-rw-r--r-- | src/cairo.h | 4 | ||||
-rw-r--r-- | src/cairoint.h | 1 |
4 files changed, 77 insertions, 19 deletions
diff --git a/src/cairo-region.c b/src/cairo-region.c index c355b4ad..aeb2ef22 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 (®ion->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 092bd9d0..d8464cc8 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 2fef37c6..e21cc8ae 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 9021ebf4..0bb4d026 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); |