/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
#ifdef DCAF
#define COMPILER_BUG
/**********************************************************************/
/*                                                                    */
/*   Module          = SCBOUNDS                                       */
/*                                                                    */
/*   Description     = Accumulates screen bounding rectangles         */
/*                     AccumulateScreenBound                          */
/*                     AccumulateScreenBoundsThroughClips             */
/*                                                                    */
/*   Function        = Takes the supplied rectangle and merges it     */
/*                     into all of the currently active Screen Change */
/*                     Areas.                                         */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
#define INCL_GRE_SCREEN
#define INCL_GRE_CLIP
#include <eddinclt.h>
#include <edddtypt.h>
#include <dcaf.h>

extern DDTType      DDT;
extern PSCA         pscaStart;
extern PPFNL        EnginesDispatchTable;
extern SCA          scaSeamless;

/**********************************************************************/
/* AccumulateScreenBounds                                             */
/*                                                                    */
/* This routine takes the passed rectangle, and accumulates it into   */
/* all the current ScreenChangeAreas.                                 */
/*                                                                    */
/* When possible the supplied rectangle has been pre-clipped, to      */
/* avoid unnecessary areas being included in the bounds.              */
/*                                                                    */
/* The passed rectangle is in exclusive SCREEN coords.                */
/* i.e. origin is bottom left of the screen.                          */
/**********************************************************************/

VOID AccumulateScreenBounds(PRECTL   prclArgBound)
{
    unsigned int    iRect;
    unsigned int    iLastRect;
    unsigned int    iRect1;
    unsigned int    iRect2;
    unsigned int    iBestRect1;
    unsigned int    iBestRect2;
    RECTL           rclMerged;
    RECTL           rclIntersected;
    RECTL           rclBestMerged;
    ULONG           ulBestSize;
    ULONG           ulSmallestIncrease;
    PSCA            psca;
    BOOL            fContained;
    ULONG           ulMergedSize;
    ULONG           ulIntersectedSize;
    ULONG           ulMergedIncrease;
    RECTL           rclArg;
#ifdef COMPILER_BUG
    RECTL           rcl1;
#endif

    /******************************************************************/
    /* Take a local copy of the passed bound rectangle.               */
    /******************************************************************/
    rclArg = *prclArgBound;

#ifdef FIREWALLS
    /******************************************************************/
    /* Check that the supplied rectangle is correctly ordered.        */
    /******************************************************************/
    if ( (rclArg.xRight < rclArg.xLeft) ||
         (rclArg.yTop < rclArg.yBottom) )
    {
        DebugOutput("DCAF: Rectangle is badly ordered\n\r");
        goto asb_exit;
    }

    /******************************************************************/
    /* Check that the supplied rectangle lies fully within the        */
    /* screen (it should be pre-clipped).                             */
    /******************************************************************/
    if ( (rclArg.xLeft < 0) ||
         (rclArg.xLeft > (LONG)DDT.ScreenWidth ) ||
         (rclArg.xRight < 0) ||
         (rclArg.xRight > (LONG)DDT.ScreenWidth ) ||
         (rclArg.yBottom < 0) ||
         (rclArg.yBottom > (LONG)DDT.ScreenHeight) ||
         (rclArg.yTop < 0) ||
         (rclArg.yTop > (LONG)DDT.ScreenHeight) )
    {
        DebugOutput("DCAF: Rectangle is off screen\n\r");
        haltproc();

        if (rclArg.xLeft < 0)
        {
            rclArg.xLeft = 0;
            DebugOutput("DCAF: Negative xLeft\n\r");
        }
        if (rclArg.xRight < 0)
        {
            rclArg.xRight = 0;
            DebugOutput("DCAF: Negative xRight\n\r");
        }
        if (rclArg.yBottom < 0)
        {
            rclArg.yBottom = 0;
            DebugOutput("DCAF: Negative yBottom\n\r");
        }
        if (rclArg.yTop < 0)
        {
            rclArg.yTop = 0;
            DebugOutput("DCAF: Negative yTop\n\r");
        }
        if (rclArg.xLeft > (LONG)DDT.ScreenWidth)
        {
            rclArg.xLeft = DDT.ScreenWidth;
            DebugOutput("DCAF: xLeft too big\n\r");
        }
        if (rclArg.xRight > (LONG)DDT.ScreenWidth)
        {
            rclArg.xRight = DDT.ScreenWidth;
            DebugOutput("DCAF: xRight too big\n\r");
        }
        if (rclArg.yBottom > (LONG)DDT.ScreenHeight)
        {
            rclArg.yBottom = DDT.ScreenHeight;
            DebugOutput("DCAF: yBottom too big\n\r");
        }
        if (rclArg.yTop > (LONG)DDT.ScreenHeight)
        {
            rclArg.yTop = DDT.ScreenHeight;
            DebugOutput("DCAF: yTop too big\n\r");
        }
    }

#endif /* FIREWALLS */

    /******************************************************************/
    /* Now loop through all the Screen Change Areas.                  */
    /******************************************************************/
    for ( psca = pscaStart;
          psca != NULL;
          psca = psca->pscaNext )
    {
        /**************************************************************/
        /* See if this rectangle lies completely within one of the    */
        /* existing rectangles.                                       */
        /**************************************************************/
        fContained = FALSE;
        for (iRect = 0; iRect < psca->cRects; iRect++)
        {
            if ( (rclArg.yTop <= psca->arcl[iRect].yTop) &&
                 (rclArg.yBottom >= psca->arcl[iRect].yBottom) &&
                 (rclArg.xLeft >= psca->arcl[iRect].xLeft) &&
                 (rclArg.xRight <= psca->arcl[iRect].xRight) )
            {
                /******************************************************/
                /* The rectangle is fully contained.                  */
                /* Skip straight to the next Screen Change Area.      */
                /******************************************************/
                fContained = TRUE;
                break;
            }
        }

        /**************************************************************/
        /* If the supplied rectangle is fully contained within one    */
        /* of the existing rectangles then we can skip straight to    */
        /* the next SCA.                                              */
        /**************************************************************/
        if (fContained)
        {
            continue;
        }

        /**************************************************************/
        /* The supplied rectangle was not fully contained by the      */
        /* existing ones, so we must accumulate it.                   */
        /**************************************************************/

        /**************************************************************/
        /* Store the new rectangle.  This may only be temporary       */
        /* if we have already reached the maximum number of           */
        /* rectangles we can store.                                   */
        /* iRect currently indexes the next free rectangle.           */
        /**************************************************************/
        psca->arcl[iRect] = rclArg;
        psca->aulRectSize[iRect] = (rclArg.yTop - rclArg.yBottom) *
                                         (rclArg.xRight - rclArg.xLeft);

        /**************************************************************/
        /* If we have less than our full number of rectangles then    */
        /* we can just add the new one.                               */
        /**************************************************************/
        if (iRect < MAX_SCA_RECTS)
        {
            /******************************************************/
            /* Increment the number of rectangles in the current  */
            /* SCA, and skip straight to the next SCA.            */
            /******************************************************/
            psca->cRects++;
            continue;
        }

        /**************************************************************/
        /* We already have the maximum number of rects stored for     */
        /* this area, so we must combine 2 rectangles in order to     */
        /* keep our number within the maximum.                        */
        /*                                                            */
        /* The rectangles combined may be two of the existing         */
        /* rectangles, or one of the existing ones together with the  */
        /* new one.                                                   */
        /*                                                            */
        /* We do this by allowing the new rectangle to be stored in   */
        /* the SCA (done above) and then find the best merge out of   */
        /* all the stored rectangles, i.e. the merge which causes     */
        /* the smallest increase in area.                             */
        /*                                                            */
        /**************************************************************/

        /**************************************************************/
        /* Initialise the smallest area increase to be the maximum    */
        /* value.                                                     */
        /**************************************************************/
        ulSmallestIncrease = MAXULONG;
        iLastRect = iRect;

        for (iRect1 = 0; iRect1 < iLastRect; iRect1++)
        {
#ifdef COMPILER_BUG
            rcl1 = psca->arcl[iRect1];
#endif
            for ( iRect2 = iRect1+1;
                  iRect2 <= iLastRect;   /* NB <= is correct ! */
                  iRect2++ )
            {
                /******************************************************/
                /* Find the area of the rectangle which results from  */
                /* merging Rect1 and Rect2.                           */
                /******************************************************/
#ifdef COMPILER_BUG
                rclMerged.xLeft = min( rcl1.xLeft,
                                       psca->arcl[iRect2].xLeft );
                rclMerged.yBottom = min( rcl1.yBottom,
                                         psca->arcl[iRect2].yBottom );
                rclMerged.xRight = max( rcl1.xRight,
                                        psca->arcl[iRect2].xRight );
                rclMerged.yTop = max( rcl1.yTop,
                                      psca->arcl[iRect2].yTop );
#else
                rclMerged.xLeft = min( psca->arcl[iRect1].xLeft,
                                       psca->arcl[iRect2].xLeft );
                rclMerged.yBottom = min( psca->arcl[iRect1].yBottom,
                                         psca->arcl[iRect2].yBottom );
                rclMerged.xRight = max( psca->arcl[iRect1].xRight,
                                        psca->arcl[iRect2].xRight );
                rclMerged.yTop = max( psca->arcl[iRect1].yTop,
                                      psca->arcl[iRect2].yTop );
#endif

                ulMergedSize = (rclMerged.yTop - rclMerged.yBottom) *
                                   (rclMerged.xRight - rclMerged.xLeft);

                /******************************************************/
                /* Find the area of the rectangle which               */
                /* results from intersecting Rect1 and Rect2.         */
                /******************************************************/
#ifdef COMPILER_BUG
                rclIntersected.xLeft = max( rcl1.xLeft,
                                            psca->arcl[iRect2].xLeft );
                rclIntersected.yBottom = max( rcl1.yBottom,
                                              psca->arcl[iRect2].yBottom );
                rclIntersected.xRight = min( rcl1.xRight,
                                             psca->arcl[iRect2].xRight );
                rclIntersected.yTop = min( rcl1.yTop,
                                           psca->arcl[iRect2].yTop );
#else
                rclIntersected.xLeft = max( psca->arcl[iRect1].xLeft,
                                            psca->arcl[iRect2].xLeft );
                rclIntersected.yBottom = max( psca->arcl[iRect1].yBottom,
                                              psca->arcl[iRect2].yBottom );
                rclIntersected.xRight = min( psca->arcl[iRect1].xRight,
                                             psca->arcl[iRect2].xRight );
                rclIntersected.yTop = min( psca->arcl[iRect1].yTop,
                                           psca->arcl[iRect2].yTop );
#endif

                /******************************************************/
                /* Badly ordered rectangle means zero intersection    */
                /******************************************************/
                if ( (rclIntersected.xRight <= rclIntersected.xLeft) ||
                     (rclIntersected.yTop <= rclIntersected.yBottom) )
                {
                    ulIntersectedSize = 0;
                }
                else
                {
                    ulIntersectedSize =
                      (rclIntersected.yTop - rclIntersected.yBottom) *
                         (rclIntersected.xRight - rclIntersected.xLeft);
                }

                /******************************************************/
                /* Now see if the increase due to merging             */
                /* these 2 rectangles is the best yet.                */
                /******************************************************/
                ulMergedIncrease = ulMergedSize +
                                   ulIntersectedSize -
                                   psca->aulRectSize[iRect1] -
                                   psca->aulRectSize[iRect2];
#ifdef FIREWALLS
                if ( (LONG)ulMergedIncrease < 0 )
                {
                    DebugOutput("DCAF: !!! MergedIncrease is negative !!!\n\r");
                    ulMergedIncrease = 0;
                }
#endif

                if (ulMergedIncrease < ulSmallestIncrease)
                {
                    iBestRect1 = iRect1;
                    iBestRect2 = iRect2;
                    ulSmallestIncrease = ulMergedIncrease;
                    ulBestSize = ulMergedSize;
                    rclBestMerged = rclMerged;
                }
            }
        }

        /**************************************************************/
        /* We have now calculated the best pair of rectangles to      */
        /* merge, and thoughtfully remembered the merged rectangle    */
        /* (so we do not have to recalculate it).                     */
        /* Store the merged rectangle into the slot occupied by the   */
        /* first of the best pair.                                    */
        /**************************************************************/
#ifdef FIREWALLS
        if ( (psca->arcl[iBestRect1].xLeft < rclBestMerged.xLeft) ||
             (psca->arcl[iBestRect1].xRight > rclBestMerged.xRight) ||
             (psca->arcl[iBestRect1].yTop > rclBestMerged.yTop) ||
             (psca->arcl[iBestRect1].yBottom < rclBestMerged.yBottom) )
        {
            haltproc();
        }
#endif

        psca->arcl[iBestRect1] = rclBestMerged;
        psca->aulRectSize[iBestRect1] = ulBestSize;



        /**************************************************************/
        /* BestRect1 and BestRect2 have now been merged into the      */
        /* slot originally occupied by BestRect1.                     */
        /*                                                            */
        /* BestRect2's slot is now free.                              */
        /*                                                            */
        /* If BestRect2 was the new (last) rectangle then we don't    */
        /* need to take further action, as we want the last slot to   */
        /* be free.                                                   */
        /*                                                            */
        /* If BestRect2 was not the new (last) rectangle then we need */
        /* to copy this rect from the last slot to the empty          */
        /* BestRect2 slot.                                            */
        /**************************************************************/
        if (iBestRect2 != iLastRect)
        {
            /**********************************************************/
            /* Copy the rectangle coords and size.                    */
            /**********************************************************/
            psca->arcl[iBestRect2] = psca->arcl[iLastRect];
            psca->aulRectSize[iBestRect2] = psca->aulRectSize[iLastRect];
        }

    } /* for each Screen Change Area */

#ifdef FIREWALLS
asb_exit:
#endif

    ;
} /* AccumulateScreenBounds */


/**********************************************************************/
/* AccumulateSeamlessBounds accumulates the Seamless exclusion        */
/* rectangle supplied by         into the Seamless SCA.               */
/* We accumulate into a separate SCA because we can only access       */
/* memory that was granted addressability at init time.               */
/*                                                                    */
/* The supplied rectangle is in AI coords, and must be converted      */
/* to device coords before calling onto AccumulateScreenBounds.       */
/**********************************************************************/
VOID AccumulateSeamlessBounds(pDevRect   pSeamlessExclusionRect)
{
    RECTL   rclSeamlessBounds;
    PSCA    pscaSaved;

    /******************************************************************/
    /* Copy the rectangle onto our stack, expanding to 32 bits and    */
    /* making exclusive.                                              */
    /******************************************************************/
    rclSeamlessBounds.xLeft = (LONG)((*pSeamlessExclusionRect)[0].X);
    rclSeamlessBounds.xRight =
                            (LONG)((*pSeamlessExclusionRect)[1].X) + 1L;
    rclSeamlessBounds.yBottom = DDT.ScreenHeight-1 -
                                 (LONG)((*pSeamlessExclusionRect)[1].Y);
    rclSeamlessBounds.yTop = DDT.ScreenHeight-1 -
                            (LONG)((*pSeamlessExclusionRect)[0].Y) + 1L;

    /******************************************************************/
    /* Clip the Seamless bounds to the screen (Windows sometimes      */
    /* passes coords off the screen).                                 */
    /******************************************************************/
    if (rclSeamlessBounds.xLeft < 0L)
    {
        rclSeamlessBounds.xLeft = 0L;
    }
    if (rclSeamlessBounds.yBottom < 0L)
    {
        rclSeamlessBounds.yBottom = 0L;
    }
    if (rclSeamlessBounds.yTop > (LONG)DDT.ScreenHeight)
    {
        rclSeamlessBounds.yTop = (LONG)DDT.ScreenHeight;
    }
    if (rclSeamlessBounds.xRight > (LONG)DDT.ScreenWidth)
    {
        rclSeamlessBounds.xRight = (LONG)DDT.ScreenWidth;
    }

    /******************************************************************/
    /* Change the pointer to the linked list of SCAs to point to      */
    /* the Seamless SCA.                                              */
    /******************************************************************/
    pscaSaved = pscaStart;
    pscaStart = &scaSeamless;

    /******************************************************************/
    /* Accumulate the rectangle.                                      */
    /******************************************************************/
    AccumulateScreenBounds(&rclSeamlessBounds);

    /******************************************************************/
    /* Restore the original linked list pointer.                      */
    /******************************************************************/
    pscaStart = pscaSaved;

}

/**********************************************************************/
/* Declare a dummy function to mark the end of the                    */
/* AccumulateScreenBounds routine.                                    */
/* This lets us calculate the length of the routine, which is         */
/* required for Seamless Windows.                                     */
/**********************************************************************/
VOID    EndOfAccumulateScreenBounds(VOID)
{
}


/**********************************************************************/
/* AccumulateScreenBoundsThroughClips.                                */
/*                                                                    */
/* This function takes the supplied (unclipped) bounding rectangle,   */
/* intersects it with each of the clip rectangles in the DC and       */
/* accumulates each of the clipped bounds into the active Screen      */
/* Change Areas.                                                      */
/*                                                                    */
/* The supplied bounding rectangle can be in:                         */
/*   - 16-bit AI coordinates (COORD_AI)                               */
/*     (flipped, origin is top-left of screen)                        */
/*   - 16-bit Device Coords (COORD_DEVICE_WORD)                       */
/*     (origin is current DC origin)                                  */
/*   - 32-bit Screen Coords                                           */
/*     (origin is bottom-left of screen)                              */
/*                                                                    */
/* The ulCoordType parameter specifies which of these coords are      */
/* being supplied.                                                    */
/*                                                                    */
/* This routine is real useful, because it can be called from the     */
/* same point in drawing functions as the ordinary (unclipped)        */
/* bounds are accumulated. This minimises the complexity and          */
/* changes required in the main drawing code (rather than rooting     */
/* around in the main code to find clipped rectangles).               */
/*                                                                    */
/**********************************************************************/
VOID    AccumulateScreenBoundsThroughClips( pDevRect pBoundCoords,
                                            ULONG    ulCoordType )
{
    #define NUM_LOCAL_CLIPS 10
    RECTL           arclCachedRects[NUM_LOCAL_CLIPS];
    RECTL           rclClipped;
    RECTL           rclBound;
    PRECTL          prclClippedBound;
    PRECTL          prclClip;
    RGNRECT         rgnControl;
    ULONG           cRectsInBuffer;
    BOOL            fMoreRectsInEngine;
    unsigned int    i;

    /******************************************************************/
    /* Convert the supplied rectangle to a 32-bit exclusive screen    */
    /* RECTL.                                                         */
    /******************************************************************/
    if (ulCoordType == COORD_AI)
    {
        /**************************************************************/
        /* The supplied rectangle is in 16-bit inclusive AI coords    */
        /* i.e. relative to the top of the screen.                    */
        /* Flip the y coords and expand them to 32-bit.               */
        /**************************************************************/
        rclBound.xLeft   = (LONG)((*pBoundCoords)[0].X);
        rclBound.yBottom = (LONG)(DDT.ScreenHeight-1) -
                                           (LONG)((*pBoundCoords)[1].Y);
        rclBound.xRight  = (LONG)((*pBoundCoords)[1].X) + 1L;
        rclBound.yTop    = (LONG)(DDT.ScreenHeight-1) -
                                      (LONG)((*pBoundCoords)[0].Y) + 1L;
    }
    else if (ulCoordType == COORD_DEVICE_WORD)
    {
        /**************************************************************/
        /* The supplied rectangle is in 16-bit inclusive device       */
        /* coords i.e. relative to the current DC origin.             */
        /**************************************************************/
        rclBound.xLeft   = (*pBoundCoords)[0].X + pdc->DCIOrigin.X;
        rclBound.yBottom = (*pBoundCoords)[0].Y + pdc->DCIOrigin.Y;
        rclBound.xRight  = (*pBoundCoords)[1].X + pdc->DCIOrigin.X + 1;
        rclBound.yTop    = (*pBoundCoords)[1].Y + pdc->DCIOrigin.Y + 1;
    }
    else
    {
        /**************************************************************/
        /* The supplied rectangle is in 32-bit exclusive screen       */
        /* coords i.e. just what we want!                             */
        /**************************************************************/
        rclBound = *((PRECTL)pBoundCoords);
    }


    /******************************************************************/
    /* Decide whether we can use the clip rectangles in the DC cache, */
    /* or whether we need to call back to the Graphics Engine to      */
    /* get them.                                                      */
    /******************************************************************/
    if ( (pdc->DCIEngineClips > CACHED_CLIPS) || (pdc->ClipChanged) )
    {
        /**************************************************************/
        /* Initialise the control structure for fetching clip rects   */
        /* from the Graphics Engine.                                  */
        /**************************************************************/
        rgnControl.ircStart = 1;
        rgnControl.crc = NUM_LOCAL_CLIPS;
        rgnControl.ulDirection = RECTDIR_LFRT_TOPBOT;
        cRectsInBuffer = 0;
        fMoreRectsInEngine = TRUE;

        /**************************************************************/
        /* While there are more intersected rectangles, acummulate    */
        /* each one into the active Screen Change Areas.              */
        /**************************************************************/
        while ( (cRectsInBuffer != 0) || fMoreRectsInEngine)
        {
            if (cRectsInBuffer == 0)
            {
                /******************************************************/
                /* Call the engine to get the clip rectangles.        */
                /* We pass in our bounding rectangle to limit the     */
                /* rects that are returned. This, in effect, clips    */
                /* the bounding rect for us and we can pass the       */
                /* returned rects directly to the bounds accumulation */
                /* routine.                                           */
                /******************************************************/
                if (RGN_ERROR ==
                     EnginesDispatchTable[NGreGetClipRects & 0xff](
                                                  pdc->DCIhdc,
                                                  &rclBound,
                                                  &rgnControl,
                                                  arclCachedRects,
                                                  NULL,
                                                  NGreGetClipRects ) )
                {
                    haltproc();
                    goto asbtc_exit;
                }

                /******************************************************/
                /* Update values according to the number of rects     */
                /* returned.                                          */
                /******************************************************/
                cRectsInBuffer = rgnControl.crcReturned;

                /******************************************************/
                /* If no rects returned then quickly exit.            */
                /******************************************************/
                if (cRectsInBuffer == 0)
                {
                    break;
                }

                /******************************************************/
                /* Decide whether there may be more rects in the      */
                /* Engine.                                            */
                /******************************************************/
                fMoreRectsInEngine =
                             (rgnControl.crcReturned == rgnControl.crc);
                rgnControl.ircStart += rgnControl.crcReturned;

                /******************************************************/
                /* Set the rectangle pointer to the beginning of the  */
                /* buffer.                                            */
                /******************************************************/
                prclClippedBound = arclCachedRects;
            }

            /**********************************************************/
            /* Accumulate the rectangle (we do not have to clip it -  */
            /* it has been pre-clipped by the Graphics Engine).       */
            /**********************************************************/
            AccumulateScreenBounds(prclClippedBound);

            /**********************************************************/
            /* Move to the next rectangle.                            */
            /**********************************************************/
            prclClippedBound++;
            cRectsInBuffer--;
        }

    }
    else
    {
        /**************************************************************/
        /* We can use the rectangles that are already in the DC cache.*/
        /* However, these rectangles are in inclusive AI coords,      */
        /* rather than exclusive device coords.                       */
        /* First convert them to our format (exclusive screen coords).*/
        /**************************************************************/
        for (i = 0; i < pdc->DCIClipNum; i++)
        {
            arclCachedRects[i].xLeft = pdc->DCIClipRects[i].X0;
            arclCachedRects[i].xRight = pdc->DCIClipRects[i].X1+1;
            arclCachedRects[i].yBottom = (DDT.ScreenHeight-1) -
                                                pdc->DCIClipRects[i].Y1;
            arclCachedRects[i].yTop = (DDT.ScreenHeight-1) -
                                            pdc->DCIClipRects[i].Y0 + 1;
        }


        /**************************************************************/
        /* Initialise the pointer to the current clip rect to point   */
        /* to the beginning of the local buffer.                      */
        /**************************************************************/
        prclClip = arclCachedRects;

        /**************************************************************/
        /* For each clip rectangle, clip the bounding rectangle and   */
        /* pass it on to the bounds accumulation routine.             */
        /**************************************************************/
        for (i = 0; i < pdc->DCIClipNum; i++)
        {
            /**********************************************************/
            /* Clip the bounding rectangle to the current clip        */
            /* rectangle.                                             */
            /**********************************************************/
            rclClipped.xLeft   = max(rclBound.xLeft, prclClip->xLeft);
            rclClipped.yBottom = max(rclBound.yBottom,
                                                     prclClip->yBottom);
            rclClipped.xRight  = min(rclBound.xRight, prclClip->xRight);
            rclClipped.yTop    = min(rclBound.yTop, prclClip->yTop);

            /**********************************************************/
            /* Check that the rectangle has not been completely       */
            /* clipped away (i.e. that is still correctly ordered)    */
            /* and if so, accumulate it into the Screen Change Area.  */
            /**********************************************************/
            if ( (rclClipped.xLeft < rclClipped.xRight) &&
                 (rclClipped.yBottom < rclClipped.yTop) )
            {
                AccumulateScreenBounds(&rclClipped);
            }

            /**********************************************************/
            /* Move to the next clip rectangle.                       */
            /**********************************************************/
            prclClip++;
        }
    }

asbtc_exit:
    ;
}

#endif  /* DCAF */
