/******************************Module*Header*******************************\ * Module Name: bitblt.c * * Banked Frame Buffer bitblit * * Copyright (c) 1992 Microsoft Corporation * \**************************************************************************/ #include "driver.h" /************************************************************************\ * bIntersectRect * * Calculates the intersection between *prcSrc1 and *prcSrc2, * returning the resulting rect in *prcDst. Returns TRUE if * *prcSrc1 intersects *prcSrc2, FALSE otherwise. If there is no * intersection, an empty rect is returned in *prcDst. \************************************************************************/ static const RECTL rclEmpty = { 0, 0, 0, 0 }; BOOL bIntersectRect( PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2) { prcDst->left = max(prcSrc1->left, prcSrc2->left); prcDst->right = min(prcSrc1->right, prcSrc2->right); // check for empty rect if (prcDst->left < prcDst->right) { prcDst->top = max(prcSrc1->top, prcSrc2->top); prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom); // check for empty rect if (prcDst->top < prcDst->bottom) return(TRUE); // not empty } // empty rect *prcDst = rclEmpty; return(FALSE); } /******************************Public*Routine******************************\ * BOOL bPuntScreenToScreenCopyBits(ppdev, pco, pxlo, prclDest, pptlSrc) * * Performs a screen-to-screen CopyBits entirely using an intermediate * temporary buffer and GDI. * * We found that on most machines it was faster to have the engine copy * the source to a buffer, then blit the buffer to the destination, than * to have optimized ASM code that copies a word at a time. The reason? * The engine does d-word moves, which are faster than word moves even * going over the bus to a 16 bit display device. * * We could also write optimized ASM code that does d-word moves, but the * win will be marginal, we're time constrained, we also need a routine * like this to handle complex clip objects and palette translates, and * most of the other times we can use planar copies for important things * like scrolls, anyways. * \**************************************************************************/ BOOL bPuntScreenToScreenCopyBits( PPDEV ppdev, CLIPOBJ* pco, XLATEOBJ* pxlo, RECTL* prclDest, POINTL* pptlSrc) { RECTL rclDest; POINTL ptlSrc; BOOL b = TRUE; SURFOBJ* pso = ppdev->pSurfObj; SURFOBJ* psoTmp = ppdev->psoTmp; if (prclDest->top < pptlSrc->y) { //////////////////////////////////////////////////////////////// // Do a top-to-bottom copy: //////////////////////////////////////////////////////////////// LONG ySrcBottom; LONG yDestBottom; LONG yDestTop = prclDest->top; LONG ySrcTop = pptlSrc->y; LONG ySrcLast = ySrcTop + (prclDest->bottom - prclDest->top); if (ySrcTop < ppdev->rcl1WindowClip.top || ySrcTop >= ppdev->rcl1WindowClip.bottom) { ppdev->pfnBankControl(ppdev, ySrcTop, JustifyTop); } pso->pvScan0 = ppdev->pvBitmapStart; while (TRUE) { // Copy an entire source bank into the temporary buffer: ySrcBottom = min(ySrcLast, ppdev->rcl1WindowClip.bottom); ptlSrc.x = pptlSrc->x; ptlSrc.y = ySrcTop; rclDest.left = prclDest->left; rclDest.top = 0; rclDest.right = prclDest->right; rclDest.bottom = ySrcBottom - ySrcTop; b &= EngCopyBits(psoTmp, pso, NULL, NULL, &rclDest, &ptlSrc); yDestBottom = yDestTop + rclDest.bottom; if (ppdev->rcl1WindowClip.top >= yDestBottom) { ppdev->pfnBankControl(ppdev, yDestBottom - 1, JustifyBottom); pso->pvScan0 = ppdev->pvBitmapStart; } while (TRUE) { // Copy the temporary buffer into one or more destination // banks: LONG yThisTop; LONG yThisBottom; LONG yOffset; yThisBottom = min(yDestBottom, ppdev->rcl1WindowClip.bottom); yThisTop = max(yDestTop, ppdev->rcl1WindowClip.top); yOffset = yThisTop - yDestTop; ptlSrc.x = prclDest->left; ptlSrc.y = yOffset; rclDest.left = prclDest->left; rclDest.top = yThisTop; rclDest.right = prclDest->right; rclDest.bottom = yThisBottom; b &= EngCopyBits(pso, psoTmp, pco, pxlo, &rclDest, &ptlSrc); if (yOffset == 0) break; ppdev->pfnBankControl(ppdev, yThisTop - 1, JustifyBottom); pso->pvScan0 = ppdev->pvBitmapStart; } if (ySrcBottom >= ySrcLast) break; yDestTop = yDestBottom; ySrcTop = ySrcBottom; ppdev->pfnBankControl(ppdev, ySrcTop, JustifyTop); pso->pvScan0 = ppdev->pvBitmapStart; } } else { //////////////////////////////////////////////////////////////// // Do a bottom-to-top copy: //////////////////////////////////////////////////////////////// LONG ySrcTop; LONG yDestTop; LONG yDestBottom = prclDest->bottom; LONG ySrcFirst = pptlSrc->y; LONG ySrcBottom = ySrcFirst + (prclDest->bottom - prclDest->top); if (ySrcBottom <= ppdev->rcl1WindowClip.top || ySrcBottom > ppdev->rcl1WindowClip.bottom) { ppdev->pfnBankControl(ppdev, ySrcBottom - 1, JustifyBottom); } pso->pvScan0 = ppdev->pvBitmapStart; while (TRUE) { // Copy an entire source bank into the temporary buffer: ySrcTop = max(ySrcFirst, ppdev->rcl1WindowClip.top); ptlSrc.x = pptlSrc->x; ptlSrc.y = ySrcTop; rclDest.left = prclDest->left; rclDest.top = 0; rclDest.right = prclDest->right; rclDest.bottom = ySrcBottom - ySrcTop; b &= EngCopyBits(psoTmp, pso, NULL, NULL, &rclDest, &ptlSrc); yDestTop = yDestBottom - rclDest.bottom; if (ppdev->rcl1WindowClip.bottom <= yDestTop) { ppdev->pfnBankControl(ppdev, yDestTop, JustifyTop); pso->pvScan0 = ppdev->pvBitmapStart; } while (TRUE) { // Copy the temporary buffer into one or more destination // banks: LONG yThisTop; LONG yThisBottom; LONG yOffset; yThisTop = max(yDestTop, ppdev->rcl1WindowClip.top); yThisBottom = min(yDestBottom, ppdev->rcl1WindowClip.bottom); yOffset = yThisTop - yDestTop; ptlSrc.x = prclDest->left; ptlSrc.y = yOffset; rclDest.left = prclDest->left; rclDest.top = yThisTop; rclDest.right = prclDest->right; rclDest.bottom = yThisBottom; b &= EngCopyBits(pso, psoTmp, pco, pxlo, &rclDest, &ptlSrc); if (yThisBottom == yDestBottom) break; ppdev->pfnBankControl(ppdev, yThisBottom, JustifyTop); pso->pvScan0 = ppdev->pvBitmapStart; } if (ySrcTop <= ySrcFirst) break; yDestBottom = yDestTop; ySrcBottom = ySrcTop; ppdev->pfnBankControl(ppdev, ySrcBottom - 1, JustifyBottom); pso->pvScan0 = ppdev->pvBitmapStart; } } return(b); } /******************************Public*Routine******************************\ * BOOL bPuntScreenToScreenBitBlt(...) * * Performs a screen-to-screen BitBlt entirely using an intermediate temporary * buffer and GDI. * * This function is basically a clone of bPuntScreenToScreenCopyBits, * except that it can handle funky ROPs and stuff. \**************************************************************************/ BOOL bPuntScreenToScreenBitBlt( PPDEV ppdev, SURFOBJ* psoMask, CLIPOBJ* pco, XLATEOBJ* pxlo, RECTL* prclDest, POINTL* pptlSrc, POINTL* pptlMask, BRUSHOBJ* pbo, POINTL* pptlBrush, ROP4 rop4) { RECTL rclDest; // Temporary destination rectangle POINTL ptlSrc; // Temporary source point POINTL ptlMask; // Temporary mask offset POINTL ptlMaskAdjust; // Adjustment for mask offset BOOL b = TRUE; SURFOBJ* pso = ppdev->pSurfObj; SURFOBJ* psoTmp = ppdev->psoTmp; if (psoMask != NULL) { ptlMaskAdjust.x = prclDest->left - pptlMask->x; ptlMaskAdjust.y = prclDest->top - pptlMask->y; } if (prclDest->top < pptlSrc->y) { //////////////////////////////////////////////////////////////// // Do a top-to-bottom copy: //////////////////////////////////////////////////////////////// LONG ySrcBottom; LONG yDestBottom; LONG yDestTop = prclDest->top; LONG ySrcTop = pptlSrc->y; LONG ySrcLast = ySrcTop + (prclDest->bottom - prclDest->top); if (ySrcTop < ppdev->rcl1WindowClip.top || ySrcTop >= ppdev->rcl1WindowClip.bottom) { ppdev->pfnBankControl(ppdev, ySrcTop, JustifyTop); } pso->pvScan0 = ppdev->pvBitmapStart; while (TRUE) { // Copy an entire source bank into the temporary buffer: ySrcBottom = min(ySrcLast, ppdev->rcl1WindowClip.bottom); ptlSrc.x = pptlSrc->x; ptlSrc.y = ySrcTop; rclDest.left = prclDest->left; rclDest.top = 0; rclDest.right = prclDest->right; rclDest.bottom = ySrcBottom - ySrcTop; b &= EngCopyBits(psoTmp, pso, NULL, NULL, &rclDest, &ptlSrc); yDestBottom = yDestTop + rclDest.bottom; if (ppdev->rcl1WindowClip.top >= yDestBottom) { ppdev->pfnBankControl(ppdev, yDestBottom - 1, JustifyBottom); pso->pvScan0 = ppdev->pvBitmapStart; } while (TRUE) { // Copy the temporary buffer into one or more destination // banks: LONG yThisTop; LONG yThisBottom; LONG yOffset; yThisBottom = min(yDestBottom, ppdev->rcl1WindowClip.bottom); yThisTop = max(yDestTop, ppdev->rcl1WindowClip.top); yOffset = yThisTop - yDestTop; ptlSrc.x = prclDest->left; ptlSrc.y = yOffset; rclDest.left = prclDest->left; rclDest.top = yThisTop; rclDest.right = prclDest->right; rclDest.bottom = yThisBottom; ptlMask.x = rclDest.left - ptlMaskAdjust.x; ptlMask.y = rclDest.top - ptlMaskAdjust.y; b &= EngBitBlt(pso, psoTmp, psoMask, pco, pxlo, &rclDest, &ptlSrc, &ptlMask, pbo, pptlBrush, rop4); if (yOffset == 0) break; ppdev->pfnBankControl(ppdev, yThisTop - 1, JustifyBottom); pso->pvScan0 = ppdev->pvBitmapStart; } if (ySrcBottom >= ySrcLast) break; yDestTop = yDestBottom; ySrcTop = ySrcBottom; ppdev->pfnBankControl(ppdev, ySrcTop, JustifyTop); pso->pvScan0 = ppdev->pvBitmapStart; } } else { //////////////////////////////////////////////////////////////// // Do a bottom-to-top copy: //////////////////////////////////////////////////////////////// LONG ySrcTop; LONG yDestTop; LONG yDestBottom = prclDest->bottom; LONG ySrcFirst = pptlSrc->y; LONG ySrcBottom = ySrcFirst + (prclDest->bottom - prclDest->top); if (ySrcBottom <= ppdev->rcl1WindowClip.top || ySrcBottom > ppdev->rcl1WindowClip.bottom) { ppdev->pfnBankControl(ppdev, ySrcBottom - 1, JustifyBottom); } pso->pvScan0 = ppdev->pvBitmapStart; while (TRUE) { // Copy an entire source bank into the temporary buffer: ySrcTop = max(ySrcFirst, ppdev->rcl1WindowClip.top); ptlSrc.x = pptlSrc->x; ptlSrc.y = ySrcTop; rclDest.left = prclDest->left; rclDest.top = 0; rclDest.right = prclDest->right; rclDest.bottom = ySrcBottom - ySrcTop; b &= EngCopyBits(psoTmp, pso, NULL, NULL, &rclDest, &ptlSrc); yDestTop = yDestBottom - rclDest.bottom; if (ppdev->rcl1WindowClip.bottom <= yDestTop) { ppdev->pfnBankControl(ppdev, yDestTop, JustifyTop); pso->pvScan0 = ppdev->pvBitmapStart; } while (TRUE) { // Copy the temporary buffer into one or more destination // banks: LONG yThisTop; LONG yThisBottom; LONG yOffset; yThisTop = max(yDestTop, ppdev->rcl1WindowClip.top); yThisBottom = min(yDestBottom, ppdev->rcl1WindowClip.bottom); yOffset = yThisTop - yDestTop; ptlSrc.x = prclDest->left; ptlSrc.y = yOffset; rclDest.left = prclDest->left; rclDest.top = yThisTop; rclDest.right = prclDest->right; rclDest.bottom = yThisBottom; ptlMask.x = rclDest.left - ptlMaskAdjust.x; ptlMask.y = rclDest.top - ptlMaskAdjust.y; b &= EngBitBlt(pso, psoTmp, psoMask, pco, pxlo, &rclDest, &ptlSrc, &ptlMask, pbo, pptlBrush, rop4); if (yThisBottom == yDestBottom) break; ppdev->pfnBankControl(ppdev, yThisBottom, JustifyTop); pso->pvScan0 = ppdev->pvBitmapStart; } if (ySrcTop <= ySrcFirst) break; yDestBottom = yDestTop; ySrcBottom = ySrcTop; ppdev->pfnBankControl(ppdev, ySrcBottom - 1, JustifyBottom); pso->pvScan0 = ppdev->pvBitmapStart; } } return(b); } /******************************Public*Data*********************************\ * ROP to mix translation table * * Table to translate ternary raster ops to mixes (binary raster ops). Ternary * raster ops that can't be translated to mixes are translated to 0 (0 is not * a valid mix). * \**************************************************************************/ UCHAR jRop3ToMix[256] = { R2_BLACK, 0, 0, 0, 0, R2_NOTMERGEPEN, 0, 0, 0, 0, R2_MASKNOTPEN, 0, 0, 0, 0, R2_NOTCOPYPEN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, R2_MASKPENNOT, 0, 0, 0, 0, R2_NOT, 0, 0, 0, 0, R2_XORPEN, 0, 0, 0, 0, R2_NOTMASKPEN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, R2_MASKPEN, 0, 0, 0, 0, R2_NOTXORPEN, 0, 0, 0, 0, R2_NOP, 0, 0, 0, 0, R2_MERGENOTPEN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, R2_COPYPEN, 0, 0, 0, 0, R2_MERGEPENNOT, 0, 0, 0, 0, R2_MERGEPEN, 0, 0, 0, 0, R2_WHITE }; /******************************Public*Routine******************************\ * BOOL DrvBitBlt(psoDest, psoSrc, psoMask, pco, pxlo, prclDest, pptlSrc, * pptlMask, pbo, pptlBrush, rop4) * * This routine will handle any blit. Perhaps glacially, but it will be * handled. \**************************************************************************/ BOOL DrvBitBlt( SURFOBJ* psoDest, SURFOBJ* psoSrc, SURFOBJ* psoMask, CLIPOBJ* pco, XLATEOBJ* pxlo, RECTL* prclDest, POINTL* pptlSrc, POINTL* pptlMask, BRUSHOBJ* pbo, POINTL* pptlBrush, ROP4 rop4) { BOOL b; POINTL ptlSrc; RECTL rclDest; PPDEV ppdev; SURFOBJ* pso; BYTE jClipping; RECTL rclTmp; POINTL ptlTmp; BBENUM bben; // Clip enumerator BOOL bMore; // Clip continuation flag POINTL ptlMask; // Temporary mask for engine call-backs POINTL ptlMaskAdjust; // Adjustment for mask INT iCopyDir; // Set up the clipping type if (pco == (CLIPOBJ *) NULL) { // No CLIPOBJ provided, so we don't have to worry about clipping jClipping = DC_TRIVIAL; } else { // Use the CLIPOBJ-provided clipping jClipping = pco->iDComplexity; } // Get the correct surface object for the target and the source if (psoDest->iType == STYPE_DEVICE) { if ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE)) { //////////////////////////////////////////////////////////////// // BitBlt screen-to-screen: //////////////////////////////////////////////////////////////// ppdev = (PPDEV) psoDest->dhsurf; // See if we can do a simple CopyBits: if (rop4 == 0x0000CCCC) { ppdev = (PPDEV) psoDest->dhsurf; // We can handle quadpixel-aligned screen-to-screen blts with // no translation: if ((((pptlSrc->x ^ prclDest->left) & 1) == 0) && (ppdev->fl & DRIVER_PLANAR_CAPABLE) && ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL))) { switch(jClipping) { case DC_TRIVIAL: vPlanarCopyBits(ppdev, prclDest, pptlSrc); return(TRUE); case DC_RECT: // Clip the target rectangle to the clip rectangle: if (!bIntersectRect(&rclTmp, prclDest, &pco->rclBounds)) { DISPDBG((0, "DrvBitBlt: Nothing to draw.")); return(TRUE); } ptlTmp.x = pptlSrc->x + rclTmp.left - prclDest->left; ptlTmp.y = pptlSrc->y + rclTmp.top - prclDest->top; vPlanarCopyBits(ppdev, &rclTmp, &ptlTmp); return(TRUE); case DC_COMPLEX: if (pptlSrc->y >= prclDest->top) { if (pptlSrc->x >= prclDest->left) iCopyDir = CD_RIGHTDOWN; else iCopyDir = CD_LEFTDOWN; } else { if (pptlSrc->x >= prclDest->left) iCopyDir = CD_RIGHTUP; else iCopyDir = CD_LEFTUP; } CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, iCopyDir, 0); do { RECTL* prcl; RECTL* prclEnd; bMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(bben), (PVOID) &bben); prclEnd = &bben.arcl[bben.c]; for (prcl = bben.arcl; prcl < prclEnd; prcl++) { if (bIntersectRect(prcl, prclDest, prcl)) { ptlTmp.x = pptlSrc->x + prcl->left - prclDest->left; ptlTmp.y = pptlSrc->y + prcl->top - prclDest->top; vPlanarCopyBits(ppdev, prcl, &ptlTmp); } } } while (bMore); return(TRUE); } } // Can't handle in hardware, so punt: return(bPuntScreenToScreenCopyBits(ppdev, pco, pxlo, prclDest, pptlSrc)); } // It's more complicated than a CopyBits, so punt it: return(bPuntScreenToScreenBitBlt(ppdev, psoMask, pco, pxlo, prclDest, pptlSrc, pptlMask, pbo, pptlBrush, rop4)); } //////////////////////////////////////////////////////////////// // BitBlt to screen: //////////////////////////////////////////////////////////////// ppdev = (PPDEV) psoDest->dhsurf; // Punt the memory-to-screen call back to the engine: if (psoMask != NULL) { ptlMaskAdjust.x = prclDest->left - pptlMask->x; ptlMaskAdjust.y = prclDest->top - pptlMask->y; } pso = ppdev->pSurfObj; vBankStartBltDest(ppdev, pso, pptlSrc, prclDest, &ptlSrc, &rclDest); do { ptlMask.x = rclDest.left - ptlMaskAdjust.x; ptlMask.y = rclDest.top - ptlMaskAdjust.y; b = EngBitBlt(pso, psoSrc, psoMask, pco, pxlo, &rclDest, &ptlSrc, &ptlMask, pbo, pptlBrush, rop4); } while (b && bBankEnumBltDest(ppdev, pso, pptlSrc, prclDest, &ptlSrc, &rclDest)); return(b); } else if ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE)) { //////////////////////////////////////////////////////////////// // BitBlt from screen: //////////////////////////////////////////////////////////////// if (psoMask != NULL) { ptlMaskAdjust.x = prclDest->left - pptlMask->x; ptlMaskAdjust.y = prclDest->top - pptlMask->y; } ppdev = (PPDEV) psoSrc->dhsurf; pso = ppdev->pSurfObj; vBankStartBltSrc(ppdev, pso, pptlSrc, prclDest, &ptlSrc, &rclDest); do { ptlMask.x = rclDest.left - ptlMaskAdjust.x; ptlMask.y = rclDest.top - ptlMaskAdjust.y; b = EngBitBlt(psoDest, pso, psoMask, pco, pxlo, &rclDest, &ptlSrc, &ptlMask, pbo, pptlBrush, rop4); } while (b && bBankEnumBltSrc(ppdev, pso, pptlSrc, prclDest, &ptlSrc, &rclDest)); return(b); } RIP("Got a funky format?"); return(FALSE); } /***************************************************************************\ * DrvCopyBits \***************************************************************************/ BOOL DrvCopyBits( SURFOBJ* psoDest, SURFOBJ* psoSrc, CLIPOBJ* pco, XLATEOBJ* pxlo, RECTL* prclDest, POINTL* pptlSrc) { BOOL b; POINTL ptlSrc; RECTL rclDest; PPDEV ppdev; SURFOBJ* pso; BBENUM bben; BOOL bMore; BYTE jClipping; POINTL ptlTmp; RECTL rclTmp; INT iCopyDir; // Get the correct surface object for the target and the source if (psoDest->iType == STYPE_DEVICE) { // We have to special case screen-to-screen operations: if ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE)) { //////////////////////////////////////////////////////////////// // CopyBits screen-to-screen: //////////////////////////////////////////////////////////////// ppdev = (PPDEV) psoDest->dhsurf; // We check to see if we can do a planar copy, because usually // it will be faster. But the hardware has to be capable of // doing it, and the source and destination must be 4-pel // aligned. if ((((pptlSrc->x ^ prclDest->left) & 1) == 0) && (ppdev->fl & DRIVER_PLANAR_CAPABLE) && ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL))) { jClipping = (pco != NULL) ? pco->iDComplexity : DC_TRIVIAL; switch(jClipping) { case DC_TRIVIAL: vPlanarCopyBits(ppdev, prclDest, pptlSrc); return(TRUE); case DC_RECT: // Clip the target rectangle to the clip rectangle: if (!bIntersectRect(&rclTmp, prclDest, &pco->rclBounds)) { DISPDBG((0, "DrvCopyBits: Nothing to draw.")); return(TRUE); } ptlTmp.x = pptlSrc->x + rclTmp.left - prclDest->left; ptlTmp.y = pptlSrc->y + rclTmp.top - prclDest->top; vPlanarCopyBits(ppdev, &rclTmp, &ptlTmp); return(TRUE); case DC_COMPLEX: if (pptlSrc->y >= prclDest->top) { if (pptlSrc->x >= prclDest->left) iCopyDir = CD_RIGHTDOWN; else iCopyDir = CD_LEFTDOWN; } else { if (pptlSrc->x >= prclDest->left) iCopyDir = CD_RIGHTUP; else iCopyDir = CD_LEFTUP; } CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, iCopyDir, 0); do { RECTL* prcl; RECTL* prclEnd; bMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(bben), (PVOID) &bben); prclEnd = &bben.arcl[bben.c]; for (prcl = bben.arcl; prcl < prclEnd; prcl++) { if (bIntersectRect(prcl, prclDest, prcl)) { ptlTmp.x = pptlSrc->x + prcl->left - prclDest->left; ptlTmp.y = pptlSrc->y + prcl->top - prclDest->top; vPlanarCopyBits(ppdev, prcl, &ptlTmp); } } } while (bMore); return(TRUE); } } return(bPuntScreenToScreenCopyBits(ppdev, pco, pxlo, prclDest, pptlSrc)); } ppdev = (PPDEV) psoDest->dhsurf; // Fall back to the engine: pso = ppdev->pSurfObj; vBankStartBltDest(ppdev, pso, pptlSrc, prclDest, &ptlSrc, &rclDest); do { b = EngCopyBits(pso, psoSrc, pco, pxlo, &rclDest, &ptlSrc); } while (b && bBankEnumBltDest(ppdev, pso, pptlSrc, prclDest, &ptlSrc, &rclDest)); return(b); } else if ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE)) { //////////////////////////////////////////////////////////////// // CopyBits from screen: //////////////////////////////////////////////////////////////// ppdev = (PPDEV) psoSrc->dhsurf; pso = ppdev->pSurfObj; vBankStartBltSrc(ppdev, pso, pptlSrc, prclDest, &ptlSrc, &rclDest); do { b = EngCopyBits(psoDest, pso, pco, pxlo, &rclDest, &ptlSrc); } while (b && bBankEnumBltSrc(ppdev, pso, pptlSrc, prclDest, &ptlSrc, &rclDest)); return(b); } /* we should never be here */ return FALSE; }