diff options
Diffstat (limited to 'common/region.c')
-rw-r--r-- | common/region.c | 893 |
1 files changed, 893 insertions, 0 deletions
diff --git a/common/region.c b/common/region.c new file mode 100644 index 0000000..3f51f7b --- /dev/null +++ b/common/region.c @@ -0,0 +1,893 @@ +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + Copyright (C) 2009 Red Hat, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <spice/macros.h> + +#include "region.h" +#include "rect.h" +#include "mem.h" + +#define ASSERT(x) if (!(x)) { \ + printf("%s: ASSERT %s failed\n", __FUNCTION__, #x); \ + abort(); \ +} + +/* true iff two Boxes overlap */ +#define EXTENTCHECK(r1, r2) \ + (!( ((r1)->x2 <= (r2)->x1) || \ + ((r1)->x1 >= (r2)->x2) || \ + ((r1)->y2 <= (r2)->y1) || \ + ((r1)->y1 >= (r2)->y2) ) ) + +/* true iff Box r1 contains Box r2 */ +#define SUBSUMES(r1, r2) \ + ( ((r1)->x1 <= (r2)->x1) && \ + ((r1)->x2 >= (r2)->x2) && \ + ((r1)->y1 <= (r2)->y1) && \ + ((r1)->y2 >= (r2)->y2) ) + + +void region_init(QRegion *rgn) +{ + pixman_region32_init(rgn); +} + +void region_clear(QRegion *rgn) +{ + pixman_region32_fini(rgn); + pixman_region32_init(rgn); +} + +void region_destroy(QRegion *rgn) +{ + pixman_region32_fini(rgn); +} + +void region_clone(QRegion *dest, const QRegion *src) +{ + pixman_region32_init(dest); + pixman_region32_copy(dest, (pixman_region32_t *)src); +} + +#define FIND_BAND(r, r_band_end, r_end, ry1) \ + do { \ + ry1 = r->y1; \ + r_band_end = r + 1; \ + while ((r_band_end != r_end) && (r_band_end->y1 == ry1)) { \ + r_band_end++; \ + } \ + } while (0) + +static int test_band(int query, + int res, + pixman_box32_t *r1, + pixman_box32_t *r1_end, + pixman_box32_t *r2, + pixman_box32_t *r2_end) +{ + int x1; + int x2; + + do { + x1 = MAX(r1->x1, r2->x1); + x2 = MIN(r1->x2, r2->x2); + + /* + * Is there any overlap between the two rectangles? + */ + if (x1 < x2) { + res |= REGION_TEST_SHARED; + + if (r1->x1 < r2->x1 || r1->x2 > r2->x2) { + res |= REGION_TEST_LEFT_EXCLUSIVE; + } + + if (r2->x1 < r1->x1 || r2->x2 > r1->x2) { + res |= REGION_TEST_RIGHT_EXCLUSIVE; + } + } else { + /* No overlap at all, the leftmost is exclusive */ + if (r1->x1 < r2->x1) { + res |= REGION_TEST_LEFT_EXCLUSIVE; + } else { + res |= REGION_TEST_RIGHT_EXCLUSIVE; + } + } + + if ((res & query) == query) { + return res; + } + + /* + * Advance the pointer(s) with the leftmost right side, since the next + * rectangle on that list may still overlap the other region's + * current rectangle. + */ + if (r1->x2 == x2) { + r1++; + } + if (r2->x2 == x2) { + r2++; + } + } while ((r1 != r1_end) && (r2 != r2_end)); + + /* + * Deal with whichever band (if any) still has rectangles left. + */ + if (r1 != r1_end) { + res |= REGION_TEST_LEFT_EXCLUSIVE; + } else if (r2 != r2_end) { + res |= REGION_TEST_RIGHT_EXCLUSIVE; + } + + return res; +} + +static int test_generic (pixman_region32_t *reg1, + pixman_region32_t *reg2, + int query) +{ + pixman_box32_t *r1; /* Pointer into first region */ + pixman_box32_t *r2; /* Pointer into 2d region */ + pixman_box32_t *r1_end; /* End of 1st region */ + pixman_box32_t *r2_end; /* End of 2d region */ + int ybot; /* Bottom of intersection */ + int ytop; /* Top of intersection */ + pixman_box32_t * r1_band_end; /* End of current band in r1 */ + pixman_box32_t * r2_band_end; /* End of current band in r2 */ + int top; /* Top of non-overlapping band */ + int bot; /* Bottom of non-overlapping band*/ + int r1y1; /* Temps for r1->y1 and r2->y1 */ + int r2y1; + int r1_num_rects; + int r2_num_rects; + int res; + + r1 = pixman_region32_rectangles(reg1, &r1_num_rects); + r1_end = r1 + r1_num_rects; + + r2 = pixman_region32_rectangles(reg2, &r2_num_rects); + r2_end = r2 + r2_num_rects; + + res = 0; + + /* + * Initialize ybot. + * In the upcoming loop, ybot and ytop serve different functions depending + * on whether the band being handled is an overlapping or non-overlapping + * band. + * In the case of a non-overlapping band (only one of the regions + * has points in the band), ybot is the bottom of the most recent + * intersection and thus clips the top of the rectangles in that band. + * ytop is the top of the next intersection between the two regions and + * serves to clip the bottom of the rectangles in the current band. + * For an overlapping band (where the two regions intersect), ytop clips + * the top of the rectangles of both regions and ybot clips the bottoms. + */ + + ybot = MIN(r1->y1, r2->y1); + + do { + /* + * This algorithm proceeds one source-band (as opposed to a + * destination band, which is determined by where the two regions + * intersect) at a time. r1_band_end and r2_band_end serve to mark the + * rectangle after the last one in the current band for their + * respective regions. + */ + FIND_BAND(r1, r1_band_end, r1_end, r1y1); + FIND_BAND(r2, r2_band_end, r2_end, r2y1); + + /* + * First handle the band that doesn't intersect, if any. + * + * Note that attention is restricted to one band in the + * non-intersecting region at once, so if a region has n + * bands between the current position and the next place it overlaps + * the other, this entire loop will be passed through n times. + */ + if (r1y1 < r2y1) { + top = MAX (r1y1, ybot); + bot = MIN (r1->y2, r2y1); + if (top != bot) { + res |= REGION_TEST_LEFT_EXCLUSIVE; + + if ((res & query) == query) { + return res & query; + } + } + + ytop = r2y1; + } else if (r2y1 < r1y1) { + top = MAX (r2y1, ybot); + bot = MIN (r2->y2, r1y1); + + if (top != bot) { + res |= REGION_TEST_RIGHT_EXCLUSIVE; + + if ((res & query) == query) { + return res & query; + } + } + ytop = r1y1; + } else { + ytop = r1y1; + } + + /* + * Now see if we've hit an intersecting band. The two bands only + * intersect if ybot > ytop + */ + ybot = MIN (r1->y2, r2->y2); + if (ybot > ytop) { + res = test_band(query, res, + r1, r1_band_end, + r2, r2_band_end); + if ((res & query) == query) { + return res & query; + } + } + + /* + * If we've finished with a band (y2 == ybot) we skip forward + * in the region to the next band. + */ + if (r1->y2 == ybot) { + r1 = r1_band_end; + } + + if (r2->y2 == ybot) { + r2 = r2_band_end; + } + + } + while (r1 != r1_end && r2 != r2_end); + + /* + * Deal with whichever region (if any) still has rectangles left. + */ + + if (r1 != r1_end) { + res |= REGION_TEST_LEFT_EXCLUSIVE; + } else if (r2 != r2_end) { + res |= REGION_TEST_RIGHT_EXCLUSIVE; + } + + return res & query; +} + +int region_test(const QRegion *_reg1, const QRegion *_reg2, int query) +{ + int res; + pixman_region32_t *reg1 = (pixman_region32_t *)_reg1; + pixman_region32_t *reg2 = (pixman_region32_t *)_reg2; + + query = (query) ? query & REGION_TEST_ALL : REGION_TEST_ALL; + + res = 0; + + if (!pixman_region32_not_empty(reg1) || !pixman_region32_not_empty(reg2) || + !EXTENTCHECK (®1->extents, ®2->extents)) { + /* One or more regions are empty or they are disjoint */ + + if (pixman_region32_not_empty(reg1)) { + res |= REGION_TEST_LEFT_EXCLUSIVE; + } + + if (pixman_region32_not_empty(reg2)) { + res |= REGION_TEST_RIGHT_EXCLUSIVE; + } + + return res & query; + } else if (!reg1->data && !reg2->data) { + /* Just two rectangles that intersect */ + res |= REGION_TEST_SHARED; + + if (!SUBSUMES(®1->extents, ®2->extents)) { + res |= REGION_TEST_RIGHT_EXCLUSIVE; + } + + if (!SUBSUMES(®2->extents, ®1->extents)) { + res |= REGION_TEST_LEFT_EXCLUSIVE; + } + + return res & query; + } else if (!reg2->data && SUBSUMES (®2->extents, ®1->extents)) { + /* reg2 is just a rect that contains all of reg1 */ + + res |= REGION_TEST_SHARED; /* some piece must be shared, because reg is not empty */ + res |= REGION_TEST_RIGHT_EXCLUSIVE; /* reg2 contains all of reg1 and then some */ + + return res & query; + } else if (!reg1->data && SUBSUMES (®1->extents, ®2->extents)) { + /* reg1 is just a rect that contains all of reg2 */ + + res |= REGION_TEST_SHARED; /* some piece must be shared, because reg is not empty */ + res |= REGION_TEST_LEFT_EXCLUSIVE; /* reg1 contains all of reg2 and then some */ + + return res & query; + } else if (reg1 == reg2) { + res |= REGION_TEST_SHARED; + return res & query; + } else { + /* General purpose intersection */ + return test_generic (reg1, reg2, query); + } +} + +int region_is_valid(const QRegion *rgn) +{ + return pixman_region32_selfcheck((pixman_region32_t *)rgn); +} + +int region_is_empty(const QRegion *rgn) +{ + return !pixman_region32_not_empty((pixman_region32_t *)rgn); +} + +SpiceRect *region_dup_rects(const QRegion *rgn, uint32_t *num_rects) +{ + pixman_box32_t *boxes; + SpiceRect *rects; + int n, i; + + boxes = pixman_region32_rectangles((pixman_region32_t *)rgn, &n); + if (num_rects) { + *num_rects = n; + } + rects = spice_new(SpiceRect, n); + for (i = 0; i < n; i++) { + rects[i].left = boxes[i].x1; + rects[i].top = boxes[i].y1; + rects[i].right = boxes[i].x2; + rects[i].bottom = boxes[i].y2; + } + return rects; +} + +void region_ret_rects(const QRegion *rgn, SpiceRect *rects, uint32_t num_rects) +{ + pixman_box32_t *boxes; + unsigned int n, i; + + boxes = pixman_region32_rectangles((pixman_region32_t *)rgn, (int *)&n); + for (i = 0; i < n && i < num_rects; i++) { + rects[i].left = boxes[i].x1; + rects[i].top = boxes[i].y1; + rects[i].right = boxes[i].x2; + rects[i].bottom = boxes[i].y2; + } + + if (i && i != n) { + unsigned int x; + + for (x = 0; x < (n - num_rects); ++x) { + rects[i - 1].left = MIN(rects[i - 1].left, boxes[i + x].x1); + rects[i - 1].top = MIN(rects[i - 1].top, boxes[i + x].y1); + rects[i - 1].right = MAX(rects[i - 1].right, boxes[i + x].x2); + rects[i - 1].bottom = MAX(rects[i - 1].bottom, boxes[i + x].y2); + } + } +} + + +int region_is_equal(const QRegion *rgn1, const QRegion *rgn2) +{ + return pixman_region32_equal((pixman_region32_t *)rgn1, (pixman_region32_t *)rgn2); +} + +int region_intersects(const QRegion *rgn1, const QRegion *rgn2) +{ + int test_res; + + if (!region_bounds_intersects(rgn1, rgn2)) { + return FALSE; + } + + test_res = region_test(rgn1, rgn2, REGION_TEST_SHARED); + return !!test_res; +} + +int region_bounds_intersects(const QRegion *rgn1, const QRegion *rgn2) +{ + pixman_box32_t *extents1, *extents2; + + extents1 = pixman_region32_extents((pixman_region32_t *)rgn1); + extents2 = pixman_region32_extents((pixman_region32_t *)rgn1); + + return EXTENTCHECK(extents1, extents2); +} + +int region_contains(const QRegion *rgn, const QRegion *other) +{ + int test_res; + + test_res = region_test(rgn, other, REGION_TEST_RIGHT_EXCLUSIVE); + return !test_res; +} + +int region_contains_point(const QRegion *rgn, int32_t x, int32_t y) +{ + return pixman_region32_contains_point((pixman_region32_t *)rgn, x, y, NULL); +} + +void region_or(QRegion *rgn, const QRegion *other_rgn) +{ + pixman_region32_union(rgn, rgn, (pixman_region32_t *)other_rgn); +} + +void region_and(QRegion *rgn, const QRegion *other_rgn) +{ + pixman_region32_intersect(rgn, rgn, (pixman_region32_t *)other_rgn); +} + +void region_xor(QRegion *rgn, const QRegion *other_rgn) +{ + pixman_region32_t intersection; + + pixman_region32_copy(&intersection, rgn); + pixman_region32_intersect(&intersection, + &intersection, + (pixman_region32_t *)other_rgn); + pixman_region32_union(rgn, rgn, (pixman_region32_t *)other_rgn); + pixman_region32_subtract(rgn, rgn, &intersection); + pixman_region32_fini(&intersection); +} + +void region_exclude(QRegion *rgn, const QRegion *other_rgn) +{ + pixman_region32_subtract(rgn, rgn, (pixman_region32_t *)other_rgn); +} + +void region_add(QRegion *rgn, const SpiceRect *r) +{ + pixman_region32_union_rect(rgn, rgn, r->left, r->top, + r->right - r->left, + r->bottom - r->top); +} + +void region_remove(QRegion *rgn, const SpiceRect *r) +{ + pixman_region32_t rg; + + pixman_region32_init_rect(&rg, r->left, r->top, + r->right - r->left, + r->bottom - r->top); + pixman_region32_subtract(rgn, rgn, &rg); + pixman_region32_fini(&rg); +} + + +void region_offset(QRegion *rgn, int32_t dx, int32_t dy) +{ + pixman_region32_translate(rgn, dx, dy); +} + +void region_dump(const QRegion *rgn, const char *prefix) +{ + pixman_box32_t *rects, *extents; + int n_rects, i; + + printf("%sREGION: %p, ", prefix, rgn); + + if (!pixman_region32_not_empty((pixman_region32_t *)rgn)) { + printf("EMPTY\n"); + return; + } + + extents = pixman_region32_extents((pixman_region32_t *)rgn); + rects = pixman_region32_rectangles((pixman_region32_t *)rgn, &n_rects); + printf("num %u bounds (%d, %d, %d, %d)\n", + n_rects, + extents->x1, + extents->y1, + extents->x2, + extents->y2); + + + for (i = 0; i < n_rects; i++) { + printf("%*s %12d %12d %12d %12d\n", + (int)strlen(prefix), "", + rects[i].x1, + rects[i].y1, + rects[i].x2, + rects[i].y2); + } +} + +#ifdef REGION_TEST + +static int slow_region_test(const QRegion *rgn, const QRegion *other_rgn, int query) +{ + pixman_region32_t intersection; + int res; + + pixman_region32_init(&intersection); + pixman_region32_intersect(&intersection, + (pixman_region32_t *)rgn, + (pixman_region32_t *)other_rgn); + + res = 0; + + if (query & REGION_TEST_SHARED && + pixman_region32_not_empty(&intersection)) { + res |= REGION_TEST_SHARED; + } + + if (query & REGION_TEST_LEFT_EXCLUSIVE && + !pixman_region32_equal(&intersection, (pixman_region32_t *)rgn)) { + res |= REGION_TEST_LEFT_EXCLUSIVE; + } + + if (query & REGION_TEST_RIGHT_EXCLUSIVE && + !pixman_region32_equal(&intersection, (pixman_region32_t *)other_rgn)) { + res |= REGION_TEST_RIGHT_EXCLUSIVE; + } + + pixman_region32_fini(&intersection); + + return res; +} + + +static int rect_is_valid(const SpiceRect *r) +{ + if (r->top > r->bottom || r->left > r->right) { + printf("%s: invalid rect\n", __FUNCTION__); + return FALSE; + } + return TRUE; +} + +static void rect_set(SpiceRect *r, int32_t top, int32_t left, int32_t bottom, int32_t right) +{ + r->top = top; + r->left = left; + r->bottom = bottom; + r->right = right; + ASSERT(rect_is_valid(r)); +} + +static void random_region(QRegion *reg) +{ + int i; + int num_rects; + int x, y, w, h; + SpiceRect _r; + SpiceRect *r = &_r; + + region_clear(reg); + + num_rects = rand() % 20; + for (i = 0; i < num_rects; i++) { + x = rand()%100; + y = rand()%100; + w = rand()%100; + h = rand()%100; + rect_set(r, + x, y, + x+w, y+h); + region_add(reg, r); + } +} + +static void test(const QRegion *r1, const QRegion *r2, int *expected) +{ + printf("r1 is_empty %s [%s]\n", + region_is_empty(r1) ? "TRUE" : "FALSE", + (region_is_empty(r1) == *(expected++)) ? "OK" : "ERR"); + printf("r2 is_empty %s [%s]\n", + region_is_empty(r2) ? "TRUE" : "FALSE", + (region_is_empty(r2) == *(expected++)) ? "OK" : "ERR"); + printf("is_equal %s [%s]\n", + region_is_equal(r1, r2) ? "TRUE" : "FALSE", + (region_is_equal(r1, r2) == *(expected++)) ? "OK" : "ERR"); + printf("intersects %s [%s]\n", + region_intersects(r1, r2) ? "TRUE" : "FALSE", + (region_intersects(r1, r2) == *(expected++)) ? "OK" : "ERR"); + printf("contains %s [%s]\n", + region_contains(r1, r2) ? "TRUE" : "FALSE", + (region_contains(r1, r2) == *(expected++)) ? "OK" : "ERR"); +} + +enum { + EXPECT_R1_EMPTY, + EXPECT_R2_EMPTY, + EXPECT_EQUAL, + EXPECT_SECT, + EXPECT_CONT, +}; + +int main(void) +{ + QRegion _r1, _r2, _r3; + QRegion *r1 = &_r1; + QRegion *r2 = &_r2; + QRegion *r3 = &_r3; + SpiceRect _r; + SpiceRect *r = &_r; + int expected[5]; + int i, j; + + region_init(r1); + region_init(r2); + + printf("dump r1 empty rgn [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID"); + region_dump(r1, ""); + expected[EXPECT_R1_EMPTY] = TRUE; + expected[EXPECT_R2_EMPTY] = TRUE; + expected[EXPECT_EQUAL] = TRUE; + expected[EXPECT_SECT] = FALSE; + expected[EXPECT_CONT] = TRUE; + test(r1, r2, expected); + printf("\n"); + + region_clone(r3, r1); + printf("dump r3 clone rgn [%s]\n", region_is_valid(r3) ? "VALID" : "INVALID"); + region_dump(r3, ""); + expected[EXPECT_R1_EMPTY] = TRUE; + expected[EXPECT_R2_EMPTY] = TRUE; + expected[EXPECT_EQUAL] = TRUE; + expected[EXPECT_SECT] = FALSE; + expected[EXPECT_CONT] = TRUE; + test(r1, r3, expected); + region_destroy(r3); + printf("\n"); + + rect_set(r, 0, 0, 100, 100); + region_add(r1, r); + printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID"); + region_dump(r1, ""); + expected[EXPECT_R1_EMPTY] = FALSE; + expected[EXPECT_R2_EMPTY] = TRUE; + expected[EXPECT_EQUAL] = FALSE; + expected[EXPECT_SECT] = FALSE; + expected[EXPECT_CONT] = TRUE; + test(r1, r2, expected); + printf("\n"); + + region_clear(r1); + rect_set(r, 0, 0, 0, 0); + region_add(r1, r); + printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID"); + region_dump(r1, ""); + expected[EXPECT_R1_EMPTY] = TRUE; + expected[EXPECT_R2_EMPTY] = TRUE; + expected[EXPECT_EQUAL] = TRUE; + expected[EXPECT_SECT] = FALSE; + expected[EXPECT_CONT] = TRUE; + test(r1, r2, expected); + printf("\n"); + + rect_set(r, -100, -100, 0, 0); + region_add(r1, r); + printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID"); + region_dump(r1, ""); + expected[EXPECT_R1_EMPTY] = FALSE; + expected[EXPECT_R2_EMPTY] = TRUE; + expected[EXPECT_EQUAL] = FALSE; + expected[EXPECT_SECT] = FALSE; + expected[EXPECT_CONT] = TRUE; + test(r1, r2, expected); + printf("\n"); + + region_clear(r1); + rect_set(r, -100, -100, 100, 100); + region_add(r1, r); + printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID"); + region_dump(r1, ""); + expected[EXPECT_R1_EMPTY] = FALSE; + expected[EXPECT_R2_EMPTY] = TRUE; + expected[EXPECT_EQUAL] = FALSE; + expected[EXPECT_SECT] = FALSE; + expected[EXPECT_CONT] = TRUE; + test(r1, r2, expected); + printf("\n"); + + + region_clear(r1); + region_clear(r2); + + rect_set(r, 100, 100, 200, 200); + region_add(r1, r); + printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID"); + region_dump(r1, ""); + expected[EXPECT_R1_EMPTY] = FALSE; + expected[EXPECT_R2_EMPTY] = TRUE; + expected[EXPECT_EQUAL] = FALSE; + expected[EXPECT_SECT] = FALSE; + expected[EXPECT_CONT] = TRUE; + test(r1, r2, expected); + printf("\n"); + + rect_set(r, 300, 300, 400, 400); + region_add(r1, r); + printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID"); + region_dump(r1, ""); + expected[EXPECT_R1_EMPTY] = FALSE; + expected[EXPECT_R2_EMPTY] = TRUE; + expected[EXPECT_EQUAL] = FALSE; + expected[EXPECT_SECT] = FALSE; + expected[EXPECT_CONT] = TRUE; + test(r1, r2, expected); + printf("\n"); + + rect_set(r, 500, 500, 600, 600); + region_add(r2, r); + printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID"); + region_dump(r2, ""); + expected[EXPECT_R1_EMPTY] = FALSE; + expected[EXPECT_R2_EMPTY] = FALSE; + expected[EXPECT_EQUAL] = FALSE; + expected[EXPECT_SECT] = FALSE; + expected[EXPECT_CONT] = FALSE; + test(r1, r2, expected); + printf("\n"); + + region_clear(r2); + + rect_set(r, 100, 100, 200, 200); + region_add(r2, r); + rect_set(r, 300, 300, 400, 400); + region_add(r2, r); + printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID"); + region_dump(r2, ""); + expected[EXPECT_R1_EMPTY] = FALSE; + expected[EXPECT_R2_EMPTY] = FALSE; + expected[EXPECT_EQUAL] = TRUE; + expected[EXPECT_SECT] = TRUE; + expected[EXPECT_CONT] = TRUE; + test(r1, r2, expected); + printf("\n"); + + region_clear(r2); + + rect_set(r, 100, 100, 200, 200); + region_add(r2, r); + printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID"); + region_dump(r2, ""); + expected[EXPECT_R1_EMPTY] = FALSE; + expected[EXPECT_R2_EMPTY] = FALSE; + expected[EXPECT_EQUAL] = FALSE; + expected[EXPECT_SECT] = TRUE; + expected[EXPECT_CONT] = TRUE; + test(r1, r2, expected); + printf("\n"); + + region_clear(r2); + + rect_set(r, -2000, -2000, -1000, -1000); + region_add(r2, r); + printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID"); + region_dump(r2, ""); + expected[EXPECT_R1_EMPTY] = FALSE; + expected[EXPECT_R2_EMPTY] = FALSE; + expected[EXPECT_EQUAL] = FALSE; + expected[EXPECT_SECT] = FALSE; + expected[EXPECT_CONT] = FALSE; + test(r1, r2, expected); + printf("\n"); + + region_clear(r2); + + rect_set(r, -2000, -2000, 1000, 1000); + region_add(r2, r); + printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID"); + region_dump(r2, ""); + expected[EXPECT_R1_EMPTY] = FALSE; + expected[EXPECT_R2_EMPTY] = FALSE; + expected[EXPECT_EQUAL] = FALSE; + expected[EXPECT_SECT] = TRUE; + expected[EXPECT_CONT] = FALSE; + test(r1, r2, expected); + printf("\n"); + + region_clear(r2); + + rect_set(r, 150, 150, 175, 175); + region_add(r2, r); + printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID"); + region_dump(r2, ""); + expected[EXPECT_R1_EMPTY] = FALSE; + expected[EXPECT_R2_EMPTY] = FALSE; + expected[EXPECT_EQUAL] = FALSE; + expected[EXPECT_SECT] = TRUE; + expected[EXPECT_CONT] = TRUE; + test(r1, r2, expected); + printf("\n"); + + region_clear(r2); + + rect_set(r, 150, 150, 350, 350); + region_add(r2, r); + printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID"); + region_dump(r2, ""); + expected[EXPECT_R1_EMPTY] = FALSE; + expected[EXPECT_R2_EMPTY] = FALSE; + expected[EXPECT_EQUAL] = FALSE; + expected[EXPECT_SECT] = TRUE; + expected[EXPECT_CONT] = FALSE; + test(r1, r2, expected); + printf("\n"); + + region_and(r2, r1); + printf("dump r2 and r1 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID"); + region_dump(r2, ""); + expected[EXPECT_R1_EMPTY] = FALSE; + expected[EXPECT_R2_EMPTY] = FALSE; + expected[EXPECT_EQUAL] = FALSE; + expected[EXPECT_SECT] = TRUE; + expected[EXPECT_CONT] = FALSE; + test(r2, r1, expected); + printf("\n"); + + + region_clone(r3, r1); + printf("dump r3 clone rgn [%s]\n", region_is_valid(r3) ? "VALID" : "INVALID"); + region_dump(r3, ""); + expected[EXPECT_R1_EMPTY] = FALSE; + expected[EXPECT_R2_EMPTY] = FALSE; + expected[EXPECT_EQUAL] = TRUE; + expected[EXPECT_SECT] = TRUE; + expected[EXPECT_CONT] = TRUE; + test(r1, r3, expected); + printf("\n"); + + j = 0; + for (i = 0; i < 1000000; i++) { + int res1, res2, test; + int tests[] = { + REGION_TEST_LEFT_EXCLUSIVE, + REGION_TEST_RIGHT_EXCLUSIVE, + REGION_TEST_SHARED, + REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE, + REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_SHARED, + REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED, + REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED + }; + + random_region(r1); + random_region(r2); + + for (test = 0; test < 7; test++) { + res1 = region_test(r1, r2, tests[test]); + res2 = slow_region_test(r1, r2, tests[test]); + if (res1 != res2) { + printf ("Error in region_test %d, got %d, expected %d, query=%d\n", + j, res1, res2, tests[test]); + printf ("r1:\n"); + region_dump(r1, ""); + printf ("r2:\n"); + region_dump(r2, ""); + } + j++; + } + } + + region_destroy(r3); + region_destroy(r1); + region_destroy(r2); + + return 0; +} + +#endif + |