Bug Summary

File:src/Region.c
Location:line 540, column 2
Description:Null pointer argument in call to memory copy function

Annotated Source Code

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