You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2709 lines
78 KiB
2709 lines
78 KiB
/******************************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));
|
|
}
|
|
|
|
}
|
|
|