blob: 1acf58151988cd0857c23a73529b25b914408ae3 [file] [log] [blame]
syuri843bf672008-09-19 09:55:50 +00001/************************************************************************
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
Pierre Ossman3157ed92016-05-13 16:00:10 +020030Permission to use, copy, modify, and distribute this software and its
31documentation for any purpose and without fee is hereby granted,
syuri843bf672008-09-19 09:55:50 +000032provided that the above copyright notice appear in all copies and that
Pierre Ossman3157ed92016-05-13 16:00:10 +020033both that copyright notice and this permission notice appear in
syuri843bf672008-09-19 09:55:50 +000034supporting documentation, and that the name of Digital not be
35used in advertising or publicity pertaining to distribution of the
Pierre Ossman3157ed92016-05-13 16:00:10 +020036software without specific, written prior permission.
syuri843bf672008-09-19 09:55:50 +000037
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************************************************************************/
syuri843bf672008-09-19 09:55:50 +000047/*
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
Pierre Ossman88903f22016-05-13 15:53:25 +020073#include <string.h>
74
75#include "Xlibint.h"
76#include "Xutil.h"
syuri843bf672008-09-19 09:55:50 +000077#include "Xregion.h"
syuri843bf672008-09-19 09:55:50 +000078
79#ifndef min
80#define min(a,b) (((a) < (b)) ? (a) : (b))
81#endif
82#ifndef max
83#define max(a,b) (((a) > (b)) ? (a) : (b))
84#endif
85
86#ifdef DEBUG
87#include <stdio.h>
88#define assert(expr) {if (!(expr)) fprintf(stderr,\
89"Assertion failed file %s, line %d: expr\n", __FILE__, __LINE__); }
90#else
91#define assert(expr)
92#endif
93
Pierre Ossman3157ed92016-05-13 16:00:10 +020094typedef int (*overlapProcp)(
95 register Region pReg,
96 register BoxPtr r1,
97 BoxPtr r1End,
98 register BoxPtr r2,
99 BoxPtr r2End,
100 short y1,
101 short y2);
syuri843bf672008-09-19 09:55:50 +0000102
Pierre Ossman3157ed92016-05-13 16:00:10 +0200103typedef int (*nonOverlapProcp)(
104 register Region pReg,
105 register BoxPtr r,
106 BoxPtr rEnd,
107 register short y1,
108 register short y2);
109
110static void miRegionOp(
111 register Region newReg, /* Place to store result */
112 Region reg1, /* First region in operation */
113 Region reg2, /* 2d region in operation */
114 int (*overlapFunc)(
115 register Region pReg,
116 register BoxPtr r1,
117 BoxPtr r1End,
118 register BoxPtr r2,
119 BoxPtr r2End,
120 short y1,
121 short y2), /* Function to call for over-
122 * lapping bands */
123 int (*nonOverlap1Func)(
124 register Region pReg,
125 register BoxPtr r,
126 BoxPtr rEnd,
127 register short y1,
128 register short y2), /* Function to call for non-
129 * overlapping bands in region
130 * 1 */
131 int (*nonOverlap2Func)(
132 register Region pReg,
133 register BoxPtr r,
134 BoxPtr rEnd,
135 register short y1,
136 register short y2)); /* Function to call for non-
137 * overlapping bands in region
138 * 2 */
139
140
syuri843bf672008-09-19 09:55:50 +0000141/* Create a new empty region */
142Region
Pierre Ossman3157ed92016-05-13 16:00:10 +0200143XCreateRegion(void)
syuri843bf672008-09-19 09:55:50 +0000144{
145 Region temp;
146
Pierre Ossman3157ed92016-05-13 16:00:10 +0200147 if (! (temp = Xmalloc(sizeof( REGION ))))
syuri843bf672008-09-19 09:55:50 +0000148 return (Region) NULL;
Pierre Ossman3157ed92016-05-13 16:00:10 +0200149 if (! (temp->rects = Xmalloc(sizeof( BOX )))) {
150 Xfree(temp);
syuri843bf672008-09-19 09:55:50 +0000151 return (Region) NULL;
152 }
153 temp->numRects = 0;
154 temp->extents.x1 = 0;
155 temp->extents.y1 = 0;
156 temp->extents.x2 = 0;
157 temp->extents.y2 = 0;
158 temp->size = 1;
159 return( temp );
160}
161
162int
Pierre Ossman3157ed92016-05-13 16:00:10 +0200163XClipBox(
164 Region r,
165 XRectangle *rect)
syuri843bf672008-09-19 09:55:50 +0000166{
167 rect->x = r->extents.x1;
168 rect->y = r->extents.y1;
169 rect->width = r->extents.x2 - r->extents.x1;
170 rect->height = r->extents.y2 - r->extents.y1;
171 return 1;
172}
173
174int
Pierre Ossman3157ed92016-05-13 16:00:10 +0200175XUnionRectWithRegion(
176 register XRectangle *rect,
177 Region source, Region dest)
syuri843bf672008-09-19 09:55:50 +0000178{
179 REGION region;
180
181 if (!rect->width || !rect->height)
182 return 0;
183 region.rects = &region.extents;
184 region.numRects = 1;
185 region.extents.x1 = rect->x;
186 region.extents.y1 = rect->y;
187 region.extents.x2 = rect->x + rect->width;
188 region.extents.y2 = rect->y + rect->height;
189 region.size = 1;
190
191 return XUnionRegion(&region, source, dest);
192}
193
194/*-
195 *-----------------------------------------------------------------------
196 * miSetExtents --
197 * Reset the extents of a region to what they should be. Called by
198 * miSubtract and miIntersect b/c they can't figure it out along the
199 * way or do so easily, as miUnion can.
200 *
201 * Results:
202 * None.
203 *
204 * Side Effects:
205 * The region's 'extents' structure is overwritten.
206 *
207 *-----------------------------------------------------------------------
208 */
209static void
Pierre Ossman3157ed92016-05-13 16:00:10 +0200210miSetExtents (
211 Region pReg)
syuri843bf672008-09-19 09:55:50 +0000212{
213 register BoxPtr pBox,
214 pBoxEnd,
215 pExtents;
216
217 if (pReg->numRects == 0)
218 {
219 pReg->extents.x1 = 0;
220 pReg->extents.y1 = 0;
221 pReg->extents.x2 = 0;
222 pReg->extents.y2 = 0;
223 return;
224 }
225
226 pExtents = &pReg->extents;
227 pBox = pReg->rects;
228 pBoxEnd = &pBox[pReg->numRects - 1];
229
230 /*
231 * Since pBox is the first rectangle in the region, it must have the
232 * smallest y1 and since pBoxEnd is the last rectangle in the region,
233 * it must have the largest y2, because of banding. Initialize x1 and
234 * x2 from pBox and pBoxEnd, resp., as good things to initialize them
235 * to...
236 */
237 pExtents->x1 = pBox->x1;
238 pExtents->y1 = pBox->y1;
239 pExtents->x2 = pBoxEnd->x2;
240 pExtents->y2 = pBoxEnd->y2;
241
242 assert(pExtents->y1 < pExtents->y2);
243 while (pBox <= pBoxEnd)
244 {
245 if (pBox->x1 < pExtents->x1)
246 {
247 pExtents->x1 = pBox->x1;
248 }
249 if (pBox->x2 > pExtents->x2)
250 {
251 pExtents->x2 = pBox->x2;
252 }
253 pBox++;
254 }
255 assert(pExtents->x1 < pExtents->x2);
256}
257
syuri843bf672008-09-19 09:55:50 +0000258#if 0
259int
Pierre Ossman3157ed92016-05-13 16:00:10 +0200260XSetRegion(
261 Display *dpy,
262 GC gc,
263 register Region r)
syuri843bf672008-09-19 09:55:50 +0000264{
265 register int i;
266 register XRectangle *xr, *pr;
267 register BOX *pb;
268 unsigned long total;
269
270 LockDisplay (dpy);
271 total = r->numRects * sizeof (XRectangle);
272 if ((xr = (XRectangle *) _XAllocTemp(dpy, total))) {
273 for (pr = xr, pb = r->rects, i = r->numRects; --i >= 0; pr++, pb++) {
274 pr->x = pb->x1;
275 pr->y = pb->y1;
276 pr->width = pb->x2 - pb->x1;
277 pr->height = pb->y2 - pb->y1;
278 }
279 }
280 if (xr || !r->numRects)
281 _XSetClipRectangles(dpy, gc, 0, 0, xr, r->numRects, YXBanded);
282 if (xr)
283 _XFreeTemp(dpy, (char *)xr, total);
284 UnlockDisplay(dpy);
285 SyncHandle();
286 return 1;
287}
288#endif
289
290int
Pierre Ossman3157ed92016-05-13 16:00:10 +0200291XDestroyRegion(
292 Region r)
syuri843bf672008-09-19 09:55:50 +0000293{
294 Xfree( (char *) r->rects );
295 Xfree( (char *) r );
296 return 1;
297}
298
299
300/* TranslateRegion(pRegion, x, y)
301 translates in place
302 added by raymond
303*/
304
305int
Pierre Ossman3157ed92016-05-13 16:00:10 +0200306XOffsetRegion(
307 register Region pRegion,
308 register int x,
309 register int y)
syuri843bf672008-09-19 09:55:50 +0000310{
311 register int nbox;
312 register BOX *pbox;
313
314 pbox = pRegion->rects;
315 nbox = pRegion->numRects;
316
317 while(nbox--)
318 {
319 pbox->x1 += x;
320 pbox->x2 += x;
321 pbox->y1 += y;
322 pbox->y2 += y;
323 pbox++;
324 }
325 pRegion->extents.x1 += x;
326 pRegion->extents.x2 += x;
327 pRegion->extents.y1 += y;
328 pRegion->extents.y2 += y;
329 return 1;
330}
331
Pierre Ossman3157ed92016-05-13 16:00:10 +0200332/*
syuri843bf672008-09-19 09:55:50 +0000333 Utility procedure Compress:
Pierre Ossman3157ed92016-05-13 16:00:10 +0200334 Replace r by the region r', where
syuri843bf672008-09-19 09:55:50 +0000335 p in r' iff (Quantifer m <= dx) (p + m in r), and
336 Quantifier is Exists if grow is TRUE, For all if grow is FALSE, and
337 (x,y) + m = (x+m,y) if xdir is TRUE; (x,y+m) if xdir is FALSE.
338
339 Thus, if xdir is TRUE and grow is FALSE, r is replaced by the region
340 of all points p such that p and the next dx points on the same
341 horizontal scan line are all in r. We do this using by noting
342 that p is the head of a run of length 2^i + k iff p is the head
343 of a run of length 2^i and p+2^i is the head of a run of length
344 k. Thus, the loop invariant: s contains the region corresponding
345 to the runs of length shift. r contains the region corresponding
346 to the runs of length 1 + dxo & (shift-1), where dxo is the original
347 value of dx. dx = dxo & ~(shift-1). As parameters, s and t are
348 scratch regions, so that we don't have to allocate them on every
349 call.
350*/
351
352#define ZOpRegion(a,b,c) if (grow) XUnionRegion(a,b,c); \
353 else XIntersectRegion(a,b,c)
354#define ZShiftRegion(a,b) if (xdir) XOffsetRegion(a,b,0); \
355 else XOffsetRegion(a,0,b)
356#define ZCopyRegion(a,b) XUnionRegion(a,a,b)
357
358static void
Pierre Ossman3157ed92016-05-13 16:00:10 +0200359Compress(
360 Region r, Region s, Region t,
361 register unsigned dx,
362 register int xdir, register int grow)
syuri843bf672008-09-19 09:55:50 +0000363{
364 register unsigned shift = 1;
365
366 ZCopyRegion(r, s);
367 while (dx) {
368 if (dx & shift) {
369 ZShiftRegion(r, -(int)shift);
370 ZOpRegion(r, s, r);
371 dx -= shift;
372 if (!dx) break;
373 }
374 ZCopyRegion(s, t);
375 ZShiftRegion(s, -(int)shift);
376 ZOpRegion(s, t, s);
377 shift <<= 1;
378 }
379}
380
381#undef ZOpRegion
382#undef ZShiftRegion
383#undef ZCopyRegion
384
385int
Pierre Ossman3157ed92016-05-13 16:00:10 +0200386XShrinkRegion(
387 Region r,
388 int dx, int dy)
syuri843bf672008-09-19 09:55:50 +0000389{
390 Region s, t;
391 int grow;
392
393 if (!dx && !dy) return 0;
Pierre Ossman3157ed92016-05-13 16:00:10 +0200394 if (! (s = XCreateRegion()) )
395 return 0;
396 if (! (t = XCreateRegion()) ) {
397 XDestroyRegion(s);
398 return 0;
399 }
syuri843bf672008-09-19 09:55:50 +0000400 if ((grow = (dx < 0))) dx = -dx;
401 if (dx) Compress(r, s, t, (unsigned) 2*dx, TRUE, grow);
402 if ((grow = (dy < 0))) dy = -dy;
403 if (dy) Compress(r, s, t, (unsigned) 2*dy, FALSE, grow);
404 XOffsetRegion(r, dx, dy);
405 XDestroyRegion(s);
406 XDestroyRegion(t);
407 return 0;
408}
409
syuri843bf672008-09-19 09:55:50 +0000410
411/*======================================================================
412 * Region Intersection
413 *====================================================================*/
414/*-
415 *-----------------------------------------------------------------------
416 * miIntersectO --
417 * Handle an overlapping band for miIntersect.
418 *
419 * Results:
420 * None.
421 *
422 * Side Effects:
423 * Rectangles may be added to the region.
424 *
425 *-----------------------------------------------------------------------
426 */
427/* static void*/
428static int
Pierre Ossman3157ed92016-05-13 16:00:10 +0200429miIntersectO (
430 register Region pReg,
431 register BoxPtr r1,
432 BoxPtr r1End,
433 register BoxPtr r2,
434 BoxPtr r2End,
435 short y1,
436 short y2)
syuri843bf672008-09-19 09:55:50 +0000437{
438 register short x1;
439 register short x2;
440 register BoxPtr pNextRect;
441
442 pNextRect = &pReg->rects[pReg->numRects];
443
444 while ((r1 != r1End) && (r2 != r2End))
445 {
446 x1 = max(r1->x1,r2->x1);
447 x2 = min(r1->x2,r2->x2);
448
449 /*
450 * If there's any overlap between the two rectangles, add that
451 * overlap to the new region.
452 * There's no need to check for subsumption because the only way
453 * such a need could arise is if some region has two rectangles
454 * right next to each other. Since that should never happen...
455 */
456 if (x1 < x2)
457 {
458 assert(y1<y2);
459
460 MEMCHECK(pReg, pNextRect, pReg->rects);
461 pNextRect->x1 = x1;
462 pNextRect->y1 = y1;
463 pNextRect->x2 = x2;
464 pNextRect->y2 = y2;
465 pReg->numRects += 1;
466 pNextRect++;
467 assert(pReg->numRects <= pReg->size);
468 }
469
470 /*
471 * Need to advance the pointers. Shift the one that extends
472 * to the right the least, since the other still has a chance to
473 * overlap with that region's next rectangle, if you see what I mean.
474 */
475 if (r1->x2 < r2->x2)
476 {
477 r1++;
478 }
479 else if (r2->x2 < r1->x2)
480 {
481 r2++;
482 }
483 else
484 {
485 r1++;
486 r2++;
487 }
488 }
489 return 0; /* lint */
490}
491
492int
Pierre Ossman3157ed92016-05-13 16:00:10 +0200493XIntersectRegion(
494 Region reg1,
495 Region reg2, /* source regions */
496 register Region newReg) /* destination Region */
syuri843bf672008-09-19 09:55:50 +0000497{
498 /* check for trivial reject */
499 if ( (!(reg1->numRects)) || (!(reg2->numRects)) ||
500 (!EXTENTCHECK(&reg1->extents, &reg2->extents)))
501 newReg->numRects = 0;
502 else
Pierre Ossman3157ed92016-05-13 16:00:10 +0200503 miRegionOp (newReg, reg1, reg2,
504 miIntersectO, NULL, NULL);
505
syuri843bf672008-09-19 09:55:50 +0000506 /*
507 * Can't alter newReg's extents before we call miRegionOp because
508 * it might be one of the source regions and miRegionOp depends
509 * on the extents of those regions being the same. Besides, this
510 * way there's no checking against rectangles that will be nuked
511 * due to coalescing, so we have to examine fewer rectangles.
512 */
513 miSetExtents(newReg);
514 return 1;
515}
516
Pierre Ossman3157ed92016-05-13 16:00:10 +0200517static int
518miRegionCopy(
519 register Region dstrgn,
520 register Region rgn)
syuri843bf672008-09-19 09:55:50 +0000521
522{
523 if (dstrgn != rgn) /* don't want to copy to itself */
Pierre Ossman3157ed92016-05-13 16:00:10 +0200524 {
syuri843bf672008-09-19 09:55:50 +0000525 if (dstrgn->size < rgn->numRects)
526 {
527 if (dstrgn->rects)
528 {
529 BOX *prevRects = dstrgn->rects;
Pierre Ossman3157ed92016-05-13 16:00:10 +0200530
531 dstrgn->rects = Xrealloc(dstrgn->rects,
532 rgn->numRects * (sizeof(BOX)));
533 if (! dstrgn->rects) {
syuri843bf672008-09-19 09:55:50 +0000534 Xfree(prevRects);
Pierre Ossman3157ed92016-05-13 16:00:10 +0200535 dstrgn->size = 0;
536 return 0;
syuri843bf672008-09-19 09:55:50 +0000537 }
538 }
539 dstrgn->size = rgn->numRects;
540 }
541 dstrgn->numRects = rgn->numRects;
542 dstrgn->extents.x1 = rgn->extents.x1;
543 dstrgn->extents.y1 = rgn->extents.y1;
544 dstrgn->extents.x2 = rgn->extents.x2;
545 dstrgn->extents.y2 = rgn->extents.y2;
546
547 memcpy((char *) dstrgn->rects, (char *) rgn->rects,
548 (int) (rgn->numRects * sizeof(BOX)));
549 }
syuri843bf672008-09-19 09:55:50 +0000550 return 1;
551}
syuri843bf672008-09-19 09:55:50 +0000552
553/*======================================================================
554 * Generic Region Operator
555 *====================================================================*/
556
557/*-
558 *-----------------------------------------------------------------------
559 * miCoalesce --
560 * Attempt to merge the boxes in the current band with those in the
561 * previous one. Used only by miRegionOp.
562 *
563 * Results:
564 * The new index for the previous band.
565 *
566 * Side Effects:
567 * If coalescing takes place:
568 * - rectangles in the previous band will have their y2 fields
569 * altered.
570 * - pReg->numRects will be decreased.
571 *
572 *-----------------------------------------------------------------------
573 */
574/* static int*/
575static int
Pierre Ossman3157ed92016-05-13 16:00:10 +0200576miCoalesce(
577 register Region pReg, /* Region to coalesce */
578 int prevStart, /* Index of start of previous band */
579 int curStart) /* Index of start of current band */
syuri843bf672008-09-19 09:55:50 +0000580{
581 register BoxPtr pPrevBox; /* Current box in previous band */
582 register BoxPtr pCurBox; /* Current box in current band */
583 register BoxPtr pRegEnd; /* End of region */
584 int curNumRects; /* Number of rectangles in current
585 * band */
586 int prevNumRects; /* Number of rectangles in previous
587 * band */
588 int bandY1; /* Y1 coordinate for current band */
589
590 pRegEnd = &pReg->rects[pReg->numRects];
591
592 pPrevBox = &pReg->rects[prevStart];
593 prevNumRects = curStart - prevStart;
594
595 /*
596 * Figure out how many rectangles are in the current band. Have to do
597 * this because multiple bands could have been added in miRegionOp
598 * at the end when one region has been exhausted.
599 */
600 pCurBox = &pReg->rects[curStart];
601 bandY1 = pCurBox->y1;
602 for (curNumRects = 0;
603 (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1);
604 curNumRects++)
605 {
606 pCurBox++;
607 }
Pierre Ossman3157ed92016-05-13 16:00:10 +0200608
syuri843bf672008-09-19 09:55:50 +0000609 if (pCurBox != pRegEnd)
610 {
611 /*
612 * If more than one band was added, we have to find the start
613 * of the last band added so the next coalescing job can start
614 * at the right place... (given when multiple bands are added,
615 * this may be pointless -- see above).
616 */
617 pRegEnd--;
618 while (pRegEnd[-1].y1 == pRegEnd->y1)
619 {
620 pRegEnd--;
621 }
622 curStart = pRegEnd - pReg->rects;
623 pRegEnd = pReg->rects + pReg->numRects;
624 }
Pierre Ossman3157ed92016-05-13 16:00:10 +0200625
syuri843bf672008-09-19 09:55:50 +0000626 if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
627 pCurBox -= curNumRects;
628 /*
629 * The bands may only be coalesced if the bottom of the previous
630 * matches the top scanline of the current.
631 */
632 if (pPrevBox->y2 == pCurBox->y1)
633 {
634 /*
635 * Make sure the bands have boxes in the same places. This
636 * assumes that boxes have been added in such a way that they
637 * cover the most area possible. I.e. two boxes in a band must
638 * have some horizontal space between them.
639 */
640 do
641 {
642 if ((pPrevBox->x1 != pCurBox->x1) ||
643 (pPrevBox->x2 != pCurBox->x2))
644 {
645 /*
646 * The bands don't line up so they can't be coalesced.
647 */
648 return (curStart);
649 }
650 pPrevBox++;
651 pCurBox++;
652 prevNumRects -= 1;
653 } while (prevNumRects != 0);
654
655 pReg->numRects -= curNumRects;
656 pCurBox -= curNumRects;
657 pPrevBox -= curNumRects;
658
659 /*
660 * The bands may be merged, so set the bottom y of each box
661 * in the previous band to that of the corresponding box in
662 * the current band.
663 */
664 do
665 {
666 pPrevBox->y2 = pCurBox->y2;
667 pPrevBox++;
668 pCurBox++;
669 curNumRects -= 1;
670 } while (curNumRects != 0);
671
672 /*
673 * If only one band was added to the region, we have to backup
674 * curStart to the start of the previous band.
675 *
676 * If more than one band was added to the region, copy the
677 * other bands down. The assumption here is that the other bands
678 * came from the same region as the current one and no further
679 * coalescing can be done on them since it's all been done
680 * already... curStart is already in the right place.
681 */
682 if (pCurBox == pRegEnd)
683 {
684 curStart = prevStart;
685 }
686 else
687 {
688 do
689 {
690 *pPrevBox++ = *pCurBox++;
691 } while (pCurBox != pRegEnd);
692 }
Pierre Ossman3157ed92016-05-13 16:00:10 +0200693
syuri843bf672008-09-19 09:55:50 +0000694 }
695 }
696 return (curStart);
697}
698
699/*-
700 *-----------------------------------------------------------------------
701 * miRegionOp --
702 * Apply an operation to two regions. Called by miUnion, miInverse,
703 * miSubtract, miIntersect...
704 *
705 * Results:
706 * None.
707 *
708 * Side Effects:
709 * The new region is overwritten.
710 *
711 * Notes:
712 * The idea behind this function is to view the two regions as sets.
713 * Together they cover a rectangle of area that this function divides
714 * into horizontal bands where points are covered only by one region
715 * or by both. For the first case, the nonOverlapFunc is called with
716 * each the band and the band's upper and lower extents. For the
717 * second, the overlapFunc is called to process the entire band. It
718 * is responsible for clipping the rectangles in the band, though
719 * this function provides the boundaries.
720 * At the end of each band, the new region is coalesced, if possible,
721 * to reduce the number of rectangles in the region.
722 *
723 *-----------------------------------------------------------------------
724 */
725/* static void*/
726static void
Pierre Ossman3157ed92016-05-13 16:00:10 +0200727miRegionOp(
728 register Region newReg, /* Place to store result */
729 Region reg1, /* First region in operation */
730 Region reg2, /* 2d region in operation */
731 int (*overlapFunc)(
732 register Region pReg,
733 register BoxPtr r1,
734 BoxPtr r1End,
735 register BoxPtr r2,
736 BoxPtr r2End,
737 short y1,
738 short y2), /* Function to call for over-
syuri843bf672008-09-19 09:55:50 +0000739 * lapping bands */
Pierre Ossman3157ed92016-05-13 16:00:10 +0200740 int (*nonOverlap1Func)(
741 register Region pReg,
742 register BoxPtr r,
743 BoxPtr rEnd,
744 register short y1,
745 register short y2), /* Function to call for non-
syuri843bf672008-09-19 09:55:50 +0000746 * overlapping bands in region
747 * 1 */
Pierre Ossman3157ed92016-05-13 16:00:10 +0200748 int (*nonOverlap2Func)(
749 register Region pReg,
750 register BoxPtr r,
751 BoxPtr rEnd,
752 register short y1,
753 register short y2)) /* Function to call for non-
syuri843bf672008-09-19 09:55:50 +0000754 * overlapping bands in region
755 * 2 */
756{
757 register BoxPtr r1; /* Pointer into first region */
758 register BoxPtr r2; /* Pointer into 2d region */
759 BoxPtr r1End; /* End of 1st region */
760 BoxPtr r2End; /* End of 2d region */
761 register short ybot; /* Bottom of intersection */
762 register short ytop; /* Top of intersection */
763 BoxPtr oldRects; /* Old rects for newReg */
764 int prevBand; /* Index of start of
765 * previous band in newReg */
766 int curBand; /* Index of start of current
767 * band in newReg */
768 register BoxPtr r1BandEnd; /* End of current band in r1 */
769 register BoxPtr r2BandEnd; /* End of current band in r2 */
770 short top; /* Top of non-overlapping
771 * band */
772 short bot; /* Bottom of non-overlapping
773 * band */
Pierre Ossman3157ed92016-05-13 16:00:10 +0200774
syuri843bf672008-09-19 09:55:50 +0000775 /*
776 * Initialization:
777 * set r1, r2, r1End and r2End appropriately, preserve the important
778 * parts of the destination region until the end in case it's one of
779 * the two source regions, then mark the "new" region empty, allocating
780 * another array of rectangles for it to use.
781 */
782 r1 = reg1->rects;
783 r2 = reg2->rects;
784 r1End = r1 + reg1->numRects;
785 r2End = r2 + reg2->numRects;
Pierre Ossman3157ed92016-05-13 16:00:10 +0200786
syuri843bf672008-09-19 09:55:50 +0000787 oldRects = newReg->rects;
Pierre Ossman3157ed92016-05-13 16:00:10 +0200788
syuri843bf672008-09-19 09:55:50 +0000789 EMPTY_REGION(newReg);
790
791 /*
792 * Allocate a reasonable number of rectangles for the new region. The idea
793 * is to allocate enough so the individual functions don't need to
794 * reallocate and copy the array, which is time consuming, yet we don't
795 * have to worry about using too much memory. I hope to be able to
796 * nuke the Xrealloc() at the end of this function eventually.
797 */
798 newReg->size = max(reg1->numRects,reg2->numRects) * 2;
799
Pierre Ossman3157ed92016-05-13 16:00:10 +0200800 if (! (newReg->rects = Xmalloc (sizeof(BoxRec) * newReg->size))) {
syuri843bf672008-09-19 09:55:50 +0000801 newReg->size = 0;
802 return;
803 }
Pierre Ossman3157ed92016-05-13 16:00:10 +0200804
syuri843bf672008-09-19 09:55:50 +0000805 /*
806 * Initialize ybot and ytop.
807 * In the upcoming loop, ybot and ytop serve different functions depending
808 * on whether the band being handled is an overlapping or non-overlapping
809 * band.
810 * In the case of a non-overlapping band (only one of the regions
811 * has points in the band), ybot is the bottom of the most recent
812 * intersection and thus clips the top of the rectangles in that band.
813 * ytop is the top of the next intersection between the two regions and
814 * serves to clip the bottom of the rectangles in the current band.
815 * For an overlapping band (where the two regions intersect), ytop clips
816 * the top of the rectangles of both regions and ybot clips the bottoms.
817 */
818 if (reg1->extents.y1 < reg2->extents.y1)
819 ybot = reg1->extents.y1;
820 else
821 ybot = reg2->extents.y1;
Pierre Ossman3157ed92016-05-13 16:00:10 +0200822
syuri843bf672008-09-19 09:55:50 +0000823 /*
824 * prevBand serves to mark the start of the previous band so rectangles
825 * can be coalesced into larger rectangles. qv. miCoalesce, above.
826 * In the beginning, there is no previous band, so prevBand == curBand
827 * (curBand is set later on, of course, but the first band will always
828 * start at index 0). prevBand and curBand must be indices because of
829 * the possible expansion, and resultant moving, of the new region's
830 * array of rectangles.
831 */
832 prevBand = 0;
Pierre Ossman3157ed92016-05-13 16:00:10 +0200833
syuri843bf672008-09-19 09:55:50 +0000834 do
835 {
836 curBand = newReg->numRects;
837
838 /*
839 * This algorithm proceeds one source-band (as opposed to a
840 * destination band, which is determined by where the two regions
841 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
842 * rectangle after the last one in the current band for their
843 * respective regions.
844 */
845 r1BandEnd = r1;
846 while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1))
847 {
848 r1BandEnd++;
849 }
Pierre Ossman3157ed92016-05-13 16:00:10 +0200850
syuri843bf672008-09-19 09:55:50 +0000851 r2BandEnd = r2;
852 while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1))
853 {
854 r2BandEnd++;
855 }
Pierre Ossman3157ed92016-05-13 16:00:10 +0200856
syuri843bf672008-09-19 09:55:50 +0000857 /*
858 * First handle the band that doesn't intersect, if any.
859 *
860 * Note that attention is restricted to one band in the
861 * non-intersecting region at once, so if a region has n
862 * bands between the current position and the next place it overlaps
863 * the other, this entire loop will be passed through n times.
864 */
865 if (r1->y1 < r2->y1)
866 {
867 top = max(r1->y1,ybot);
868 bot = min(r1->y2,r2->y1);
869
Pierre Ossman3157ed92016-05-13 16:00:10 +0200870 if ((top != bot) && (nonOverlap1Func != NULL))
syuri843bf672008-09-19 09:55:50 +0000871 {
872 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
873 }
874
875 ytop = r2->y1;
876 }
877 else if (r2->y1 < r1->y1)
878 {
879 top = max(r2->y1,ybot);
880 bot = min(r2->y2,r1->y1);
881
Pierre Ossman3157ed92016-05-13 16:00:10 +0200882 if ((top != bot) && (nonOverlap2Func != NULL))
syuri843bf672008-09-19 09:55:50 +0000883 {
884 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
885 }
886
887 ytop = r1->y1;
888 }
889 else
890 {
891 ytop = r1->y1;
892 }
893
894 /*
895 * If any rectangles got added to the region, try and coalesce them
896 * with rectangles from the previous band. Note we could just do
897 * this test in miCoalesce, but some machines incur a not
898 * inconsiderable cost for function calls, so...
899 */
900 if (newReg->numRects != curBand)
901 {
902 prevBand = miCoalesce (newReg, prevBand, curBand);
903 }
904
905 /*
906 * Now see if we've hit an intersecting band. The two bands only
907 * intersect if ybot > ytop
908 */
909 ybot = min(r1->y2, r2->y2);
910 curBand = newReg->numRects;
911 if (ybot > ytop)
912 {
913 (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
914
915 }
Pierre Ossman3157ed92016-05-13 16:00:10 +0200916
syuri843bf672008-09-19 09:55:50 +0000917 if (newReg->numRects != curBand)
918 {
919 prevBand = miCoalesce (newReg, prevBand, curBand);
920 }
921
922 /*
923 * If we've finished with a band (y2 == ybot) we skip forward
924 * in the region to the next band.
925 */
926 if (r1->y2 == ybot)
927 {
928 r1 = r1BandEnd;
929 }
930 if (r2->y2 == ybot)
931 {
932 r2 = r2BandEnd;
933 }
934 } while ((r1 != r1End) && (r2 != r2End));
935
936 /*
937 * Deal with whichever region still has rectangles left.
938 */
939 curBand = newReg->numRects;
940 if (r1 != r1End)
941 {
Pierre Ossman3157ed92016-05-13 16:00:10 +0200942 if (nonOverlap1Func != NULL)
syuri843bf672008-09-19 09:55:50 +0000943 {
944 do
945 {
946 r1BandEnd = r1;
947 while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1))
948 {
949 r1BandEnd++;
950 }
951 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
952 max(r1->y1,ybot), r1->y2);
953 r1 = r1BandEnd;
954 } while (r1 != r1End);
955 }
956 }
Pierre Ossman3157ed92016-05-13 16:00:10 +0200957 else if ((r2 != r2End) && (nonOverlap2Func != NULL))
syuri843bf672008-09-19 09:55:50 +0000958 {
959 do
960 {
961 r2BandEnd = r2;
962 while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1))
963 {
964 r2BandEnd++;
965 }
966 (* nonOverlap2Func) (newReg, r2, r2BandEnd,
967 max(r2->y1,ybot), r2->y2);
968 r2 = r2BandEnd;
969 } while (r2 != r2End);
970 }
971
972 if (newReg->numRects != curBand)
973 {
974 (void) miCoalesce (newReg, prevBand, curBand);
975 }
976
977 /*
978 * A bit of cleanup. To keep regions from growing without bound,
979 * we shrink the array of rectangles to match the new number of
980 * rectangles in the region. This never goes to 0, however...
981 *
982 * Only do this stuff if the number of rectangles allocated is more than
983 * twice the number of rectangles in the region (a simple optimization...).
984 */
985 if (newReg->numRects < (newReg->size >> 1))
986 {
987 if (REGION_NOT_EMPTY(newReg))
988 {
989 BoxPtr prev_rects = newReg->rects;
Pierre Ossman3157ed92016-05-13 16:00:10 +0200990 newReg->rects = Xrealloc (newReg->rects,
991 sizeof(BoxRec) * newReg->numRects);
syuri843bf672008-09-19 09:55:50 +0000992 if (! newReg->rects)
993 newReg->rects = prev_rects;
Pierre Ossman3157ed92016-05-13 16:00:10 +0200994 else
995 newReg->size = newReg->numRects;
syuri843bf672008-09-19 09:55:50 +0000996 }
997 else
998 {
999 /*
1000 * No point in doing the extra work involved in an Xrealloc if
1001 * the region is empty
1002 */
1003 newReg->size = 1;
Pierre Ossman3157ed92016-05-13 16:00:10 +02001004 Xfree(newReg->rects);
1005 newReg->rects = Xmalloc(sizeof(BoxRec));
syuri843bf672008-09-19 09:55:50 +00001006 }
1007 }
Pierre Ossman3157ed92016-05-13 16:00:10 +02001008 Xfree (oldRects);
syuri843bf672008-09-19 09:55:50 +00001009 return;
1010}
1011
1012
1013/*======================================================================
1014 * Region Union
1015 *====================================================================*/
1016
1017/*-
1018 *-----------------------------------------------------------------------
1019 * miUnionNonO --
1020 * Handle a non-overlapping band for the union operation. Just
1021 * Adds the rectangles into the region. Doesn't have to check for
1022 * subsumption or anything.
1023 *
1024 * Results:
1025 * None.
1026 *
1027 * Side Effects:
1028 * pReg->numRects is incremented and the final rectangles overwritten
1029 * with the rectangles we're passed.
1030 *
1031 *-----------------------------------------------------------------------
1032 */
1033/* static void*/
1034static int
Pierre Ossman3157ed92016-05-13 16:00:10 +02001035miUnionNonO (
1036 register Region pReg,
1037 register BoxPtr r,
1038 BoxPtr rEnd,
1039 register short y1,
1040 register short y2)
syuri843bf672008-09-19 09:55:50 +00001041{
1042 register BoxPtr pNextRect;
1043
1044 pNextRect = &pReg->rects[pReg->numRects];
1045
1046 assert(y1 < y2);
1047
1048 while (r != rEnd)
1049 {
1050 assert(r->x1 < r->x2);
1051 MEMCHECK(pReg, pNextRect, pReg->rects);
1052 pNextRect->x1 = r->x1;
1053 pNextRect->y1 = y1;
1054 pNextRect->x2 = r->x2;
1055 pNextRect->y2 = y2;
1056 pReg->numRects += 1;
1057 pNextRect++;
1058
1059 assert(pReg->numRects<=pReg->size);
1060 r++;
1061 }
1062 return 0; /* lint */
1063}
1064
1065
1066/*-
1067 *-----------------------------------------------------------------------
1068 * miUnionO --
1069 * Handle an overlapping band for the union operation. Picks the
1070 * left-most rectangle each time and merges it into the region.
1071 *
1072 * Results:
1073 * None.
1074 *
1075 * Side Effects:
1076 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1077 * be changed.
1078 *
1079 *-----------------------------------------------------------------------
1080 */
1081
1082/* static void*/
1083static int
Pierre Ossman3157ed92016-05-13 16:00:10 +02001084miUnionO (
1085 register Region pReg,
1086 register BoxPtr r1,
1087 BoxPtr r1End,
1088 register BoxPtr r2,
1089 BoxPtr r2End,
1090 register short y1,
1091 register short y2)
syuri843bf672008-09-19 09:55:50 +00001092{
1093 register BoxPtr pNextRect;
Pierre Ossman3157ed92016-05-13 16:00:10 +02001094
syuri843bf672008-09-19 09:55:50 +00001095 pNextRect = &pReg->rects[pReg->numRects];
1096
1097#define MERGERECT(r) \
1098 if ((pReg->numRects != 0) && \
1099 (pNextRect[-1].y1 == y1) && \
1100 (pNextRect[-1].y2 == y2) && \
1101 (pNextRect[-1].x2 >= r->x1)) \
1102 { \
1103 if (pNextRect[-1].x2 < r->x2) \
1104 { \
1105 pNextRect[-1].x2 = r->x2; \
1106 assert(pNextRect[-1].x1<pNextRect[-1].x2); \
1107 } \
1108 } \
1109 else \
1110 { \
1111 MEMCHECK(pReg, pNextRect, pReg->rects); \
1112 pNextRect->y1 = y1; \
1113 pNextRect->y2 = y2; \
1114 pNextRect->x1 = r->x1; \
1115 pNextRect->x2 = r->x2; \
1116 pReg->numRects += 1; \
1117 pNextRect += 1; \
1118 } \
1119 assert(pReg->numRects<=pReg->size);\
1120 r++;
Pierre Ossman3157ed92016-05-13 16:00:10 +02001121
syuri843bf672008-09-19 09:55:50 +00001122 assert (y1<y2);
1123 while ((r1 != r1End) && (r2 != r2End))
1124 {
1125 if (r1->x1 < r2->x1)
1126 {
1127 MERGERECT(r1);
1128 }
1129 else
1130 {
1131 MERGERECT(r2);
1132 }
1133 }
Pierre Ossman3157ed92016-05-13 16:00:10 +02001134
syuri843bf672008-09-19 09:55:50 +00001135 if (r1 != r1End)
1136 {
1137 do
1138 {
1139 MERGERECT(r1);
1140 } while (r1 != r1End);
1141 }
1142 else while (r2 != r2End)
1143 {
1144 MERGERECT(r2);
1145 }
1146 return 0; /* lint */
1147}
1148
1149int
Pierre Ossman3157ed92016-05-13 16:00:10 +02001150XUnionRegion(
1151 Region reg1,
1152 Region reg2, /* source regions */
1153 Region newReg) /* destination Region */
syuri843bf672008-09-19 09:55:50 +00001154{
1155 /* checks all the simple cases */
1156
1157 /*
1158 * Region 1 and 2 are the same or region 1 is empty
1159 */
1160 if ( (reg1 == reg2) || (!(reg1->numRects)) )
1161 {
1162 if (newReg != reg2)
Pierre Ossman3157ed92016-05-13 16:00:10 +02001163 return miRegionCopy(newReg, reg2);
syuri843bf672008-09-19 09:55:50 +00001164 return 1;
1165 }
1166
1167 /*
1168 * if nothing to union (region 2 empty)
1169 */
1170 if (!(reg2->numRects))
1171 {
1172 if (newReg != reg1)
Pierre Ossman3157ed92016-05-13 16:00:10 +02001173 return miRegionCopy(newReg, reg1);
syuri843bf672008-09-19 09:55:50 +00001174 return 1;
1175 }
1176
1177 /*
1178 * Region 1 completely subsumes region 2
1179 */
Pierre Ossman3157ed92016-05-13 16:00:10 +02001180 if ((reg1->numRects == 1) &&
syuri843bf672008-09-19 09:55:50 +00001181 (reg1->extents.x1 <= reg2->extents.x1) &&
1182 (reg1->extents.y1 <= reg2->extents.y1) &&
1183 (reg1->extents.x2 >= reg2->extents.x2) &&
1184 (reg1->extents.y2 >= reg2->extents.y2))
1185 {
1186 if (newReg != reg1)
Pierre Ossman3157ed92016-05-13 16:00:10 +02001187 return miRegionCopy(newReg, reg1);
syuri843bf672008-09-19 09:55:50 +00001188 return 1;
1189 }
1190
1191 /*
1192 * Region 2 completely subsumes region 1
1193 */
Pierre Ossman3157ed92016-05-13 16:00:10 +02001194 if ((reg2->numRects == 1) &&
syuri843bf672008-09-19 09:55:50 +00001195 (reg2->extents.x1 <= reg1->extents.x1) &&
1196 (reg2->extents.y1 <= reg1->extents.y1) &&
1197 (reg2->extents.x2 >= reg1->extents.x2) &&
1198 (reg2->extents.y2 >= reg1->extents.y2))
1199 {
1200 if (newReg != reg2)
Pierre Ossman3157ed92016-05-13 16:00:10 +02001201 return miRegionCopy(newReg, reg2);
syuri843bf672008-09-19 09:55:50 +00001202 return 1;
1203 }
1204
Pierre Ossman3157ed92016-05-13 16:00:10 +02001205 miRegionOp (newReg, reg1, reg2, miUnionO,
1206 miUnionNonO, miUnionNonO);
syuri843bf672008-09-19 09:55:50 +00001207
1208 newReg->extents.x1 = min(reg1->extents.x1, reg2->extents.x1);
1209 newReg->extents.y1 = min(reg1->extents.y1, reg2->extents.y1);
1210 newReg->extents.x2 = max(reg1->extents.x2, reg2->extents.x2);
1211 newReg->extents.y2 = max(reg1->extents.y2, reg2->extents.y2);
1212
1213 return 1;
1214}
1215
1216
1217/*======================================================================
1218 * Region Subtraction
1219 *====================================================================*/
1220
1221/*-
1222 *-----------------------------------------------------------------------
1223 * miSubtractNonO --
1224 * Deal with non-overlapping band for subtraction. Any parts from
1225 * region 2 we discard. Anything from region 1 we add to the region.
1226 *
1227 * Results:
1228 * None.
1229 *
1230 * Side Effects:
1231 * pReg may be affected.
1232 *
1233 *-----------------------------------------------------------------------
1234 */
1235/* static void*/
1236static int
Pierre Ossman3157ed92016-05-13 16:00:10 +02001237miSubtractNonO1 (
1238 register Region pReg,
1239 register BoxPtr r,
1240 BoxPtr rEnd,
1241 register short y1,
1242 register short y2)
syuri843bf672008-09-19 09:55:50 +00001243{
1244 register BoxPtr pNextRect;
Pierre Ossman3157ed92016-05-13 16:00:10 +02001245
syuri843bf672008-09-19 09:55:50 +00001246 pNextRect = &pReg->rects[pReg->numRects];
Pierre Ossman3157ed92016-05-13 16:00:10 +02001247
syuri843bf672008-09-19 09:55:50 +00001248 assert(y1<y2);
1249
1250 while (r != rEnd)
1251 {
1252 assert(r->x1<r->x2);
1253 MEMCHECK(pReg, pNextRect, pReg->rects);
1254 pNextRect->x1 = r->x1;
1255 pNextRect->y1 = y1;
1256 pNextRect->x2 = r->x2;
1257 pNextRect->y2 = y2;
1258 pReg->numRects += 1;
1259 pNextRect++;
1260
1261 assert(pReg->numRects <= pReg->size);
1262
1263 r++;
1264 }
1265 return 0; /* lint */
1266}
1267
1268/*-
1269 *-----------------------------------------------------------------------
1270 * miSubtractO --
1271 * Overlapping band subtraction. x1 is the left-most point not yet
1272 * checked.
1273 *
1274 * Results:
1275 * None.
1276 *
1277 * Side Effects:
1278 * pReg may have rectangles added to it.
1279 *
1280 *-----------------------------------------------------------------------
1281 */
1282/* static void*/
1283static int
Pierre Ossman3157ed92016-05-13 16:00:10 +02001284miSubtractO (
1285 register Region pReg,
1286 register BoxPtr r1,
1287 BoxPtr r1End,
1288 register BoxPtr r2,
1289 BoxPtr r2End,
1290 register short y1,
1291 register short y2)
syuri843bf672008-09-19 09:55:50 +00001292{
1293 register BoxPtr pNextRect;
1294 register int x1;
Pierre Ossman3157ed92016-05-13 16:00:10 +02001295
syuri843bf672008-09-19 09:55:50 +00001296 x1 = r1->x1;
Pierre Ossman3157ed92016-05-13 16:00:10 +02001297
syuri843bf672008-09-19 09:55:50 +00001298 assert(y1<y2);
1299 pNextRect = &pReg->rects[pReg->numRects];
1300
1301 while ((r1 != r1End) && (r2 != r2End))
1302 {
1303 if (r2->x2 <= x1)
1304 {
1305 /*
1306 * Subtrahend missed the boat: go to next subtrahend.
1307 */
1308 r2++;
1309 }
1310 else if (r2->x1 <= x1)
1311 {
1312 /*
klemens0536d092017-01-28 20:56:56 +01001313 * Subtrahend preceds minuend: nuke left edge of minuend.
syuri843bf672008-09-19 09:55:50 +00001314 */
1315 x1 = r2->x2;
1316 if (x1 >= r1->x2)
1317 {
1318 /*
1319 * Minuend completely covered: advance to next minuend and
1320 * reset left fence to edge of new minuend.
1321 */
1322 r1++;
1323 if (r1 != r1End)
1324 x1 = r1->x1;
1325 }
1326 else
1327 {
1328 /*
1329 * Subtrahend now used up since it doesn't extend beyond
1330 * minuend
1331 */
1332 r2++;
1333 }
1334 }
1335 else if (r2->x1 < r1->x2)
1336 {
1337 /*
1338 * Left part of subtrahend covers part of minuend: add uncovered
1339 * part of minuend to region and skip to next subtrahend.
1340 */
1341 assert(x1<r2->x1);
1342 MEMCHECK(pReg, pNextRect, pReg->rects);
1343 pNextRect->x1 = x1;
1344 pNextRect->y1 = y1;
1345 pNextRect->x2 = r2->x1;
1346 pNextRect->y2 = y2;
1347 pReg->numRects += 1;
1348 pNextRect++;
1349
1350 assert(pReg->numRects<=pReg->size);
1351
1352 x1 = r2->x2;
1353 if (x1 >= r1->x2)
1354 {
1355 /*
1356 * Minuend used up: advance to new...
1357 */
1358 r1++;
1359 if (r1 != r1End)
1360 x1 = r1->x1;
1361 }
1362 else
1363 {
1364 /*
1365 * Subtrahend used up
1366 */
1367 r2++;
1368 }
1369 }
1370 else
1371 {
1372 /*
1373 * Minuend used up: add any remaining piece before advancing.
1374 */
1375 if (r1->x2 > x1)
1376 {
1377 MEMCHECK(pReg, pNextRect, pReg->rects);
1378 pNextRect->x1 = x1;
1379 pNextRect->y1 = y1;
1380 pNextRect->x2 = r1->x2;
1381 pNextRect->y2 = y2;
1382 pReg->numRects += 1;
1383 pNextRect++;
1384 assert(pReg->numRects<=pReg->size);
1385 }
1386 r1++;
Pierre Ossman3157ed92016-05-13 16:00:10 +02001387 if (r1 != r1End)
1388 x1 = r1->x1;
syuri843bf672008-09-19 09:55:50 +00001389 }
1390 }
1391
1392 /*
1393 * Add remaining minuend rectangles to region.
1394 */
1395 while (r1 != r1End)
1396 {
1397 assert(x1<r1->x2);
1398 MEMCHECK(pReg, pNextRect, pReg->rects);
1399 pNextRect->x1 = x1;
1400 pNextRect->y1 = y1;
1401 pNextRect->x2 = r1->x2;
1402 pNextRect->y2 = y2;
1403 pReg->numRects += 1;
1404 pNextRect++;
1405
1406 assert(pReg->numRects<=pReg->size);
1407
1408 r1++;
1409 if (r1 != r1End)
1410 {
1411 x1 = r1->x1;
1412 }
1413 }
1414 return 0; /* lint */
1415}
Pierre Ossman3157ed92016-05-13 16:00:10 +02001416
syuri843bf672008-09-19 09:55:50 +00001417/*-
1418 *-----------------------------------------------------------------------
1419 * miSubtract --
1420 * Subtract regS from regM and leave the result in regD.
1421 * S stands for subtrahend, M for minuend and D for difference.
1422 *
1423 * Results:
1424 * TRUE.
1425 *
1426 * Side Effects:
1427 * regD is overwritten.
1428 *
1429 *-----------------------------------------------------------------------
1430 */
1431
1432int
Pierre Ossman3157ed92016-05-13 16:00:10 +02001433XSubtractRegion(
1434 Region regM,
1435 Region regS,
1436 register Region regD)
syuri843bf672008-09-19 09:55:50 +00001437{
1438 /* check for trivial reject */
1439 if ( (!(regM->numRects)) || (!(regS->numRects)) ||
1440 (!EXTENTCHECK(&regM->extents, &regS->extents)) )
1441 {
Pierre Ossman3157ed92016-05-13 16:00:10 +02001442 return miRegionCopy(regD, regM);
syuri843bf672008-09-19 09:55:50 +00001443 }
Pierre Ossman3157ed92016-05-13 16:00:10 +02001444
1445 miRegionOp (regD, regM, regS, miSubtractO,
1446 miSubtractNonO1, NULL);
syuri843bf672008-09-19 09:55:50 +00001447
1448 /*
1449 * Can't alter newReg's extents before we call miRegionOp because
1450 * it might be one of the source regions and miRegionOp depends
1451 * on the extents of those regions being the unaltered. Besides, this
1452 * way there's no checking against rectangles that will be nuked
1453 * due to coalescing, so we have to examine fewer rectangles.
1454 */
1455 miSetExtents (regD);
1456 return 1;
1457}
1458
1459int
Pierre Ossman3157ed92016-05-13 16:00:10 +02001460XXorRegion(Region sra, Region srb, Region dr)
syuri843bf672008-09-19 09:55:50 +00001461{
1462 Region tra, trb;
1463
Pierre Ossman3157ed92016-05-13 16:00:10 +02001464 if (! (tra = XCreateRegion()) )
syuri843bf672008-09-19 09:55:50 +00001465 return 0;
Pierre Ossman3157ed92016-05-13 16:00:10 +02001466 if (! (trb = XCreateRegion()) ) {
1467 XDestroyRegion(tra);
1468 return 0;
1469 }
syuri843bf672008-09-19 09:55:50 +00001470 (void) XSubtractRegion(sra,srb,tra);
1471 (void) XSubtractRegion(srb,sra,trb);
1472 (void) XUnionRegion(tra,trb,dr);
1473 XDestroyRegion(tra);
1474 XDestroyRegion(trb);
1475 return 0;
1476}
1477
1478/*
Pierre Ossman3157ed92016-05-13 16:00:10 +02001479 * Check to see if the region is empty. Assumes a region is passed
syuri843bf672008-09-19 09:55:50 +00001480 * as a parameter
1481 */
Pierre Ossman3157ed92016-05-13 16:00:10 +02001482int
1483XEmptyRegion(
1484 Region r)
syuri843bf672008-09-19 09:55:50 +00001485{
1486 if( r->numRects == 0 ) return TRUE;
1487 else return FALSE;
1488}
1489
1490/*
Pierre Ossman3157ed92016-05-13 16:00:10 +02001491 * Check to see if two regions are equal
syuri843bf672008-09-19 09:55:50 +00001492 */
Pierre Ossman3157ed92016-05-13 16:00:10 +02001493int
1494XEqualRegion(Region r1, Region r2)
syuri843bf672008-09-19 09:55:50 +00001495{
1496 int i;
1497
1498 if( r1->numRects != r2->numRects ) return FALSE;
1499 else if( r1->numRects == 0 ) return TRUE;
1500 else if ( r1->extents.x1 != r2->extents.x1 ) return FALSE;
1501 else if ( r1->extents.x2 != r2->extents.x2 ) return FALSE;
1502 else if ( r1->extents.y1 != r2->extents.y1 ) return FALSE;
1503 else if ( r1->extents.y2 != r2->extents.y2 ) return FALSE;
1504 else for( i=0; i < r1->numRects; i++ ) {
1505 if ( r1->rects[i].x1 != r2->rects[i].x1 ) return FALSE;
1506 else if ( r1->rects[i].x2 != r2->rects[i].x2 ) return FALSE;
1507 else if ( r1->rects[i].y1 != r2->rects[i].y1 ) return FALSE;
1508 else if ( r1->rects[i].y2 != r2->rects[i].y2 ) return FALSE;
1509 }
1510 return TRUE;
1511}
1512
Pierre Ossman3157ed92016-05-13 16:00:10 +02001513int
1514XPointInRegion(
1515 Region pRegion,
1516 int x, int y)
syuri843bf672008-09-19 09:55:50 +00001517{
1518 int i;
1519
1520 if (pRegion->numRects == 0)
1521 return FALSE;
1522 if (!INBOX(pRegion->extents, x, y))
1523 return FALSE;
1524 for (i=0; i<pRegion->numRects; i++)
1525 {
1526 if (INBOX (pRegion->rects[i], x, y))
1527 return TRUE;
1528 }
1529 return FALSE;
1530}
1531
Pierre Ossman3157ed92016-05-13 16:00:10 +02001532int
1533XRectInRegion(
1534 register Region region,
1535 int rx, int ry,
1536 unsigned int rwidth, unsigned int rheight)
syuri843bf672008-09-19 09:55:50 +00001537{
1538 register BoxPtr pbox;
1539 register BoxPtr pboxEnd;
1540 Box rect;
1541 register BoxPtr prect = &rect;
1542 int partIn, partOut;
1543
1544 prect->x1 = rx;
1545 prect->y1 = ry;
1546 prect->x2 = rwidth + rx;
1547 prect->y2 = rheight + ry;
Pierre Ossman3157ed92016-05-13 16:00:10 +02001548
syuri843bf672008-09-19 09:55:50 +00001549 /* this is (just) a useful optimization */
1550 if ((region->numRects == 0) || !EXTENTCHECK(&region->extents, prect))
1551 return(RectangleOut);
1552
1553 partOut = FALSE;
1554 partIn = FALSE;
1555
1556 /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */
1557 for (pbox = region->rects, pboxEnd = pbox + region->numRects;
1558 pbox < pboxEnd;
1559 pbox++)
1560 {
1561
1562 if (pbox->y2 <= ry)
1563 continue; /* getting up to speed or skipping remainder of band */
1564
1565 if (pbox->y1 > ry)
1566 {
1567 partOut = TRUE; /* missed part of rectangle above */
1568 if (partIn || (pbox->y1 >= prect->y2))
1569 break;
1570 ry = pbox->y1; /* x guaranteed to be == prect->x1 */
1571 }
1572
1573 if (pbox->x2 <= rx)
1574 continue; /* not far enough over yet */
1575
1576 if (pbox->x1 > rx)
1577 {
1578 partOut = TRUE; /* missed part of rectangle to left */
1579 if (partIn)
1580 break;
1581 }
1582
1583 if (pbox->x1 < prect->x2)
1584 {
1585 partIn = TRUE; /* definitely overlap */
1586 if (partOut)
1587 break;
1588 }
1589
1590 if (pbox->x2 >= prect->x2)
1591 {
1592 ry = pbox->y2; /* finished with this band */
1593 if (ry >= prect->y2)
1594 break;
1595 rx = prect->x1; /* reset x out to left again */
1596 } else
1597 {
1598 /*
1599 * Because boxes in a band are maximal width, if the first box
1600 * to overlap the rectangle doesn't completely cover it in that
1601 * band, the rectangle must be partially out, since some of it
1602 * will be uncovered in that band. partIn will have been set true
1603 * by now...
1604 */
1605 break;
1606 }
1607
1608 }
1609
Pierre Ossman3157ed92016-05-13 16:00:10 +02001610 return(partIn ? ((ry < prect->y2) ? RectanglePart : RectangleIn) :
syuri843bf672008-09-19 09:55:50 +00001611 RectangleOut);
1612}