/* * The functions in this file implement the Region abstraction used extensively * throughout the X11 sample server. A Region is simply a set of disjoint * (non-overlapping) rectangles, plus an "extent" rectangle which is the * smallest single rectangle that contains all the non-overlapping rectangles. * * A Region is implemented as a "y-x-banded" array of rectangles. This array * imposes two degrees of order. First, all rectangles are sorted by top side * y coordinate first (y1), and then by left side x coordinate (x1). * * Furthermore, the rectangles are grouped into "bands". Each rectangle in a * band has the same top y coordinate (y1), and each has the same bottom y * coordinate (y2). Thus all rectangles in a band differ only in their left * and right side (x1 and x2). Bands are implicit in the array of rectangles: * there is no separate list of band start pointers. * * The y-x band representation does not minimize rectangles. In particular, * if a rectangle vertically crosses a band (the rectangle has scanlines in * the y1 to y2 area spanned by the band), then the rectangle may be broken * down into two or more smaller rectangles stacked one atop the other. * * ----------- ----------- * | | | | band 0 * | | -------- ----------- -------- * | | | | in y-x banded | | | | band 1 * | | | | form is | | | | * ----------- | | ----------- -------- * | | | | band 2 * -------- -------- * * An added constraint on the rectangles is that they must cover as much * horizontal area as possible: no two rectangles within a band are allowed * to touch. * * Whenever possible, bands will be merged together to cover a greater vertical * distance (and thus reduce the number of rectangles). Two bands can be merged * only if the bottom of one touches the top of the other and they have * rectangles in the same places (of the same width, of course). * * Adam de Boor wrote most of the original region code. Joel McCormack * substantially modified or rewrote most of the core arithmetic routines, and * added pixman_region_validate in order to support several speed improvements * to pixman_region_validate_tree. Bob Scheifler changed the representation * to be more compact when empty or a single rectangle, and did a bunch of * gratuitous reformatting. Carl Worth did further gratuitous reformatting * while re-merging the server and client region code into libpixregion. * Soren Sandmann did even more gratuitous reformatting.
*/
/*====================================================================== * Generic Region Operator
*====================================================================*/
/*- *----------------------------------------------------------------------- * pixman_coalesce -- * Attempt to merge the boxes in the current band with those in the * previous one. We are guaranteed that the current band extends to * the end of the rects array. Used only by pixman_op. * * Results: * The new index for the previous band. * * Side Effects: * If coalescing takes place: * - rectangles in the previous band will have their y2 fields * altered. * - region->data->numRects will be decreased. * *-----------------------------------------------------------------------
*/ staticinlineint
pixman_coalesce (region_type_t * region, /* Region to coalesce */ int prev_start, /* Index of start of previous band */ int cur_start) /* Index of start of current band */
{
box_type_t *prev_box; /* Current box in previous band */
box_type_t *cur_box; /* Current box in current band */ int numRects; /* Number rectangles in both bands */ int y2; /* Bottom of current band */
/* * Figure out how many rectangles are in the band.
*/
numRects = cur_start - prev_start;
critical_if_fail (numRects == region->data->numRects - cur_start);
if (!numRects) return cur_start;
/* * The bands may only be coalesced if the bottom of the previous * matches the top scanline of the current.
*/
prev_box = PIXREGION_BOX (region, prev_start);
cur_box = PIXREGION_BOX (region, cur_start); if (prev_box->y2 != cur_box->y1) return cur_start;
/* * Make sure the bands have boxes in the same places. This * assumes that boxes have been added in such a way that they * cover the most area possible. I.e. two boxes in a band must * have some horizontal space between them.
*/
y2 = cur_box->y2;
do
{ if ((prev_box->x1 != cur_box->x1) || (prev_box->x2 != cur_box->x2)) return (cur_start);
prev_box++;
cur_box++;
numRects--;
} while (numRects);
/* * The bands may be merged, so set the bottom y of each box * in the previous band to the bottom y of the current band.
*/
numRects = cur_start - prev_start;
region->data->numRects -= numRects;
do
{
prev_box--;
prev_box->y2 = y2;
numRects--;
} while (numRects);
return prev_start;
}
/* Quicky macro to avoid trivial reject procedure calls to pixman_coalesce */
/*- *----------------------------------------------------------------------- * pixman_region_append_non_o -- * Handle a non-overlapping band for the union and subtract operations. * Just adds the (top/bottom-clipped) rectangles into the region. * Doesn't have to check for subsumption or anything. * * Results: * None. * * Side Effects: * region->data->numRects is incremented and the rectangles overwritten * with the rectangles we're passed. * *-----------------------------------------------------------------------
*/ staticinline pixman_bool_t
pixman_region_append_non_o (region_type_t * region,
box_type_t * r,
box_type_t * r_end, int y1, int y2)
{
box_type_t *next_rect; int new_rects;
/* Make sure we have enough space for all rectangles to be added */
RECTALLOC (region, new_rects);
next_rect = PIXREGION_TOP (region);
region->data->numRects += new_rects;
do
{
critical_if_fail (r->x1 < r->x2);
ADDRECT (next_rect, r->x1, y1, r->x2, y2);
r++;
} while (r != r_end);
returnTRUE;
}
#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)
/*- *----------------------------------------------------------------------- * pixman_op -- * Apply an operation to two regions. Called by pixman_region_union, pixman_region_inverse, * pixman_region_subtract, pixman_region_intersect.... Both regions MUST have at least one * rectangle, and cannot be the same object. * * Results: * TRUE if successful. * * Side Effects: * The new region is overwritten. * overlap set to TRUE if overlap_func ever returns TRUE. * * Notes: * The idea behind this function is to view the two regions as sets. * Together they cover a rectangle of area that this function divides * into horizontal bands where points are covered only by one region * or by both. For the first case, the non_overlap_func is called with * each the band and the band's upper and lower extents. For the * second, the overlap_func is called to process the entire band. It * is responsible for clipping the rectangles in the band, though * this function provides the boundaries. * At the end of each band, the new region is coalesced, if possible, * to reduce the number of rectangles in the region. * *-----------------------------------------------------------------------
*/
static pixman_bool_t
pixman_op (region_type_t * new_reg, /* Place to store result */ const region_type_t * reg1, /* First region in operation */ const region_type_t * reg2, /* 2d region in operation */
overlap_proc_ptr overlap_func, /* Function to call for over-
* lapping bands */ int append_non1, /* Append non-overlapping bands * in region 1 ?
*/ int append_non2 /* Append non-overlapping bands * in region 2 ?
*/
)
{
box_type_t *r1; /* Pointer into first region */
box_type_t *r2; /* Pointer into 2d region */
box_type_t *r1_end; /* End of 1st region */
box_type_t *r2_end; /* End of 2d region */ int ybot; /* Bottom of intersection */ int ytop; /* Top of intersection */
region_data_type_t *old_data; /* Old data for new_reg */ int prev_band; /* Index of start of
* previous band in new_reg */ int cur_band; /* Index of start of current
* band in new_reg */
box_type_t * r1_band_end; /* End of current band in r1 */
box_type_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 new_size; int numRects;
/* * Break any region computed from a broken region
*/ if (PIXREGION_NAR (reg1) || PIXREGION_NAR (reg2)) return pixman_break (new_reg);
/* * Initialization: * set r1, r2, r1_end and r2_end appropriately, save the rectangles * of the destination region until the end in case it's one of * the two source regions, then mark the "new" region empty, allocating * another array of rectangles for it to use.
*/
/* guess at new size */ if (numRects > new_size)
new_size = numRects;
new_size <<= 1;
if (!new_reg->data)
new_reg->data = pixman_region_empty_data; elseif (new_reg->data->size)
new_reg->data->numRects = 0;
if (new_size > new_reg->data->size)
{ if (!pixman_rect_alloc (new_reg, new_size))
{
free (old_data); returnFALSE;
}
}
/* * 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);
/* * prev_band serves to mark the start of the previous band so rectangles * can be coalesced into larger rectangles. qv. pixman_coalesce, above. * In the beginning, there is no previous band, so prev_band == cur_band * (cur_band is set later on, of course, but the first band will always * start at index 0). prev_band and cur_band must be indices because of * the possible expansion, and resultant moving, of the new region's * array of rectangles.
*/
prev_band = 0;
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.
*/
critical_if_fail (r1 != r1_end);
critical_if_fail (r2 != r2_end);
/* * 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)
{ if (append_non1)
{
top = MAX (r1y1, ybot);
bot = MIN (r1->y2, r2y1); if (top != bot)
{
cur_band = new_reg->data->numRects; if (!pixman_region_append_non_o (new_reg, r1, r1_band_end, top, bot)) goto bail;
COALESCE (new_reg, prev_band, cur_band);
}
}
ytop = r2y1;
} elseif (r2y1 < r1y1)
{ if (append_non2)
{
top = MAX (r2y1, ybot);
bot = MIN (r2->y2, r1y1);
if (top != bot)
{
cur_band = new_reg->data->numRects;
if (!pixman_region_append_non_o (new_reg, r2, r2_band_end, top, bot)) goto bail;
/* * 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)
{
cur_band = new_reg->data->numRects;
/* * 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. * * We only need to worry about banding and coalescing for the very first * band left. After that, we can just group all remaining boxes, * regardless of how many bands, into one final append to the list.
*/
if ((r1 != r1_end) && append_non1)
{ /* Do first non_overlap1Func call, which may be able to coalesce */
FIND_BAND (r1, r1_band_end, r1_end, r1y1);
cur_band = new_reg->data->numRects;
if (!pixman_region_append_non_o (new_reg,
r1, r1_band_end,
MAX (r1y1, ybot), r1->y2))
{ goto bail;
}
COALESCE (new_reg, prev_band, cur_band);
/* Just append the rest of the boxes */
APPEND_REGIONS (new_reg, r1_band_end, r1_end);
} elseif ((r2 != r2_end) && append_non2)
{ /* Do first non_overlap2Func call, which may be able to coalesce */
FIND_BAND (r2, r2_band_end, r2_end, r2y1);
cur_band = new_reg->data->numRects;
if (!pixman_region_append_non_o (new_reg,
r2, r2_band_end,
MAX (r2y1, ybot), r2->y2))
{ goto bail;
}
/*- *----------------------------------------------------------------------- * pixman_set_extents -- * Reset the extents of a region to what they should be. Called by * pixman_region_subtract and pixman_region_intersect as they can't * figure it out along the way or do so easily, as pixman_region_union can. * * Results: * None. * * Side Effects: * The region's 'extents' structure is overwritten. * *-----------------------------------------------------------------------
*/ staticvoid
pixman_set_extents (region_type_t *region)
{
box_type_t *box, *box_end;
/* * Since box is the first rectangle in the region, it must have the * smallest y1 and since box_end is the last rectangle in the region, * it must have the largest y2, because of banding. Initialize x1 and * x2 from box and box_end, resp., as good things to initialize them * to...
*/
region->extents.x1 = box->x1;
region->extents.y1 = box->y1;
region->extents.x2 = box_end->x2;
region->extents.y2 = box_end->y2;
/*====================================================================== * Region Intersection
*====================================================================*/ /*- *----------------------------------------------------------------------- * pixman_region_intersect_o -- * Handle an overlapping band for pixman_region_intersect. * * Results: * TRUE if successful. * * Side Effects: * Rectangles may be added to the region. * *-----------------------------------------------------------------------
*/ /*ARGSUSED*/ static pixman_bool_t
pixman_region_intersect_o (region_type_t *region,
box_type_t * r1,
box_type_t * r1_end,
box_type_t * r2,
box_type_t * r2_end, int y1, int y2)
{ int x1; int x2;
box_type_t * next_rect;
do
{
x1 = MAX (r1->x1, r2->x1);
x2 = MIN (r1->x2, r2->x2);
/* * If there's any overlap between the two rectangles, add that * overlap to the new region.
*/ if (x1 < x2)
NEWRECT (region, next_rect, x1, y1, x2, y2);
/* * 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));
returnTRUE;
}
PIXMAN_EXPORT pixman_bool_t
PREFIX (_intersect) (region_type_t * new_reg, const region_type_t * reg1, const region_type_t * reg2)
{
GOOD (reg1);
GOOD (reg2);
GOOD (new_reg);
/* check for trivial reject */ if (PIXREGION_NIL (reg1) || PIXREGION_NIL (reg2) ||
!EXTENTCHECK (®1->extents, ®2->extents))
{ /* Covers about 20% of all cases */
FREE_DATA (new_reg);
new_reg->extents.x2 = new_reg->extents.x1;
new_reg->extents.y2 = new_reg->extents.y1; if (PIXREGION_NAR (reg1) || PIXREGION_NAR (reg2))
{
new_reg->data = pixman_broken_data; returnFALSE;
} else
{
new_reg->data = pixman_region_empty_data;
}
} elseif (!reg1->data && !reg2->data)
{ /* Covers about 80% of cases that aren't trivially rejected */
new_reg->extents.x1 = MAX (reg1->extents.x1, reg2->extents.x1);
new_reg->extents.y1 = MAX (reg1->extents.y1, reg2->extents.y1);
new_reg->extents.x2 = MIN (reg1->extents.x2, reg2->extents.x2);
new_reg->extents.y2 = MIN (reg1->extents.y2, reg2->extents.y2);
if (!pixman_op (new_reg, reg1, reg2, pixman_region_intersect_o, FALSE, FALSE)) returnFALSE;
pixman_set_extents (new_reg);
}
GOOD (new_reg); return(TRUE);
}
#define MERGERECT(r) \ do \
{ \ if (r->x1 <= x2) \
{ \ /* Merge with current rectangle */ \ if (x2 < r->x2) \
x2 = r->x2; \
} \ else \
{ \ /* Add current rectangle, start new one */ \
NEWRECT (region, next_rect, x1, y1, x2, y2); \
x1 = r->x1; \
x2 = r->x2; \
} \
r++; \
} while (0)
/*====================================================================== * Region Union
*====================================================================*/
/*- *----------------------------------------------------------------------- * pixman_region_union_o -- * Handle an overlapping band for the union operation. Picks the * left-most rectangle each time and merges it into the region. * * Results: * TRUE if successful. * * Side Effects: * region is overwritten. * overlap is set to TRUE if any boxes overlap. * *-----------------------------------------------------------------------
*/ static pixman_bool_t
pixman_region_union_o (region_type_t *region,
box_type_t * r1,
box_type_t * r1_end,
box_type_t * r2,
box_type_t * r2_end, int y1, int y2)
{
box_type_t *next_rect; int x1; /* left and right side of current union */ int x2;
/* Start off current rectangle */ if (r1->x1 < r2->x1)
{
x1 = r1->x1;
x2 = r1->x2;
r1++;
} else
{
x1 = r2->x1;
x2 = r2->x2;
r2++;
} while (r1 != r1_end && r2 != r2_end)
{ if (r1->x1 < r2->x1)
MERGERECT (r1); else
MERGERECT (r2);
}
/* Finish off whoever (if any) is left */ if (r1 != r1_end)
{ do
{
MERGERECT (r1);
} while (r1 != r1_end);
} elseif (r2 != r2_end)
{ do
{
MERGERECT (r2);
} while (r2 != r2_end);
}
/* Convenience function for performing union of region with a * single rectangle
*/
PIXMAN_EXPORT pixman_bool_t
PREFIX (_union_rect) (region_type_t *dest, const region_type_t *source, int x, int y, unsignedint width, unsignedint height)
{
region_type_t region;
region.extents.x1 = x;
region.extents.y1 = y;
region.extents.x2 = x + width;
region.extents.y2 = y + height;
if (!GOOD_RECT (®ion.extents))
{ if (BAD_RECT (®ion.extents))
_pixman_log_error (FUNC, "Invalid rectangle passed"); return PREFIX (_copy) (dest, source);
}
region.data = NULL;
return PREFIX (_union) (dest, source, ®ion);
}
PIXMAN_EXPORT pixman_bool_t
PREFIX (_union) (region_type_t * new_reg, const region_type_t *reg1, const region_type_t *reg2)
{ /* Return TRUE if some overlap * between reg1, reg2
*/
GOOD (reg1);
GOOD (reg2);
GOOD (new_reg);
/* checks all the simple cases */
/* * Region 1 and 2 are the same
*/ if (reg1 == reg2) return PREFIX (_copy) (new_reg, reg1);
/* * Region 1 is empty
*/ if (PIXREGION_NIL (reg1))
{ if (PIXREGION_NAR (reg1)) return pixman_break (new_reg);
if (new_reg != reg2) return PREFIX (_copy) (new_reg, reg2);
returnTRUE;
}
/* * Region 2 is empty
*/ if (PIXREGION_NIL (reg2))
{ if (PIXREGION_NAR (reg2)) return pixman_break (new_reg);
if (new_reg != reg1) return PREFIX (_copy) (new_reg, reg1);
returnTRUE;
}
/* * Region 1 completely subsumes region 2
*/ if (!reg1->data && SUBSUMES (®1->extents, ®2->extents))
{ if (new_reg != reg1) return PREFIX (_copy) (new_reg, reg1);
returnTRUE;
}
/* * Region 2 completely subsumes region 1
*/ if (!reg2->data && SUBSUMES (®2->extents, ®1->extents))
{ if (new_reg != reg2) return PREFIX (_copy) (new_reg, reg2);
returnTRUE;
}
if (!pixman_op (new_reg, reg1, reg2, pixman_region_union_o, TRUE, TRUE)) returnFALSE;
new_reg->extents.x1 = MIN (reg1->extents.x1, reg2->extents.x1);
new_reg->extents.y1 = MIN (reg1->extents.y1, reg2->extents.y1);
new_reg->extents.x2 = MAX (reg1->extents.x2, reg2->extents.x2);
new_reg->extents.y2 = MAX (reg1->extents.y2, reg2->extents.y2);
GOOD (new_reg);
returnTRUE;
}
/*====================================================================== * Batch Rectangle Union
*====================================================================*/
/*- *----------------------------------------------------------------------- * pixman_region_validate -- * * Take a ``region'' which is a non-y-x-banded random collection of * rectangles, and compute a nice region which is the union of all the * rectangles. * * Results: * TRUE if successful. * * Side Effects: * The passed-in ``region'' may be modified. * overlap set to TRUE if any retangles overlapped, * else FALSE; * * Strategy: * Step 1. Sort the rectangles into ascending order with primary key y1 * and secondary key x1. * * Step 2. Split the rectangles into the minimum number of proper y-x * banded regions. This may require horizontally merging * rectangles, and vertically coalescing bands. With any luck, * this step in an identity transformation (ala the Box widget), * or a coalescing into 1 box (ala Menus). * * Step 3. Merge the separate regions down to a single region by calling * pixman_region_union. Maximize the work each pixman_region_union call does by using * a binary merge. * *-----------------------------------------------------------------------
*/
static pixman_bool_t
validate (region_type_t * badreg)
{ /* Descriptor for regions under construction in Step 2. */ typedefstruct
{
region_type_t reg; int prev_band; int cur_band;
} region_info_t;
region_info_t stack_regions[64];
int numRects; /* Original numRects for badreg */
region_info_t *ri; /* Array of current regions */ int num_ri; /* Number of entries used in ri */ int size_ri; /* Number of entries available in ri */ int i; /* Index into rects */ int j; /* Index into ri */
region_info_t *rit; /* &ri[j] */
region_type_t *reg; /* ri[j].reg */
box_type_t *box; /* Current box in rects */
box_type_t *ri_box; /* Last box in ri[j].reg */
region_type_t *hreg; /* ri[j_half].reg */
pixman_bool_t ret = TRUE;
if (!badreg->data)
{
GOOD (badreg); returnTRUE;
}
numRects = badreg->data->numRects; if (!numRects)
{ if (PIXREGION_NAR (badreg)) returnFALSE;
GOOD (badreg); returnTRUE;
}
/* Step 1: Sort the rects array into ascending (y1, x1) order */
quick_sort_rects (PIXREGION_BOXPTR (badreg), numRects);
/* Step 2: Scatter the sorted array into the minimum number of regions */
/* Set up the first region to be the first rectangle in badreg */ /* Note that step 2 code will never overflow the ri[0].reg rects array */
ri = stack_regions;
size_ri = sizeof (stack_regions) / sizeof (stack_regions[0]);
num_ri = 1;
ri[0].prev_band = 0;
ri[0].cur_band = 0;
ri[0].reg = *badreg;
box = PIXREGION_BOXPTR (&ri[0].reg);
ri[0].reg.extents = *box;
ri[0].reg.data->numRects = 1;
badreg->extents = *pixman_region_empty_box;
badreg->data = pixman_region_empty_data;
/* Now scatter rectangles into the minimum set of valid regions. If the * next rectangle to be added to a region would force an existing rectangle * in the region to be split up in order to maintain y-x banding, just * forget it. Try the next region. If it doesn't fit cleanly into any * region, make a new one.
*/
for (i = numRects; --i > 0;)
{
box++; /* Look for a region to append box to */ for (j = num_ri, rit = ri; --j >= 0; rit++)
{
reg = &rit->reg;
ri_box = PIXREGION_END (reg);
if (box->y1 == ri_box->y1 && box->y2 == ri_box->y2)
{ /* box is in same band as ri_box. Merge or append it */ if (box->x1 <= ri_box->x2)
{ /* Merge it with ri_box */ if (box->x2 > ri_box->x2)
ri_box->x2 = box->x2;
} else
{
RECTALLOC_BAIL (reg, 1, bail);
*PIXREGION_TOP (reg) = *box;
reg->data->numRects++;
}
goto next_rect; /* So sue me */
} elseif (box->y1 >= ri_box->y2)
{ /* Put box into new band */ if (reg->extents.x2 < ri_box->x2)
reg->extents.x2 = ri_box->x2;
if (reg->extents.x1 > box->x1)
reg->extents.x1 = box->x1;
if (ri == stack_regions)
{
rit = malloc (data_size); if (!rit) goto bail;
memcpy (rit, ri, num_ri * sizeof (region_info_t));
} else
{
rit = (region_info_t *) realloc (ri, data_size); if (!rit) goto bail;
}
ri = rit;
rit = &ri[num_ri];
}
num_ri++;
rit->prev_band = 0;
rit->cur_band = 0;
rit->reg.extents = *box;
rit->reg.data = (region_data_type_t *)NULL;
/* MUST force allocation */ if (!pixman_rect_alloc (&rit->reg, (i + num_ri) / num_ri)) goto bail;
next_rect: ;
} /* for i */
/* Make a final pass over each region in order to COALESCE and set * extents.x2 and extents.y2
*/ for (j = num_ri, rit = ri; --j >= 0; rit++)
{
reg = &rit->reg;
ri_box = PIXREGION_END (reg);
reg->extents.y2 = ri_box->y2;
if (reg->extents.x2 < ri_box->x2)
reg->extents.x2 = ri_box->x2;
/* Step 3: Union all regions into a single region */ while (num_ri > 1)
{ int half = num_ri / 2; for (j = num_ri & 1; j < (half + (num_ri & 1)); j++)
{
reg = &ri[j].reg;
hreg = &ri[j + half].reg;
if (!pixman_op (reg, reg, hreg, pixman_region_union_o, TRUE, TRUE))
ret = FALSE;
if (hreg->extents.x1 < reg->extents.x1)
reg->extents.x1 = hreg->extents.x1;
if (hreg->extents.y1 < reg->extents.y1)
reg->extents.y1 = hreg->extents.y1;
if (hreg->extents.x2 > reg->extents.x2)
reg->extents.x2 = hreg->extents.x2;
if (hreg->extents.y2 > reg->extents.y2)
reg->extents.y2 = hreg->extents.y2;
FREE_DATA (hreg);
}
num_ri -= half;
if (!ret) goto bail;
}
*badreg = ri[0].reg;
if (ri != stack_regions)
free (ri);
GOOD (badreg); return ret;
bail: for (i = 0; i < num_ri; i++)
FREE_DATA (&ri[i].reg);
if (ri != stack_regions)
free (ri);
return pixman_break (badreg);
}
/*====================================================================== * Region Subtraction
*====================================================================*/
/*- *----------------------------------------------------------------------- * pixman_region_subtract_o -- * Overlapping band subtraction. x1 is the left-most point not yet * checked. * * Results: * TRUE if successful. * * Side Effects: * region may have rectangles added to it. * *-----------------------------------------------------------------------
*/ /*ARGSUSED*/ static pixman_bool_t
pixman_region_subtract_o (region_type_t * region,
box_type_t * r1,
box_type_t * r1_end,
box_type_t * r2,
box_type_t * r2_end, int y1, int y2)
{
box_type_t * next_rect; int x1;
do
{ if (r2->x2 <= x1)
{ /* * Subtrahend entirely to left of minuend: go to next subtrahend.
*/
r2++;
} elseif (r2->x1 <= x1)
{ /* * Subtrahend precedes minuend: nuke left edge of minuend.
*/
x1 = r2->x2; if (x1 >= r1->x2)
{ /* * Minuend completely covered: advance to next minuend and * reset left fence to edge of new minuend.
*/
r1++; if (r1 != r1_end)
x1 = r1->x1;
} else
{ /* * Subtrahend now used up since it doesn't extend beyond * minuend
*/
r2++;
}
} elseif (r2->x1 < r1->x2)
{ /* * Left part of subtrahend covers part of minuend: add uncovered * part of minuend to region and skip to next subtrahend.
*/
critical_if_fail (x1 < r2->x1);
NEWRECT (region, next_rect, x1, y1, r2->x1, y2);
x1 = r2->x2; if (x1 >= r1->x2)
{ /* * Minuend used up: advance to new...
*/
r1++; if (r1 != r1_end)
x1 = r1->x1;
} else
{ /* * Subtrahend used up
*/
r2++;
}
} else
{ /* * Minuend used up: add any remaining piece before advancing.
*/ if (r1->x2 > x1)
NEWRECT (region, next_rect, x1, y1, r1->x2, y2);
r1++;
if (r1 != r1_end)
x1 = r1->x1;
}
} while ((r1 != r1_end) && (r2 != r2_end));
/* * Add remaining minuend rectangles to region.
*/ while (r1 != r1_end)
{
critical_if_fail (x1 < r1->x2);
/*- *----------------------------------------------------------------------- * pixman_region_subtract -- * Subtract reg_s from reg_m and leave the result in reg_d. * S stands for subtrahend, M for minuend and D for difference. * * Results: * TRUE if successful. * * Side Effects: * reg_d is overwritten. * *-----------------------------------------------------------------------
*/
PIXMAN_EXPORT pixman_bool_t
PREFIX (_subtract) (region_type_t * reg_d, const region_type_t *reg_m, const region_type_t *reg_s)
{
GOOD (reg_m);
GOOD (reg_s);
GOOD (reg_d);
/* check for trivial rejects */ if (PIXREGION_NIL (reg_m) || PIXREGION_NIL (reg_s) ||
!EXTENTCHECK (®_m->extents, ®_s->extents))
{ if (PIXREGION_NAR (reg_s)) return pixman_break (reg_d);
/* Add those rectangles in region 1 that aren't in region 2, do yucky subtraction for overlaps, and
just throw away rectangles in region 2 that aren't in region 1 */ if (!pixman_op (reg_d, reg_m, reg_s, pixman_region_subtract_o, TRUE, FALSE)) returnFALSE;
/* * Can't alter reg_d's extents before we call pixman_op because * it might be one of the source regions and pixman_op depends * on the extents of those regions being unaltered. Besides, this * way there's no checking against rectangles that will be nuked * due to coalescing, so we have to examine fewer rectangles.
*/
pixman_set_extents (reg_d);
GOOD (reg_d); returnTRUE;
}
/*====================================================================== * Region Inversion
*====================================================================*/
/*- *----------------------------------------------------------------------- * pixman_region_inverse -- * Take a region and a box and return a region that is everything * in the box but not in the region. The careful reader will note * that this is the same as subtracting the region from the box... * * Results: * TRUE. * * Side Effects: * new_reg is overwritten. * *-----------------------------------------------------------------------
*/
PIXMAN_EXPORT pixman_bool_t
PREFIX (_inverse) (region_type_t * new_reg, /* Destination region */ const region_type_t *reg1, /* Region to invert */ const box_type_t * inv_rect) /* Bounding box for inversion */
{
region_type_t inv_reg; /* Quick and dirty region made from the
* bounding box */
GOOD (reg1);
GOOD (new_reg);
/* check for trivial rejects */ if (PIXREGION_NIL (reg1) || !EXTENTCHECK (inv_rect, ®1->extents))
{ if (PIXREGION_NAR (reg1)) return pixman_break (new_reg);
/* Add those rectangles in region 1 that aren't in region 2, * do yucky subtraction for overlaps, and * just throw away rectangles in region 2 that aren't in region 1
*/
inv_reg.extents = *inv_rect;
inv_reg.data = (region_data_type_t *)NULL; if (!pixman_op (new_reg, &inv_reg, reg1, pixman_region_subtract_o, TRUE, FALSE)) returnFALSE;
/* * Can't alter new_reg's extents before we call pixman_op because * it might be one of the source regions and pixman_op depends * on the extents of those regions being unaltered. Besides, this * way there's no checking against rectangles that will be nuked * due to coalescing, so we have to examine fewer rectangles.
*/
pixman_set_extents (new_reg);
GOOD (new_reg); returnTRUE;
}
/* In time O(log n), locate the first box whose y2 is greater than y. * Return @end if no such box exists.
*/ static box_type_t *
find_box_for_y (box_type_t *begin, box_type_t *end, int y)
{
box_type_t *mid;
if (end == begin) return end;
if (end - begin == 1)
{ if (begin->y2 > y) return begin; else return end;
}
mid = begin + (end - begin) / 2; if (mid->y2 > y)
{ /* If no box is found in [begin, mid], the function * will return @mid, which is then known to be the * correct answer.
*/ return find_box_for_y (begin, mid, y);
} else
{ return find_box_for_y (mid, end, y);
}
}
/* * rect_in(region, rect) * This routine takes a pointer to a region and a pointer to a box * and determines if the box is outside/inside/partly inside the region. * * The idea is to travel through the list of rectangles trying to cover the * passed box with them. Anytime a piece of the rectangle isn't covered * by a band of rectangles, part_out is set TRUE. Any time a rectangle in * the region covers part of the box, part_in is set TRUE. The process ends * when either the box has been completely covered (we reached a band that * doesn't overlap the box, part_in is TRUE and part_out is false), the * box has been partially covered (part_in == part_out == TRUE -- because of * the banding, the first time this is true we know the box is only * partially in the region) or is outside the region (we reached a band * that doesn't overlap the box at all and part_in is false)
*/
PIXMAN_EXPORT pixman_region_overlap_t
PREFIX (_contains_rectangle) (const region_type_t * region, const box_type_t * prect)
{
box_type_t * pbox;
box_type_t * pbox_end; int part_in, part_out; int numRects; int x, y;
if (numRects == 1)
{ /* We know that it must be PIXMAN_REGION_IN or PIXMAN_REGION_PART */ if (SUBSUMES (®ion->extents, prect)) return(PIXMAN_REGION_IN); else return(PIXMAN_REGION_PART);
}
part_out = FALSE;
part_in = FALSE;
/* (x,y) starts at upper left of rect, moving to the right and down */
x = prect->x1;
y = prect->y1;
/* can stop when both part_out and part_in are TRUE, or we reach prect->y2 */ for (pbox = PIXREGION_BOXPTR (region), pbox_end = pbox + numRects;
pbox != pbox_end;
pbox++)
{ /* getting up to speed or skipping remainder of band */ if (pbox->y2 <= y)
{ if ((pbox = find_box_for_y (pbox, pbox_end, y)) == pbox_end) break;
}
if (pbox->y1 > y)
{
part_out = TRUE; /* missed part of rectangle above */ if (part_in || (pbox->y1 >= prect->y2)) break;
y = pbox->y1; /* x guaranteed to be == prect->x1 */
}
if (pbox->x2 <= x) continue; /* not far enough over yet */
if (pbox->x1 > x)
{
part_out = TRUE; /* missed part of rectangle to left */ if (part_in) break;
}
if (pbox->x1 < prect->x2)
{
part_in = TRUE; /* definitely overlap */ if (part_out) break;
}
if (pbox->x2 >= prect->x2)
{
y = pbox->y2; /* finished with this band */ if (y >= prect->y2) break;
x = prect->x1; /* reset x out to left again */
} else
{ /* * Because boxes in a band are maximal width, if the first box * to overlap the rectangle doesn't completely cover it in that * band, the rectangle must be partially out, since some of it * will be uncovered in that band. part_in will have been set true * by now...
*/
part_out = TRUE; break;
}
}
if (part_in)
{ if (y < prect->y2) return PIXMAN_REGION_PART; else return PIXMAN_REGION_IN;
} else
{ return PIXMAN_REGION_OUT;
}
}
/* PREFIX(_translate) (region, x, y) * translates in place
*/
PIXMAN_EXPORT void
PREFIX (_translate) (region_type_t *region, int x, int y)
{
overflow_int_t x1, x2, y1, y2; int nbox;
box_type_t * pbox;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.92Bemerkung:
(vorverarbeitet)
¤