Annotation of researchv9/X11/src/X.V11R1/server/ddx/mi/miregion.c, revision 1.1

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

unix.superglobalmegacorp.com

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