|
|
/******************************Module*Header*******************************\
* Module Name: strchblt.cxx * * This contains the API and DDI entry points to the graphics engine * for StretchBlt and EngStretchBlt. * * Created: 04-Apr-1991 10:57:37 * Author: Patrick Haluptzok patrickh * * Copyright (c) 1990-1999 Microsoft Corporation \**************************************************************************/
#include "precomp.hxx"
#include "stretch.hxx"
//the limit of our coordinate systems (2^27)
#define MAX_STRETCH_COOR 128000000L
ULONG gaulMonoExpand[] = { 0x00000000, //
0x00000001, // BMF_1BPP
0x0000000F, // BMF_4BPP
0x000000FF, // BMF_8BPP
0x0000FFFF, // BMF_16BPP
0x00FFFFFF, // BMF_24BPP
0xFFFFFFFF // BMF_32BPP
};
/******************************Public*Routine******************************\
* GreStretchBlt * * Stretches the source image to the destination. * * Returns: TRUE if successful, FALSE for failure. * * History: * Thu Mar-05-1998 -by- Samer Arafeh [samera] * Support LAYOUT_BITMAPORIENTATIONPRESERVED. Make sure * to exit thru one of the RETURN_XXX labels if you are writing * code past the layout code (see comments below). * * Tue 02-Jun-1992 -by- Patrick Haluptzok [patrickh] * Fix clipping bugs * * 21-Mar-1992 -by- Donald Sidoroff [donalds] * Rewrote it. * * 15-Jan-1992 -by- Patrick Haluptzok patrickh * add mask support * * Thu 19-Sep-1991 -by- Patrick Haluptzok [patrickh] * add support for rops * * 07-Nov-1990 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/
BOOL GreStretchBlt( HDC hdcTrg, int x, int y, int cx, int cy, HDC hdcSrc, int xSrc, int ySrc, int cxSrc, int cySrc, DWORD rop4, DWORD crBackColor ) { GDITraceHandle2(GreStretchBlt, "(%X, %d, %d, %d, %d, %X, %d, %d, %d, %d, %X, %X)\n", (va_list)&hdcTrg, hdcTrg, hdcSrc); return (GreStretchBltInternal( hdcTrg, x, y, cx, cy, hdcSrc, xSrc, ySrc, cxSrc, cySrc, rop4, crBackColor, 0)); }
BOOL GreStretchBltInternal( HDC hdcTrg, int x, int y, int cx, int cy, HDC hdcSrc, int xSrc, int ySrc, int cxSrc, int cySrc, DWORD rop4, DWORD crBackColor, FLONG ulFlags ) { BLTRECORD blt; BOOL bRet; POINTL ptOrgDst; DWORD OrgRop4 = rop4, dwOldLayout;
rop4 = rop4 & ~NOMIRRORBITMAP;
// [Bug #278291] - CAPTUREBLT
// The CAPTUREBLT rop flag is used for screen capture. When it's set, we bypass
// the sprite code which normally hides the sprites, so that the caller gets
// an exact copy of what's on the screen (except for the cursor).
BOOL bCaptureBlt = 0; if (rop4 & CAPTUREBLT) { bCaptureBlt = 1; rop4 = rop4 & ~CAPTUREBLT; }
// Initialize the blt record
blt.rop((rop4 | (rop4 & 0x00ff0000) << 8) >> 16);
// Convert the rop into something useful.
ULONG ulAvec = ((ULONG) gajRop3[blt.ropFore()]) | ((ULONG) gajRop3[blt.ropBack()]);
// See if we can special case this operation
if (!(ulAvec & AVEC_NEED_SOURCE)) { // We can't require a mask, since one can't be passed.
if (blt.ropFore() == blt.ropBack()) return(NtGdiPatBlt(hdcTrg, x, y, cx, cy, rop4)); }
// Lock the DC's, no optimization is made for same surface
DCOBJ dcoTrg(hdcTrg); DCOBJ dcoSrc(hdcSrc);
if (dcoTrg.bValid() && !dcoTrg.bStockBitmap()) { ULONG ulDirty = dcoTrg.pdc->ulDirty();
if ( ulDirty & DC_BRUSH_DIRTY) { GreDCSelectBrush (dcoTrg.pdc, dcoTrg.pdc->hbrush()); } }
if (!dcoTrg.bValid() || dcoTrg.bStockBitmap() || (!dcoSrc.bValid() && (ulAvec & AVEC_NEED_SOURCE))) { SAVE_ERROR_CODE(ERROR_INVALID_HANDLE); return(!(ulAvec & AVEC_NEED_SOURCE) || dcoSrc.bValid()); }
// Lock the relevant surfaces
DEVLOCKBLTOBJ dlo;
if (ulAvec & AVEC_NEED_SOURCE) dlo.bLock(dcoTrg, dcoSrc); else dlo.bLock(dcoTrg);
if (!dlo.bValid()) { return(dcoTrg.bFullScreen()); }
if (!dcoTrg.bValidSurf() || !dcoSrc.bValidSurf() || !dcoSrc.pSurface()->bReadable()) { if ((dcoTrg.dctp() == DCTYPE_INFO) || !dcoSrc.bValidSurf()) { if (dcoTrg.fjAccum()) { EXFORMOBJ exo(dcoTrg, WORLD_TO_DEVICE); ERECTL ercl(x, y, x + cx, y + cy);
if (exo.bXform(ercl)) { ercl.vOrder(); dcoTrg.vAccumulate(ercl); } }
// if we need a source and the source isn't valid, return failure
return(TRUE); }
// Do the security test on SCREEN to MEMORY blits.
if (dcoSrc.bDisplay() && !dcoTrg.bDisplay()) { if (!UserScreenAccessCheck()) { SAVE_ERROR_CODE(ERROR_ACCESS_DENIED); return(FALSE); } }
// If the source isn't a DISPLAY we should exit
if (!dcoSrc.bDisplay()) return(FALSE); }
if(dcoTrg.bDisplay() && !dcoTrg.bRedirection() && dcoSrc.bValidSurf() && !dcoSrc.bDisplay() && !UserScreenAccessCheck()) { SAVE_ERROR_CODE(ERROR_ACCESS_DENIED); return(FALSE); }
// We can't require a mask, since one can't be passed.
if (blt.ropFore() != blt.ropBack()) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return(FALSE); }
// ATTENTION: Please pay attention here
//
// Any code you are going to write past the following
// section of code (mirroring code below that changes the
// windows origin of the DC) should exit (return) -if it needs-
// through either RETURN_FAIL, RETURN_FAIL_ONLY or RETURN_STATUS
// labels by doing a goto statement to them. The reason for this
// is to restore the DC's window origin by executing
// the code located at the RETURN_STATUS label (see end of fn). [samera]
//
// Let's preserve the bitmap shape if the target DC
// is a mirrored one. [samera]
//
if ( (((OrgRop4 & NOMIRRORBITMAP) && MIRRORED_DC(dcoTrg.pdc) ) || MIRRORED_DC_NO_BITMAP_FLIP(dcoTrg.pdc)) && (hdcSrc != hdcTrg) ) { dcoTrg.pdc->vGet_ptlWindowOrg( &ptOrgDst ); dwOldLayout = dcoTrg.pdc->dwSetLayout(-1, 0); x = ptOrgDst.x - x - cx;
// Restore the DC if the flag is in the DC and not part
// of the Rops. [samera]
//
OrgRop4 = NOMIRRORBITMAP; } else { OrgRop4 = 0; }
HANDLE hcmXform = NULL;
// Don't put any goto's before here.
//
// [Bug #278291] - CAPTUREBLT
// If we're doing a screen capture, hide the cursor, and set a
// flag in the destination surface, to notify the sprite code.
SURFACE *pSurfTrg = dcoTrg.pSurfaceEff(); SURFACE *pSurfSrc = dcoSrc.pSurfaceEff(); PDEVOBJ pdoSrc(pSurfSrc->hdev()); POINTL pointerPos;
if (bCaptureBlt) { if (dcoSrc.bDisplay() && !dcoSrc.bPrinter() && (dcoSrc.hdev() == dcoTrg.hdev())) { ASSERTGDI(pSurfTrg, "Null destination surface"); ASSERTGDI(pSurfSrc, "Null source surface");
// Because the sprites are going to be visible, we must explicitly
// hide the cursor (since it may be a sprite).
// Grab the pointer semaphore to ensure that no-one else moves
// the pointer until we restore it.
GreAcquireSemaphoreEx(pdoSrc.hsemPointer(), SEMORDER_POINTER, dcoSrc.hsemDcDevLock());
pointerPos = pdoSrc.ptlPointer();
//
// Don't make this a procedural mouse move for TS otherwise during
// scenarios like magnifier with a lot of stretchblits the client
// gets repeated programmatic mouse moves (with delay) that cause
// it to get a jerky mouse. See bug#450927
//
GreMovePointer(pSurfSrc->hdev(), -1, -1, MP_NORMAL);
// Set the 'IncludeSprites' flag in the destination surface. This tells
// bSpBltFromScreen to include the sprites.
pSurfTrg->vSetIncludeSprites(); } else { // Clear bCaptureBlt, to bypass the cleanup code at the end.
bCaptureBlt = 0; } }
// Fill the BLTRECORD
blt.pxoTrg()->vInit(dcoTrg,WORLD_TO_DEVICE); blt.pSurfTrg(dcoTrg.pSurfaceEff()); blt.ppoTrg()->ppalSet(blt.pSurfTrg()->ppal()); blt.ppoTrgDC()->ppalSet(dcoTrg.ppal());
blt.pxoSrc()->vInit(dcoSrc,WORLD_TO_DEVICE); blt.pSurfSrc(dcoSrc.pSurfaceEff()); blt.ppoSrc()->ppalSet(blt.pSurfSrc()->ppal()); blt.ppoSrcDC()->ppalSet(dcoSrc.ppal());
if (crBackColor == (COLORREF)-1) crBackColor = dcoSrc.pdc->ulBackClr();
// Initialize the color translation object.
//
// No ICM with StretchBlt() so pass NULL color transform to XLATEOBJ.
if (ulFlags & STRETCHBLT_ENABLE_ICM) { hcmXform = dcoTrg.pdc->hcmXform(); }
if (!blt.pexlo()->bInitXlateObj(hcmXform, // hColorTransform
dcoTrg.pdc->lIcmMode(), // ICM mode
*blt.ppoSrc(), *blt.ppoTrg(), *blt.ppoSrcDC(), *blt.ppoTrgDC(), dcoTrg.pdc->crTextClr(), dcoTrg.pdc->crBackClr(), crBackColor)) { WARNING("bInitXlateObj failed in StretchBlt\n"); goto RETURN_FAIL_ONLY; }
blt.flSet(BLTREC_PXLO);
if (ulAvec & AVEC_NEED_PATTERN) { // Set up the brush if necesary.
blt.pbo(dcoTrg.peboFill());
if ((dcoTrg.ulDirty() & DIRTY_FILL) || (dcoTrg.pdc->flbrush() & DIRTY_FILL)) { dcoTrg.ulDirtySub(DIRTY_FILL); dcoTrg.pdc->flbrushSub(DIRTY_FILL);
blt.pbo()->vInitBrush( dcoTrg.pdc, dcoTrg.pdc->pbrushFill(), *((XEPALOBJ *) blt.ppoTrgDC()), *((XEPALOBJ *) blt.ppoTrg()), blt.pSurfTrg()); }
blt.Brush(dcoTrg.pdc->ptlFillOrigin()); } else { blt.pbo (NULL); }
// Initialize some stuff for DDI.
blt.pSurfMsk((SURFACE *) NULL);
// Set the source rectangle
if (blt.pxoSrc()->bRotation() || !blt.Src(xSrc, ySrc, cxSrc, cySrc)) { goto RETURN_FAIL; }
// Don't call the driver with an empty source rectangle.
if((ulAvec & AVEC_NEED_SOURCE) && (blt.perclSrc()->bEmpty())) { // We really should fail here, but return TRUE in order to maintain
// backward compatibility.
bRet = TRUE; goto RETURN_STATUS; }
// Now all the essential information has been collected. We now
// need to check for promotion or demotion and call the appropriate
// method to finish the blt. If we rotate we must send the call away.
if (blt.pxoTrg()->bRotation()) { blt.TrgPlg(x, y, cx, cy); bRet = blt.bRotate(dcoTrg, dcoSrc, ulAvec, dcoTrg.pdc->jStretchBltMode()); goto RETURN_STATUS; }
// We can now set the target rectangle
if (!blt.Trg(x, y, cx, cy)) { goto RETURN_FAIL; }
// If we are halftoning or the extents aren't equal, call bStretch
if (( dcoTrg.pdc->jStretchBltMode() == HALFTONE) || !blt.bEqualExtents()) { bRet = blt.bStretch(dcoTrg, dcoSrc, ulAvec, dcoTrg.pdc->jStretchBltMode() ); goto RETURN_STATUS; }
// Since there can't be a mask, call bBitBlt.
bRet = blt.bBitBlt(dcoTrg, dcoSrc, ulAvec); goto RETURN_STATUS;
RETURN_FAIL:
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
RETURN_FAIL_ONLY:
bRet = FALSE;
RETURN_STATUS: if (OrgRop4 & NOMIRRORBITMAP) { dcoTrg.pdc->dwSetLayout(-1, dwOldLayout); }
// [Bug #278291] - CAPTUREBLT
// Undo what was done above
if (bCaptureBlt) { // Clear the flag
pSurfTrg->vClearIncludeSprites();
// Restore the cursor
GreMovePointer(pSurfSrc->hdev(), pointerPos.x, pointerPos.y, MP_NORMAL); GreReleaseSemaphoreEx(pdoSrc.hsemPointer());
}
return bRet; }
/******************************Public*Routine******************************\
* BOOL BLTRECORD::bStretch(dcoTrg, dcoSrc, ulAvec, jMode) * * Do a stretch blt from the blt record * * History: * 21-Mar-1992 -by- Donald Sidoroff [donalds] * Rewrote it. \**************************************************************************/
BOOL BLTRECORD::bStretch( DCOBJ& dcoTrg, DCOBJ& dcoSrc, ULONG ulAvec, BYTE jMode) { // Make the target rectangle well ordered and remember flips.
vOrderStupid(perclTrg());
// before we do a pattern only blt. The mask will be replaced in the
// BLTRECORD and its offset correctly adjusted.
if (!(ulAvec & AVEC_NEED_SOURCE)) { vOrderStupid(perclMask());
// Before we call to the driver, validate that the mask will actually
// cover the entire target.
if (pSurfMskOut() != (SURFACE *) NULL) { if ((aptlMask[0].x < 0) || (aptlMask[0].y < 0) || (aptlMask[1].x > pSurfMsk()->sizl().cx) || (aptlMask[1].y > pSurfMsk()->sizl().cy)) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return(FALSE); } }
SURFMEM dimoMask;
if ((ulAvec & AVEC_NEED_MASK) && !bStretch(dimoMask, (ULONG) jMode)) return(FALSE);
// Now, we need to fake out the source extents for the mask
aptlSrc[1].x = aptlSrc[0].x + (aptlTrg[1].x - aptlTrg[0].x); aptlSrc[1].y = aptlSrc[0].y + (aptlTrg[1].y - aptlTrg[0].y);
return(bBitBlt(dcoTrg, dcoTrg, ulAvec)); }
PDEVOBJ pdoTrg(pSurfTrg()->hdev());
// WINBUG #298689 4-4-2001 jasonha Handle any device stretch to Meta
BOOL bTrgMetaDriver = (dcoTrg.bSynchronizeAccess() && pdoTrg.bValid() && pdoTrg.bMetaDriver());
// If the devices are on different PDEV's and we are not targeting a meta driver
// we can only call driver if the Engine manages one or both of the surfaces.
// Check for this.
// WINBUG #256643 12-13-2000 bhouse Need to review handling of cross device operatons
// We need to review this logic. This check and others like it are spread
// throughout GDI and are in some cases now outdated. For example, there
// is no reason not to call the multi-mon driver as a target.
// We are fixing this case now but we should examine this check in light
// of other possible cases.
if (dcoTrg.hdev() != dcoSrc.hdev()) { if (!bTrgMetaDriver) { if(((dcoTrg.pSurfaceEff()->iType() != STYPE_BITMAP) || (dcoTrg.pSurfaceEff()->dhsurf() != NULL)) && ((dcoSrc.pSurfaceEff()->iType() != STYPE_BITMAP) || (dcoSrc.pSurfaceEff()->dhsurf() != NULL))) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return (FALSE); } } }
// Before we get too involved, validate that the mask will actually
// cover the entire source.
if (pSurfMskOut() != (SURFACE *) NULL) { if ((aptlMask[0].x < 0) || (aptlMask[0].y < 0) || (aptlMask[1].x > pSurfMsk()->sizl().cx) || (aptlMask[1].y > pSurfMsk()->sizl().cy)) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return(FALSE); } }
// Make the source rectangle well ordered and remember flips.
vOrderStupid(perclSrc()); vOrderAmnesia(perclMask());
// Win 3.1 has a lovely little 'feature' where they decide
// you called StretchBlt but you really didn't mean it. This
// ludicrous behaviour needs to be supported forever because
// some pinhead applications have grown to rely on this act
// of insanity. Flips cancel this, since EngBitBlt can't
// handle negative extents. Also note that we can't fail to
// call DanielC if HALFTONE has been requested. [donalds]
if ((jMode != HALFTONE) && (dcoTrg.pdc->iGraphicsMode() != GM_ADVANCED) && (pSurfMskOut() == (SURFACE *) NULL) && !(flState & (BLTREC_MIRROR_X | BLTREC_MIRROR_Y))) { LONG lHStr = (perclTrg()->right - perclTrg()->left) - (perclSrc()->right - perclSrc()->left);
LONG lVStr = (perclTrg()->bottom - perclTrg()->top) - (perclSrc()->bottom - perclSrc()->top);
if ((lHStr >= -1) && (lHStr <= 1) && (lVStr >= -1) && (lVStr <= 1)) return(bBitBlt(dcoTrg, dcoSrc, ulAvec, lHStr, lVStr)); }
// Accumulate bounds. We can do this before knowing if the operation is
// successful because bounds can be loose.
if (dcoTrg.fjAccum()) dcoTrg.vAccumulate(*perclTrg());
// With a fixed DC origin we can change the rectangles to SCREEN coordinates.
*perclTrg() += dcoTrg.eptlOrigin(); *perclSrc() += dcoSrc.eptlOrigin();
// Compute the clipping complexity and maybe reduce the exclusion rectangle.
ECLIPOBJ eco(dcoTrg.prgnEffRao(), *perclTrg());
// Check the destination which is reduced by clipping.
if (eco.erclExclude().bEmpty()) return(TRUE);
// Compute the exclusion rectangle.
ERECTL erclExclude = eco.erclExclude();
// If we are going to the same source, prevent bad overlap situations
if (dcoSrc.pSurface() == dcoTrg.pSurface()) { if (perclSrc()->left < erclExclude.left) erclExclude.left = perclSrc()->left;
if (perclSrc()->top < erclExclude.top) erclExclude.top = perclSrc()->top;
if (perclSrc()->right > erclExclude.right) erclExclude.right = perclSrc()->right;
if (perclSrc()->bottom > erclExclude.bottom) erclExclude.bottom = perclSrc()->bottom; }
// We might have to exclude the source or the target, get ready to do either.
DEVEXCLUDEOBJ dxo;
PDEVOBJ pdoSrc(pSurfSrc()->hdev());
// They can't both be display
if (dcoSrc.bDisplay()) { ERECTL ercl(0,0,pSurfSrc()->sizl().cx,pSurfSrc()->sizl().cy);
if (dcoSrc.pSurface() == dcoTrg.pSurface()) ercl *= erclExclude; else ercl *= *perclSrc();
dxo.vExclude(dcoSrc.hdev(),&ercl,NULL); } else if (dcoTrg.bDisplay()) dxo.vExclude(dcoTrg.hdev(),&erclExclude,&eco);
// Dispatch the call.
PFN_DrvStretchBltROP pfn = PPFNGET(pdoTrg, StretchBltROP, pSurfTrg()->flags());
if (!bTrgMetaDriver) { if (jMode == HALFTONE) { // Don't call the driver if it doesn't do halftone.
if (!(pdoTrg.flGraphicsCapsNotDynamic() & GCAPS_HALFTONE)) pfn = (PFN_DrvStretchBltROP)EngStretchBltROP; }
// WINBUG #95246 3-17-2000 jasonha GDI: StretchBlt optimizations: Let drivers handle more cases
// Don't call the driver if the source rectangle exceeds the source
// surface. Some drivers punt using a duplicate of the source
// SURFOBJ, but without preserving its sizlBitmap member.
BOOL bSrcExceeds = FALSE;
if(pSurfSrc()->iType() == STYPE_DEVICE && pdoSrc.bValid() && pdoSrc.bMetaDriver()) { if((perclSrc()->left < pdoSrc.pptlOrigin()->x ) || (perclSrc()->top < pdoSrc.pptlOrigin()->y ) || (perclSrc()->right > pdoSrc.pptlOrigin()->x + pSurfSrc()->sizl().cx) || (perclSrc()->bottom > pdoSrc.pptlOrigin()->y + pSurfSrc()->sizl().cy)) { bSrcExceeds = TRUE; }
} else { if((perclSrc()->left < 0) || (perclSrc()->top < 0) || (perclSrc()->right > pSurfSrc()->sizl().cx) || (perclSrc()->bottom > pSurfSrc()->sizl().cy)) { bSrcExceeds = TRUE; } }
if( bSrcExceeds ) { pfn = (PFN_DrvStretchBltROP)EngStretchBltROP; }
// WINBUG #95246 3-17-2000 jasonha GDI: StretchBlt optimizations: Let drivers handle more cases
// Don't call the driver if the source overlaps the destination.
// Some drivers don't handle this case.
if ((pSurfTrg() == pSurfSrc()) && bIntersect(perclSrc(), perclTrg())) { pfn = (PFN_DrvStretchBltROP)EngStretchBltROP; } }
// Deal with target mirroring
vMirror(perclTrg());
// Inc the target surface uniqueness
INC_SURF_UNIQ(pSurfTrg());
return((*pfn)(pSurfTrg()->pSurfobj(), pSurfSrc()->pSurfobj(), (rop4 == 0x0000CCCC) ? (SURFOBJ *) NULL : pSurfMskOut()->pSurfobj(), &eco, pexlo()->pxlo(), (dcoTrg.pColorAdjustment()->caFlags & CA_DEFAULT) ? (PCOLORADJUSTMENT)NULL : dcoTrg.pColorAdjustment(), &dcoTrg.pdc->ptlFillOrigin(), perclTrg(), perclSrc(), aptlMask, jMode, pbo(), rop4)); }
/******************************Public*Routine******************************\
* BOOL BLTRECORD::bStretch(dimo, iMode) * * Stretch just the mask. * * History: * 23-Mar-1992 -by- Donald Sidoroff [donalds] * Wrote it. \**************************************************************************/
BOOL BLTRECORD::bStretch( SURFMEM& dimo, ULONG iMode) { // Use the ordered target extents for the size
DEVBITMAPINFO dbmi;
dbmi.iFormat = BMF_1BPP; dbmi.cxBitmap = aptlTrg[1].x - aptlTrg[0].x; dbmi.cyBitmap = aptlTrg[1].y - aptlTrg[0].y; dbmi.hpal = (HPALETTE) 0; dbmi.fl = pSurfMskOut()->bUMPD() ? UMPD_SURFACE : 0;
// Build a shadow rectangle.
ERECTL erclTrg(0, 0, dbmi.cxBitmap, dbmi.cyBitmap);
// Take care of mirroring.
vMirror(&erclTrg);
dimo.bCreateDIB(&dbmi, (VOID *) NULL);
if (!dimo.bValid()) return(FALSE);
// Call EngStretchBlt to stretch the mask.
EPOINTL ptl(0,0);
if (!EngStretchBlt(dimo.pSurfobj(), pSurfMskOut()->pSurfobj(), (SURFOBJ *) NULL, (CLIPOBJ *) NULL, NULL, NULL, (POINTL *)&ptl, &erclTrg, perclMask(), (POINTL *) NULL, iMode)) { return(FALSE); }
// Adjust the mask origin.
aptlMask[0].x = 0; aptlMask[0].y = 0;
// Release the previous pSurfMask, tell ~BLTRECORD its gone and put the
// new DIB in its place.
flState &= ~BLTREC_MASK_LOCKED; pSurfMsk()->vAltUnlockFast(); pSurfMsk((SURFACE *) dimo.ps);
return(TRUE); }
/******************************Public*Routine******************************\
* BOOL BLTRECORD::bStretch(dcoSrc, dimoShadow, dimoMask, ulAvec) * * Stretch the shadow and mask. * * History: * 24-Mar-1992 -by- Donald Sidoroff [donalds] * Wrote it. \**************************************************************************/
BOOL BLTRECORD::bStretch( DCOBJ& dcoSrc, SURFMEM& dimoShadow, SURFMEM& dimoMask, ULONG ulAvec, ULONG iMode) { // If there is a mask, stretch it.
if ((ulAvec & AVEC_NEED_MASK) && !bStretch(dimoMask, iMode)) return(FALSE);
// Use the ordered target extents for the size
DEVBITMAPINFO dbmi;
dbmi.cxBitmap = aptlTrg[1].x - aptlTrg[0].x; dbmi.cyBitmap = aptlTrg[1].y - aptlTrg[0].y; dbmi.hpal = 0; dbmi.iFormat = pSurfSrc()->iFormat(); dbmi.fl = pSurfSrc()->bUMPD() ? UMPD_SURFACE : 0;
// Build a shadow rectangle.
ERECTL erclTrg(0, 0, dbmi.cxBitmap, dbmi.cyBitmap);
// Take care of mirroring.
vMirror(&erclTrg);
dimoShadow.bCreateDIB(&dbmi, (VOID *) NULL);
if (!dimoShadow.bValid()) return(FALSE);
// Now comes the tricky part. The source may be a display. While it may
// be somewhat faster to assume it isn't, code would be much more complex.
{ // Adjust the source rectangle.
*perclSrc() += dcoSrc.eptlOrigin();
// Exclude the pointer.
ERECTL ercl(0,0,pSurfSrc()->sizl().cx,pSurfSrc()->sizl().cy); ercl *= *perclSrc();
DEVEXCLUDEOBJ dxo(dcoSrc, &ercl);
EPOINTL ptl(0,0);
// Stretch the bits to the DIB.
if (!EngStretchBlt(dimoShadow.pSurfobj(), pSurfSrc()->pSurfobj(), (SURFOBJ *) NULL, (CLIPOBJ *) NULL, NULL, NULL, (POINTL *)&ptl, &erclTrg, perclSrc(), (POINTL *) NULL, iMode)) { return(FALSE); }
// Update the source surface and origin.
pSurfSrc((SURFACE *) dimoShadow.ps);
perclSrc()->left = -dcoSrc.eptlOrigin().x; perclSrc()->top = -dcoSrc.eptlOrigin().y; perclSrc()->right = dbmi.cxBitmap - dcoSrc.eptlOrigin().x; perclSrc()->bottom = dbmi.cyBitmap - dcoSrc.eptlOrigin().y; }
return(TRUE); }
/******************************Public*Routine******************************\
* VOID BLTRECORD::vOrder(percl) * * Make the rectangle well ordered, remembering how we flipped. * * History: * 23-Mar-1992 -by- Donald Sidoroff [donalds] * Wrote it. \**************************************************************************/
VOID BLTRECORD::vOrder(ERECTL *percl) { LONG l;
if (percl->left > percl->right) { l = percl->left, percl->left = percl->right, percl->right = l;
flState ^= BLTREC_MIRROR_X; }
if (percl->top > percl->bottom) { l = percl->top, percl->top = percl->bottom, percl->bottom = l;
flState ^= BLTREC_MIRROR_Y; } }
/******************************Public*Routine******************************\
* VOID BLTRECORD::vOrderStupid(percl) * * Make the rectangle well ordered, remembering how we flipped. Uses the * Win3.1 compatible swap method. * * History: * 23-Mar-1992 -by- Donald Sidoroff [donalds] * Wrote it. \**************************************************************************/
VOID BLTRECORD::vOrderStupid(ERECTL *percl) { LONG l;
if (percl->left > percl->right) { l = percl->left, percl->left = percl->right, percl->right = l;
percl->left++; percl->right++;
flState ^= BLTREC_MIRROR_X; }
if (percl->top > percl->bottom) { l = percl->top, percl->top = percl->bottom, percl->bottom = l;
percl->top++; percl->bottom++;
flState ^= BLTREC_MIRROR_Y; } }
/******************************Public*Routine******************************\
* VOID BLTRECORD::vOrderAmnesia(percl) * * Make the rectangle well ordered. Uses the Win 3.1 compatible swap * method. * * History: * 23-Mar-1992 -by- Donald Sidoroff [donalds] * Wrote it. \**************************************************************************/
VOID BLTRECORD::vOrderAmnesia(ERECTL *percl) { LONG l;
if (percl->left > percl->right) { l = percl->left, percl->left = percl->right, percl->right = l;
percl->left++; percl->right++; }
if (percl->top > percl->bottom) { l = percl->top, percl->top = percl->bottom, percl->bottom = l;
percl->top++; percl->bottom++; } }
/******************************Public*Routine******************************\
* VOID BLTRECORD::vMirror(percl) * * Flip the rectangle according to the mirroring flags * * History: * 24-Mar-1992 -by- Donald Sidoroff [donalds] * Wrote it. \**************************************************************************/
VOID BLTRECORD::vMirror(ERECTL *percl) { LONG l;
if (flState & BLTREC_MIRROR_X) l = percl->left, percl->left = percl->right, percl->right = l;
if (flState & BLTREC_MIRROR_Y) l = percl->top, percl->top = percl->bottom, percl->bottom = l; }
/******************************Public*Routine******************************\
* VOID BLTRECORD::bBitBlt(dcoTrg, dcoSrc, ul, lH, lV) * * Do a near-miss ???BitBlt instead of ???StretchBlt. * * History: * 12-Apr-1993 -by- Donald Sidoroff [donalds] * Wrote it. \**************************************************************************/
#define PUT_RECTS erclTrg = *perclTrg(); erclSrc = *perclSrc()
#define GET_RECTS *perclSrc() = erclSrc; *perclTrg() = erclTrg
BOOL BLTRECORD::bBitBlt( DCOBJ& dcoTrg, DCOBJ& dcoSrc, ULONG ulAvec, LONG lHStr, LONG lVStr) { ERECTL erclTrg; ERECTL erclSrc; BOOL bHack;
switch (lHStr) { case -1: perclSrc()->right--;
if (lVStr == 1) { perclTrg()->bottom--;
PUT_RECTS; bHack = bBitBlt(dcoTrg, dcoSrc, ulAvec); GET_RECTS;
perclTrg()->top = perclTrg()->bottom; perclTrg()->bottom++; perclSrc()->top = perclSrc()->bottom - 1;
return(bHack & bBitBlt(dcoTrg, dcoSrc, ulAvec)); } else { perclSrc()->bottom += lVStr;
return(bBitBlt(dcoTrg, dcoSrc, ulAvec)); } break;
case 0: if (lVStr == 1) { perclTrg()->bottom--;
PUT_RECTS; bHack = bBitBlt(dcoTrg, dcoSrc, ulAvec); GET_RECTS;
perclTrg()->top = perclTrg()->bottom; perclTrg()->bottom++; perclSrc()->top = perclSrc()->bottom - 1;
return(bHack & bBitBlt(dcoTrg, dcoSrc, ulAvec)); } else { perclSrc()->bottom += lVStr;
return(bBitBlt(dcoTrg, dcoSrc, ulAvec)); } break;
case 1: perclTrg()->right--;
if (lVStr == 1) { perclTrg()->bottom--;
PUT_RECTS; bHack = bBitBlt(dcoTrg, dcoSrc, ulAvec); GET_RECTS;
perclTrg()->left = perclTrg()->right; perclTrg()->right++; perclSrc()->left = perclSrc()->right - 1;
bHack &= bBitBlt(dcoTrg, dcoSrc, ulAvec); GET_RECTS;
perclTrg()->top = perclTrg()->bottom; perclTrg()->bottom++; perclSrc()->top = perclSrc()->bottom - 1;
bHack &= bBitBlt(dcoTrg, dcoSrc, ulAvec); GET_RECTS;
perclTrg()->top = perclTrg()->bottom; perclTrg()->bottom++; perclSrc()->top = perclSrc()->bottom - 1; perclTrg()->left = perclTrg()->right; perclTrg()->right++; perclSrc()->left = perclSrc()->right - 1;
return(bHack & bBitBlt(dcoTrg, dcoSrc, ulAvec)); } else { perclSrc()->bottom += lVStr;
PUT_RECTS; bHack = bBitBlt(dcoTrg, dcoSrc, ulAvec); GET_RECTS;
perclTrg()->left = perclTrg()->right; perclTrg()->right++; perclSrc()->left = perclSrc()->right - 1;
return(bHack & bBitBlt(dcoTrg, dcoSrc, ulAvec)); } break;
default: break; } return FALSE; }
#ifdef DBG_STRBLT
LONG gflStrBlt = 0;
VOID vShowRect( CHAR *psz, RECTL *prcl) { if (gflStrBlt & STRBLT_RECTS) DbgPrint("%s [(%ld,%ld) (%ld,%ld)]\n", psz, prcl->left, prcl->top, prcl->right, prcl->bottom); } #endif
/******************************Public*Routine******************************\
* EngStretchBlt * * This does stretched bltting. The source rectangle is stretched to fit * the target rectangle. * * NOTE! The source rectangle MUST BE WELL ORDERED IN DEVICE SPACE. * * This call returns TRUE for success, FALSE for ERROR. * * History: * 16-Feb-1993 -by- Donald Sidoroff [donalds] * Wrote. \**************************************************************************/
BOOL EngStretchBlt( SURFOBJ *psoTrg, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo, COLORADJUSTMENT *pca, POINTL *pptlBrushOrg, RECTL *prclTrg, RECTL *prclSrc, POINTL *pptlMask, ULONG iMode) { //
// Prevent bad driver call backs
//
if ((iMode == 0) || (iMode > MAXSTRETCHBLTMODE)) { WARNING1("EngStretchBlt: Unsupported iMode\n"); return(FALSE); }
PSURFACE pSurfTrg = SURFOBJ_TO_SURFACE(psoTrg); PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE(psoSrc); PSURFACE pSurfMask = SURFOBJ_TO_SURFACE(psoMask);
//
// Can't StretchBlt to an RLE
// Can't StretchBlt to/from a JPEG or PNG
//
if ((pSurfTrg->iFormat() == BMF_4RLE) || (pSurfTrg->iFormat() == BMF_8RLE) || (pSurfTrg->iFormat() == BMF_JPEG) || (pSurfSrc->iFormat() == BMF_JPEG) || (pSurfTrg->iFormat() == BMF_PNG ) || (pSurfSrc->iFormat() == BMF_PNG )) { WARNING1("EngStretchBlt: Unsupported source/target\n"); return(FALSE); }
//
// If the source or target rectangles are empty, don't bother.
//
if ((prclSrc->left == prclSrc->right) || (prclSrc->top == prclSrc->bottom) || (prclTrg->left == prclTrg->right) || (prclTrg->top == prclTrg->bottom)) return(TRUE);
//
// Get the LDEV for the target and source surfaces
//
PDEVOBJ pdoTrg( pSurfTrg->hdev()); PDEVOBJ pdoSrc( pSurfSrc->hdev());
//
// We should have gone to the Mul layer if the destination
// is a meta.
//
ASSERTGDI( !( psoTrg->iType != STYPE_BITMAP && pdoTrg.bValid() && pdoTrg.bMetaDriver()), "EngStretchBlt called with a destination meta device" );
//
// We cannot handle cases where the source is a meta,
// so make a copy in this case.
//
SURFMEM srcCopy; RECTL rclCopy = *prclSrc;
if( psoSrc->iType == STYPE_DEVICE && pdoSrc.bValid() && pdoSrc.bMetaDriver()) { if(!MulCopyDeviceToDIB( psoSrc, &srcCopy, &rclCopy )) return FALSE;
if(srcCopy.ps == NULL ) { // We didn't get to the point of creating the surface
// becasue the rect was out of bounds.
return TRUE; }
prclSrc = &rclCopy; psoSrc = srcCopy.pSurfobj(); pSurfSrc = SURFOBJ_TO_SURFACE(psoSrc); pdoSrc.vInit(pSurfSrc->hdev()); }
//
// CMYK based source bitmap support.
//
// limilation:
// - Source surface must be STYPE_BITMAP, since we can't read CMYK surface from device.
// - Target surface must be STYPE_DEVICE, since other Eng function can't handle.
// - Source surface must not be same as target surface.
// - No mask surface.
// - No halftone mode, since EngHTBlt can't handle.
//
BOOL bSrcCMYKColor = (pxlo && (pxlo->flXlate & XO_FROM_CMYK)) ? TRUE : FALSE;
if (bSrcCMYKColor) { WARNING("EngStretchBlt called with XO_FROM_CMYK - limited support");
// source surface must be STYPE_BITMAP.
// target surface must be STYPE_DEVICE.
// Must be no mask
if ((psoSrc->iType != STYPE_BITMAP) || (psoTrg->iType != STYPE_DEVICE) || (psoMask != NULL)) { return (FALSE); } }
//
// Send Halftoning to DanielC.
//
if (iMode == HALFTONE) { //
// If source bitmap is CMYK, EngHTBlt can't handle.
//
if (bSrcCMYKColor) { return (FALSE); }
int iRet = EngHTBlt(psoTrg, psoSrc, psoMask, pco, pxlo, pca, pptlBrushOrg, prclTrg, prclSrc, pptlMask, 0, NULL);
switch (iRet) { case HTBLT_ERROR: return(FALSE);
case HTBLT_SUCCESS: return(TRUE);
case HTBLT_NOTSUPPORTED: iMode = COLORONCOLOR; break; }; }
#ifdef DBG_STRBLT
if (!(gflStrBlt & STRBLT_ENABLE)) { POINTFIX aptfx[3];
aptfx[0].x = FIX_FROM_LONG(prclTrg->left); aptfx[0].y = FIX_FROM_LONG(prclTrg->top); aptfx[1].x = FIX_FROM_LONG(prclTrg->right); aptfx[1].y = FIX_FROM_LONG(prclTrg->top); aptfx[2].x = FIX_FROM_LONG(prclTrg->left); aptfx[2].y = FIX_FROM_LONG(prclTrg->bottom);
return(EngPlgBlt(psoTrg, psoSrc, psoMask, pco, pxlo, pca, pptlBrushOrg, aptfx, prclSrc, pptlMask, iMode)); }
if (gflStrBlt & STRBLT_FORMAT) { LONG foo[] = { 0, 1, 4, 8, 16, 24, 32 };
DbgPrint("Target = %2ldBPP, Source = %2ldBPP\n", foo[pSurfTrg->iFormat()], foo[pSurfSrc->iFormat()]);
} #endif
//
// We may have to 'mirror'.
//
FLONG flMirror = 0;
if (prclTrg->bottom < prclTrg->top) { LONG lTemp = prclTrg->top; prclTrg->top = prclTrg->bottom; prclTrg->bottom = lTemp;
flMirror |= STRBLT_MIRROR_Y; }
if (prclTrg->right < prclTrg->left) { LONG lTemp = prclTrg->left; prclTrg->left = prclTrg->right; prclTrg->right = lTemp;
flMirror |= STRBLT_MIRROR_X; }
//
// We may need to do a WHITEONBLACK or BLACKONWHITE from a monochrome source.
// Find out and set the bogusity flag.
//
BOOL bBogus = ((iMode < COLORONCOLOR) && (pSurfMask == (SURFACE *) NULL));
//
// Bogusity mode only applies on shrinking blts. Test the dx/dy for source
// and targets and see if it still applies.
//
if (bBogus) { if (((prclTrg->right - prclTrg->left) >= (prclSrc->right - prclSrc->left)) && ((prclTrg->bottom - prclTrg->top) >= (prclSrc->bottom - prclSrc->top))) bBogus = FALSE; }
//
// If we don't need bogusity, eliminate it.
//
if ((!bBogus) && (iMode < COLORONCOLOR)) iMode = COLORONCOLOR;
//
// Many display drivers have fast-paths for stretches that handle only
// source formats that are the same as the destination format, and only
// with identity translates. They also typically handle only STYPE_BITMAP
// formats.
//
// So we will consider making a copy of the source bitmap up-front to
// remove any translations and also to convert non-STYPE_BITMAP formats.
//
// Note that this isn't terribly efficient when clipping is involved,
// but that will be a later optimization...
//
if (!pSurfTrg->bUMPD() && (((pxlo != NULL) && !(pxlo->flXlate & XO_TRIVIAL)) || (psoSrc->iType != STYPE_BITMAP))) { //
// To go any further, the driver must of course hook StretchBlt.
//
// In addition, we'll add some further restrictions here to make
// our life easier. The driver's fast paths typically handle only
// stretches that are non-inverting, don't involve a mask, and don't
// have source clipping, and we'll do the same (otherwise we'd have
// to add more code):
//
// Note that some drivers (specifically the Weitek driver) have a
// bug where they set "psoDst = ppdev->psoPunt" and then call
// EngStretchBlt on that. This would work fine, except that they
// had also called EngAssociateSurface on the surface and said they
// hooked STRETCHBLT for that punt surface -- which is a lie because
// they fall over if we call DrvStretchBlt on that punt surface!
// (They don't really expect their DrvStretchBlt routine to be called
// for an engine-managed surface, even though that's what they're
// saying they support via the EngAssociateSurface call.) So
// we add a (pSurfTrg->iType() != STYPE_BITMAP) check and don't
// execute this fast-path at all for engine-managed surfaces, and
// thus we avoid driver bugs like the Weitek's.
//
//
// WINBUG #95246 3-17-2000 jasonha GDI: StretchBlt optimizations: Let drivers handle more cases
//
// Actually, we must NEVER call the driver if there is source
// clipping. Some drivers punt using a duplicate of the source
// SURFOBJ, but without preserving its sizlBitmap member.
//
if ((pSurfTrg->iType() != STYPE_BITMAP) && (pSurfTrg->flags() & HOOK_STRETCHBLT) && (flMirror == 0) && (psoMask == NULL) && (prclSrc->left >= 0) && (prclSrc->top >= 0) && (prclSrc->right <= psoSrc->sizlBitmap.cx) && (prclSrc->bottom <= psoSrc->sizlBitmap.cy)) { SIZEL sizlNewSrc; HSURF hsurfNewSrc; SURFOBJ *psoNewSrc; RECTL rclNew; BOOL bRet;
sizlNewSrc.cx = prclSrc->right - prclSrc->left; sizlNewSrc.cy = prclSrc->bottom - prclSrc->top;
if ((sizlNewSrc.cx <= (prclTrg->right - prclTrg->left)) && (sizlNewSrc.cy <= (prclTrg->bottom - prclTrg->top))) { hsurfNewSrc = (HSURF) EngCreateBitmap(sizlNewSrc, 0, psoTrg->iBitmapFormat, 0, NULL);
psoNewSrc = EngLockSurface(hsurfNewSrc);
if (psoNewSrc) { //
// Bug #69739
//
// Set uniqueness to zero so that the driver does not bother
// trying to cache the temporary bitmap.
//
psoNewSrc->iUniq = 0;
rclNew.left = 0; rclNew.top = 0; rclNew.right = sizlNewSrc.cx; rclNew.bottom = sizlNewSrc.cy;
bRet = (PPFNGET(pdoSrc, CopyBits, pSurfSrc->flags()) (psoNewSrc, psoSrc, NULL, pxlo, &rclNew, (POINTL*) prclSrc)) && (PPFNDRV(pdoTrg, StretchBlt)(psoTrg, psoNewSrc, psoMask, pco, NULL, pca, pptlBrushOrg, prclTrg, &rclNew, pptlMask, iMode));
EngUnlockSurface(psoNewSrc); EngDeleteSurface(hsurfNewSrc);
return(bRet); } } } }
//
// Set up frame variables for possible switch to temporary output surface
//
SURFMEM dimoOut; SURFACE *pSurfOut; RECTL rclOut; RECTL *prclOut; ECLIPOBJ ecoOut; CLIPOBJ *pcoOut; ERECTL erclDev; EPOINTL eptlDev; ERECTL erclTrim(0, 0, pSurfSrc->sizl().cx, pSurfSrc->sizl().cy); RECTL rclTrim; RGNMEMOBJTMP rmoOut;
//
// If the target is not a DIB, or the target and source are on the same
// surface and the extents overlap, create a target DIB of the needed
// size and format.
//
if ((pSurfTrg->iType() == STYPE_BITMAP) && (pSurfTrg->hsurf() != pSurfSrc->hsurf())) { pSurfOut = pSurfTrg; prclOut = prclTrg; pcoOut = pco; } else { rclOut = *prclTrg;
erclDev.left = rclOut.left - 1; erclDev.top = rclOut.top - 1; erclDev.right = rclOut.right + 1; erclDev.bottom = rclOut.bottom + 1;
//
// Trim to the target surface.
//
ERECTL erclTrg(0, 0, pSurfTrg->sizl().cx, pSurfTrg->sizl().cy);
#ifdef DBG_STRBLT
vShowRect("Trg Rect", (RECTL *) &erclDev); vShowRect("Trg Surf", (RECTL *) &erclTrg); #endif
erclDev *= erclTrg;
//
// If we have nothing left, we're done.
//
if (erclDev.bEmpty()) return(TRUE);
#ifdef DBG_STRBLT
vShowRect("Trg Surf & Rect", (RECTL *) &erclDev); #endif
//
// If we are only here on possible overlap, test for misses
//
if (( pSurfTrg->iType() == STYPE_BITMAP) && ((erclDev.left > prclSrc->right) || (erclDev.right < prclSrc->left) || (erclDev.top > prclSrc->bottom) || (erclDev.bottom < prclSrc->top))) { pSurfOut = pSurfTrg; prclOut = prclTrg; pcoOut = pco; } else { //
// Compute the adjusted rectangle in the temporary surface.
//
rclOut.left -= erclDev.left; rclOut.top -= erclDev.top; rclOut.right -= erclDev.left; rclOut.bottom -= erclDev.top;
DEVBITMAPINFO dbmi;
dbmi.cxBitmap = erclDev.right - erclDev.left + 1; dbmi.cyBitmap = erclDev.bottom - erclDev.top + 1; dbmi.hpal = (HPALETTE) 0; if (bSrcCMYKColor) { //
// On CMYK color mode, create temporary surface based on source surface.
//
dbmi.iFormat = pSurfSrc->iFormat(); } else { dbmi.iFormat = pSurfTrg->iFormat(); } dbmi.fl = pSurfTrg->bUMPD() ? UMPD_SURFACE : 0;
#ifdef DBG_STRBLT
if (gflStrBlt & STRBLT_ALLOC) { DbgPrint("Allocating temporary target\n"); DbgPrint("Size (%lx, %lx)\n", dbmi.cxBitmap, dbmi.cyBitmap); DbgPrint("Format = %lx\n", dbmi.iFormat); } #endif
dimoOut.bCreateDIB(&dbmi, (VOID *) NULL);
if (!dimoOut.bValid()) return(FALSE);
//
// What point in the target surface is 0,0 in temporary surface.
//
eptlDev = *((EPOINTL *) &erclDev);
//
// Build a CLIPOBJ for the new surface.
//
if (!rmoOut.bValid()) return(FALSE);
erclDev.left = 0; erclDev.top = 0; erclDev.right -= eptlDev.x; erclDev.bottom -= eptlDev.y;
#ifdef DBG_STRBLT
vShowRect("Trg Clip", (RECTL *) &erclDev); #endif
rmoOut.vSet((RECTL *) &erclDev);
ecoOut.vSetup(rmoOut.prgnGet(), erclDev, CLIP_FORCE);
//
// Synchronize with the device driver before touching the device surface.
//
{ PDEVOBJ po( pSurfTrg->hdev()); po.vSync(pSurfTrg->pSurfobj(),NULL,0); }
//
// If there is a mask, copy the actual target to the temporary.
//
if (pSurfMask != (SURFACE *) NULL) { (*PPFNGET(pdoTrg,CopyBits, pSurfTrg->flags()))( dimoOut.pSurfobj(), pSurfTrg->pSurfobj(), (CLIPOBJ *) NULL, &xloIdent, &erclDev, &eptlDev); }
//
// Point to the new target.
//
pSurfOut = dimoOut.ps; prclOut = &rclOut; pcoOut = &ecoOut; } }
//
// Synchronize with the device driver before touching the device surface.
//
{ PDEVOBJ po( pSurfSrc->hdev()); po.vSync(psoSrc,NULL,0); }
//
// Compute what area of the source surface will actually be used. We do
// this so we never read off the end of the surface and fault or worse,
// write bad pixels onto the target. Trim the source rectangle to the
// source surface.
//
#ifdef DBG_STRBLT
vShowRect("Src Surf", (RECTL *) &erclTrim); vShowRect("Src Rect", prclSrc); #endif
erclTrim *= *prclSrc;
#ifdef DBG_STRBLT
vShowRect("Src Surf & Src Rect", (RECTL *) &erclTrim); #endif
//
// If we have nothing left, we're done.
//
if (erclTrim.bEmpty()) return(TRUE);
//
// Now we must worry about the source surface. Its possible we are blitting
// from an RLE to the VGA for instance. We convert the surface to the same
// bitmap format as the target for convience.
//
SURFMEM dimoIn; SURFACE *pSurfIn; RECTL rclIn; RECTL *prclIn; XLATEOBJ *pxloIn;
if ((flMirror == 0) && ( pSurfSrc->iType() == STYPE_BITMAP) && ( pSurfSrc->iFormat() != BMF_4RLE) && ( pSurfSrc->iFormat() != BMF_8RLE)) { pSurfIn = pSurfSrc; if (bSrcCMYKColor) { //
// The surface will be kept as compatible as source, so no translation at this point.
//
pxloIn = NULL; } else { pxloIn = pxlo; } prclIn = prclSrc; } else { DEVBITMAPINFO dbmi;
dbmi.cxBitmap = erclTrim.right - erclTrim.left; dbmi.cyBitmap = erclTrim.bottom - erclTrim.top; dbmi.hpal = (HPALETTE) 0; if (bSrcCMYKColor) { //
// On CMYK color mode, create temporary surface based on source surface.
//
dbmi.iFormat = pSurfSrc->iFormat(); } else { dbmi.iFormat = pSurfOut->iFormat(); } dbmi.fl = pSurfSrc->bUMPD() ? UMPD_SURFACE : 0;
#ifdef DBG_STRBLT
if (gflStrBlt & STRBLT_ALLOC) { DbgPrint("Allocating temporary source\n"); DbgPrint("Size (%lx, %lx)\n", dbmi.cxBitmap, dbmi.cyBitmap); DbgPrint("Format = %lx\n", dbmi.iFormat); } #endif
dimoIn.bCreateDIB(&dbmi, (VOID *) NULL);
if (!dimoIn.bValid()) return(FALSE);
//
// The cursor should already be excluded at this point, so just copy
// to the DIB.
//
rclIn.left = 0; rclIn.top = 0; rclIn.right = erclTrim.right - erclTrim.left; rclIn.bottom = erclTrim.bottom - erclTrim.top;
(*PPFNGET(pdoSrc,CopyBits, pSurfSrc->flags()))( dimoIn.pSurfobj(), pSurfSrc->pSurfobj(), (CLIPOBJ *) NULL, (bSrcCMYKColor ? NULL : pxlo), &rclIn, (POINTL *) &erclTrim);
//
// Point at the new source
//
rclIn.left = prclSrc->left - erclTrim.left; rclIn.top = prclSrc->top - erclTrim.top; rclIn.right = prclSrc->right - erclTrim.left; rclIn.bottom = prclSrc->bottom - erclTrim.top;
pSurfIn = dimoIn.ps; prclIn = &rclIn; pxloIn = NULL;
//
// Adjust the trimmed source origin and extent
//
erclTrim.right -= erclTrim.left; erclTrim.bottom -= erclTrim.top; erclTrim.left = 0; erclTrim.top = 0;
//
// If we needed to, do mirroring. Y mirroring is easy.
//
if (flMirror & STRBLT_MIRROR_Y) { if (dimoIn.ps->lDelta() > 0) dimoIn.ps->pvScan0(((BYTE *) dimoIn.ps->pvBits()) + dimoIn.ps->lDelta() * (erclTrim.bottom - 1)); else dimoIn.ps->pvScan0(dimoIn.ps->pvBits());
dimoIn.ps->lDelta(-dimoIn.ps->lDelta()); }
//
// X mirroring is not.
//
if (flMirror & STRBLT_MIRROR_X) (*apfnMirror[dimoIn.ps->iFormat()])(dimoIn.ps); }
//
// Synchronize with the device driver before touching the device surface.
//
{ PDEVOBJ po( pSurfOut->hdev()); po.vSync(pSurfOut->pSurfobj(),NULL, 0); }
//
// Compute the space needed for the DDA to see if we can do it on the frame.
// Clip it to the limit of our coordinate systems (2^27) to avoid math
// overflow in the subsequent calculations.
//
if (((prclIn->right - prclIn->left) >= MAX_STRETCH_COOR) || ((prclIn->bottom - prclIn->top) >= MAX_STRETCH_COOR)) { return(FALSE); }
if (((prclOut->right - prclOut->left) >= MAX_STRETCH_COOR) || ((prclOut->bottom - prclOut->top) >= MAX_STRETCH_COOR) || ((prclOut->right - prclOut->left) <= -MAX_STRETCH_COOR) || ((prclOut->bottom - prclOut->top) <= -MAX_STRETCH_COOR)) { return(FALSE); }
//
// Special acceleration case:
//
// SrcFormat and Destination format are the same
// Color translation is NULL
// Src width and height and less than 2 ^ 30
//
if ( (iMode == COLORONCOLOR) && (psoMask == (SURFOBJ *) NULL) && ((pxloIn == (XLATEOBJ *)NULL) || ((XLATE *)pxloIn)->bIsIdentity()) && (pSurfOut->iFormat() == pSurfIn->iFormat()) && ( (pSurfIn->iFormat() == BMF_8BPP) || (pSurfIn->iFormat() == BMF_16BPP) || (pSurfIn->iFormat() == BMF_32BPP) ) ) { if((pcoOut == (CLIPOBJ *)NULL) || (pcoOut->iDComplexity != DC_COMPLEX)) { //
// Case for no clip region (DC_TRIVIAL) or single rectangle
// clipping (DC_RECT).
//
//
// set clipping for DC_RECT case only, otherwise
// use dst rectangle
//
PRECTL prclClipOut = prclOut; //
// StretchDIBDirect has early out cases which leave erclTrim
// uninitialized. This line of code is left commented out because
// nobody has found a bug caused by this.
//
// erclTrim.left = erclTrim.right = erclTrim.top = erclTrim.bottom = 0;
//
if ((pcoOut != (CLIPOBJ *)NULL) && (pcoOut->iDComplexity == DC_RECT)) { prclClipOut = &(pcoOut->rclBounds); } //
// call stretch blt accelerator
//
StretchDIBDirect( pSurfOut->pvScan0(), pSurfOut->lDelta(), pSurfOut->sizl().cx, pSurfOut->sizl().cy, prclOut, pSurfIn->pvScan0(), pSurfIn->lDelta(), pSurfIn->sizl().cx, pSurfIn->sizl().cy, prclIn, &erclTrim, prclClipOut, pSurfOut->iFormat() ); } else { //
// Handle the complex CLIPOBJ case (DC_COMPLEX)
//
//
// Temp storage for individual trim sub-rectangles
//
ERECTL erclTrimTmp(0,0,0,0);
//
// Initialize erclTrim for accumulation using the += operator below
// Setting everything to zero ensures the first RECTL is copied.
// Theoretically we could just set left=right for this to work.
//
erclTrim.left = erclTrim.right = erclTrim.top = erclTrim.bottom = 0;
BOOL bMore; ENUMRECTS arclComplexEnum; CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0); //
// Point this at the RECTL location and then the loop code below
// will slide each successive RECTL under this pointer.
//
PRECTL prclClipOut=&arclComplexEnum.arcl[0];
do {
//
// Enumerate each rectangle one-by-one in any order.
//
bMore = CLIPOBJ_bEnum(pco, sizeof(arclComplexEnum), (ULONG*) &arclComplexEnum); //
// Call the stretch blt accelerator for this RECTL
//
if(arclComplexEnum.c > 0) { StretchDIBDirect( pSurfOut->pvScan0(), pSurfOut->lDelta(), pSurfOut->sizl().cx, pSurfOut->sizl().cy, prclOut, pSurfIn->pvScan0(), pSurfIn->lDelta(), pSurfIn->sizl().cx, pSurfIn->sizl().cy, prclIn, &erclTrimTmp, prclClipOut, pSurfOut->iFormat() );
//
// Accumulate the Trim rectangle
//
erclTrim += erclTrimTmp; } } while (bMore); } //
// save reduced target rectangle for use in CopyBits
// to write a temp DIB to the target
//
rclTrim.left = erclTrim.left; rclTrim.right = erclTrim.right; rclTrim.top = erclTrim.top; rclTrim.bottom = erclTrim.bottom; } else { //
// Initialize the DDA
//
STRDDA *pdda;
LONG cjSpace = sizeof(STRDDA) + (sizeof(LONG) * (prclIn->right - prclIn->left + prclIn->bottom - prclIn->top));
pdda = (STRDDA *) PALLOCNOZ(cjSpace, 'htsG'); if (pdda == (STRDDA *) NULL) { return(FALSE); }
#ifdef DBG_STRBLT
if (gflStrBlt & STRBLT_ALLOC) { DbgPrint("Need %ld bytes for DDA\n", cjSpace); DbgPrint("DDA @%08lx\n", (ULONG) pdda); } #endif
vInitStrDDA(pdda, (RECTL *) &erclTrim, prclIn, prclOut);
//
// Save the reduced target rectangle.
//
rclTrim = pdda->rcl;
//
// See if we can accelerate anything.
//
if ((pxloIn != NULL) && (pxloIn->flXlate & XO_TRIVIAL)) { pxloIn = NULL; }
if ((pcoOut != (CLIPOBJ *) NULL) && (pcoOut->iDComplexity == DC_TRIVIAL)) { pcoOut = (CLIPOBJ *) NULL; }
PFN_STRREAD pfnRead; PFN_STRWRITE pfnWrite = apfnWrite[pSurfOut->iFormat()];
if (bBogus) { pdda->iColor = (iMode == BLACKONWHITE) ? ~0L : 0L; }
pfnRead = apfnRead[pSurfIn->iFormat()][iMode - BLACKONWHITE];
STRRUN *prun;
//
// Now compute the space needed for the stretch buffers
//
if ((prclIn->right - prclIn->left) > (prclOut->right - prclOut->left)) { //
// Shrink case -- even though shrinking the mask may cause
// separate runs to merge together, the low-level stretch code
// does not handle this. Therefore, may have a run for every
// single pixel.
//
cjSpace = sizeof(STRRUN) + (sizeof(XRUNLEN) * (rclTrim.right - rclTrim.left)) + sizeof(DWORD); } else { //
// Stretch case -- worse case: every other pixel is masked, so
// number of runs is 1/2 the number of pixels.
//
cjSpace = sizeof(STRRUN) + sizeof(XRUNLEN) * ((rclTrim.right - rclTrim.left + 3) / 2) + sizeof(DWORD); }
if ( ((rclTrim.right - rclTrim.left) > 100000000L) || ((prun = (STRRUN *) AllocFreeTmpBuffer(cjSpace)) == NULL) ) { VFREEMEM(pdda); return(FALSE); }
#ifdef DBG_STRBLT
if (gflStrBlt & STRBLT_ALLOC) { DbgPrint("Need %ld bytes for buffer\n", cjSpace); DbgPrint("Buffer @%08lx\n", (ULONG) prun); } #endif
BYTE *pjSrc = (BYTE *) pSurfIn->pvScan0() + pSurfIn->lDelta() * erclTrim.top; BYTE *pjMask; POINTL ptlMask; LONG yRow; LONG yCnt;
if (psoMask == (SURFOBJ *) NULL) { pjMask = (BYTE *) NULL; } else { ptlMask.x = erclTrim.left - prclIn->left + pptlMask->x; ptlMask.y = erclTrim.top - prclIn->top + pptlMask->y;
pjMask = (BYTE *) pSurfMask->pvScan0() + pSurfMask->lDelta() * ptlMask.y; }
//
// If we are in bogus mode, initialize the buffer
//
ULONG iOver;
if (bBogus) { iOver = (iMode == BLACKONWHITE) ? -1 : 0;
vInitBuffer(prun, &rclTrim, iOver); }
prun->yPos = pdda->rcl.top;
SUSPENDWATCH sw(pdoTrg);
for (yRow = erclTrim.top, yCnt = 0; yRow < erclTrim.bottom; yRow++, yCnt++) { prun->cRep = pdda->plYStep[yCnt];
if (prun->cRep) { (*pfnWrite)(prun, (*pfnRead)(pdda, prun, pjSrc, pjMask, pxloIn, erclTrim.left, erclTrim.right, ptlMask.x), pSurfOut, pcoOut);
//
// If we are in bogus mode, reinitialize the buffer
//
if (bBogus) vInitBuffer(prun, &rclTrim, iOver); } else { //
// If we are in BLACKONWHITE or WHITEONBLACK mode, we need to read
// the scan and mix it with the current buffer.
//
if (bBogus) { (*pfnRead)(pdda, prun, pjSrc, (BYTE *) NULL, pxloIn, erclTrim.left, erclTrim.right, 0); } }
pjSrc += pSurfIn->lDelta(); prun->yPos += prun->cRep;
if (pjMask != (BYTE *) NULL) { pjMask += pSurfMask->lDelta(); } }
sw.Resume();
//
// Free up the work buffers.
//
FreeTmpBuffer(prun); VFREEMEM(pdda); }
//
// See if we have drawn on the actual output surface.
//
if (pSurfOut == pSurfTrg) #ifndef DBG_STRBLT
return(TRUE); #else
{ if (gflStrBlt & STRBLT_FORMAT) DbgBreakPoint();
return(TRUE); } #endif
//
// We need to build a clipping region equal to the trimmed target.
//
rclTrim.left += eptlDev.x; rclTrim.top += eptlDev.y; rclTrim.right += eptlDev.x; rclTrim.bottom += eptlDev.y;
RGNMEMOBJTMP rmo;
if (!rmo.bValid()) return(FALSE);
if (pco == (CLIPOBJ *) NULL) rmo.vSet(&rclTrim); else { RGNMEMOBJTMP rmoTmp;
if (!rmoTmp.bValid()) return(FALSE);
rmoTmp.vSet(&rclTrim);
if (!rmo.bMerge(rmoTmp, *((ECLIPOBJ *)pco), gafjRgnOp[RGN_AND])) return(FALSE); }
ERECTL ercl;
rmo.vGet_rcl(&ercl);
if (pco != NULL) { //
// Make sure that the bounds are tight to the destination rectangle.
//
if (!bIntersect(&ercl, &pco->rclBounds, &ercl)) { return(TRUE); } }
ECLIPOBJ eco(rmo.prgnGet(), ercl, CLIP_FORCE);
if (eco.erclExclude().bEmpty()) return(TRUE);
//
// Copy from the temporary to the target surface.
//
erclDev.left += eptlDev.x; erclDev.top += eptlDev.y; erclDev.right += eptlDev.x; erclDev.bottom += eptlDev.y; eptlDev.x = 0; eptlDev.y = 0;
#ifdef DBG_STRBLT
vShowRect("Trg Out", (RECTL *) &erclDev); #endif
//
// With CMYK color, temp surface is based on source, while non-CMYK
// case it's target. So we need xlateobj for CMYK color case, but
// don't need for non-CMYK case.
//
(*PPFNGET(pdoTrg,CopyBits, pSurfTrg->flags())) (pSurfTrg->pSurfobj(), dimoOut.pSurfobj(), &eco, (bSrcCMYKColor ? pxlo : NULL), &erclDev, &eptlDev);
#ifdef DBG_STRBLT
if (gflStrBlt & STRBLT_FORMAT) DbgBreakPoint(); #endif
return(TRUE); }
/******************************Public*Routine******************************\
* EngStretchBltROP * * This does stretched bltting with a rop. * * This call returns TRUE for success, FALSE for ERROR. * * History: * 24-Sept-1996 -by- Lingyun Wang [lingyunw] * Wrote it. \**************************************************************************/
BOOL EngStretchBltROP( SURFOBJ *psoTrg, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo, COLORADJUSTMENT *pca, POINTL *pptlBrushOrg, RECTL *prclTrg, RECTL *prclSrc, POINTL *pptlMask, ULONG iMode, BRUSHOBJ *pbo, ROP4 rop4) { GDIFunctionID(EngStretchBltROP);
ASSERTGDI(psoTrg != (SURFOBJ *) NULL, "psoTrg == NULL\n"); ASSERTGDI(prclTrg != (PRECTL) NULL, "dst rectangle is NULL\n");
PSURFACE pSurfTrg = SURFOBJ_TO_SURFACE(psoTrg); PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE(psoSrc);
ASSERTGDI(rop4, "rop4 == NULL\n"); ASSERTGDI(pSurfTrg->iFormat() != BMF_JPEG, "dst BMF_JPEG not supported\n"); ASSERTGDI(pSurfTrg->iFormat() != BMF_PNG, "dst BMF_PNG not supported\n"); ASSERTGDI(!(ROP4NEEDSRC(rop4) && (psoSrc == (SURFOBJ *) NULL)), "psoSrc == NULL\n"); ASSERTGDI(!(ROP4NEEDSRC(rop4) && (prclSrc == (PRECTL) NULL)), "src rectangle is NULL\n"); ASSERTGDI(!(ROP4NEEDSRC(rop4) && (pSurfSrc->iFormat() == BMF_JPEG)), "src BMF_JPEG not supported\n"); ASSERTGDI(!(ROP4NEEDSRC(rop4) && (pSurfSrc->iFormat() == BMF_PNG)), "src BMF_PNG not supported\n"); ASSERTGDI(!(ROP4NEEDPAT(rop4) && (pbo == (BRUSHOBJ *) NULL)), "Pattern is NULL\n"); ASSERTGDI(!(ROP4NEEDPAT(rop4) && (pbo->iSolidColor == 0xFFFFFFFF) && (pptlBrushOrg == (PPOINTL) NULL)), "Pattern offset is NULL\n");
if ((rop4 != 0x0000CCCC) && (rop4 != 0x0000AACC)) { //
// Dont halftone if we got a weird ROP.
//
if (iMode == HALFTONE) iMode = COLORONCOLOR;
LONG l; BOOL bFlipX = FALSE; BOOL bFlipY = FALSE;
//
// order the target extents
//
if (prclTrg->left > prclTrg->right) { l = prclTrg->left, prclTrg->left = prclTrg->right, prclTrg->right = l;
bFlipX = TRUE; }
if (prclTrg->top > prclTrg->bottom) { l = prclTrg->top, prclTrg->top = prclTrg->bottom, prclTrg->bottom = l;
bFlipY = TRUE; }
DEVBITMAPINFO dbmi; SURFMEM dimoShadow; SURFMEM dimoMask;
ULONG ulAvec = ((ULONG) gajRop3[rop4 & 0x00ff]) | ((ULONG) gajRop3[(rop4 >> 8) & 0x00ff]);
// The check above does not tell if we need a mask.
// Check explicitly.
if (ROP4NEEDMASK(rop4)) { ulAvec |= AVEC_NEED_MASK; }
EPOINTL ptl(0,0);
//
// Stretch the Mask
//
if (ulAvec & AVEC_NEED_MASK) {
ASSERTGDI (psoMask, "psoMask == NULL\n");
PSURFACE pSurfMask = SURFOBJ_TO_SURFACE(psoMask);
//
// use ordered target extents for the size
//
dbmi.iFormat = BMF_1BPP; dbmi.cxBitmap = prclTrg->right - prclTrg->left; dbmi.cyBitmap = prclTrg->bottom - prclTrg->top; dbmi.hpal = (HPALETTE) 0; dbmi.fl = pSurfMask->bUMPD() ? UMPD_SURFACE : 0;
ERECTL erclTrg(0, 0, dbmi.cxBitmap, dbmi.cyBitmap);
if (bFlipX) l = erclTrg.left, erclTrg.left = erclTrg.right, erclTrg.right = l;
if (bFlipY) l = erclTrg.top, erclTrg.top = erclTrg.bottom, erclTrg.bottom = l;
dimoMask.bCreateDIB(&dbmi, (VOID *) NULL);
if (!dimoMask.bValid()) return(FALSE);
ULONG cx = prclSrc->right - prclSrc->left; ULONG cy = prclSrc->bottom - prclSrc->top;
ERECTL erclMask(pptlMask->x, pptlMask->y, pptlMask->x+cx, pptlMask->y+cy);
//
// Call EngStretchBlt to stretch the mask.
//
if (!EngStretchBlt(dimoMask.pSurfobj(), psoMask, (SURFOBJ *) NULL, (CLIPOBJ *) NULL, NULL, NULL, (POINTL *)&ptl, &erclTrg, &erclMask, (POINTL *) NULL, iMode)) { return(FALSE); }
}
//
// Stretch the Src
//
if (ulAvec & AVEC_NEED_SOURCE) { //
// use ordered target extents for the size
//
dbmi.iFormat = pSurfSrc->iFormat(); dbmi.cxBitmap = prclTrg->right - prclTrg->left; dbmi.cyBitmap = prclTrg->bottom - prclTrg->top; dbmi.hpal = (HPALETTE) 0; dbmi.fl = pSurfSrc->bUMPD() ? UMPD_SURFACE : 0;
// Build a shadow rectangle.
ERECTL erclTrg(0, 0, dbmi.cxBitmap, dbmi.cyBitmap);
if (bFlipX) l = erclTrg.left, erclTrg.left = erclTrg.right, erclTrg.right = l;
if (bFlipY) l = erclTrg.top, erclTrg.top = erclTrg.bottom, erclTrg.bottom = l;
dimoShadow.bCreateDIB(&dbmi, (VOID *) NULL);
if (!dimoShadow.bValid()) { WARNING("dimoShadow invalid\n"); return(FALSE); }
//
// Call EngStretchBlt to stretch the source.
//
if (!EngStretchBlt(dimoShadow.pSurfobj(), psoSrc, (SURFOBJ *) NULL, (CLIPOBJ *) NULL, NULL, NULL, (POINTL *)&ptl, &erclTrg, prclSrc, (POINTL *) NULL, iMode)) { return(FALSE); }
}
//
// Call BitBlt
//
return((*(pSurfTrg->pfnBitBlt())) ( psoTrg, dimoShadow.pSurfobj(), dimoMask.pSurfobj(), pco, pxlo, prclTrg, (POINTL *)&ptl, (POINTL *)&ptl, pbo, pptlBrushOrg, rop4)); } else { //
// Just pass it off to EngStretchBlt since it doesn't have a complex ROP
//
PDEVOBJ pdoTrg(pSurfTrg->hdev()); PDEVOBJ pdoSrc(pSurfSrc->hdev());
// Inc the target surface uniqueness
INC_SURF_UNIQ(pSurfTrg);
PFN_DrvStretchBlt pfn = PPFNGET(pdoTrg, StretchBlt, pSurfTrg->flags());
//
// There are a bunch of conditions that we don't want to
// call the driver, so we make pfn point to the Eng
// function. But if the destination is a meta, we want it
// to actually call the Mul layer.
//
// WINBUG #357937 4-3-2001 jasonha Meta DEVBITMAPs must go thru Mul layer
// Don't check iType:
// DEVICE/DEVBITMAP -> MulStretchBlt
// BITMAP (not hooked) -> EngStretchBlt
if ((pSurfTrg->flags() & HOOK_StretchBlt) && !pdoTrg.bMetaDriver()) { // Don't call the driver if it doesn't do halftone.
if (iMode == HALFTONE) { if (!(pdoTrg.flGraphicsCapsNotDynamic() & GCAPS_HALFTONE)) pfn = (PFN_DrvStretchBlt)EngStretchBlt; }
// WINBUG #95246 3-17-2000 jasonha GDI: StretchBlt optimizations: Let drivers handle more cases
// Don't call the driver if the source rectangle exceeds the source
// surface. Some drivers punt using a duplicate of the source
// SURFOBJ, but without preserving its sizlBitmap member.
BOOL bSrcExceeds = FALSE;
if(pSurfSrc->iType() == STYPE_DEVICE && pdoSrc.bValid() && pdoSrc.bMetaDriver()) { if((prclSrc->left < pdoSrc.pptlOrigin()->x ) || (prclSrc->top < pdoSrc.pptlOrigin()->y ) || (prclSrc->right > pdoSrc.pptlOrigin()->x + pSurfSrc->sizl().cx) || (prclSrc->bottom > pdoSrc.pptlOrigin()->y + pSurfSrc->sizl().cy)) { bSrcExceeds = TRUE; }
} else { if((prclSrc->left < 0) || (prclSrc->top < 0) || (prclSrc->right > pSurfSrc->sizl().cx) || (prclSrc->bottom > pSurfSrc->sizl().cy)) { bSrcExceeds = TRUE; } }
if( bSrcExceeds ) { pfn = (PFN_DrvStretchBlt)EngStretchBlt; }
// WINBUG #95246 3-17-2000 jasonha GDI: StretchBlt optimizations: Let drivers handle more cases
// Don't call the driver if the source overlaps the destination.
// Some drivers don't handle this case.
ASSERTGDI((prclSrc->left <= prclSrc->right) && (prclSrc->top <= prclSrc->bottom), "Source rectangle not well-ordered\n");
// Use a well-ordered copy of the destination rectangle to do the
// intersection test.
ERECTL rclTrg(*prclTrg); rclTrg.vOrder();
if ((psoSrc == psoTrg) && bIntersect(prclSrc, &rclTrg)) { pfn = (PFN_DrvStretchBlt)EngStretchBlt; }
}
return ((*pfn)(psoTrg, psoSrc, (rop4 == 0x0000CCCC) ? (SURFOBJ *) NULL : psoMask, pco, pxlo, pca, pptlBrushOrg, prclTrg, prclSrc, pptlMask, iMode)); }
}
|