blob: c0b1e5a21899e91bd20c6567f25308669119a69b [file] [log] [blame]
syuri843bf672008-09-19 09:55:50 +00001/* $Xorg: Region.c,v 1.6 2001/02/09 02:03:35 xorgcvs Exp $ */
2/************************************************************************
3
4Copyright 1987, 1988, 1998 The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25
26
27Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
28
29 All Rights Reserved
30
31Permission to use, copy, modify, and distribute this software and its
32documentation for any purpose and without fee is hereby granted,
33provided that the above copyright notice appear in all copies and that
34both that copyright notice and this permission notice appear in
35supporting documentation, and that the name of Digital not be
36used in advertising or publicity pertaining to distribution of the
37software without specific, written prior permission.
38
39DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45SOFTWARE.
46
47************************************************************************/
48/* $XFree86: xc/lib/X11/Region.c,v 1.8 2001/12/14 19:54:05 dawes Exp $ */
49/*
50 * The functions in this file implement the Region abstraction, similar to one
51 * used in the X11 sample server. A Region is simply an area, as the name
52 * implies, and is implemented as a "y-x-banded" array of rectangles. To
53 * explain: Each Region is made up of a certain number of rectangles sorted
54 * by y coordinate first, and then by x coordinate.
55 *
56 * Furthermore, the rectangles are banded such that every rectangle with a
57 * given upper-left y coordinate (y1) will have the same lower-right y
58 * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
59 * will span the entire vertical distance of the band. This means that some
60 * areas that could be merged into a taller rectangle will be represented as
61 * several shorter rectangles to account for shorter rectangles to its left
62 * or right but within its "vertical scope".
63 *
64 * An added constraint on the rectangles is that they must cover as much
65 * horizontal area as possible. E.g. no two rectangles in a band are allowed
66 * to touch.
67 *
68 * Whenever possible, bands will be merged together to cover a greater vertical
69 * distance (and thus reduce the number of rectangles). Two bands can be merged
70 * only if the bottom of one touches the top of the other and they have
71 * rectangles in the same places (of the same width, of course). This maintains
72 * the y-x-banding that's so nice to have...
73 */
74
75#include "Xregion.h"
76//#include "Xlibint.h"
77//#include "Xutil.h"
78#include "region.h"
79//#include "poly.h"
80
81#ifndef min
82#define min(a,b) (((a) < (b)) ? (a) : (b))
83#endif
84#ifndef max
85#define max(a,b) (((a) > (b)) ? (a) : (b))
86#endif
87
88#ifdef DEBUG
89#include <stdio.h>
90#define assert(expr) {if (!(expr)) fprintf(stderr,\
91"Assertion failed file %s, line %d: expr\n", __FILE__, __LINE__); }
92#else
93#define assert(expr)
94#endif
95
96typedef void (*voidProcp)();
97
98static void miRegionOp();
99/* Create a new empty region */
100Region
101XCreateRegion()
102{
103 Region temp;
104
105 if (! (temp = ( Region )Xmalloc( (unsigned) sizeof( REGION ))))
106 return (Region) NULL;
107 if (! (temp->rects = ( BOX * )Xmalloc( (unsigned) sizeof( BOX )))) {
108 Xfree((char *) temp);
109 return (Region) NULL;
110 }
111 temp->numRects = 0;
112 temp->extents.x1 = 0;
113 temp->extents.y1 = 0;
114 temp->extents.x2 = 0;
115 temp->extents.y2 = 0;
116 temp->size = 1;
117 return( temp );
118}
119
120int
121XClipBox( r, rect )
122 Region r;
123 XRectangle *rect;
124{
125 rect->x = r->extents.x1;
126 rect->y = r->extents.y1;
127 rect->width = r->extents.x2 - r->extents.x1;
128 rect->height = r->extents.y2 - r->extents.y1;
129 return 1;
130}
131
132int
133XUnionRectWithRegion(rect, source, dest)
134 register XRectangle *rect;
135 Region source, dest;
136{
137 REGION region;
138
139 if (!rect->width || !rect->height)
140 return 0;
141 region.rects = &region.extents;
142 region.numRects = 1;
143 region.extents.x1 = rect->x;
144 region.extents.y1 = rect->y;
145 region.extents.x2 = rect->x + rect->width;
146 region.extents.y2 = rect->y + rect->height;
147 region.size = 1;
148
149 return XUnionRegion(&region, source, dest);
150}
151
152/*-
153 *-----------------------------------------------------------------------
154 * miSetExtents --
155 * Reset the extents of a region to what they should be. Called by
156 * miSubtract and miIntersect b/c they can't figure it out along the
157 * way or do so easily, as miUnion can.
158 *
159 * Results:
160 * None.
161 *
162 * Side Effects:
163 * The region's 'extents' structure is overwritten.
164 *
165 *-----------------------------------------------------------------------
166 */
167static void
168miSetExtents (pReg)
169 Region pReg;
170{
171 register BoxPtr pBox,
172 pBoxEnd,
173 pExtents;
174
175 if (pReg->numRects == 0)
176 {
177 pReg->extents.x1 = 0;
178 pReg->extents.y1 = 0;
179 pReg->extents.x2 = 0;
180 pReg->extents.y2 = 0;
181 return;
182 }
183
184 pExtents = &pReg->extents;
185 pBox = pReg->rects;
186 pBoxEnd = &pBox[pReg->numRects - 1];
187
188 /*
189 * Since pBox is the first rectangle in the region, it must have the
190 * smallest y1 and since pBoxEnd is the last rectangle in the region,
191 * it must have the largest y2, because of banding. Initialize x1 and
192 * x2 from pBox and pBoxEnd, resp., as good things to initialize them
193 * to...
194 */
195 pExtents->x1 = pBox->x1;
196 pExtents->y1 = pBox->y1;
197 pExtents->x2 = pBoxEnd->x2;
198 pExtents->y2 = pBoxEnd->y2;
199
200 assert(pExtents->y1 < pExtents->y2);
201 while (pBox <= pBoxEnd)
202 {
203 if (pBox->x1 < pExtents->x1)
204 {
205 pExtents->x1 = pBox->x1;
206 }
207 if (pBox->x2 > pExtents->x2)
208 {
209 pExtents->x2 = pBox->x2;
210 }
211 pBox++;
212 }
213 assert(pExtents->x1 < pExtents->x2);
214}
215
216extern void _XSetClipRectangles();
217
218#if 0
219int
220XSetRegion( dpy, gc, r )
221 Display *dpy;
222 GC gc;
223 register Region r;
224{
225 register int i;
226 register XRectangle *xr, *pr;
227 register BOX *pb;
228 unsigned long total;
229
230 LockDisplay (dpy);
231 total = r->numRects * sizeof (XRectangle);
232 if ((xr = (XRectangle *) _XAllocTemp(dpy, total))) {
233 for (pr = xr, pb = r->rects, i = r->numRects; --i >= 0; pr++, pb++) {
234 pr->x = pb->x1;
235 pr->y = pb->y1;
236 pr->width = pb->x2 - pb->x1;
237 pr->height = pb->y2 - pb->y1;
238 }
239 }
240 if (xr || !r->numRects)
241 _XSetClipRectangles(dpy, gc, 0, 0, xr, r->numRects, YXBanded);
242 if (xr)
243 _XFreeTemp(dpy, (char *)xr, total);
244 UnlockDisplay(dpy);
245 SyncHandle();
246 return 1;
247}
248#endif
249
250int
251XDestroyRegion( r )
252 Region r;
253{
254 Xfree( (char *) r->rects );
255 Xfree( (char *) r );
256 return 1;
257}
258
259
260/* TranslateRegion(pRegion, x, y)
261 translates in place
262 added by raymond
263*/
264
265int
266XOffsetRegion(pRegion, x, y)
267 register Region pRegion;
268 register int x;
269 register int y;
270{
271 register int nbox;
272 register BOX *pbox;
273
274 pbox = pRegion->rects;
275 nbox = pRegion->numRects;
276
277 while(nbox--)
278 {
279 pbox->x1 += x;
280 pbox->x2 += x;
281 pbox->y1 += y;
282 pbox->y2 += y;
283 pbox++;
284 }
285 pRegion->extents.x1 += x;
286 pRegion->extents.x2 += x;
287 pRegion->extents.y1 += y;
288 pRegion->extents.y2 += y;
289 return 1;
290}
291
292/*
293 Utility procedure Compress:
294 Replace r by the region r', where
295 p in r' iff (Quantifer m <= dx) (p + m in r), and
296 Quantifier is Exists if grow is TRUE, For all if grow is FALSE, and
297 (x,y) + m = (x+m,y) if xdir is TRUE; (x,y+m) if xdir is FALSE.
298
299 Thus, if xdir is TRUE and grow is FALSE, r is replaced by the region
300 of all points p such that p and the next dx points on the same
301 horizontal scan line are all in r. We do this using by noting
302 that p is the head of a run of length 2^i + k iff p is the head
303 of a run of length 2^i and p+2^i is the head of a run of length
304 k. Thus, the loop invariant: s contains the region corresponding
305 to the runs of length shift. r contains the region corresponding
306 to the runs of length 1 + dxo & (shift-1), where dxo is the original
307 value of dx. dx = dxo & ~(shift-1). As parameters, s and t are
308 scratch regions, so that we don't have to allocate them on every
309 call.
310*/
311
312#define ZOpRegion(a,b,c) if (grow) XUnionRegion(a,b,c); \
313 else XIntersectRegion(a,b,c)
314#define ZShiftRegion(a,b) if (xdir) XOffsetRegion(a,b,0); \
315 else XOffsetRegion(a,0,b)
316#define ZCopyRegion(a,b) XUnionRegion(a,a,b)
317
318static void
319Compress(r, s, t, dx, xdir, grow)
320 Region r, s, t;
321 register unsigned dx;
322 register int xdir, grow;
323{
324 register unsigned shift = 1;
325
326 ZCopyRegion(r, s);
327 while (dx) {
328 if (dx & shift) {
329 ZShiftRegion(r, -(int)shift);
330 ZOpRegion(r, s, r);
331 dx -= shift;
332 if (!dx) break;
333 }
334 ZCopyRegion(s, t);
335 ZShiftRegion(s, -(int)shift);
336 ZOpRegion(s, t, s);
337 shift <<= 1;
338 }
339}
340
341#undef ZOpRegion
342#undef ZShiftRegion
343#undef ZCopyRegion
344
345int
346XShrinkRegion(r, dx, dy)
347 Region r;
348 int dx, dy;
349{
350 Region s, t;
351 int grow;
352
353 if (!dx && !dy) return 0;
354 if ((! (s = XCreateRegion())) || (! (t = XCreateRegion()))) return 0;
355 if ((grow = (dx < 0))) dx = -dx;
356 if (dx) Compress(r, s, t, (unsigned) 2*dx, TRUE, grow);
357 if ((grow = (dy < 0))) dy = -dy;
358 if (dy) Compress(r, s, t, (unsigned) 2*dy, FALSE, grow);
359 XOffsetRegion(r, dx, dy);
360 XDestroyRegion(s);
361 XDestroyRegion(t);
362 return 0;
363}
364
365#ifdef notdef
366/***********************************************************
367 * Bop down the array of rects until we have passed
368 * scanline y. numRects is the size of the array.
369 ***********************************************************/
370
371static BOX
372*IndexRects(rects, numRects, y)
373 register BOX *rects;
374 register int numRects;
375 register int y;
376{
377 while ((numRects--) && (rects->y2 <= y))
378 rects++;
379 return(rects);
380}
381#endif
382
383/*======================================================================
384 * Region Intersection
385 *====================================================================*/
386/*-
387 *-----------------------------------------------------------------------
388 * miIntersectO --
389 * Handle an overlapping band for miIntersect.
390 *
391 * Results:
392 * None.
393 *
394 * Side Effects:
395 * Rectangles may be added to the region.
396 *
397 *-----------------------------------------------------------------------
398 */
399/* static void*/
400static int
401miIntersectO (pReg, r1, r1End, r2, r2End, y1, y2)
402 register Region pReg;
403 register BoxPtr r1;
404 BoxPtr r1End;
405 register BoxPtr r2;
406 BoxPtr r2End;
407 short y1;
408 short y2;
409{
410 register short x1;
411 register short x2;
412 register BoxPtr pNextRect;
413
414 pNextRect = &pReg->rects[pReg->numRects];
415
416 while ((r1 != r1End) && (r2 != r2End))
417 {
418 x1 = max(r1->x1,r2->x1);
419 x2 = min(r1->x2,r2->x2);
420
421 /*
422 * If there's any overlap between the two rectangles, add that
423 * overlap to the new region.
424 * There's no need to check for subsumption because the only way
425 * such a need could arise is if some region has two rectangles
426 * right next to each other. Since that should never happen...
427 */
428 if (x1 < x2)
429 {
430 assert(y1<y2);
431
432 MEMCHECK(pReg, pNextRect, pReg->rects);
433 pNextRect->x1 = x1;
434 pNextRect->y1 = y1;
435 pNextRect->x2 = x2;
436 pNextRect->y2 = y2;
437 pReg->numRects += 1;
438 pNextRect++;
439 assert(pReg->numRects <= pReg->size);
440 }
441
442 /*
443 * Need to advance the pointers. Shift the one that extends
444 * to the right the least, since the other still has a chance to
445 * overlap with that region's next rectangle, if you see what I mean.
446 */
447 if (r1->x2 < r2->x2)
448 {
449 r1++;
450 }
451 else if (r2->x2 < r1->x2)
452 {
453 r2++;
454 }
455 else
456 {
457 r1++;
458 r2++;
459 }
460 }
461 return 0; /* lint */
462}
463
464int
465XIntersectRegion(reg1, reg2, newReg)
466 Region reg1;
467 Region reg2; /* source regions */
468 register Region newReg; /* destination Region */
469{
470 /* check for trivial reject */
471 if ( (!(reg1->numRects)) || (!(reg2->numRects)) ||
472 (!EXTENTCHECK(&reg1->extents, &reg2->extents)))
473 newReg->numRects = 0;
474 else
475 miRegionOp (newReg, reg1, reg2,
476 (voidProcp) miIntersectO, (voidProcp) NULL, (voidProcp) NULL);
477
478 /*
479 * Can't alter newReg's extents before we call miRegionOp because
480 * it might be one of the source regions and miRegionOp depends
481 * on the extents of those regions being the same. Besides, this
482 * way there's no checking against rectangles that will be nuked
483 * due to coalescing, so we have to examine fewer rectangles.
484 */
485 miSetExtents(newReg);
486 return 1;
487}
488
489static void
490miRegionCopy(dstrgn, rgn)
491 register Region dstrgn;
492 register Region rgn;
493
494{
495 if (dstrgn != rgn) /* don't want to copy to itself */
496 {
497 if (dstrgn->size < rgn->numRects)
498 {
499 if (dstrgn->rects)
500 {
501 BOX *prevRects = dstrgn->rects;
502
503 if (! (dstrgn->rects = (BOX *)
504 Xrealloc((char *) dstrgn->rects,
505 (unsigned) rgn->numRects * (sizeof(BOX))))) {
506 Xfree(prevRects);
507 return;
508 }
509 }
510 dstrgn->size = rgn->numRects;
511 }
512 dstrgn->numRects = rgn->numRects;
513 dstrgn->extents.x1 = rgn->extents.x1;
514 dstrgn->extents.y1 = rgn->extents.y1;
515 dstrgn->extents.x2 = rgn->extents.x2;
516 dstrgn->extents.y2 = rgn->extents.y2;
517
518 memcpy((char *) dstrgn->rects, (char *) rgn->rects,
519 (int) (rgn->numRects * sizeof(BOX)));
520 }
521}
522
523#ifdef notdef
524
525/*
526 * combinRegs(newReg, reg1, reg2)
527 * if one region is above or below the other.
528*/
529
530static void
531combineRegs(newReg, reg1, reg2)
532 register Region newReg;
533 Region reg1;
534 Region reg2;
535{
536 register Region tempReg;
537 register BOX *rects;
538 register BOX *rects1;
539 register BOX *rects2;
540 register int total;
541
542 rects1 = reg1->rects;
543 rects2 = reg2->rects;
544
545 total = reg1->numRects + reg2->numRects;
546 if (! (tempReg = XCreateRegion()))
547 return;
548 tempReg->size = total;
549 /* region 1 is below region 2 */
550 if (reg1->extents.y1 > reg2->extents.y1)
551 {
552 miRegionCopy(tempReg, reg2);
553 rects = &tempReg->rects[tempReg->numRects];
554 total -= tempReg->numRects;
555 while (total--)
556 *rects++ = *rects1++;
557 }
558 else
559 {
560 miRegionCopy(tempReg, reg1);
561 rects = &tempReg->rects[tempReg->numRects];
562 total -= tempReg->numRects;
563 while (total--)
564 *rects++ = *rects2++;
565 }
566 tempReg->extents = reg1->extents;
567 tempReg->numRects = reg1->numRects + reg2->numRects;
568 EXTENTS(&reg2->extents, tempReg);
569 miRegionCopy(newReg, tempReg);
570 Xfree((char *)tempReg);
571}
572
573/*
574 * QuickCheck checks to see if it does not have to go through all the
575 * the ugly code for the region call. It returns 1 if it did all
576 * the work for Union, otherwise 0 - still work to be done.
577*/
578
579static int
580QuickCheck(newReg, reg1, reg2)
581 Region newReg, reg1, reg2;
582{
583
584 /* if unioning with itself or no rects to union with */
585 if ( (reg1 == reg2) || (!(reg1->numRects)) )
586 {
587 miRegionCopy(newReg, reg2);
588 return TRUE;
589 }
590
591 /* if nothing to union */
592 if (!(reg2->numRects))
593 {
594 miRegionCopy(newReg, reg1);
595 return TRUE;
596 }
597
598 /* could put an extent check to see if add above or below */
599
600 if ((reg1->extents.y1 >= reg2->extents.y2) ||
601 (reg2->extents.y1 >= reg1->extents.y2) )
602 {
603 combineRegs(newReg, reg1, reg2);
604 return TRUE;
605 }
606 return FALSE;
607}
608
609/* TopRects(rects, reg1, reg2)
610 * N.B. We now assume that reg1 and reg2 intersect. Therefore we are
611 * NOT checking in the two while loops for stepping off the end of the
612 * region.
613 */
614
615static int
616TopRects(newReg, rects, reg1, reg2, FirstRect)
617 register Region newReg;
618 register BOX *rects;
619 register Region reg1;
620 register Region reg2;
621 BOX *FirstRect;
622{
623 register BOX *tempRects;
624
625 /* need to add some rects from region 1 */
626 if (reg1->extents.y1 < reg2->extents.y1)
627 {
628 tempRects = reg1->rects;
629 while(tempRects->y1 < reg2->extents.y1)
630 {
631 MEMCHECK(newReg, rects, FirstRect);
632 ADDRECTNOX(newReg,rects, tempRects->x1, tempRects->y1,
633 tempRects->x2, MIN(tempRects->y2, reg2->extents.y1));
634 tempRects++;
635 }
636 }
637 /* need to add some rects from region 2 */
638 if (reg2->extents.y1 < reg1->extents.y1)
639 {
640 tempRects = reg2->rects;
641 while (tempRects->y1 < reg1->extents.y1)
642 {
643 MEMCHECK(newReg, rects, FirstRect);
644 ADDRECTNOX(newReg, rects, tempRects->x1,tempRects->y1,
645 tempRects->x2, MIN(tempRects->y2, reg1->extents.y1));
646 tempRects++;
647 }
648 }
649 return 1;
650}
651#endif
652
653/*======================================================================
654 * Generic Region Operator
655 *====================================================================*/
656
657/*-
658 *-----------------------------------------------------------------------
659 * miCoalesce --
660 * Attempt to merge the boxes in the current band with those in the
661 * previous one. Used only by miRegionOp.
662 *
663 * Results:
664 * The new index for the previous band.
665 *
666 * Side Effects:
667 * If coalescing takes place:
668 * - rectangles in the previous band will have their y2 fields
669 * altered.
670 * - pReg->numRects will be decreased.
671 *
672 *-----------------------------------------------------------------------
673 */
674/* static int*/
675static int
676miCoalesce (pReg, prevStart, curStart)
677 register Region pReg; /* Region to coalesce */
678 int prevStart; /* Index of start of previous band */
679 int curStart; /* Index of start of current band */
680{
681 register BoxPtr pPrevBox; /* Current box in previous band */
682 register BoxPtr pCurBox; /* Current box in current band */
683 register BoxPtr pRegEnd; /* End of region */
684 int curNumRects; /* Number of rectangles in current
685 * band */
686 int prevNumRects; /* Number of rectangles in previous
687 * band */
688 int bandY1; /* Y1 coordinate for current band */
689
690 pRegEnd = &pReg->rects[pReg->numRects];
691
692 pPrevBox = &pReg->rects[prevStart];
693 prevNumRects = curStart - prevStart;
694
695 /*
696 * Figure out how many rectangles are in the current band. Have to do
697 * this because multiple bands could have been added in miRegionOp
698 * at the end when one region has been exhausted.
699 */
700 pCurBox = &pReg->rects[curStart];
701 bandY1 = pCurBox->y1;
702 for (curNumRects = 0;
703 (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1);
704 curNumRects++)
705 {
706 pCurBox++;
707 }
708
709 if (pCurBox != pRegEnd)
710 {
711 /*
712 * If more than one band was added, we have to find the start
713 * of the last band added so the next coalescing job can start
714 * at the right place... (given when multiple bands are added,
715 * this may be pointless -- see above).
716 */
717 pRegEnd--;
718 while (pRegEnd[-1].y1 == pRegEnd->y1)
719 {
720 pRegEnd--;
721 }
722 curStart = pRegEnd - pReg->rects;
723 pRegEnd = pReg->rects + pReg->numRects;
724 }
725
726 if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
727 pCurBox -= curNumRects;
728 /*
729 * The bands may only be coalesced if the bottom of the previous
730 * matches the top scanline of the current.
731 */
732 if (pPrevBox->y2 == pCurBox->y1)
733 {
734 /*
735 * Make sure the bands have boxes in the same places. This
736 * assumes that boxes have been added in such a way that they
737 * cover the most area possible. I.e. two boxes in a band must
738 * have some horizontal space between them.
739 */
740 do
741 {
742 if ((pPrevBox->x1 != pCurBox->x1) ||
743 (pPrevBox->x2 != pCurBox->x2))
744 {
745 /*
746 * The bands don't line up so they can't be coalesced.
747 */
748 return (curStart);
749 }
750 pPrevBox++;
751 pCurBox++;
752 prevNumRects -= 1;
753 } while (prevNumRects != 0);
754
755 pReg->numRects -= curNumRects;
756 pCurBox -= curNumRects;
757 pPrevBox -= curNumRects;
758
759 /*
760 * The bands may be merged, so set the bottom y of each box
761 * in the previous band to that of the corresponding box in
762 * the current band.
763 */
764 do
765 {
766 pPrevBox->y2 = pCurBox->y2;
767 pPrevBox++;
768 pCurBox++;
769 curNumRects -= 1;
770 } while (curNumRects != 0);
771
772 /*
773 * If only one band was added to the region, we have to backup
774 * curStart to the start of the previous band.
775 *
776 * If more than one band was added to the region, copy the
777 * other bands down. The assumption here is that the other bands
778 * came from the same region as the current one and no further
779 * coalescing can be done on them since it's all been done
780 * already... curStart is already in the right place.
781 */
782 if (pCurBox == pRegEnd)
783 {
784 curStart = prevStart;
785 }
786 else
787 {
788 do
789 {
790 *pPrevBox++ = *pCurBox++;
791 } while (pCurBox != pRegEnd);
792 }
793
794 }
795 }
796 return (curStart);
797}
798
799/*-
800 *-----------------------------------------------------------------------
801 * miRegionOp --
802 * Apply an operation to two regions. Called by miUnion, miInverse,
803 * miSubtract, miIntersect...
804 *
805 * Results:
806 * None.
807 *
808 * Side Effects:
809 * The new region is overwritten.
810 *
811 * Notes:
812 * The idea behind this function is to view the two regions as sets.
813 * Together they cover a rectangle of area that this function divides
814 * into horizontal bands where points are covered only by one region
815 * or by both. For the first case, the nonOverlapFunc is called with
816 * each the band and the band's upper and lower extents. For the
817 * second, the overlapFunc is called to process the entire band. It
818 * is responsible for clipping the rectangles in the band, though
819 * this function provides the boundaries.
820 * At the end of each band, the new region is coalesced, if possible,
821 * to reduce the number of rectangles in the region.
822 *
823 *-----------------------------------------------------------------------
824 */
825/* static void*/
826static void
827miRegionOp(newReg, reg1, reg2, overlapFunc, nonOverlap1Func, nonOverlap2Func)
828 register Region newReg; /* Place to store result */
829 Region reg1; /* First region in operation */
830 Region reg2; /* 2d region in operation */
831 void (*overlapFunc)(); /* Function to call for over-
832 * lapping bands */
833 void (*nonOverlap1Func)(); /* Function to call for non-
834 * overlapping bands in region
835 * 1 */
836 void (*nonOverlap2Func)(); /* Function to call for non-
837 * overlapping bands in region
838 * 2 */
839{
840 register BoxPtr r1; /* Pointer into first region */
841 register BoxPtr r2; /* Pointer into 2d region */
842 BoxPtr r1End; /* End of 1st region */
843 BoxPtr r2End; /* End of 2d region */
844 register short ybot; /* Bottom of intersection */
845 register short ytop; /* Top of intersection */
846 BoxPtr oldRects; /* Old rects for newReg */
847 int prevBand; /* Index of start of
848 * previous band in newReg */
849 int curBand; /* Index of start of current
850 * band in newReg */
851 register BoxPtr r1BandEnd; /* End of current band in r1 */
852 register BoxPtr r2BandEnd; /* End of current band in r2 */
853 short top; /* Top of non-overlapping
854 * band */
855 short bot; /* Bottom of non-overlapping
856 * band */
857
858 /*
859 * Initialization:
860 * set r1, r2, r1End and r2End appropriately, preserve the important
861 * parts of the destination region until the end in case it's one of
862 * the two source regions, then mark the "new" region empty, allocating
863 * another array of rectangles for it to use.
864 */
865 r1 = reg1->rects;
866 r2 = reg2->rects;
867 r1End = r1 + reg1->numRects;
868 r2End = r2 + reg2->numRects;
869
870 oldRects = newReg->rects;
871
872 EMPTY_REGION(newReg);
873
874 /*
875 * Allocate a reasonable number of rectangles for the new region. The idea
876 * is to allocate enough so the individual functions don't need to
877 * reallocate and copy the array, which is time consuming, yet we don't
878 * have to worry about using too much memory. I hope to be able to
879 * nuke the Xrealloc() at the end of this function eventually.
880 */
881 newReg->size = max(reg1->numRects,reg2->numRects) * 2;
882
883 if (! (newReg->rects = (BoxPtr)
884 Xmalloc ((unsigned) (sizeof(BoxRec) * newReg->size)))) {
885 newReg->size = 0;
886 return;
887 }
888
889 /*
890 * Initialize ybot and ytop.
891 * In the upcoming loop, ybot and ytop serve different functions depending
892 * on whether the band being handled is an overlapping or non-overlapping
893 * band.
894 * In the case of a non-overlapping band (only one of the regions
895 * has points in the band), ybot is the bottom of the most recent
896 * intersection and thus clips the top of the rectangles in that band.
897 * ytop is the top of the next intersection between the two regions and
898 * serves to clip the bottom of the rectangles in the current band.
899 * For an overlapping band (where the two regions intersect), ytop clips
900 * the top of the rectangles of both regions and ybot clips the bottoms.
901 */
902 if (reg1->extents.y1 < reg2->extents.y1)
903 ybot = reg1->extents.y1;
904 else
905 ybot = reg2->extents.y1;
906
907 /*
908 * prevBand serves to mark the start of the previous band so rectangles
909 * can be coalesced into larger rectangles. qv. miCoalesce, above.
910 * In the beginning, there is no previous band, so prevBand == curBand
911 * (curBand is set later on, of course, but the first band will always
912 * start at index 0). prevBand and curBand must be indices because of
913 * the possible expansion, and resultant moving, of the new region's
914 * array of rectangles.
915 */
916 prevBand = 0;
917
918 do
919 {
920 curBand = newReg->numRects;
921
922 /*
923 * This algorithm proceeds one source-band (as opposed to a
924 * destination band, which is determined by where the two regions
925 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
926 * rectangle after the last one in the current band for their
927 * respective regions.
928 */
929 r1BandEnd = r1;
930 while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1))
931 {
932 r1BandEnd++;
933 }
934
935 r2BandEnd = r2;
936 while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1))
937 {
938 r2BandEnd++;
939 }
940
941 /*
942 * First handle the band that doesn't intersect, if any.
943 *
944 * Note that attention is restricted to one band in the
945 * non-intersecting region at once, so if a region has n
946 * bands between the current position and the next place it overlaps
947 * the other, this entire loop will be passed through n times.
948 */
949 if (r1->y1 < r2->y1)
950 {
951 top = max(r1->y1,ybot);
952 bot = min(r1->y2,r2->y1);
953
954 if ((top != bot) && (nonOverlap1Func != (void (*)())NULL))
955 {
956 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
957 }
958
959 ytop = r2->y1;
960 }
961 else if (r2->y1 < r1->y1)
962 {
963 top = max(r2->y1,ybot);
964 bot = min(r2->y2,r1->y1);
965
966 if ((top != bot) && (nonOverlap2Func != (void (*)())NULL))
967 {
968 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
969 }
970
971 ytop = r1->y1;
972 }
973 else
974 {
975 ytop = r1->y1;
976 }
977
978 /*
979 * If any rectangles got added to the region, try and coalesce them
980 * with rectangles from the previous band. Note we could just do
981 * this test in miCoalesce, but some machines incur a not
982 * inconsiderable cost for function calls, so...
983 */
984 if (newReg->numRects != curBand)
985 {
986 prevBand = miCoalesce (newReg, prevBand, curBand);
987 }
988
989 /*
990 * Now see if we've hit an intersecting band. The two bands only
991 * intersect if ybot > ytop
992 */
993 ybot = min(r1->y2, r2->y2);
994 curBand = newReg->numRects;
995 if (ybot > ytop)
996 {
997 (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
998
999 }
1000
1001 if (newReg->numRects != curBand)
1002 {
1003 prevBand = miCoalesce (newReg, prevBand, curBand);
1004 }
1005
1006 /*
1007 * If we've finished with a band (y2 == ybot) we skip forward
1008 * in the region to the next band.
1009 */
1010 if (r1->y2 == ybot)
1011 {
1012 r1 = r1BandEnd;
1013 }
1014 if (r2->y2 == ybot)
1015 {
1016 r2 = r2BandEnd;
1017 }
1018 } while ((r1 != r1End) && (r2 != r2End));
1019
1020 /*
1021 * Deal with whichever region still has rectangles left.
1022 */
1023 curBand = newReg->numRects;
1024 if (r1 != r1End)
1025 {
1026 if (nonOverlap1Func != (void (*)())NULL)
1027 {
1028 do
1029 {
1030 r1BandEnd = r1;
1031 while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1))
1032 {
1033 r1BandEnd++;
1034 }
1035 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
1036 max(r1->y1,ybot), r1->y2);
1037 r1 = r1BandEnd;
1038 } while (r1 != r1End);
1039 }
1040 }
1041 else if ((r2 != r2End) && (nonOverlap2Func != (void (*)())NULL))
1042 {
1043 do
1044 {
1045 r2BandEnd = r2;
1046 while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1))
1047 {
1048 r2BandEnd++;
1049 }
1050 (* nonOverlap2Func) (newReg, r2, r2BandEnd,
1051 max(r2->y1,ybot), r2->y2);
1052 r2 = r2BandEnd;
1053 } while (r2 != r2End);
1054 }
1055
1056 if (newReg->numRects != curBand)
1057 {
1058 (void) miCoalesce (newReg, prevBand, curBand);
1059 }
1060
1061 /*
1062 * A bit of cleanup. To keep regions from growing without bound,
1063 * we shrink the array of rectangles to match the new number of
1064 * rectangles in the region. This never goes to 0, however...
1065 *
1066 * Only do this stuff if the number of rectangles allocated is more than
1067 * twice the number of rectangles in the region (a simple optimization...).
1068 */
1069 if (newReg->numRects < (newReg->size >> 1))
1070 {
1071 if (REGION_NOT_EMPTY(newReg))
1072 {
1073 BoxPtr prev_rects = newReg->rects;
1074 newReg->size = newReg->numRects;
1075 newReg->rects = (BoxPtr) Xrealloc ((char *) newReg->rects,
1076 (unsigned) (sizeof(BoxRec) * newReg->size));
1077 if (! newReg->rects)
1078 newReg->rects = prev_rects;
1079 }
1080 else
1081 {
1082 /*
1083 * No point in doing the extra work involved in an Xrealloc if
1084 * the region is empty
1085 */
1086 newReg->size = 1;
1087 Xfree((char *) newReg->rects);
1088 newReg->rects = (BoxPtr) Xmalloc(sizeof(BoxRec));
1089 }
1090 }
1091 Xfree ((char *) oldRects);
1092 return;
1093}
1094
1095
1096/*======================================================================
1097 * Region Union
1098 *====================================================================*/
1099
1100/*-
1101 *-----------------------------------------------------------------------
1102 * miUnionNonO --
1103 * Handle a non-overlapping band for the union operation. Just
1104 * Adds the rectangles into the region. Doesn't have to check for
1105 * subsumption or anything.
1106 *
1107 * Results:
1108 * None.
1109 *
1110 * Side Effects:
1111 * pReg->numRects is incremented and the final rectangles overwritten
1112 * with the rectangles we're passed.
1113 *
1114 *-----------------------------------------------------------------------
1115 */
1116/* static void*/
1117static int
1118miUnionNonO (pReg, r, rEnd, y1, y2)
1119 register Region pReg;
1120 register BoxPtr r;
1121 BoxPtr rEnd;
1122 register short y1;
1123 register short y2;
1124{
1125 register BoxPtr pNextRect;
1126
1127 pNextRect = &pReg->rects[pReg->numRects];
1128
1129 assert(y1 < y2);
1130
1131 while (r != rEnd)
1132 {
1133 assert(r->x1 < r->x2);
1134 MEMCHECK(pReg, pNextRect, pReg->rects);
1135 pNextRect->x1 = r->x1;
1136 pNextRect->y1 = y1;
1137 pNextRect->x2 = r->x2;
1138 pNextRect->y2 = y2;
1139 pReg->numRects += 1;
1140 pNextRect++;
1141
1142 assert(pReg->numRects<=pReg->size);
1143 r++;
1144 }
1145 return 0; /* lint */
1146}
1147
1148
1149/*-
1150 *-----------------------------------------------------------------------
1151 * miUnionO --
1152 * Handle an overlapping band for the union operation. Picks the
1153 * left-most rectangle each time and merges it into the region.
1154 *
1155 * Results:
1156 * None.
1157 *
1158 * Side Effects:
1159 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1160 * be changed.
1161 *
1162 *-----------------------------------------------------------------------
1163 */
1164
1165/* static void*/
1166static int
1167miUnionO (pReg, r1, r1End, r2, r2End, y1, y2)
1168 register Region pReg;
1169 register BoxPtr r1;
1170 BoxPtr r1End;
1171 register BoxPtr r2;
1172 BoxPtr r2End;
1173 register short y1;
1174 register short y2;
1175{
1176 register BoxPtr pNextRect;
1177
1178 pNextRect = &pReg->rects[pReg->numRects];
1179
1180#define MERGERECT(r) \
1181 if ((pReg->numRects != 0) && \
1182 (pNextRect[-1].y1 == y1) && \
1183 (pNextRect[-1].y2 == y2) && \
1184 (pNextRect[-1].x2 >= r->x1)) \
1185 { \
1186 if (pNextRect[-1].x2 < r->x2) \
1187 { \
1188 pNextRect[-1].x2 = r->x2; \
1189 assert(pNextRect[-1].x1<pNextRect[-1].x2); \
1190 } \
1191 } \
1192 else \
1193 { \
1194 MEMCHECK(pReg, pNextRect, pReg->rects); \
1195 pNextRect->y1 = y1; \
1196 pNextRect->y2 = y2; \
1197 pNextRect->x1 = r->x1; \
1198 pNextRect->x2 = r->x2; \
1199 pReg->numRects += 1; \
1200 pNextRect += 1; \
1201 } \
1202 assert(pReg->numRects<=pReg->size);\
1203 r++;
1204
1205 assert (y1<y2);
1206 while ((r1 != r1End) && (r2 != r2End))
1207 {
1208 if (r1->x1 < r2->x1)
1209 {
1210 MERGERECT(r1);
1211 }
1212 else
1213 {
1214 MERGERECT(r2);
1215 }
1216 }
1217
1218 if (r1 != r1End)
1219 {
1220 do
1221 {
1222 MERGERECT(r1);
1223 } while (r1 != r1End);
1224 }
1225 else while (r2 != r2End)
1226 {
1227 MERGERECT(r2);
1228 }
1229 return 0; /* lint */
1230}
1231
1232int
1233XUnionRegion(reg1, reg2, newReg)
1234 Region reg1;
1235 Region reg2; /* source regions */
1236 Region newReg; /* destination Region */
1237{
1238 /* checks all the simple cases */
1239
1240 /*
1241 * Region 1 and 2 are the same or region 1 is empty
1242 */
1243 if ( (reg1 == reg2) || (!(reg1->numRects)) )
1244 {
1245 if (newReg != reg2)
1246 miRegionCopy(newReg, reg2);
1247 return 1;
1248 }
1249
1250 /*
1251 * if nothing to union (region 2 empty)
1252 */
1253 if (!(reg2->numRects))
1254 {
1255 if (newReg != reg1)
1256 miRegionCopy(newReg, reg1);
1257 return 1;
1258 }
1259
1260 /*
1261 * Region 1 completely subsumes region 2
1262 */
1263 if ((reg1->numRects == 1) &&
1264 (reg1->extents.x1 <= reg2->extents.x1) &&
1265 (reg1->extents.y1 <= reg2->extents.y1) &&
1266 (reg1->extents.x2 >= reg2->extents.x2) &&
1267 (reg1->extents.y2 >= reg2->extents.y2))
1268 {
1269 if (newReg != reg1)
1270 miRegionCopy(newReg, reg1);
1271 return 1;
1272 }
1273
1274 /*
1275 * Region 2 completely subsumes region 1
1276 */
1277 if ((reg2->numRects == 1) &&
1278 (reg2->extents.x1 <= reg1->extents.x1) &&
1279 (reg2->extents.y1 <= reg1->extents.y1) &&
1280 (reg2->extents.x2 >= reg1->extents.x2) &&
1281 (reg2->extents.y2 >= reg1->extents.y2))
1282 {
1283 if (newReg != reg2)
1284 miRegionCopy(newReg, reg2);
1285 return 1;
1286 }
1287
1288 miRegionOp (newReg, reg1, reg2, (voidProcp) miUnionO,
1289 (voidProcp) miUnionNonO, (voidProcp) miUnionNonO);
1290
1291 newReg->extents.x1 = min(reg1->extents.x1, reg2->extents.x1);
1292 newReg->extents.y1 = min(reg1->extents.y1, reg2->extents.y1);
1293 newReg->extents.x2 = max(reg1->extents.x2, reg2->extents.x2);
1294 newReg->extents.y2 = max(reg1->extents.y2, reg2->extents.y2);
1295
1296 return 1;
1297}
1298
1299
1300/*======================================================================
1301 * Region Subtraction
1302 *====================================================================*/
1303
1304/*-
1305 *-----------------------------------------------------------------------
1306 * miSubtractNonO --
1307 * Deal with non-overlapping band for subtraction. Any parts from
1308 * region 2 we discard. Anything from region 1 we add to the region.
1309 *
1310 * Results:
1311 * None.
1312 *
1313 * Side Effects:
1314 * pReg may be affected.
1315 *
1316 *-----------------------------------------------------------------------
1317 */
1318/* static void*/
1319static int
1320miSubtractNonO1 (pReg, r, rEnd, y1, y2)
1321 register Region pReg;
1322 register BoxPtr r;
1323 BoxPtr rEnd;
1324 register short y1;
1325 register short y2;
1326{
1327 register BoxPtr pNextRect;
1328
1329 pNextRect = &pReg->rects[pReg->numRects];
1330
1331 assert(y1<y2);
1332
1333 while (r != rEnd)
1334 {
1335 assert(r->x1<r->x2);
1336 MEMCHECK(pReg, pNextRect, pReg->rects);
1337 pNextRect->x1 = r->x1;
1338 pNextRect->y1 = y1;
1339 pNextRect->x2 = r->x2;
1340 pNextRect->y2 = y2;
1341 pReg->numRects += 1;
1342 pNextRect++;
1343
1344 assert(pReg->numRects <= pReg->size);
1345
1346 r++;
1347 }
1348 return 0; /* lint */
1349}
1350
1351/*-
1352 *-----------------------------------------------------------------------
1353 * miSubtractO --
1354 * Overlapping band subtraction. x1 is the left-most point not yet
1355 * checked.
1356 *
1357 * Results:
1358 * None.
1359 *
1360 * Side Effects:
1361 * pReg may have rectangles added to it.
1362 *
1363 *-----------------------------------------------------------------------
1364 */
1365/* static void*/
1366static int
1367miSubtractO (pReg, r1, r1End, r2, r2End, y1, y2)
1368 register Region pReg;
1369 register BoxPtr r1;
1370 BoxPtr r1End;
1371 register BoxPtr r2;
1372 BoxPtr r2End;
1373 register short y1;
1374 register short y2;
1375{
1376 register BoxPtr pNextRect;
1377 register int x1;
1378
1379 x1 = r1->x1;
1380
1381 assert(y1<y2);
1382 pNextRect = &pReg->rects[pReg->numRects];
1383
1384 while ((r1 != r1End) && (r2 != r2End))
1385 {
1386 if (r2->x2 <= x1)
1387 {
1388 /*
1389 * Subtrahend missed the boat: go to next subtrahend.
1390 */
1391 r2++;
1392 }
1393 else if (r2->x1 <= x1)
1394 {
1395 /*
1396 * Subtrahend preceeds minuend: nuke left edge of minuend.
1397 */
1398 x1 = r2->x2;
1399 if (x1 >= r1->x2)
1400 {
1401 /*
1402 * Minuend completely covered: advance to next minuend and
1403 * reset left fence to edge of new minuend.
1404 */
1405 r1++;
1406 if (r1 != r1End)
1407 x1 = r1->x1;
1408 }
1409 else
1410 {
1411 /*
1412 * Subtrahend now used up since it doesn't extend beyond
1413 * minuend
1414 */
1415 r2++;
1416 }
1417 }
1418 else if (r2->x1 < r1->x2)
1419 {
1420 /*
1421 * Left part of subtrahend covers part of minuend: add uncovered
1422 * part of minuend to region and skip to next subtrahend.
1423 */
1424 assert(x1<r2->x1);
1425 MEMCHECK(pReg, pNextRect, pReg->rects);
1426 pNextRect->x1 = x1;
1427 pNextRect->y1 = y1;
1428 pNextRect->x2 = r2->x1;
1429 pNextRect->y2 = y2;
1430 pReg->numRects += 1;
1431 pNextRect++;
1432
1433 assert(pReg->numRects<=pReg->size);
1434
1435 x1 = r2->x2;
1436 if (x1 >= r1->x2)
1437 {
1438 /*
1439 * Minuend used up: advance to new...
1440 */
1441 r1++;
1442 if (r1 != r1End)
1443 x1 = r1->x1;
1444 }
1445 else
1446 {
1447 /*
1448 * Subtrahend used up
1449 */
1450 r2++;
1451 }
1452 }
1453 else
1454 {
1455 /*
1456 * Minuend used up: add any remaining piece before advancing.
1457 */
1458 if (r1->x2 > x1)
1459 {
1460 MEMCHECK(pReg, pNextRect, pReg->rects);
1461 pNextRect->x1 = x1;
1462 pNextRect->y1 = y1;
1463 pNextRect->x2 = r1->x2;
1464 pNextRect->y2 = y2;
1465 pReg->numRects += 1;
1466 pNextRect++;
1467 assert(pReg->numRects<=pReg->size);
1468 }
1469 r1++;
1470 if (r1 != r1End)
1471 x1 = r1->x1;
1472 }
1473 }
1474
1475 /*
1476 * Add remaining minuend rectangles to region.
1477 */
1478 while (r1 != r1End)
1479 {
1480 assert(x1<r1->x2);
1481 MEMCHECK(pReg, pNextRect, pReg->rects);
1482 pNextRect->x1 = x1;
1483 pNextRect->y1 = y1;
1484 pNextRect->x2 = r1->x2;
1485 pNextRect->y2 = y2;
1486 pReg->numRects += 1;
1487 pNextRect++;
1488
1489 assert(pReg->numRects<=pReg->size);
1490
1491 r1++;
1492 if (r1 != r1End)
1493 {
1494 x1 = r1->x1;
1495 }
1496 }
1497 return 0; /* lint */
1498}
1499
1500/*-
1501 *-----------------------------------------------------------------------
1502 * miSubtract --
1503 * Subtract regS from regM and leave the result in regD.
1504 * S stands for subtrahend, M for minuend and D for difference.
1505 *
1506 * Results:
1507 * TRUE.
1508 *
1509 * Side Effects:
1510 * regD is overwritten.
1511 *
1512 *-----------------------------------------------------------------------
1513 */
1514
1515int
1516XSubtractRegion(regM, regS, regD)
1517 Region regM;
1518 Region regS;
1519 register Region regD;
1520{
1521 /* check for trivial reject */
1522 if ( (!(regM->numRects)) || (!(regS->numRects)) ||
1523 (!EXTENTCHECK(&regM->extents, &regS->extents)) )
1524 {
1525 miRegionCopy(regD, regM);
1526 return 1;
1527 }
1528
1529 miRegionOp (regD, regM, regS, (voidProcp) miSubtractO,
1530 (voidProcp) miSubtractNonO1, (voidProcp) NULL);
1531
1532 /*
1533 * Can't alter newReg's extents before we call miRegionOp because
1534 * it might be one of the source regions and miRegionOp depends
1535 * on the extents of those regions being the unaltered. Besides, this
1536 * way there's no checking against rectangles that will be nuked
1537 * due to coalescing, so we have to examine fewer rectangles.
1538 */
1539 miSetExtents (regD);
1540 return 1;
1541}
1542
1543int
1544XXorRegion( sra, srb, dr )
1545 Region sra, srb, dr;
1546{
1547 Region tra, trb;
1548
1549 if ((! (tra = XCreateRegion())) || (! (trb = XCreateRegion())))
1550 return 0;
1551 (void) XSubtractRegion(sra,srb,tra);
1552 (void) XSubtractRegion(srb,sra,trb);
1553 (void) XUnionRegion(tra,trb,dr);
1554 XDestroyRegion(tra);
1555 XDestroyRegion(trb);
1556 return 0;
1557}
1558
1559/*
1560 * Check to see if the region is empty. Assumes a region is passed
1561 * as a parameter
1562 */
1563int
1564XEmptyRegion( r )
1565 Region r;
1566{
1567 if( r->numRects == 0 ) return TRUE;
1568 else return FALSE;
1569}
1570
1571/*
1572 * Check to see if two regions are equal
1573 */
1574int
1575XEqualRegion( r1, r2 )
1576 Region r1, r2;
1577{
1578 int i;
1579
1580 if( r1->numRects != r2->numRects ) return FALSE;
1581 else if( r1->numRects == 0 ) return TRUE;
1582 else if ( r1->extents.x1 != r2->extents.x1 ) return FALSE;
1583 else if ( r1->extents.x2 != r2->extents.x2 ) return FALSE;
1584 else if ( r1->extents.y1 != r2->extents.y1 ) return FALSE;
1585 else if ( r1->extents.y2 != r2->extents.y2 ) return FALSE;
1586 else for( i=0; i < r1->numRects; i++ ) {
1587 if ( r1->rects[i].x1 != r2->rects[i].x1 ) return FALSE;
1588 else if ( r1->rects[i].x2 != r2->rects[i].x2 ) return FALSE;
1589 else if ( r1->rects[i].y1 != r2->rects[i].y1 ) return FALSE;
1590 else if ( r1->rects[i].y2 != r2->rects[i].y2 ) return FALSE;
1591 }
1592 return TRUE;
1593}
1594
1595int
1596XPointInRegion( pRegion, x, y )
1597 Region pRegion;
1598 int x, y;
1599{
1600 int i;
1601
1602 if (pRegion->numRects == 0)
1603 return FALSE;
1604 if (!INBOX(pRegion->extents, x, y))
1605 return FALSE;
1606 for (i=0; i<pRegion->numRects; i++)
1607 {
1608 if (INBOX (pRegion->rects[i], x, y))
1609 return TRUE;
1610 }
1611 return FALSE;
1612}
1613
1614int
1615XRectInRegion(region, rx, ry, rwidth, rheight)
1616 register Region region;
1617 int rx, ry;
1618 unsigned int rwidth, rheight;
1619{
1620 register BoxPtr pbox;
1621 register BoxPtr pboxEnd;
1622 Box rect;
1623 register BoxPtr prect = &rect;
1624 int partIn, partOut;
1625
1626 prect->x1 = rx;
1627 prect->y1 = ry;
1628 prect->x2 = rwidth + rx;
1629 prect->y2 = rheight + ry;
1630
1631 /* this is (just) a useful optimization */
1632 if ((region->numRects == 0) || !EXTENTCHECK(&region->extents, prect))
1633 return(RectangleOut);
1634
1635 partOut = FALSE;
1636 partIn = FALSE;
1637
1638 /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */
1639 for (pbox = region->rects, pboxEnd = pbox + region->numRects;
1640 pbox < pboxEnd;
1641 pbox++)
1642 {
1643
1644 if (pbox->y2 <= ry)
1645 continue; /* getting up to speed or skipping remainder of band */
1646
1647 if (pbox->y1 > ry)
1648 {
1649 partOut = TRUE; /* missed part of rectangle above */
1650 if (partIn || (pbox->y1 >= prect->y2))
1651 break;
1652 ry = pbox->y1; /* x guaranteed to be == prect->x1 */
1653 }
1654
1655 if (pbox->x2 <= rx)
1656 continue; /* not far enough over yet */
1657
1658 if (pbox->x1 > rx)
1659 {
1660 partOut = TRUE; /* missed part of rectangle to left */
1661 if (partIn)
1662 break;
1663 }
1664
1665 if (pbox->x1 < prect->x2)
1666 {
1667 partIn = TRUE; /* definitely overlap */
1668 if (partOut)
1669 break;
1670 }
1671
1672 if (pbox->x2 >= prect->x2)
1673 {
1674 ry = pbox->y2; /* finished with this band */
1675 if (ry >= prect->y2)
1676 break;
1677 rx = prect->x1; /* reset x out to left again */
1678 } else
1679 {
1680 /*
1681 * Because boxes in a band are maximal width, if the first box
1682 * to overlap the rectangle doesn't completely cover it in that
1683 * band, the rectangle must be partially out, since some of it
1684 * will be uncovered in that band. partIn will have been set true
1685 * by now...
1686 */
1687 break;
1688 }
1689
1690 }
1691
1692 return(partIn ? ((ry < prect->y2) ? RectanglePart : RectangleIn) :
1693 RectangleOut);
1694}