1 /************************************************************************
3 Copyright 1987, 1988, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
26 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
30 Permission to use, copy, modify, and distribute this software and its
31 documentation for any purpose and without fee is hereby granted,
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in
34 supporting documentation, and that the name of Digital not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.
38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
46 ************************************************************************/
48 * The functions in this file implement the Region abstraction, similar to one
49 * used in the X11 sample server. A Region is simply an area, as the name
50 * implies, and is implemented as a "y-x-banded" array of rectangles. To
51 * explain: Each Region is made up of a certain number of rectangles sorted
52 * by y coordinate first, and then by x coordinate.
54 * Furthermore, the rectangles are banded such that every rectangle with a
55 * given upper-left y coordinate (y1) will have the same lower-right y
56 * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
57 * will span the entire vertical distance of the band. This means that some
58 * areas that could be merged into a taller rectangle will be represented as
59 * several shorter rectangles to account for shorter rectangles to its left
60 * or right but within its "vertical scope".
62 * An added constraint on the rectangles is that they must cover as much
63 * horizontal area as possible. E.g. no two rectangles in a band are allowed
66 * Whenever possible, bands will be merged together to cover a greater vertical
67 * distance (and thus reduce the number of rectangles). Two bands can be merged
68 * only if the bottom of one touches the top of the other and they have
69 * rectangles in the same places (of the same width, of course). This maintains
70 * the y-x-banding that's so nice to have...
78 #include <X11/Xregion.h>
83 #define assert(expr) {if (!(expr)) fprintf(stderr,\
84 "Assertion failed file %s, line %d: expr\n", __FILE__, __LINE__); }
89 typedef int (*overlapProcp)(
98 typedef int (*nonOverlapProcp)(
105 static void miRegionOp(
106 register Region newReg, /* Place to store result */
107 Region reg1, /* First region in operation */
108 Region reg2, /* 2d region in operation */
110 register Region pReg,
116 short y2), /* Function to call for over-
118 int (*nonOverlap1Func)(
119 register Region pReg,
123 register short y2), /* Function to call for non-
124 * overlapping bands in region
126 int (*nonOverlap2Func)(
127 register Region pReg,
131 register short y2)); /* Function to call for non-
132 * overlapping bands in region
136 /* Create a new empty region */
142 if (! (temp = ( Region )Xmalloc( (unsigned) sizeof( REGION ))))
143 return (Region) NULL;
144 if (! (temp->rects = ( BOX * )Xmalloc( (unsigned) sizeof( BOX )))) {
145 Xfree((char *) temp);
146 return (Region) NULL;
149 temp->extents.x1 = 0;
150 temp->extents.y1 = 0;
151 temp->extents.x2 = 0;
152 temp->extents.y2 = 0;
162 rect->x = r->extents.x1;
163 rect->y = r->extents.y1;
164 rect->width = r->extents.x2 - r->extents.x1;
165 rect->height = r->extents.y2 - r->extents.y1;
170 XUnionRectWithRegion(
171 register XRectangle *rect,
172 Region source, Region dest)
176 if (!rect->width || !rect->height)
178 region.rects = ®ion.extents;
180 region.extents.x1 = rect->x;
181 region.extents.y1 = rect->y;
182 region.extents.x2 = rect->x + rect->width;
183 region.extents.y2 = rect->y + rect->height;
186 return XUnionRegion(®ion, source, dest);
190 *-----------------------------------------------------------------------
192 * Reset the extents of a region to what they should be. Called by
193 * miSubtract and miIntersect b/c they can't figure it out along the
194 * way or do so easily, as miUnion can.
200 * The region's 'extents' structure is overwritten.
202 *-----------------------------------------------------------------------
208 register BoxPtr pBox,
212 if (pReg->numRects == 0)
214 pReg->extents.x1 = 0;
215 pReg->extents.y1 = 0;
216 pReg->extents.x2 = 0;
217 pReg->extents.y2 = 0;
221 pExtents = &pReg->extents;
223 pBoxEnd = &pBox[pReg->numRects - 1];
226 * Since pBox is the first rectangle in the region, it must have the
227 * smallest y1 and since pBoxEnd is the last rectangle in the region,
228 * it must have the largest y2, because of banding. Initialize x1 and
229 * x2 from pBox and pBoxEnd, resp., as good things to initialize them
232 pExtents->x1 = pBox->x1;
233 pExtents->y1 = pBox->y1;
234 pExtents->x2 = pBoxEnd->x2;
235 pExtents->y2 = pBoxEnd->y2;
237 assert(pExtents->y1 < pExtents->y2);
238 while (pBox <= pBoxEnd)
240 if (pBox->x1 < pExtents->x1)
242 pExtents->x1 = pBox->x1;
244 if (pBox->x2 > pExtents->x2)
246 pExtents->x2 = pBox->x2;
250 assert(pExtents->x1 < pExtents->x2);
260 register XRectangle *xr, *pr;
265 total = r->numRects * sizeof (XRectangle);
266 if ((xr = (XRectangle *) _XAllocTemp(dpy, total))) {
267 for (pr = xr, pb = r->rects, i = r->numRects; --i >= 0; pr++, pb++) {
270 pr->width = pb->x2 - pb->x1;
271 pr->height = pb->y2 - pb->y1;
274 if (xr || !r->numRects)
275 _XSetClipRectangles(dpy, gc, 0, 0, xr, r->numRects, YXBanded);
277 _XFreeTemp(dpy, (char *)xr, total);
287 Xfree( (char *) r->rects );
293 /* TranslateRegion(pRegion, x, y)
300 register Region pRegion,
307 pbox = pRegion->rects;
308 nbox = pRegion->numRects;
318 pRegion->extents.x1 += x;
319 pRegion->extents.x2 += x;
320 pRegion->extents.y1 += y;
321 pRegion->extents.y2 += y;
326 Utility procedure Compress:
327 Replace r by the region r', where
328 p in r' iff (Quantifer m <= dx) (p + m in r), and
329 Quantifier is Exists if grow is TRUE, For all if grow is FALSE, and
330 (x,y) + m = (x+m,y) if xdir is TRUE; (x,y+m) if xdir is FALSE.
332 Thus, if xdir is TRUE and grow is FALSE, r is replaced by the region
333 of all points p such that p and the next dx points on the same
334 horizontal scan line are all in r. We do this using by noting
335 that p is the head of a run of length 2^i + k iff p is the head
336 of a run of length 2^i and p+2^i is the head of a run of length
337 k. Thus, the loop invariant: s contains the region corresponding
338 to the runs of length shift. r contains the region corresponding
339 to the runs of length 1 + dxo & (shift-1), where dxo is the original
340 value of dx. dx = dxo & ~(shift-1). As parameters, s and t are
341 scratch regions, so that we don't have to allocate them on every
345 #define ZOpRegion(a,b,c) if (grow) XUnionRegion(a,b,c); \
346 else XIntersectRegion(a,b,c)
347 #define ZShiftRegion(a,b) if (xdir) XOffsetRegion(a,b,0); \
348 else XOffsetRegion(a,0,b)
349 #define ZCopyRegion(a,b) XUnionRegion(a,a,b)
353 Region r, Region s, Region t,
354 register unsigned dx,
355 register int xdir, register int grow)
357 register unsigned shift = 1;
362 ZShiftRegion(r, -(int)shift);
368 ZShiftRegion(s, -(int)shift);
386 if (!dx && !dy) return 0;
387 if (! (s = XCreateRegion()) )
389 if (! (t = XCreateRegion()) ) {
393 if ((grow = (dx < 0))) dx = -dx;
394 if (dx) Compress(r, s, t, (unsigned) 2*dx, TRUE, grow);
395 if ((grow = (dy < 0))) dy = -dy;
396 if (dy) Compress(r, s, t, (unsigned) 2*dy, FALSE, grow);
397 XOffsetRegion(r, dx, dy);
404 /*======================================================================
405 * Region Intersection
406 *====================================================================*/
408 *-----------------------------------------------------------------------
410 * Handle an overlapping band for miIntersect.
416 * Rectangles may be added to the region.
418 *-----------------------------------------------------------------------
423 register Region pReg,
433 register BoxPtr pNextRect;
435 pNextRect = &pReg->rects[pReg->numRects];
437 while ((r1 != r1End) && (r2 != r2End))
439 x1 = max(r1->x1,r2->x1);
440 x2 = min(r1->x2,r2->x2);
443 * If there's any overlap between the two rectangles, add that
444 * overlap to the new region.
445 * There's no need to check for subsumption because the only way
446 * such a need could arise is if some region has two rectangles
447 * right next to each other. Since that should never happen...
453 MEMCHECK(pReg, pNextRect, pReg->rects);
460 assert(pReg->numRects <= pReg->size);
464 * Need to advance the pointers. Shift the one that extends
465 * to the right the least, since the other still has a chance to
466 * overlap with that region's next rectangle, if you see what I mean.
472 else if (r2->x2 < r1->x2)
488 Region reg2, /* source regions */
489 register Region newReg) /* destination Region */
491 /* check for trivial reject */
492 if ( (!(reg1->numRects)) || (!(reg2->numRects)) ||
493 (!EXTENTCHECK(®1->extents, ®2->extents)))
494 newReg->numRects = 0;
496 miRegionOp (newReg, reg1, reg2,
497 miIntersectO, NULL, NULL);
500 * Can't alter newReg's extents before we call miRegionOp because
501 * it might be one of the source regions and miRegionOp depends
502 * on the extents of those regions being the same. Besides, this
503 * way there's no checking against rectangles that will be nuked
504 * due to coalescing, so we have to examine fewer rectangles.
506 miSetExtents(newReg);
512 register Region dstrgn,
516 if (dstrgn != rgn) /* don't want to copy to itself */
518 if (dstrgn->size < rgn->numRects)
522 BOX *prevRects = dstrgn->rects;
524 if (! (dstrgn->rects = (BOX *)
525 Xrealloc((char *) dstrgn->rects,
526 (unsigned) rgn->numRects * (sizeof(BOX))))) {
531 dstrgn->size = rgn->numRects;
533 dstrgn->numRects = rgn->numRects;
534 dstrgn->extents.x1 = rgn->extents.x1;
535 dstrgn->extents.y1 = rgn->extents.y1;
536 dstrgn->extents.x2 = rgn->extents.x2;
537 dstrgn->extents.y2 = rgn->extents.y2;
539 memcpy((char *) dstrgn->rects, (char *) rgn->rects,
540 (int) (rgn->numRects * sizeof(BOX)));
544 /*======================================================================
545 * Generic Region Operator
546 *====================================================================*/
549 *-----------------------------------------------------------------------
551 * Attempt to merge the boxes in the current band with those in the
552 * previous one. Used only by miRegionOp.
555 * The new index for the previous band.
558 * If coalescing takes place:
559 * - rectangles in the previous band will have their y2 fields
561 * - pReg->numRects will be decreased.
563 *-----------------------------------------------------------------------
568 register Region pReg, /* Region to coalesce */
569 int prevStart, /* Index of start of previous band */
570 int curStart) /* Index of start of current band */
572 register BoxPtr pPrevBox; /* Current box in previous band */
573 register BoxPtr pCurBox; /* Current box in current band */
574 register BoxPtr pRegEnd; /* End of region */
575 int curNumRects; /* Number of rectangles in current
577 int prevNumRects; /* Number of rectangles in previous
579 int bandY1; /* Y1 coordinate for current band */
581 pRegEnd = &pReg->rects[pReg->numRects];
583 pPrevBox = &pReg->rects[prevStart];
584 prevNumRects = curStart - prevStart;
587 * Figure out how many rectangles are in the current band. Have to do
588 * this because multiple bands could have been added in miRegionOp
589 * at the end when one region has been exhausted.
591 pCurBox = &pReg->rects[curStart];
592 bandY1 = pCurBox->y1;
593 for (curNumRects = 0;
594 (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1);
600 if (pCurBox != pRegEnd)
603 * If more than one band was added, we have to find the start
604 * of the last band added so the next coalescing job can start
605 * at the right place... (given when multiple bands are added,
606 * this may be pointless -- see above).
609 while (pRegEnd[-1].y1 == pRegEnd->y1)
613 curStart = pRegEnd - pReg->rects;
614 pRegEnd = pReg->rects + pReg->numRects;
617 if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
618 pCurBox -= curNumRects;
620 * The bands may only be coalesced if the bottom of the previous
621 * matches the top scanline of the current.
623 if (pPrevBox->y2 == pCurBox->y1)
626 * Make sure the bands have boxes in the same places. This
627 * assumes that boxes have been added in such a way that they
628 * cover the most area possible. I.e. two boxes in a band must
629 * have some horizontal space between them.
633 if ((pPrevBox->x1 != pCurBox->x1) ||
634 (pPrevBox->x2 != pCurBox->x2))
637 * The bands don't line up so they can't be coalesced.
644 } while (prevNumRects != 0);
646 pReg->numRects -= curNumRects;
647 pCurBox -= curNumRects;
648 pPrevBox -= curNumRects;
651 * The bands may be merged, so set the bottom y of each box
652 * in the previous band to that of the corresponding box in
657 pPrevBox->y2 = pCurBox->y2;
661 } while (curNumRects != 0);
664 * If only one band was added to the region, we have to backup
665 * curStart to the start of the previous band.
667 * If more than one band was added to the region, copy the
668 * other bands down. The assumption here is that the other bands
669 * came from the same region as the current one and no further
670 * coalescing can be done on them since it's all been done
671 * already... curStart is already in the right place.
673 if (pCurBox == pRegEnd)
675 curStart = prevStart;
681 *pPrevBox++ = *pCurBox++;
682 } while (pCurBox != pRegEnd);
691 *-----------------------------------------------------------------------
693 * Apply an operation to two regions. Called by miUnion, miInverse,
694 * miSubtract, miIntersect...
700 * The new region is overwritten.
703 * The idea behind this function is to view the two regions as sets.
704 * Together they cover a rectangle of area that this function divides
705 * into horizontal bands where points are covered only by one region
706 * or by both. For the first case, the nonOverlapFunc is called with
707 * each the band and the band's upper and lower extents. For the
708 * second, the overlapFunc is called to process the entire band. It
709 * is responsible for clipping the rectangles in the band, though
710 * this function provides the boundaries.
711 * At the end of each band, the new region is coalesced, if possible,
712 * to reduce the number of rectangles in the region.
714 *-----------------------------------------------------------------------
719 register Region newReg, /* Place to store result */
720 Region reg1, /* First region in operation */
721 Region reg2, /* 2d region in operation */
723 register Region pReg,
729 short y2), /* Function to call for over-
731 int (*nonOverlap1Func)(
732 register Region pReg,
736 register short y2), /* Function to call for non-
737 * overlapping bands in region
739 int (*nonOverlap2Func)(
740 register Region pReg,
744 register short y2)) /* Function to call for non-
745 * overlapping bands in region
748 register BoxPtr r1; /* Pointer into first region */
749 register BoxPtr r2; /* Pointer into 2d region */
750 BoxPtr r1End; /* End of 1st region */
751 BoxPtr r2End; /* End of 2d region */
752 register short ybot; /* Bottom of intersection */
753 register short ytop; /* Top of intersection */
754 BoxPtr oldRects; /* Old rects for newReg */
755 int prevBand; /* Index of start of
756 * previous band in newReg */
757 int curBand; /* Index of start of current
759 register BoxPtr r1BandEnd; /* End of current band in r1 */
760 register BoxPtr r2BandEnd; /* End of current band in r2 */
761 short top; /* Top of non-overlapping
763 short bot; /* Bottom of non-overlapping
768 * set r1, r2, r1End and r2End appropriately, preserve the important
769 * parts of the destination region until the end in case it's one of
770 * the two source regions, then mark the "new" region empty, allocating
771 * another array of rectangles for it to use.
775 r1End = r1 + reg1->numRects;
776 r2End = r2 + reg2->numRects;
778 oldRects = newReg->rects;
780 EMPTY_REGION(newReg);
783 * Allocate a reasonable number of rectangles for the new region. The idea
784 * is to allocate enough so the individual functions don't need to
785 * reallocate and copy the array, which is time consuming, yet we don't
786 * have to worry about using too much memory. I hope to be able to
787 * nuke the Xrealloc() at the end of this function eventually.
789 newReg->size = max(reg1->numRects,reg2->numRects) * 2;
791 if (! (newReg->rects = (BoxPtr)
792 Xmalloc ((unsigned) (sizeof(BoxRec) * newReg->size)))) {
798 * Initialize ybot and ytop.
799 * In the upcoming loop, ybot and ytop serve different functions depending
800 * on whether the band being handled is an overlapping or non-overlapping
802 * In the case of a non-overlapping band (only one of the regions
803 * has points in the band), ybot is the bottom of the most recent
804 * intersection and thus clips the top of the rectangles in that band.
805 * ytop is the top of the next intersection between the two regions and
806 * serves to clip the bottom of the rectangles in the current band.
807 * For an overlapping band (where the two regions intersect), ytop clips
808 * the top of the rectangles of both regions and ybot clips the bottoms.
810 if (reg1->extents.y1 < reg2->extents.y1)
811 ybot = reg1->extents.y1;
813 ybot = reg2->extents.y1;
816 * prevBand serves to mark the start of the previous band so rectangles
817 * can be coalesced into larger rectangles. qv. miCoalesce, above.
818 * In the beginning, there is no previous band, so prevBand == curBand
819 * (curBand is set later on, of course, but the first band will always
820 * start at index 0). prevBand and curBand must be indices because of
821 * the possible expansion, and resultant moving, of the new region's
822 * array of rectangles.
828 curBand = newReg->numRects;
831 * This algorithm proceeds one source-band (as opposed to a
832 * destination band, which is determined by where the two regions
833 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
834 * rectangle after the last one in the current band for their
835 * respective regions.
838 while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1))
844 while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1))
850 * First handle the band that doesn't intersect, if any.
852 * Note that attention is restricted to one band in the
853 * non-intersecting region at once, so if a region has n
854 * bands between the current position and the next place it overlaps
855 * the other, this entire loop will be passed through n times.
859 top = max(r1->y1,ybot);
860 bot = min(r1->y2,r2->y1);
862 if ((top != bot) && (nonOverlap1Func != NULL))
864 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
869 else if (r2->y1 < r1->y1)
871 top = max(r2->y1,ybot);
872 bot = min(r2->y2,r1->y1);
874 if ((top != bot) && (nonOverlap2Func != NULL))
876 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
887 * If any rectangles got added to the region, try and coalesce them
888 * with rectangles from the previous band. Note we could just do
889 * this test in miCoalesce, but some machines incur a not
890 * inconsiderable cost for function calls, so...
892 if (newReg->numRects != curBand)
894 prevBand = miCoalesce (newReg, prevBand, curBand);
898 * Now see if we've hit an intersecting band. The two bands only
899 * intersect if ybot > ytop
901 ybot = min(r1->y2, r2->y2);
902 curBand = newReg->numRects;
905 (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
909 if (newReg->numRects != curBand)
911 prevBand = miCoalesce (newReg, prevBand, curBand);
915 * If we've finished with a band (y2 == ybot) we skip forward
916 * in the region to the next band.
926 } while ((r1 != r1End) && (r2 != r2End));
929 * Deal with whichever region still has rectangles left.
931 curBand = newReg->numRects;
934 if (nonOverlap1Func != NULL)
939 while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1))
943 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
944 max(r1->y1,ybot), r1->y2);
946 } while (r1 != r1End);
949 else if ((r2 != r2End) && (nonOverlap2Func != NULL))
954 while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1))
958 (* nonOverlap2Func) (newReg, r2, r2BandEnd,
959 max(r2->y1,ybot), r2->y2);
961 } while (r2 != r2End);
964 if (newReg->numRects != curBand)
966 (void) miCoalesce (newReg, prevBand, curBand);
970 * A bit of cleanup. To keep regions from growing without bound,
971 * we shrink the array of rectangles to match the new number of
972 * rectangles in the region. This never goes to 0, however...
974 * Only do this stuff if the number of rectangles allocated is more than
975 * twice the number of rectangles in the region (a simple optimization...).
977 if (newReg->numRects < (newReg->size >> 1))
979 if (REGION_NOT_EMPTY(newReg))
981 BoxPtr prev_rects = newReg->rects;
982 newReg->size = newReg->numRects;
983 newReg->rects = (BoxPtr) Xrealloc ((char *) newReg->rects,
984 (unsigned) (sizeof(BoxRec) * newReg->size));
986 newReg->rects = prev_rects;
991 * No point in doing the extra work involved in an Xrealloc if
992 * the region is empty
995 Xfree((char *) newReg->rects);
996 newReg->rects = (BoxPtr) Xmalloc(sizeof(BoxRec));
999 Xfree ((char *) oldRects);
1004 /*======================================================================
1006 *====================================================================*/
1009 *-----------------------------------------------------------------------
1011 * Handle a non-overlapping band for the union operation. Just
1012 * Adds the rectangles into the region. Doesn't have to check for
1013 * subsumption or anything.
1019 * pReg->numRects is incremented and the final rectangles overwritten
1020 * with the rectangles we're passed.
1022 *-----------------------------------------------------------------------
1027 register Region pReg,
1033 register BoxPtr pNextRect;
1035 pNextRect = &pReg->rects[pReg->numRects];
1041 assert(r->x1 < r->x2);
1042 MEMCHECK(pReg, pNextRect, pReg->rects);
1043 pNextRect->x1 = r->x1;
1045 pNextRect->x2 = r->x2;
1047 pReg->numRects += 1;
1050 assert(pReg->numRects<=pReg->size);
1053 return 0; /* lint */
1058 *-----------------------------------------------------------------------
1060 * Handle an overlapping band for the union operation. Picks the
1061 * left-most rectangle each time and merges it into the region.
1067 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1070 *-----------------------------------------------------------------------
1076 register Region pReg,
1084 register BoxPtr pNextRect;
1086 pNextRect = &pReg->rects[pReg->numRects];
1088 #define MERGERECT(r) \
1089 if ((pReg->numRects != 0) && \
1090 (pNextRect[-1].y1 == y1) && \
1091 (pNextRect[-1].y2 == y2) && \
1092 (pNextRect[-1].x2 >= r->x1)) \
1094 if (pNextRect[-1].x2 < r->x2) \
1096 pNextRect[-1].x2 = r->x2; \
1097 assert(pNextRect[-1].x1<pNextRect[-1].x2); \
1102 MEMCHECK(pReg, pNextRect, pReg->rects); \
1103 pNextRect->y1 = y1; \
1104 pNextRect->y2 = y2; \
1105 pNextRect->x1 = r->x1; \
1106 pNextRect->x2 = r->x2; \
1107 pReg->numRects += 1; \
1110 assert(pReg->numRects<=pReg->size);\
1114 while ((r1 != r1End) && (r2 != r2End))
1116 if (r1->x1 < r2->x1)
1131 } while (r1 != r1End);
1133 else while (r2 != r2End)
1137 return 0; /* lint */
1143 Region reg2, /* source regions */
1144 Region newReg) /* destination Region */
1146 /* checks all the simple cases */
1149 * Region 1 and 2 are the same or region 1 is empty
1151 if ( (reg1 == reg2) || (!(reg1->numRects)) )
1154 miRegionCopy(newReg, reg2);
1159 * if nothing to union (region 2 empty)
1161 if (!(reg2->numRects))
1164 miRegionCopy(newReg, reg1);
1169 * Region 1 completely subsumes region 2
1171 if ((reg1->numRects == 1) &&
1172 (reg1->extents.x1 <= reg2->extents.x1) &&
1173 (reg1->extents.y1 <= reg2->extents.y1) &&
1174 (reg1->extents.x2 >= reg2->extents.x2) &&
1175 (reg1->extents.y2 >= reg2->extents.y2))
1178 miRegionCopy(newReg, reg1);
1183 * Region 2 completely subsumes region 1
1185 if ((reg2->numRects == 1) &&
1186 (reg2->extents.x1 <= reg1->extents.x1) &&
1187 (reg2->extents.y1 <= reg1->extents.y1) &&
1188 (reg2->extents.x2 >= reg1->extents.x2) &&
1189 (reg2->extents.y2 >= reg1->extents.y2))
1192 miRegionCopy(newReg, reg2);
1196 miRegionOp (newReg, reg1, reg2, miUnionO,
1197 miUnionNonO, miUnionNonO);
1199 newReg->extents.x1 = min(reg1->extents.x1, reg2->extents.x1);
1200 newReg->extents.y1 = min(reg1->extents.y1, reg2->extents.y1);
1201 newReg->extents.x2 = max(reg1->extents.x2, reg2->extents.x2);
1202 newReg->extents.y2 = max(reg1->extents.y2, reg2->extents.y2);
1208 /*======================================================================
1209 * Region Subtraction
1210 *====================================================================*/
1213 *-----------------------------------------------------------------------
1215 * Deal with non-overlapping band for subtraction. Any parts from
1216 * region 2 we discard. Anything from region 1 we add to the region.
1222 * pReg may be affected.
1224 *-----------------------------------------------------------------------
1229 register Region pReg,
1235 register BoxPtr pNextRect;
1237 pNextRect = &pReg->rects[pReg->numRects];
1243 assert(r->x1<r->x2);
1244 MEMCHECK(pReg, pNextRect, pReg->rects);
1245 pNextRect->x1 = r->x1;
1247 pNextRect->x2 = r->x2;
1249 pReg->numRects += 1;
1252 assert(pReg->numRects <= pReg->size);
1256 return 0; /* lint */
1260 *-----------------------------------------------------------------------
1262 * Overlapping band subtraction. x1 is the left-most point not yet
1269 * pReg may have rectangles added to it.
1271 *-----------------------------------------------------------------------
1276 register Region pReg,
1284 register BoxPtr pNextRect;
1290 pNextRect = &pReg->rects[pReg->numRects];
1292 while ((r1 != r1End) && (r2 != r2End))
1297 * Subtrahend missed the boat: go to next subtrahend.
1301 else if (r2->x1 <= x1)
1304 * Subtrahend preceeds minuend: nuke left edge of minuend.
1310 * Minuend completely covered: advance to next minuend and
1311 * reset left fence to edge of new minuend.
1320 * Subtrahend now used up since it doesn't extend beyond
1326 else if (r2->x1 < r1->x2)
1329 * Left part of subtrahend covers part of minuend: add uncovered
1330 * part of minuend to region and skip to next subtrahend.
1333 MEMCHECK(pReg, pNextRect, pReg->rects);
1336 pNextRect->x2 = r2->x1;
1338 pReg->numRects += 1;
1341 assert(pReg->numRects<=pReg->size);
1347 * Minuend used up: advance to new...
1356 * Subtrahend used up
1364 * Minuend used up: add any remaining piece before advancing.
1368 MEMCHECK(pReg, pNextRect, pReg->rects);
1371 pNextRect->x2 = r1->x2;
1373 pReg->numRects += 1;
1375 assert(pReg->numRects<=pReg->size);
1384 * Add remaining minuend rectangles to region.
1389 MEMCHECK(pReg, pNextRect, pReg->rects);
1392 pNextRect->x2 = r1->x2;
1394 pReg->numRects += 1;
1397 assert(pReg->numRects<=pReg->size);
1405 return 0; /* lint */
1409 *-----------------------------------------------------------------------
1411 * Subtract regS from regM and leave the result in regD.
1412 * S stands for subtrahend, M for minuend and D for difference.
1418 * regD is overwritten.
1420 *-----------------------------------------------------------------------
1427 register Region regD)
1429 /* check for trivial reject */
1430 if ( (!(regM->numRects)) || (!(regS->numRects)) ||
1431 (!EXTENTCHECK(®M->extents, ®S->extents)) )
1433 miRegionCopy(regD, regM);
1437 miRegionOp (regD, regM, regS, miSubtractO,
1438 miSubtractNonO1, NULL);
1441 * Can't alter newReg's extents before we call miRegionOp because
1442 * it might be one of the source regions and miRegionOp depends
1443 * on the extents of those regions being the unaltered. Besides, this
1444 * way there's no checking against rectangles that will be nuked
1445 * due to coalescing, so we have to examine fewer rectangles.
1447 miSetExtents (regD);
1452 XXorRegion(Region sra, Region srb, Region dr)
1456 if (! (tra = XCreateRegion()) )
1458 if (! (trb = XCreateRegion()) ) {
1459 XDestroyRegion(tra);
1462 (void) XSubtractRegion(sra,srb,tra);
1463 (void) XSubtractRegion(srb,sra,trb);
1464 (void) XUnionRegion(tra,trb,dr);
1465 XDestroyRegion(tra);
1466 XDestroyRegion(trb);
1471 * Check to see if the region is empty. Assumes a region is passed
1478 if( r->numRects == 0 ) return TRUE;
1483 * Check to see if two regions are equal
1486 XEqualRegion(Region r1, Region r2)
1490 if( r1->numRects != r2->numRects ) return FALSE;
1491 else if( r1->numRects == 0 ) return TRUE;
1492 else if ( r1->extents.x1 != r2->extents.x1 ) return FALSE;
1493 else if ( r1->extents.x2 != r2->extents.x2 ) return FALSE;
1494 else if ( r1->extents.y1 != r2->extents.y1 ) return FALSE;
1495 else if ( r1->extents.y2 != r2->extents.y2 ) return FALSE;
1496 else for( i=0; i < r1->numRects; i++ ) {
1497 if ( r1->rects[i].x1 != r2->rects[i].x1 ) return FALSE;
1498 else if ( r1->rects[i].x2 != r2->rects[i].x2 ) return FALSE;
1499 else if ( r1->rects[i].y1 != r2->rects[i].y1 ) return FALSE;
1500 else if ( r1->rects[i].y2 != r2->rects[i].y2 ) return FALSE;
1512 if (pRegion->numRects == 0)
1514 if (!INBOX(pRegion->extents, x, y))
1516 for (i=0; i<pRegion->numRects; i++)
1518 if (INBOX (pRegion->rects[i], x, y))
1526 register Region region,
1528 unsigned int rwidth, unsigned int rheight)
1530 register BoxPtr pbox;
1531 register BoxPtr pboxEnd;
1533 register BoxPtr prect = ▭
1534 int partIn, partOut;
1538 prect->x2 = rwidth + rx;
1539 prect->y2 = rheight + ry;
1541 /* this is (just) a useful optimization */
1542 if ((region->numRects == 0) || !EXTENTCHECK(®ion->extents, prect))
1543 return(RectangleOut);
1548 /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */
1549 for (pbox = region->rects, pboxEnd = pbox + region->numRects;
1555 continue; /* getting up to speed or skipping remainder of band */
1559 partOut = TRUE; /* missed part of rectangle above */
1560 if (partIn || (pbox->y1 >= prect->y2))
1562 ry = pbox->y1; /* x guaranteed to be == prect->x1 */
1566 continue; /* not far enough over yet */
1570 partOut = TRUE; /* missed part of rectangle to left */
1575 if (pbox->x1 < prect->x2)
1577 partIn = TRUE; /* definitely overlap */
1582 if (pbox->x2 >= prect->x2)
1584 ry = pbox->y2; /* finished with this band */
1585 if (ry >= prect->y2)
1587 rx = prect->x1; /* reset x out to left again */
1591 * Because boxes in a band are maximal width, if the first box
1592 * to overlap the rectangle doesn't completely cover it in that
1593 * band, the rectangle must be partially out, since some of it
1594 * will be uncovered in that band. partIn will have been set true
1602 return(partIn ? ((ry < prect->y2) ? RectanglePart : RectangleIn) :