/* * Copyright © 2004 David Reveman * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation, and that the name of * David Reveman not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior permission. * David Reveman makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: David Reveman */ #ifdef HAVE_CONFIG_H # include "../config.h" #endif #include "glitzint.h" #define REGION_ALLOC_CHUNK 16 #define BOX_SUBSUMS_BOX(b1, b2) \ ((b2)->x1 >= (b1)->x1 && \ (b2)->x2 <= (b1)->x2 && \ (b2)->y1 >= (b1)->y1 && \ (b2)->y2 <= (b1)->y2) #define BOX_INTERSECTS_BOX(b1, b2) \ ((b1)->x1 < (b2)->x2 && \ (b1)->x2 > (b2)->x1 && \ (b1)->y1 < (b2)->y2 && \ (b1)->y2 > (b2)->y1) #define BOX_CLOSE_TO_BOX(b1, b2) \ ((b1)->x1 < ((b2)->x2 + 1) && \ (b1)->x2 > ((b2)->x1 - 1) && \ (b1)->y1 < ((b2)->y2 + 1) && \ (b1)->y2 > ((b2)->y1 - 1)) #define BOX_NEXT_TO_BOX(b1, b2) \ ((((b1)->x1 == (b2)->x2 || \ (b1)->x2 == (b2)->x1) && \ (b1)->y1 == (b2)->y1 && \ (b1)->y2 == (b2)->y2) || \ (((b1)->y1 == (b2)->y2 || \ (b1)->y2 == (b2)->y1) && \ (b1)->x1 == (b2)->x1 && \ (b1)->x2 == (b2)->x2)) #define MERGE_BOXES(d, b1, b2) \ { \ (d)->x1 = MIN ((b1)->x1, (b2)->x1); \ (d)->y1 = MIN ((b1)->y1, (b2)->y1); \ (d)->x2 = MAX ((b1)->x2, (b2)->x2); \ (d)->y2 = MAX ((b1)->y2, (b2)->y2); \ } /* * No real union, boxes that intersect are just joined into bigger boxes. * This is OK for our needs and it keeps the number of boxes down to a * minimum and makes it faster. */ glitz_status_t glitz_region_union (glitz_region_t *region, glitz_box_t *ubox) { if (region->n_box == 0) { region->extents = *ubox; region->box = ®ion->extents; region->n_box = 1; return GLITZ_STATUS_SUCCESS; } if (BOX_CLOSE_TO_BOX (ubox, ®ion->extents)) { glitz_box_t *box, *new_box, *dst_box; int n_box; box = region->box; n_box = region->n_box; while (n_box--) { if (BOX_SUBSUMS_BOX (box, ubox)) return GLITZ_STATUS_SUCCESS; box++; } box = region->box; n_box = region->n_box; new_box = ubox; dst_box = NULL; while (n_box--) { if (BOX_INTERSECTS_BOX (box, new_box) || BOX_NEXT_TO_BOX (box, new_box)) { if (dst_box) { /* * Remove box from region */ region->n_box--; if (region->n_box == 1) { MERGE_BOXES (®ion->extents, box, new_box); region->box = ®ion->extents; return GLITZ_STATUS_SUCCESS; } else { MERGE_BOXES (dst_box, box, new_box); if (n_box) memmove (box, box + 1, n_box * sizeof (glitz_box_t)); } continue; } else { dst_box = box; MERGE_BOXES (dst_box, box, new_box); new_box = dst_box; } } box++; } if (dst_box) { if (region->n_box > 1) MERGE_BOXES (®ion->extents, ®ion->extents, ubox); return GLITZ_STATUS_SUCCESS; } } /* * Add box to region */ if (region->size < (region->n_box + 1)) { region->size += REGION_ALLOC_CHUNK; region->data = (void *) realloc (region->data, sizeof (glitz_box_t) * region->size); if (!region->data) return GLITZ_STATUS_NO_MEMORY; } region->box = (glitz_box_t *) region->data; region->box[region->n_box] = *ubox; if (region->n_box == 1) region->box[0] = region->extents; region->n_box++; MERGE_BOXES (®ion->extents, ®ion->extents, ubox); return GLITZ_STATUS_SUCCESS; }