/******************************Module*Header***********************************\
 *
 *                           *******************
 *                           * GDI SAMPLE CODE *
 *                           *******************
 *
 * Module Name: stretch.c
 *
 * Contains all the stretch blt functions.
 *
 * Copyright (C) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
 * Copyright (C) 1995-1999 Microsoft Corporation.  All rights reserved.
 ******************************************************************************/
#include "precomp.h"
#include "gdi.h"
#include "directx.h"
#include "clip.h"

//-----------------------------------------------------------------------------
//
// DWORD dwGetPixelSize()
//
// This routine converts current bitmap format to Permedia pixel size
//
//-----------------------------------------------------------------------------
DWORD
dwGetPixelSize(ULONG    ulBitmapFormat,
               DWORD*   pdwFormatBits,
               DWORD*   pdwFormatExtention)
{
    DWORD dwPixelSize;

    switch ( ulBitmapFormat )
    {
        case BMF_8BPP:
            dwPixelSize = 0;
            *pdwFormatBits = PERMEDIA_8BIT_PALETTEINDEX;
            *pdwFormatExtention = PERMEDIA_8BIT_PALETTEINDEX_EXTENSION;
            break;

        case BMF_16BPP:
            dwPixelSize = 1;
            *pdwFormatBits = PERMEDIA_565_RGB;
            *pdwFormatExtention = PERMEDIA_565_RGB_EXTENSION;
            break;

        case BMF_32BPP:
            dwPixelSize = 2;
            *pdwFormatBits = PERMEDIA_888_RGB;
            *pdwFormatExtention = PERMEDIA_888_RGB_EXTENSION;
            break;

        default:
            dwPixelSize = -1;
    }

    return dwPixelSize;
}// dwGetPixelSize()

//-----------------------------------------------------------------------------
//
// DWORD bStretchInit()
//
// This routine initializes all the registers needed for doing a stretch blt
//
//-----------------------------------------------------------------------------
BOOL
bStretchInit(SURFOBJ*    psoDst,
             SURFOBJ*    psoSrc)
{
    Surf*   pSurfDst = (Surf*)psoDst->dhsurf;
    Surf*   pSurfSrc = (Surf*)psoSrc->dhsurf;
    DWORD   dwDstPixelSize;
    DWORD   dwDstFormatBits;
    DWORD   dwDstFormatExtention;
    DWORD   dwSrcPixelSize;
    DWORD   dwSrcFormatBits;
    DWORD   dwSrcFormatExtention;
    PDev*   ppdev = (PDev*)psoDst->dhpdev;
    ULONG*  pBuffer;

    DISPDBG((6, "bStretchInit called"));
    
    ASSERTDD(pSurfSrc, "Not valid private surface in source");
    ASSERTDD(pSurfDst, "Not valid private surface in destination");

    dwDstPixelSize = dwGetPixelSize(psoDst->iBitmapFormat,
                                    &dwDstFormatBits,
                                    &dwDstFormatExtention);

    if ( dwDstPixelSize == -1 )
    {
        DISPDBG((1, "bStretchBlt return FALSE because of wrong DstPixel Size"));
        //
        // Unsupported bitmap format, return false
        //
        return FALSE;
    }
    
    InputBufferReserve(ppdev, 26, &pBuffer);

    if ( dwDstPixelSize != __PERMEDIA_8BITPIXEL)
    {
        pBuffer[0] = __Permedia2TagDitherMode;
        pBuffer[1] = (COLOR_MODE << PM_DITHERMODE_COLORORDER) // RGB color order
                   |(dwDstFormatBits << PM_DITHERMODE_COLORFORMAT)
                   |(dwDstFormatExtention << PM_DITHERMODE_COLORFORMATEXTENSION)
                   |(1 << PM_DITHERMODE_ENABLE);
    }
    else
    {
        pBuffer[0] = __Permedia2TagDitherMode;
        pBuffer[1] = __PERMEDIA_DISABLE;
    }

    pBuffer[2] = __Permedia2TagFBWindowBase;
    pBuffer[3] = pSurfDst->ulPixOffset;

    //
    // Set no read of source.
    //
    pBuffer[4]  = __Permedia2TagFBReadMode;
    pBuffer[5]  = PM_FBREADMODE_PARTIAL(pSurfDst->ulPackedPP);
    pBuffer[6]  = __Permedia2TagLogicalOpMode;
    pBuffer[7]  = __PERMEDIA_DISABLE;
    pBuffer[8]  = __Permedia2TagTextureBaseAddress;
    pBuffer[9]  = pSurfSrc->ulPixOffset;
    pBuffer[10] = __Permedia2TagTextureAddressMode;
    pBuffer[11] = 1 << PM_TEXADDRESSMODE_ENABLE;
    pBuffer[12] = __Permedia2TagTextureColorMode;
    pBuffer[13] = (1 << PM_TEXCOLORMODE_ENABLE)
                | (0 << 4)                                           // RGB  
                | (_P2_TEXTURE_COPY << PM_TEXCOLORMODE_APPLICATION);

    //
    // Note: we have to turn off BiLinear filtering here, even for stretch
    // because GDI doesn't do it. Otherwise, we will fail during the
    // comparison
    //
    pBuffer[14] = __Permedia2TagTextureReadMode;
    pBuffer[15] = PM_TEXREADMODE_ENABLE(__PERMEDIA_ENABLE)
                | PM_TEXREADMODE_FILTER(__PERMEDIA_DISABLE)
                | PM_TEXREADMODE_WIDTH(11)
                | PM_TEXREADMODE_HEIGHT(11);

    dwSrcPixelSize = dwGetPixelSize(psoSrc->iBitmapFormat,
                                    &dwSrcFormatBits,
                                    &dwSrcFormatExtention);

    if ( dwSrcPixelSize == -1 )
    {
        DISPDBG((1, "bStretchBlt return FALSE because of wrong SrcPixel Size"));
        //
        // Unsupported bitmap format, return false
        //
        return FALSE;
    }
    
    pBuffer[16] = __Permedia2TagTextureDataFormat;
    pBuffer[17] = (dwSrcFormatBits << PM_TEXDATAFORMAT_FORMAT)
                | (dwSrcFormatExtention << PM_TEXDATAFORMAT_FORMATEXTENSION)
                | (COLOR_MODE << PM_TEXDATAFORMAT_COLORORDER);
    pBuffer[18] = __Permedia2TagTextureMapFormat;
    pBuffer[19] = pSurfSrc->ulPackedPP
                |(dwSrcPixelSize << PM_TEXMAPFORMAT_TEXELSIZE);
    pBuffer[20] = __Permedia2TagScissorMode;
    pBuffer[21] = SCREEN_SCISSOR_DEFAULT
                | USER_SCISSOR_ENABLE;
    
    pBuffer[22] = __Permedia2TagdSdyDom;
    pBuffer[23] = 0;
    pBuffer[24] = __Permedia2TagdTdx;
    pBuffer[25] = 0;

    pBuffer += 26;
    InputBufferCommit(ppdev, pBuffer);

    DISPDBG((6, "bStretchInit return TRUE"));
    return TRUE;
}// bStretchInit()

//-----------------------------------------------------------------------------
//
// DWORD bStretchReset()
//
// This routine resets all the registers changed during stretch blt
//
//-----------------------------------------------------------------------------
void
vStretchReset(PDev* ppdev)
{
    ULONG*  pBuffer;
    
    DISPDBG((6, "vStretchReset called"));
    
    InputBufferReserve(ppdev, 12, &pBuffer);
    
    //
    // Restore the default settings
    //
    pBuffer[0] = __Permedia2TagScissorMode;
    pBuffer[1] = SCREEN_SCISSOR_DEFAULT;
    pBuffer[2] = __Permedia2TagDitherMode;
    pBuffer[3] = __PERMEDIA_DISABLE;
    pBuffer[4] = __Permedia2TagTextureAddressMode;
    pBuffer[5] = __PERMEDIA_DISABLE;
    pBuffer[6] = __Permedia2TagTextureColorMode;
    pBuffer[7] = __PERMEDIA_DISABLE;
    pBuffer[8] = __Permedia2TagTextureReadMode;
    pBuffer[9] = __PERMEDIA_DISABLE;
    pBuffer[10] = __Permedia2TagdY;
    pBuffer[11] = INTtoFIXED(1);

    pBuffer += 12;
    InputBufferCommit(ppdev, pBuffer);

    DISPDBG((6, "vStretchReset done"));
    return;
}// vStretchReset()

//-----------------------------------------------------------------------------
//
// VOID vStretchBlt()
//
// This routine does the stretch blt work through the texture engine
//
//-----------------------------------------------------------------------------
VOID
vStretchBlt(SURFOBJ*    psoDst,
            SURFOBJ*    psoSrc,
            RECTL*      rDest,
            RECTL*      rSrc,
            RECTL*      prclClip)
{
    Surf*   pSurfDst = (Surf*)psoDst->dhsurf;
    Surf*   pSurfSrc = (Surf*)psoSrc->dhsurf;
    LONG    lXScale;
    LONG    lYScale;
    DWORD   dwDestWidth = rDest->right - rDest->left;
    DWORD   dwDestHeight = rDest->bottom - rDest->top;
    DWORD   dwSourceWidth = rSrc->right - rSrc->left;
    DWORD   dwSourceHeight = rSrc->bottom - rSrc->top;
    DWORD   dwRenderDirection;
    DWORD   dwDstPixelSize;
    DWORD   dwDstFormatBits;
    DWORD   dwDstFormatExtention;
    DWORD   dwSrcPixelSize;
    DWORD   dwSrcFormatBits;
    DWORD   dwSrcFormatExtention;
    ULONG*  pBuffer;
    PDev*   ppdev = (PDev*)psoDst->dhpdev;

    DISPDBG((6, "vStretchBlt called"));
    DISPDBG((6, "prclClip (left, right, top, bottom)=(%d, %d, %d,%d)",
             prclClip->left, prclClip->right, prclClip->top, prclClip->bottom));
    DISPDBG((6, "rSrc (left, right, top, bottom=(%d, %d, %d,%d)",rSrc->left,
             rSrc->right, rSrc->top, rSrc->bottom));
    DISPDBG((6, "rDest (left, right, top, bottom)=(%d, %d, %d,%d)",rDest->left,
             rDest->right, rDest->top, rDest->bottom));
    
    ASSERTDD(prclClip != NULL, "Wrong clippng rectangle");

    //
    // Note: the scale factor register value: dsDx, dTdyDom's interger part
    // starts at bit 20. So we need to "<< 20" here
    //
    lXScale = (dwSourceWidth << 20) / dwDestWidth;
    lYScale = (dwSourceHeight << 20) / dwDestHeight;
//    lXScale = (((dwSourceWidth << 18) - 1) / dwDestWidth) << 2;
//    lYScale = (((dwSourceHeight << 18) - 1) / dwDestHeight) << 2;
    DISPDBG((6, "lXScale=0x%x, lYScale=0x%x", lXScale, lYScale));
    DISPDBG((6, "dwSourceWidth=%d, dwDestWidth=%d",
             dwSourceWidth, dwDestWidth));
    DISPDBG((6, "dwSourceHeight=%d, dwDestHeight=%d",
             dwSourceHeight, dwDestHeight));
    
    InputBufferReserve(ppdev, 24, &pBuffer);

    pBuffer[0] = __Permedia2TagScissorMinXY;
    pBuffer[1] = ((prclClip->left)<< SCISSOR_XOFFSET)
                |((prclClip->top)<< SCISSOR_YOFFSET);
    pBuffer[2] = __Permedia2TagScissorMaxXY;
    pBuffer[3] = ((prclClip->right)<< SCISSOR_XOFFSET)
                |((prclClip->bottom)<< SCISSOR_YOFFSET);

    //
    // We need to be carefull with overlapping rectangles
    //
    if ( (pSurfSrc->ulPixOffset) != (pSurfDst->ulPixOffset) )
    {
        //
        // Src and dst are differnt surface
        //
        dwRenderDirection = 1;
    }
    else
    {
        //
        // Src and dst are the same surface
        // We will set dwRenderDirection=1 if the src is lower or righter
        // than the dst, that is, if it is bottom-up or right-left, we set
        // dwRenderDirection=1, otherwise it = 0
        //
        if ( rSrc->top < rDest->top )
        {
            dwRenderDirection = 0;
        }
        else if ( rSrc->top > rDest->top )
        {
            dwRenderDirection = 1;
        }
        else if ( rSrc->left < rDest->left )
        {
            dwRenderDirection = 0;
        }
        else
        {
            dwRenderDirection = 1;
        }
    }// src and dst are different

    DISPDBG((6, "dwRenderDirection=%d", dwRenderDirection));

    //
    // Render the rectangle
    //
    if ( dwRenderDirection )
    {
        pBuffer[4] = __Permedia2TagSStart;
        pBuffer[5] = (rSrc->left << 20) + ((lXScale >> 1) & 0xfffffffc);
        pBuffer[6] = __Permedia2TagTStart;
        pBuffer[7] = (rSrc->top << 20) + ((lYScale >> 1) & 0xfffffffc);
        pBuffer[8] = __Permedia2TagdSdx;
        pBuffer[9] = lXScale;
        pBuffer[10] = __Permedia2TagdTdyDom;
        pBuffer[11] = lYScale;
        pBuffer[12] = __Permedia2TagStartXDom;
        pBuffer[13] = INTtoFIXED(rDest->left);
        pBuffer[14] = __Permedia2TagStartXSub;
        pBuffer[15] = INTtoFIXED(rDest->right);
        pBuffer[16] = __Permedia2TagStartY;
        pBuffer[17] = INTtoFIXED(rDest->top);
        pBuffer[18] = __Permedia2TagdY;
        pBuffer[19] = INTtoFIXED(1);
        pBuffer[20] = __Permedia2TagCount;
        pBuffer[21] = rDest->bottom - rDest->top;
        pBuffer[22] = __Permedia2TagRender;
        pBuffer[23] = __RENDER_TRAPEZOID_PRIMITIVE
                    | __RENDER_TEXTURED_PRIMITIVE;
    }
    else
    {
        //
        // Render right to left, bottom to top
        //
        pBuffer[4] = __Permedia2TagSStart;
        pBuffer[5] = (rSrc->right << 20) + ((lXScale >> 1)& 0xfffffffc);
        pBuffer[6] = __Permedia2TagTStart;
        pBuffer[7] = (rSrc->bottom << 20) - ((lYScale >> 1)& 0xfffffffc);
        
        lXScale = -lXScale;
        lYScale = -lYScale;

        pBuffer[8] = __Permedia2TagdSdx;
        pBuffer[9] = lXScale;
        pBuffer[10] = __Permedia2TagdTdyDom;
        pBuffer[11] = lYScale;
        pBuffer[12] = __Permedia2TagStartXDom;
        pBuffer[13] = INTtoFIXED(rDest->right);
        pBuffer[14] = __Permedia2TagStartXSub;
        pBuffer[15] = INTtoFIXED(rDest->left);
        pBuffer[16] = __Permedia2TagStartY;
        pBuffer[17] = INTtoFIXED(rDest->bottom - 1);
        pBuffer[18] = __Permedia2TagdY;
        pBuffer[19] = (DWORD)INTtoFIXED(-1);
        pBuffer[20] = __Permedia2TagCount;
        pBuffer[21] = rDest->bottom - rDest->top;
        pBuffer[22] = __Permedia2TagRender;    
        pBuffer[23] = __RENDER_TRAPEZOID_PRIMITIVE
                    | __RENDER_TEXTURED_PRIMITIVE;
    }

    pBuffer += 24;
    InputBufferCommit(ppdev, pBuffer);
    
    DISPDBG((6, "vStretchBlt done"));
    return;
}// vStretchBlt()

//-----------------------------Public*Routine----------------------------------
//
// BOOL DrvStretchBlt
//
// DrvStretchBlt provides stretching bit-block transfer capabilities between any
// combination of device-managed and GDI-managed surfaces. This function enables
// the device driver to write to GDI bitmaps, especially when the driver can do
// halftoning. This function allows the same halftoning algorithm to be applied
// to GDI bitmaps and device surfaces.
//
// Parameters
//  psoDest-----Points to a SURFOBJ that identifies the surface on which to draw
//  psoSrc------Points to a SURFOBJ that defines the source for the bit-block
//              transfer operation. 
//  psoMask-----This optional parameter points to a surface that provides a mask
//              for the source. The mask is defined by a logic map, which is a
//              bitmap with 1 bit per pixel. 
//              The mask limits the area of the source that is copied. If this
//              parameter is specified, it has an implicit rop4 of 0xCCAA,
//              meaning the source should be copied wherever the mask is one,
//              but the destination should be left alone wherever the mask is
//              zero. 
//
//              When this parameter is null there is an implicit rop4 of 0xCCCC,
//              which means that the source should be copied everywhere in the
//              source rectangle. 
//
//              The mask will always be large enough to contain the relevant
//              source; tiling is unnecessary. 
//  pco---------Points to a CLIPOBJ that limits the area to be modified in the
//              destination. GDI services are provided to enumerate the clip
//              region as a set of rectangles. 
//              Whenever possible, GDI simplifies the clipping involved.
//              However, unlike DrvBitBlt, DrvStretchBlt can be called with a
//              single clipping rectangle. This prevents rounding errors in
//              clipping the output.
//  pxlo--------Points to a XLATEOBJ that specifies how color indices are to be
//              translated between the source and target surfaces. 
//              The XLATEOBJ can also be queried to find the RGB color for any
//              source index. A high quality stretching bit-block transfer will
//              need to interpolate colors in some cases. 
//  pca---------Points to a COLORADJUSTMENT structure that defines the color
//              adjustment values to be applied to the source bitmap before
//              stretching the bits. (See the Platform SDK.) 
//  pptlHTOrg---Specifies the origin of the halftone brush. Device drivers that
//              use halftone brushes should align the upper left pixel of the
//              brush's pattern with this point on the device surface. 
//  prclDest----Points to a RECTL structure that defines the area to be modified
//              in the coordinate system of the destination surface. This
//              rectangle is defined by two points that are not necessarily well
//              ordered, meaning the coordinates of the second point are not
//              necessarily larger than those of the first point. The rectangle
//              they describe does not include the lower and right edges. This
//              function is never called with an empty destination rectangle.
//
//              DrvStretchBlt can do inversions of x and y when the destination
//              rectangle is not well ordered. 
//  prclSrc-----Points to a RECTL that defines the area that will be copied in
//              the coordinate system of the source surface. The rectangle is
//              defined by two points, and will map onto the rectangle defined
//              by prclDest. The points of the source rectangle are well ordered
//              This function is never given an empty source rectangle.
//
//              The mapping is defined by prclSrc and prclDest. The points
//              specified in prclDest and prclSrc lie on integer coordinates,
//              which correspond to pixel centers. A rectangle defined by two
//              such points is considered to be a geometric rectangle with two
//              vertices whose coordinates are the given points, but with 0.5
//              subtracted from each coordinate. (POINTL structures should be
//              considered a shorthand notation for specifying these fractional
//              coordinate vertices.) 
//
//              The edges of any rectangle never intersect a pixel, but go
//              around a set of pixels. The pixels inside the rectangle are
//              those expected for a "bottom-right exclusive" rectangle.
//              DrvStretchBlt will map the geometric source rectangle exactly
//              onto the geometric destination rectangle. 
//  pptlMask----Points to a POINTL structure that specifies which pixel in the
//              given mask corresponds to the upper left pixel in the source
//              rectangle. Ignore this parameter if no mask is specified. 
//  iMode-------Specifies how source pixels are combined to get output pixels.
//              The HALFTONE mode is slower than the other modes, but produces
//              higher quality images.
//                      Value               Meaning 
//                  WHITEONBLACK    On a shrinking bit-block transfer, pixels
//                                  should be combined with a Boolean OR
//                                  operation. On a stretching bit-block
//                                  transfer, pixels should be replicated. 
//                  BLACKONWHITE    On a shrinking bit-block transfer, pixels
//                                  should be combined with a Boolean AND
//                                  operation. On a stretching bit-block
//                                  transfer, pixels should be replicated.
//                  COLORONCOLOR    On a shrinking bit-block transfer, enough
//                                  pixels should be ignored so that pixels
//                                  don't need to be combined. On a stretching
//                                  bit-block transfer, pixels should be
//                                  replicated. 
//                  HALFTONE        The driver can use groups of pixels in the
//                                  output surface to best approximate the color
//                                  or gray level of the input.
//
// Return Value
//  The return value is TRUE if the function is successful. Otherwise, it is
//  FALSE, and an error code is logged.
//
// Comments
//  This function can be provided to handle only certain forms of stretching,
//  such as by integer multiples. If the driver has hooked the call and is asked
//  to perform an operation it does not support, the driver should forward the
//  data to EngStretchBlt for GDI to handle.
//
//  If the driver wants GDI to handle halftoning, and wants to ensure the proper
//  iMode value, the driver can hook DrvStretchBlt, set iMode to HALFTONE, and
//  call back to GDI with EngStretchBlt with the set iMode value.
//
//  DrvStretchBlt is optional for display drivers.
//
//-----------------------------------------------------------------------------
BOOL
DrvStretchBlt(SURFOBJ*            psoDst,
              SURFOBJ*            psoSrc,
              SURFOBJ*            psoMsk,
              CLIPOBJ*            pco,
              XLATEOBJ*           pxlo,
              COLORADJUSTMENT*    pca,
              POINTL*             pptlHTOrg,
              RECTL*              prclDst,
              RECTL*              prclSrc,
              POINTL*             pptlMsk,
              ULONG               iMode)
{
    Surf*       pSurfSrc = (Surf*)psoSrc->dhsurf;
    Surf*       pSurfDst = (Surf*)psoDst->dhsurf;
    PDev*       ppdev = (PDev*)psoDst->dhpdev;
    BOOL        bRet;
    RECTL       rclClip;
    RECTL*      prclClip;
    ULONG       cxDst;
    ULONG       cyDst;
    ULONG       cxSrc;
    ULONG       cySrc;
    BOOL        bMore;
    ClipEnum    ceInfo;
    LONG        lNumOfIntersections;
    LONG        i;

goto Punt_It;

    DISPDBG((6, "DrvStretchBlt called with iMode = %d", iMode));

    vCheckGdiContext(ppdev);
    
    //
    // GDI guarantees us that for a StretchBlt the destination surface
    // will always be in video memory, not in system memory
    //
    ASSERTDD(pSurfDst->flags & SF_VM, "Dest surface is not in video memory");

    //
    // If the source is not a driver created surface or currently not sit
    // in the video memory, we just punt it back because GDI doing it will
    // be faster
    //
    if ( (!pSurfSrc) || (pSurfSrc->flags & SF_SM) )
    {
        DISPDBG((6, "Punt because source = 0x%x or in sys memory", pSurfSrc));
        goto Punt_It;
    }

    //
    // We don't do the stretch blt if the mask is not NULL or the translate is
    // not trivial. We also don't do it if the source and current screen has
    // different color depth
    //
    if ( (psoMsk == NULL)
       &&((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL))
       &&((psoSrc->iBitmapFormat == ppdev->iBitmapFormat)) )
    {
        cxDst = prclDst->right - prclDst->left;
        cyDst = prclDst->bottom - prclDst->top;
        cxSrc = prclSrc->right - prclSrc->left;
        cySrc = prclSrc->bottom - prclSrc->top;

        //
        // Our 'vStretchDIB' routine requires that the stretch be
        // non-inverting, within a certain size, to have no source
        // clipping, and to have no empty rectangles (the latter is the
        // reason for the '- 1' on the unsigned compare here):
        //
        if ( ((cxSrc - 1) < STRETCH_MAX_EXTENT)
           &&((cySrc - 1) < STRETCH_MAX_EXTENT)
           &&((cxDst - 1) < STRETCH_MAX_EXTENT)
           &&((cyDst - 1) < STRETCH_MAX_EXTENT)
           &&(prclSrc->left   >= 0)
           &&(prclSrc->top    >= 0)
           &&(prclSrc->right  <= psoSrc->sizlBitmap.cx)
           &&(prclSrc->bottom <= psoSrc->sizlBitmap.cy))
        {
            //
            // Our snazzy routine only does COLORONCOLOR.  But for
            // stretching blts, BLACKONWHITE and WHITEONBLACK are also
            // equivalent to COLORONCOLOR
            //
            if ( !bStretchInit(psoDst, psoSrc) )
            {
                goto Punt_It;
            }

            if ( (pco == NULL) || (pco->iDComplexity == DC_TRIVIAL) )
            {
                //
                // If there is no clipping, we just set the clipping area
                // as the maximum
                // Note: SCISSOR_MAX is defined as 2047 because this is
                // the maximum clip size P2 can handle.
                // It is OK to set this maximum clip size since no device
                // bitmap will be bigger than 2047. This is the limitation
                // of P2 hardware. See DrvCreateDeviceBitmap() for more
                // detail
                //
                rclClip.left   = 0;
                rclClip.top    = 0;
                rclClip.right  = SCISSOR_MAX;
                rclClip.bottom = SCISSOR_MAX;
                prclClip = &rclClip;

                DISPDBG((7, "Trivial clipping"));
                StretchSingleClipRect:

                vStretchBlt(psoDst,
                            psoSrc,
                            prclDst,
                            prclSrc,
                            prclClip);

                DISPDBG((6, "DrvStretchBlt return TRUE"));
                goto Return_True;
            }
            else if (pco->iDComplexity == DC_RECT)
            {
                DISPDBG((7, "DC_RECT clipping"));
                prclClip = &pco->rclBounds;
                goto StretchSingleClipRect;
            }
            else
            {
                DISPDBG((7, "Complex clipping"));
                CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);

                //
                // Enumerate all the clip rectangles
                //
                do
                {
                    //
                    // Get one clip rectangle
                    //
                    bMore = CLIPOBJ_bEnum(pco, sizeof(ceInfo),
                                          (ULONG*)&ceInfo);

                    //
                    // Get the intersect region with the dest rectangle
                    //
                    lNumOfIntersections = cIntersect(prclDst, ceInfo.arcl,
                                                     ceInfo.c);

                    //
                    // If there is clipping, then we do stretch region
                    // by region
                    //
                    if ( lNumOfIntersections != 0 )
                    {
                        for ( i = 0; i < lNumOfIntersections; ++i )
                        {
                            vStretchBlt(psoDst,
                                        psoSrc,
                                        prclDst,
                                        prclSrc,
                                        &ceInfo.arcl[i]);
                        }
                    }
                } while (bMore);

                DISPDBG((6, "DrvStretchBlt return TRUE"));
                goto Return_True;
            }// Non-DC rect clipping
        }// source/dest withnin range
    }// No mask, trivial xlate, same BMP format

Return_True:
    vStretchReset(ppdev);
    InputBufferFlush(ppdev);
    return TRUE;

Punt_It:
    DISPDBG((6, "DrvStretchBlt punt"));
    bRet = EngStretchBlt(psoDst, psoSrc, psoMsk, pco, pxlo, pca,
                         pptlHTOrg, prclDst, prclSrc, pptlMsk, iMode);

    return(bRet);
}// DrvStretchBlt()


