/******************************Module*Header*******************************\
* Module Name: trivblt.cxx
*
* EngCopyBits does the bitmap simulations source copy blts.
* The Rop is 0xCCCC, no brush or mask required.  Dib src
* and Dib dest are required.
*
* Created: 05-Feb-1991 21:06:12
* Author: Patrick Haluptzok patrickh
*
* Copyright (c) 1990-1999 Microsoft Corporation
\**************************************************************************/

#include "precomp.hxx"

//
// The following table is used to lookup the function to be used for a
// particular type of copy operation. The table is indexed by a loosely
// encoded index composed of the source format, the destination format,
// the direction of the move, and whether the function is an identify
// function.
//
// This table is used in lieu of a doubly nested switch structure that
// not only takes more room, but requires more execution time.
//
// The index is formed as:
//
//     Index = (iFormatDst << 5) | (iFormatSrc << 2);
//     if (xDir < 0) {
//         Index += 2;
//     }
//
//     if (pxlo->bIsIdentity()) {
//         Index += 1;
//     }
//
// N.B. The entire table is filled. Entries that are illegal are tested
//     for using assertions. In free systems, dummy entries are used.
//



VOID
vSrcCopyDummy (
    PBLTINFO BltInfo
    );

PFN_SRCCPY SrcCopyFunctionTable[] = {
        vSrcCopyDummy,              // 000-000-0-0 Dst = ?, Src = ?
        vSrcCopyDummy,              // 000-000-0-1
        vSrcCopyDummy,              // 000-000-1-0
        vSrcCopyDummy,              // 000-000-1-1

        vSrcCopyDummy,              // 000-001-0-0 Dst = ?, Src = BMF_1BPP
        vSrcCopyDummy,              // 000-001-0-1
        vSrcCopyDummy,              // 000-001-1-0
        vSrcCopyDummy,              // 000-001-1-1

        vSrcCopyDummy,              // 000-010-0-0 Dst = ?, Src = BMF_4BPP
        vSrcCopyDummy,              // 000-010-0-1
        vSrcCopyDummy,              // 000-010-1-0
        vSrcCopyDummy,              // 000-010-1-1

        vSrcCopyDummy,              // 000-011-0-0 Dst = ?, Src = BMF_8BPP
        vSrcCopyDummy,              // 000-011-0-1
        vSrcCopyDummy,              // 000-011-1-0
        vSrcCopyDummy,              // 000-011-1-1

        vSrcCopyDummy,              // 000-100-0-0 Dst = ?, Src = BMF_16BPP
        vSrcCopyDummy,              // 000-100-0-1
        vSrcCopyDummy,              // 000-100-1-0
        vSrcCopyDummy,              // 000-100-1-1

        vSrcCopyDummy,              // 000-101-0-0 Dst = ?, Src = BMF_24BPP
        vSrcCopyDummy,              // 000-101-0-1
        vSrcCopyDummy,              // 000-101-1-0
        vSrcCopyDummy,              // 000-101-1-1

        vSrcCopyDummy,              // 000-110-0-0 Dst = ?, Src = BMF_32BPP
        vSrcCopyDummy,              // 000-110-0-1
        vSrcCopyDummy,              // 000-110-1-0
        vSrcCopyDummy,              // 000-110-1-1

        vSrcCopyDummy,              // 000-111-0-0 Dst = ?, Src = ?
        vSrcCopyDummy,              // 000-111-0-1
        vSrcCopyDummy,              // 000-111-1-0
        vSrcCopyDummy,              // 000-111-1-1

        vSrcCopyDummy,              // 001-000-0-0 Dst = BMF_1BPP, Src = ?
        vSrcCopyDummy,              // 001-000-0-1
        vSrcCopyDummy,              // 001-000-1-0
        vSrcCopyDummy,              // 001-000-1-1

        vSrcCopyS1D1LtoR,           // 001-001-0-0 Dst = BMF_1BPP, Src = BMF_1BPP
        vSrcCopyS1D1LtoR,           // 001-001-0-1
        vSrcCopyS1D1RtoL,           // 001-001-1-0
        vSrcCopyS1D1RtoL,           // 001-001-1-1

        vSrcCopyS4D1,               // 001-010-0-0 Dst = BMF_1BPP, Src = BMF_4BPP
        vSrcCopyS4D1,               // 001-010-0-1
        vSrcCopyS4D1,               // 001-010-1-0
        vSrcCopyS4D1,               // 001-010-1-1

        vSrcCopyS8D1,               // 001-011-0-0 Dst = BMF_1BPP, Src = BMF_8BPP
        vSrcCopyS8D1,               // 001-011-0-1
        vSrcCopyS8D1,               // 001-011-1-0
        vSrcCopyS8D1,               // 001-011-1-1

        vSrcCopyS16D1,              // 001-100-0-0 Dst = BMF_1BPP, Src = BMF_16BPP
        vSrcCopyS16D1,              // 001-100-0-1
        vSrcCopyS16D1,              // 001-100-1-0
        vSrcCopyS16D1,              // 001-100-1-1

        vSrcCopyS24D1,              // 001-101-0-0 Dst = BMF_1BPP, Src = BMF_24BPP
        vSrcCopyS24D1,              // 001-101-0-1
        vSrcCopyS24D1,              // 001-101-1-0
        vSrcCopyS24D1,              // 001-101-1-1

        vSrcCopyS32D1,              // 001-110-0-0 Dst = BMF_1BPP, Src = BMF_32BPP
        vSrcCopyS32D1,              // 001-110-0-1
        vSrcCopyS32D1,              // 001-110-1-0
        vSrcCopyS32D1,              // 001-110-1-1

        vSrcCopyDummy,              // 001-111-0-0 Dst = BMF_1BPP, Src = ?
        vSrcCopyDummy,              // 001-111-0-1
        vSrcCopyDummy,              // 001-111-1-0
        vSrcCopyDummy,              // 001-111-1-1

        vSrcCopyDummy,              // 010-000-0-0 Dst = BMF_4BPP, Src = ?
        vSrcCopyDummy,              // 010-000-0-1
        vSrcCopyDummy,              // 010-000-1-0
        vSrcCopyDummy,              // 010-000-1-1

        vSrcCopyS1D4,               // 010-001-0-0 Dst = BMF_4BPP, Src = BMF_1BPP
        vSrcCopyS1D4,               // 010-001-0-1
        vSrcCopyS1D4,               // 010-001-1-0
        vSrcCopyS1D4,               // 010-001-1-1

        vSrcCopyS4D4,               // 010-010-0-0 Dst = BMF_4BPP, Src =BMF_4BPP
        vSrcCopyS4D4Identity,       // 010-010-0-1
        vSrcCopyS4D4,               // 010-010-1-0
        vSrcCopyS4D4Identity,       // 010-010-1-1

        vSrcCopyS8D4,               // 010-011-0-0 Dst = BMF_4BPP, Src = BMF_8BPP
        vSrcCopyS8D4,               // 010-011-0-1
        vSrcCopyS8D4,               // 010-011-1-0
        vSrcCopyS8D4,               // 010-011-1-1

        vSrcCopyS16D4,              // 010-100-0-0 Dst = BMF_4BPP, Src = BMF_16BPP
        vSrcCopyS16D4,              // 010-100-0-1
        vSrcCopyS16D4,              // 010-100-1-0
        vSrcCopyS16D4,              // 010-100-1-1

        vSrcCopyS24D4,              // 010-101-0-0 Dst = BMF_4BPP, Src = BMF_24BPP
        vSrcCopyS24D4,              // 010-101-0-1
        vSrcCopyS24D4,              // 010-101-1-0
        vSrcCopyS24D4,              // 010-101-1-1

        vSrcCopyS32D4,              // 010-110-0-0 Dst = BMF_4BPP, Src = BMF_32BPP
        vSrcCopyS32D4,              // 010-110-0-1
        vSrcCopyS32D4,              // 010-110-1-0
        vSrcCopyS32D4,              // 010-110-1-1

        vSrcCopyDummy,              // 010-111-0-0 Dst = BMF_4BPP, Src = ?
        vSrcCopyDummy,              // 010-111-0-1
        vSrcCopyDummy,              // 010-111-1-0
        vSrcCopyDummy,              // 010-111-1-1

        vSrcCopyDummy,              // 011-000-0-0 Dst = BMF_8BPP, Src = ?
        vSrcCopyDummy,              // 011-000-0-1
        vSrcCopyDummy,              // 011-000-1-0
        vSrcCopyDummy,              // 011-000-1-1

        vSrcCopyS1D8,               // 011-001-0-0 Dst = BMF_8BPP, Src = BMF_1BPP
        vSrcCopyS1D8,               // 011-001-0-1
        vSrcCopyS1D8,               // 011-001-1-0
        vSrcCopyS1D8,               // 011-001-1-1

        vSrcCopyS4D8,               // 011-010-0-0 Dst = BMF_8BPP, Src = BMF_4BPP
        vSrcCopyS4D8,               // 011-010-0-1
        vSrcCopyS4D8,               // 011-010-1-0
        vSrcCopyS4D8,               // 011-010-1-1

        vSrcCopyS8D8,               // 011-011-0-0 Dst = BMF_8BPP, Src = BMF_8BPP
        vSrcCopyS8D8IdentityLtoR,   // 011-011-0-1
        vSrcCopyS8D8,               // 011-011-1-0
        vSrcCopyS8D8IdentityRtoL,   // 011-011-1-1

        vSrcCopyS16D8,              // 011-100-0-0 Dst = BMF_8BPP, Src = BMF_16BPP
        vSrcCopyS16D8,              // 011-100-0-1
        vSrcCopyS16D8,              // 011-100-1-0
        vSrcCopyS16D8,              // 011-100-1-1

        vSrcCopyS24D8,              // 011-101-0-0 Dst = BMF_8BPP, Src = BMF_24BPP
        vSrcCopyS24D8,              // 011-101-0-1
        vSrcCopyS24D8,              // 011-101-1-0
        vSrcCopyS24D8,              // 011-101-1-1

        vSrcCopyS32D8,              // 011-110-0-0 Dst = BMF_8BPP, Src = BMF_32BPP
        vSrcCopyS32D8,              // 011-110-0-1
        vSrcCopyS32D8,              // 011-110-1-0
        vSrcCopyS32D8,              // 011-110-1-1

        vSrcCopyDummy,              // 011-111-0-0 Dst = BMF_8BPP, Src = ?
        vSrcCopyDummy,              // 011-111-0-1
        vSrcCopyDummy,              // 011-111-1-0
        vSrcCopyDummy,              // 011-111-1-1

        vSrcCopyDummy,              // 100-000-0-0 Dst = BMF_16BPP, Src = ?
        vSrcCopyDummy,              // 100-000-0-1
        vSrcCopyDummy,              // 100-000-1-0
        vSrcCopyDummy,              // 100-000-1-1

        vSrcCopyS1D16,              // 100-001-0-0 Dst = BMF_16BPP, Src = BMF_1BPP
        vSrcCopyS1D16,              // 100-001-0-1
        vSrcCopyS1D16,              // 100-001-1-0
        vSrcCopyS1D16,              // 100-001-1-1

        vSrcCopyS4D16,              // 100-010-0-0 Dst = BMF_16BPP, Src = BMF_4BPP
        vSrcCopyS4D16,              // 100-010-0-1
        vSrcCopyS4D16,              // 100-010-1-0
        vSrcCopyS4D16,              // 100-010-1-1

        vSrcCopyS8D16,              // 100-011-0-0 Dst = BMF_16BPP, Src = BMF_8BPP
        vSrcCopyS8D16,              // 100-011-0-1
        vSrcCopyS8D16,              // 100-011-1-0
        vSrcCopyS8D16,              // 100-011-1-1

        vSrcCopyS16D16,             // 100-100-0-0 Dst = BMF_16BPP, Src = BMF_16BPP
        vSrcCopyS16D16Identity,     // 100-100-0-1
        vSrcCopyS16D16,             // 100-100-1-0
        vSrcCopyS16D16Identity,     // 100-100-1-1

        vSrcCopyS24D16,             // 100-101-0-0 Dst = BMF_16BPP, Src = BMF_24BPP
        vSrcCopyS24D16,             // 100-101-0-1
        vSrcCopyS24D16,             // 100-101-1-0
        vSrcCopyS24D16,             // 100-101-1-1

        vSrcCopyS32D16,             // 100-110-0-0 Dst = BMF_16BPP, Src = BMF_32BPP
        vSrcCopyS32D16,             // 100-110-0-1
        vSrcCopyS32D16,             // 100-110-1-0
        vSrcCopyS32D16,             // 100-110-1-1

        vSrcCopyDummy,              // 100-111-0-0 Dst = BMF_16BPP, Src = ?
        vSrcCopyDummy,              // 100-111-0-1
        vSrcCopyDummy,              // 100-111-1-0
        vSrcCopyDummy,              // 100-111-1-1

        vSrcCopyDummy,              // 101-000-0-0 Dst = BMF_24BPP, Src = ?
        vSrcCopyDummy,              // 101-000-0-1
        vSrcCopyDummy,              // 101-000-1-0
        vSrcCopyDummy,              // 101-000-1-1

        vSrcCopyS1D24,              // 101-001-0-0 Dst = BMF_24BPP, Src = BMF_1BPP
        vSrcCopyS1D24,              // 101-001-0-1
        vSrcCopyS1D24,              // 101-001-1-0
        vSrcCopyS1D24,              // 101-001-1-1

        vSrcCopyS4D24,              // 101-010-0-0 Dst = BMF_24BPP, Src = BMF_4BPP
        vSrcCopyS4D24,              // 101-010-0-1
        vSrcCopyS4D24,              // 101-010-1-0
        vSrcCopyS4D24,              // 101-010-1-1

        vSrcCopyS8D24,              // 101-011-0-0 Dst = BMF_24BPP, Src = BMF_8BPP
        vSrcCopyS8D24,              // 101-011-0-1
        vSrcCopyS8D24,              // 101-011-1-0
        vSrcCopyS8D24,              // 101-011-1-1

        vSrcCopyS16D24,             // 101-100-0-0 Dst = BMF_24BPP, Src = BMF_16BPP
        vSrcCopyS16D24,             // 101-100-0-1
        vSrcCopyS16D24,             // 101-100-1-0
        vSrcCopyS16D24,             // 101-100-1-1

        vSrcCopyS24D24,             // 101-101-0-0 Dst = BMF_24BPP, Src = BMF_24BPP
        vSrcCopyS24D24Identity,     // 101-101-0-1
        vSrcCopyS24D24,             // 101-101-1-0
        vSrcCopyS24D24Identity,     // 101-101-1-1

        vSrcCopyS32D24,             // 101-110-0-0 Dst = BMF_24BPP, Src = BMF_32BPP
        vSrcCopyS32D24,             // 101-110-0-1
        vSrcCopyS32D24,             // 101-110-1-0
        vSrcCopyS32D24,             // 101-110-1-1

        vSrcCopyDummy,              // 101-111-0-0 Dst = BMF_24BPP, Src = ?
        vSrcCopyDummy,              // 101-111-0-1
        vSrcCopyDummy,              // 101-111-1-0
        vSrcCopyDummy,              // 101-111-1-1

        vSrcCopyDummy,              // 110-000-0-0 Dst = BMF_32BPP, Src = ?
        vSrcCopyDummy,              // 110-000-0-1
        vSrcCopyDummy,              // 110-000-1-0
        vSrcCopyDummy,              // 110-000-1-1

        vSrcCopyS1D32,              // 110-001-0-0 Dst = BMF_32BPP, Src = BMF_1BPP
        vSrcCopyS1D32,              // 110-001-0-1
        vSrcCopyS1D32,              // 110-001-1-0
        vSrcCopyS1D32,              // 110-001-1-1

        vSrcCopyS4D32,              // 110-010-0-0 Dst = BMF_32BPP, Src = BMF_4BPP
        vSrcCopyS4D32,              // 110-010-0-1
        vSrcCopyS4D32,              // 110-010-1-0
        vSrcCopyS4D32,              // 110-010-1-1

        vSrcCopyS8D32,              // 110-011-0-0 Dst = BMF_32BPP, Src = BMF_8BPP
        vSrcCopyS8D32,              // 110-011-0-1
        vSrcCopyS8D32,              // 110-011-1-0
        vSrcCopyS8D32,              // 110-011-1-1

        vSrcCopyS16D32,             // 110-100-0-0 Dst = BMF_32BPP, Src = BMF_16BPP
        vSrcCopyS16D32,             // 110-100-0-1
        vSrcCopyS16D32,             // 110-100-1-0
        vSrcCopyS16D32,             // 110-100-1-1

        vSrcCopyS24D32,             // 110-101-0-0 Dst = BMF_32BPP, Src = BMF_24BPP
        vSrcCopyS24D32,             // 110-101-0-1
        vSrcCopyS24D32,             // 110-101-1-0
        vSrcCopyS24D32,             // 110-101-1-1

        vSrcCopyS32D32,             // 110-110-0-0 Dst = BMF_32BPP, Src = BMF_32BPP
        vSrcCopyS32D32Identity,     // 110-110-0-1
        vSrcCopyS32D32,             // 110-110-1-0
        vSrcCopyS32D32Identity,     // 110-110-1-1

        vSrcCopyDummy,              // 110-111-0-0 Dst = BMF_32BPP, Src = ?
        vSrcCopyDummy,              // 110-111-0-1
        vSrcCopyDummy,              // 110-111-1-0
        vSrcCopyDummy               // 110-111-1-1
};

/******************************Public*Routine******************************\
* EngCopyBits
*
* Purpose:  Does all 0xCCCC blts.  This includes RLE blts.
*
* Description:
*
*    Sets up for a blt from <psoSrc> to <psoDst>.  The actual copying of
*    the bits is performed by a function call.  The function to be used
*    is determined by the formats of the source & destination - and is
*    is selected by making a call to <pfnSrcCpy>.
*
*    The blt setup consists of filling a BLTINFO structure with
*       - offsets into the source and destination bitmaps
*       - intial values of the source and destination pointers
*       - ending points in source and destination.
*
*    This function also controls clipping:  In the complex clipping case,
*    the BLTINFO structure is set up and the blt function is called for
*    EACH rectangle in the clipping object <pco>.
*
*    NB:  RLE Sources are treated as a special case, since we can't cheat
*         and start copying from inside the source bitmap.  We must play
*         the RLE from the beginning for each clipping region.
*         An optimization to get around this is coming.
*
* History:
*  22-Jan-1992 - Andrew Milton (w-andym):
*      Isolated the RLE source cases and provided some RLE play
*      optimizations.
*
*  02-May-1991 -by- Patrick Haluptzok patrickh
* Wrote it.
\**************************************************************************/

BOOL
EngCopyBits(
    SURFOBJ    *psoDst,
    SURFOBJ    *psoSrc,
    CLIPOBJ    *pco,
    XLATEOBJ   *pxlo,
    PRECTL      prclDst,
    PPOINTL     pptlSrc
)
{
    ASSERTGDI(psoDst != NULL, "ERROR EngCopyBits:  No Dst. Object\n");
    ASSERTGDI(psoSrc != NULL, "ERROR EngCopyBits:  No Src. Object\n");
    ASSERTGDI(prclDst != (PRECTL) NULL,  "ERROR EngCopyBits:  No Target Rect.\n");
    ASSERTGDI(pptlSrc != (PPOINTL) NULL, "ERROR EngCopyBits:  No Start Point.\n");
    ASSERTGDI(prclDst->left < prclDst->right, "ERROR EngCopyBits0\n");
    ASSERTGDI(prclDst->top < prclDst->bottom, "ERROR EngCopyBits1\n");

    ASSERTGDI(psoDst->iType == STYPE_BITMAP,
              "ERROR EngCopyBits:  Dst. Object is not a bitmap.\n");

    PSURFACE pSurfDst = SURFOBJ_TO_SURFACE(psoDst);
    PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE(psoSrc);

    ASSERTGDI(pSurfDst->iFormat() != BMF_JPEG,
              "ERROR EngCopyBits: dst BMF_JPEG\n");
    ASSERTGDI(pSurfDst->iFormat() != BMF_PNG,
              "ERROR EngCopyBits: dst BMF_PNG\n");
    ASSERTGDI(pSurfSrc->iFormat() != BMF_JPEG,
              "ERROR EngCopyBits: src BMF_JPEG\n");
    ASSERTGDI(pSurfSrc->iFormat() != BMF_PNG,
              "ERROR EngCopyBits: src BMF_PNG\n");

// If this is a device surface pass it off to the driver.

    if (psoSrc->iType != STYPE_BITMAP)
    {
        PDEVOBJ pdoSrc(pSurfSrc->hdev());

        PFN_DrvCopyBits pfnCopyBits = PPFNDRV(pdoSrc,CopyBits);

    // If the source is a mirrored surface, pass the read request back 
    // through the DDML.  This allows a driver like NetMeeting to read
    // from the screen:

        EXLATEOBJ xloParent;

        if (pSurfSrc->bMirrorSurface() &&
            (pdoSrc.hdev() != pdoSrc.hdevParent()))
        {
            PDEVOBJ pdoSrc(pSurfSrc->hdev());
            PDEVOBJ pdoParent(pdoSrc.hdevParent());
            SURFREF srParent((HSURF)pSurfSrc->hMirrorParent);
            if (!srParent.bValid()) return (FALSE);
            if (xloParent.bInitXlateObj(
                          NULL,DC_ICM_OFF,
                          pdoParent.ppalSurf(), pdoSrc.ppalSurf(),
                          ppalDefault, ppalDefault, 
                          0L,0L,0L, XLATE_USE_SURFACE_PAL))
                pxlo = xloParent.pxlo();
            else
                return (FALSE);

            psoSrc      = srParent.ps->pSurfobj();
            pfnCopyBits = PPFNDRV(pdoParent, CopyBits);
        }

        return(pfnCopyBits(psoDst,
                           psoSrc,
                           pco,
                           pxlo,
                           prclDst,
                           pptlSrc));
    }

// Synchronize with the device driver before touching the device surface.

    {
        PDEVOBJ po(psoDst->hdev);
        po.vSync(psoDst,NULL,0);
    }

    {
        PDEVOBJ po(psoSrc->hdev);
        po.vSync(psoSrc,NULL,0);
    }

// Local Variables required for the blt

    BOOL     bMore;            // True while more clip regions exist
    BOOL     bRLE = FALSE;     // True if the source is an RLE bitmap
    ULONG    ircl;             // Clip region index
    BLTINFO  bltinfo;          // Data passed to our vSrcCopySnDn fxn

    /* Compute the directions for the copy and clipping enumeration.  There
     * are two cases:  RLE & not.
     *
     * RLE's are always copied Left-Right, Bottom-Top; which is also their
     * clipping enumeration.
     *
     * For non-RLE's, the copy direction is dependant on overlap.  The
     * X and Y directions must be chosen so ensure no portion of the source
     * is clobbered by the copy operation.  If there is no overlap, the
     * copy and clipping enumeration is Left-Right, Top-Bottom.
     */

    LONG xDir = 1L, yDir = 1L;  /* X, Y Directions.  Positive = Left, Down */
    LONG iDir;                  // Order to fetch clip region rectangles

    /*
     * Are we going to do reads from BMF_NOTSYSMEM ie Video memory ?
     * If so set up bltinfo so the blitting routine wil do source aligned reads.
     */

    if ((psoSrc->iBitmapFormat == BMF_8RLE) || (psoSrc->iBitmapFormat == BMF_4RLE))
    {
        /* RLE Case. */

        iDir = CD_RIGHTUP;
        xDir =  1L;
        yDir = -1L;

        bltinfo.lDeltaDst = -psoDst->lDelta;
        bltinfo.lDeltaSrc = 0;

        bRLE = TRUE;
    }
    else
    {
        /* Non-RLE Case.  
         *
     * Check whether source and destination are the same by comparing
     * the pvScan0 pointers.  We can't simply compare surface pointers or
     * handles because some drivers punt this call to GDI, but pass us
     * different SURFOBJs for the source and destination even when
     * they're really the same surface.
     */

        if (psoSrc->pvScan0 == psoDst->pvScan0) 
        {
            if (pptlSrc->x < prclDst->left)
            {
                xDir = -1L;                   /* Copy Right to Left          */
                if (pptlSrc->y < prclDst->top)
                {
                    yDir = -1L;               /* Copy Bottom to Top          */
                    iDir = CD_LEFTUP;         /* Clip Left-Right, Bottom-Top */
                }
                else
                {
                    iDir = CD_LEFTDOWN;       /* Clip Left-Right, Top-Bottom */
                }
            }
            else
            {
                if (pptlSrc->y < prclDst->top)
                {
                    yDir = -1L;               /* Copy Bottom to Top          */
                    iDir = CD_RIGHTUP;        /* Clip Right-Left, Bottom-Top */
                }
                else
                    iDir = CD_RIGHTDOWN;
            }
        }
        else
            iDir = CD_ANY;

        bltinfo.lDeltaSrc  = (yDir > 0) ?  psoSrc->lDelta :
                                          -psoSrc->lDelta;
        bltinfo.lDeltaDst  = (yDir > 0) ?  psoDst->lDelta :
                                          -psoDst->lDelta;
    }

    /* Determine the clipping region complexity. */

    CLIPENUMRECT    clenr;           /* buffer for storing clip rectangles */
    if (pco != (CLIPOBJ *) NULL)
    {
        switch(pco->iDComplexity)
        {
        case DC_TRIVIAL:
            bMore = FALSE;
            clenr.c = 1;
            clenr.arcl[0] = *prclDst;    // Use the target for clipping
            break;

        case DC_RECT:
            bMore = FALSE;
            clenr.c = 1;
            clenr.arcl[0] = pco->rclBounds;
            break;

        case DC_COMPLEX:
            bMore = TRUE;
            ((ECLIPOBJ *) pco)->cEnumStart(FALSE, CT_RECTANGLES, iDir,
                                           CLIPOBJ_ENUM_LIMIT);
            break;

        default:
            RIP("ERROR EngCopyBits bad clipping type");

        } /* switch */
    }
    else
    {
        bMore = FALSE;                   /* Default to TRIVIAL for no clip */
        clenr.c = 1;
        clenr.arcl[0] = *prclDst;        // Use the target for clipping
    } /* if */


    /* Set up the static blt information into the BLTINFO structure -
     * The colour translation, & the copy directions.
     */

    /* pxlo is NULL implies identity colour translation. */
    if (pxlo == NULL)
        bltinfo.pxlo = &xloIdent;
    else
        bltinfo.pxlo = (XLATE *) pxlo;

    bltinfo.xDir = xDir;
    bltinfo.yDir = yDir;

    /* Use a seperate loop for RLE bitmaps.  This way, we won't slow down
     * an iteration with an IF on each pass.  The trade-off is to duplicate
     * a portion of the code.
     */

    if (bRLE)
    {
        /* Fetch our blt function.  Die if NULL */

        PFN_RLECPY pfnRLECopy = pfnGetRLESrcCopy(psoSrc->iBitmapFormat,
                                                 psoDst->iBitmapFormat);
        if (pfnRLECopy == (PFN_RLECPY) NULL)
            return (FALSE);

        BOOL bBytesRemain = TRUE;

        /* Since an RLE bitmap must be played from its beginning,
         * we do not need to calculate offsets into the source bitmap.
         * This way, most of the information required for the BLTINFO
         * can be read off the Source & Destination objects.
         */

        bltinfo.ptlSrc    = *pptlSrc;
        bltinfo.pdioSrc   = pSurfSrc;
        bltinfo.yDstStart = (LONG)(prclDst->top + psoSrc->sizlBitmap.cy -
                                   pptlSrc->y - 1);

        bltinfo.xDstStart = (LONG)(prclDst->left - pptlSrc->x);
        bltinfo.ulOutCol  = bltinfo.xDstStart;

        bltinfo.pjSrc   = (PBYTE) psoSrc->pvScan0;
        bltinfo.pjDst   = (PBYTE) (((PBYTE) psoDst->pvScan0) +
                          bltinfo.yDstStart*psoDst->lDelta);
        bltinfo.ulConsumed = 0;
        bltinfo.rclDst.top = 0;

        do
        {
            PRECTL prcl;
            if (bMore)
                bMore = ((ECLIPOBJ *) pco)->bEnum(sizeof(clenr),
                                                  (PVOID) &clenr);

            for (ircl = 0; ircl < clenr.c; ircl++)
            {

                prcl = &clenr.arcl[ircl];

                /* Insersect the clip rectangle with the target rectangle to
                 * determine our visible rectangle
                 */

                if (prcl->left < prclDst->left)
                    prcl->left = prclDst->left;
                if (prcl->right > prclDst->right)
                    prcl->right = prclDst->right;
                if (prcl->top < prclDst->top)
                    prcl->top = prclDst->top;
                if (prcl->bottom > prclDst->bottom)
                    prcl->bottom = prclDst->bottom;

                /* Process the result if it's a valid rectangle.       */

                if ((prcl->top  < prcl->bottom) && (prcl->left < prcl->right))
                {
                    /* Adjust our starting position based on previous clips */

                    if (prcl->bottom <= bltinfo.rclDst.top)
                    {
                        if ((ULONG)prcl->top > bltinfo.ulEndRow)
                            continue;

                        if (!bBytesRemain)
                        {
                            bMore = FALSE; // Force us out of the outer loop
                            break;         // Force us out of the inner loop
                        }

                        bltinfo.pjSrc = bltinfo.pjSrcEnd;
                        bltinfo.pjDst = bltinfo.pjDstEnd;
                        bltinfo.yDstStart  = bltinfo.ulEndRow;
                        bltinfo.ulOutCol   = bltinfo.ulEndCol;
                        bltinfo.ulConsumed = bltinfo.ulEndConsumed;
                    }

                    bltinfo.rclDst = *prcl;
                    bBytesRemain = (*pfnRLECopy)(&bltinfo);

                }

            } /* for */

        } while(bMore);

    }
    else
    {
        /* Non-RLE Case */

        ULONG Index;
        PFN_SRCCPY pfnSrcCopy;

        ASSERTGDI(BMF_1BPP == 1, "ERROR EngCopyBits:  BMF_1BPP not eq 1");
        ASSERTGDI(BMF_4BPP == 2, "ERROR EngCopyBits:  BMF_1BPP not eq 2");
        ASSERTGDI(BMF_8BPP == 3, "ERROR EngCopyBits:  BMF_1BPP not eq 3");
        ASSERTGDI(BMF_16BPP == 4, "ERROR EngCopyBits:  BMF_1BPP not eq 4");
        ASSERTGDI(BMF_24BPP == 5, "ERROR EngCopyBits:  BMF_1BPP not eq 5");
        ASSERTGDI(BMF_32BPP == 6, "ERROR EngCopyBits:  BMF_1BPP not eq 6");
        ASSERTGDI(psoDst->iBitmapFormat <= BMF_32BPP, "ERROR EngCopyBits:  bad destination format");
        ASSERTGDI(psoSrc->iBitmapFormat <= BMF_32BPP, "ERROR EngCopyBits:  bad source format");
        ASSERTGDI(psoDst->iBitmapFormat != 0, "ERROR EngCopyBits:  bad destination format");
        ASSERTGDI(psoSrc->iBitmapFormat != 0, "ERROR EngCopyBits:  bad source format");

        //
        // Compute the function table index and select the source copy
        // function.
        //

        Index = (psoDst->iBitmapFormat << 5) | (psoSrc->iBitmapFormat << 2);
        if (xDir < 0) {
            Index += 2;
        }

        KFLOATING_SAVE fpState;
        BOOL bRestoreFP = FALSE;
        if (((XLATE *)(bltinfo.pxlo))->bIsIdentity())
        {
            Index += 1;
            if(psoSrc->fjBitmap & BMF_NOTSYSMEM)
            {
                bltinfo.fSrcAlignedRd = TRUE;
#if i386
                if(HasMMX)
                {
                    bRestoreFP = TRUE;
                    if(!NT_SUCCESS(KeSaveFloatingPointState(&fpState)))
                    {
                        bltinfo.fSrcAlignedRd = FALSE;
                        bRestoreFP = FALSE;
                    }
                }
#endif
            }
        }

        pfnSrcCopy = SrcCopyFunctionTable[Index];
        do {

            if (bMore)
                bMore = ((ECLIPOBJ *) pco)->bEnum(sizeof(clenr),
                                                  (PVOID) &clenr);

            for (ircl = 0; ircl < clenr.c; ircl++)
            {
                PRECTL prcl = &clenr.arcl[ircl];

                /* Insersect the clip rectangle with the target rectangle to
                 * determine our visible recangle
                 */

                if (prcl->left < prclDst->left)
                    prcl->left = prclDst->left;
                if (prcl->right > prclDst->right)
                    prcl->right = prclDst->right;
                if (prcl->top < prclDst->top)
                    prcl->top = prclDst->top;
                if (prcl->bottom > prclDst->bottom)
                    prcl->bottom = prclDst->bottom;

                /* Process the result if it's a valid rectangle.       */

                if ((prcl->top < prcl->bottom) && (prcl->left < prcl->right))
                {
                    /* These variables are used for computing where the
                     * scanlines start.
                     */
                    LONG   xSrc;
                    LONG   ySrc;
                    LONG   xDst;
                    LONG   yDst;

                    // Figure out the upper-left coordinates of rects to blt
                    xDst = prcl->left;
                    yDst = prcl->top;
                    xSrc = pptlSrc->x + xDst - prclDst->left;
                    ySrc = pptlSrc->y + yDst - prclDst->top;

                    // Figure out the width and height of this rectangle
                    bltinfo.cx = prcl->right  - xDst;
                    bltinfo.cy = prcl->bottom - yDst;

                    /* # of pixels offset to first pixel for src and dst
                     * from start of scan
                     */
                    bltinfo.xSrcStart = (xDir > 0) ? xSrc :
                                                     (xSrc + bltinfo.cx - 1);
                    bltinfo.xSrcEnd   = bltinfo.xSrcStart +
                                         (bltinfo.cx * xDir);
                    bltinfo.xDstStart = (xDir > 0) ? xDst :
                                                     (xDst + bltinfo.cx - 1);
                    bltinfo.yDstStart = prcl->top;

                    // Src scanline begining
                    // Destination scanline begining
                    if (yDir > 0)
                    {
                        bltinfo.pjSrc = ((PBYTE) psoSrc->pvScan0) +
                                                 ySrc*(psoSrc->lDelta);
                        bltinfo.pjDst = ((PBYTE) psoDst->pvScan0) +
                                                 yDst * (psoDst->lDelta);
                    }
                    else
                    {
                        bltinfo.pjSrc = ((PBYTE) psoSrc->pvScan0) +
                                 (ySrc + bltinfo.cy - 1) * (psoSrc->lDelta);
                        bltinfo.pjDst = ((PBYTE) psoDst->pvScan0) +
                                 (yDst + bltinfo.cy - 1) * (psoDst->lDelta);
                    } /* if */

                    /* Do the blt */

                    (*pfnSrcCopy)(&bltinfo);

                } /* if */

            } /* for */

        } while (bMore);
#if i386
        if(HasMMX)
        {
            if(bRestoreFP)
            {
                KeRestoreFloatingPointState(&fpState);
            }
        }
#endif

    } /* if */
    return(TRUE);

} /* EngCopyBits */

/******************************Private*Routine*****************************\
* vSrcCopyDummy
*
* This gets the correct function to dispatch to for Src Copy Bitblt.
*
* History:
*  02-Sep-1992 -by- David N. Cutler davec
* Wrote it.
\**************************************************************************/

VOID
vSrcCopyDummy (
    PBLTINFO BltInfo
    )

{

    ASSERTGDI(FALSE, "ERROR EngCopyBits: dummy function called");
    return;
}

/******************************Public*Routine******************************\
* pfnGetRLESrcCopy
*
* This gets the correct function to dispatch to for Src Copy Bitblt,
* assuming that the source is an RLE bitmap.
*
* History:
*
*  05 Mar 1992 - Andrew Milton (w-andym):
*     Creation.
*
\**************************************************************************/

PFN_RLECPY
pfnGetRLESrcCopy(
    ULONG iFormatSrc,
    ULONG iFormatDst)
{

    switch(iFormatDst) {

    case BMF_1BPP:

        switch(iFormatSrc)
        {
        case BMF_8RLE:
            return(bSrcCopySRLE8D1);

        case BMF_4RLE:
            return(bSrcCopySRLE4D1);

        default:
            RIP("ERROR: Invalid iFormatSrc in XlateList");
        }

    case BMF_4BPP:

        switch(iFormatSrc)
        {
        case BMF_8RLE:
            return(bSrcCopySRLE8D4);

        case BMF_4RLE:
            return(bSrcCopySRLE4D4);

        default:
            RIP("ERROR: Invalid iFormatSrc in XlateList");
        }

    case BMF_8BPP:

        switch(iFormatSrc)
        {
        case BMF_8RLE:
            return(bSrcCopySRLE8D8);

        case BMF_4RLE:
            return(bSrcCopySRLE4D8);

        default:
            RIP("ERROR: Invalid iFormatSrc in XlateList");
        }

    case BMF_16BPP:

        switch(iFormatSrc)
        {
        case BMF_8RLE:
            return(bSrcCopySRLE8D16);

        case BMF_4RLE:
            return(bSrcCopySRLE4D16);

        default:
            RIP("ERROR: Invalid iFormatSrc in XlateList");
        }

    case BMF_24BPP:

        switch(iFormatSrc)
        {
        case BMF_8RLE:
            return(bSrcCopySRLE8D24);

        case BMF_4RLE:
            return(bSrcCopySRLE4D24);

        default:
            RIP("ERROR: Invalid iFormatSrc in XlateList");
        }

    case BMF_32BPP:
        switch(iFormatSrc)
        {
        case BMF_8RLE:
            return(bSrcCopySRLE8D32);

        case BMF_4RLE:
            return(bSrcCopySRLE4D32);

        default:
            RIP("ERROR: Invalid iFormatSrc in XlateList");
        }

    default:
        RIP("ERROR: Invalid iFormatDst in XlateList");
    } /* switch */

    return(NULL);
} /* pfnGetRLESrcCopy */