Annotation of researchv9/X11/src/X.V11R1/lib/X/XRegion.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.