Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1792 lines
46 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 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:
* 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
)
{
BLTRECORD blt;
// 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())
{
ULONG ulDirty = dcoTrg.pdc->ulDirty();
if ( ulDirty & DC_BRUSH_DIRTY)
{
GreDCSelectBrush (dcoTrg.pdc, dcoTrg.pdc->hbrush());
}
}
if (!dcoTrg.bValid() ||
(!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 (!(W32GetCurrentProcess()->W32PF_Flags & W32PF_READSCREENACCESSGRANTED))
{
SAVE_ERROR_CODE(ERROR_ACCESS_DENIED);
return(FALSE);
}
else if (!(W32GetCurrentProcess()->W32PF_Flags & W32PF_IOWINSTA))
{
SAVE_ERROR_CODE(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
return(FALSE);
}
}
// If the source isn't a DISPLAY we should exit
if (!dcoSrc.bDisplay())
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);
}
// 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.
if (!blt.pexlo()->bInitXlateObj(
dcoTrg.pdc->GetColorTransform(),
*blt.ppoSrc(),
*blt.ppoTrg(),
*blt.ppoSrcDC(),
*blt.ppoTrgDC(),
dcoTrg.pdc->crTextClr(),
dcoTrg.pdc->crBackClr(),
crBackColor))
{
WARNING("bInitXlateObj failed in StretchBlt\n");
return(FALSE);
}
blt.flSet(BLTREC_PXLO);
// Set up the brush if necesary.
blt.pbo(dcoTrg.peboFill());
if (ulAvec & AVEC_NEED_PATTERN)
{
if ((dcoTrg.ulDirty() & DIRTY_FILL) || (dcoTrg.pdc->flbrush() & DIRTY_FILL))
{
dcoTrg.ulDirtySub(DIRTY_FILL);
dcoTrg.pdc->flbrushSub(DIRTY_FILL);
blt.pbo()->vInitBrush(
dcoTrg.pdc->pbrushFill(),
dcoTrg.pdc->crTextClr(),
dcoTrg.pdc->crBackClr(),
*((XEPALOBJ *) blt.ppoTrgDC()),
*((XEPALOBJ *) blt.ppoTrg()),
blt.pSurfTrg());
}
blt.Brush(dcoTrg.pdc->ptlFillOrigin());
}
// Initialize some stuff for DDI.
blt.pSurfMsk((SURFACE *) NULL);
// Set the source rectangle
if (blt.pxoSrc()->bRotation() || !blt.Src(xSrc, ySrc, cxSrc, cySrc))
{
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
return(FALSE);
}
// 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);
return(blt.bRotate(dcoTrg, dcoSrc, ulAvec, dcoTrg.pdc->jStretchBltMode()));
}
// We can now set the target rectangle
if (!blt.Trg(x, y, cx, cy))
{
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
return(FALSE);
}
// If we are halftoning or the extents aren't equal, call bStretch
if (( dcoTrg.pdc->jStretchBltMode() == HALFTONE) || !blt.bEqualExtents())
return(blt.bStretch(dcoTrg, dcoSrc, ulAvec, dcoTrg.pdc->jStretchBltMode() ));
// Since there can't be a mask, call bBitBlt.
return(blt.bBitBlt(dcoTrg, dcoSrc, ulAvec));
}
/******************************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[0].x > pSurfMsk()->sizl().cx) ||
(aptlMask[0].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));
}
// If the devices are on different PDEV's we can only succeed if the Engine
// manages one or both of the surfaces. Check for this.
if ((dcoTrg.hdev() != dcoSrc.hdev()) &&
(dcoTrg.pSurfaceEff()->iType() != STYPE_BITMAP) &&
(dcoSrc.pSurfaceEff()->iType() != STYPE_BITMAP))
{
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[0].x > pSurfMsk()->sizl().cx) ||
(aptlMask[0].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));
}
// We might be here with a ROP. Again on behalf of MaskBlt, but most
// likely some yahoo called us with a ROP. Regardless, we handle this
// by making a shadow bitmap, stretching the source to it and calling
// BitBlt to finish the job. Note we have to stretch the mask as well,
// since it is tied to the source.
if ((rop4 != 0x0000CCCC) && (rop4 != 0x0000AACC))
{
SURFMEM dimoMask;
SURFMEM dimoShadow;
// Dont halftone if we got a weird ROP.
if (jMode == HALFTONE)
jMode = COLORONCOLOR;
if (!bStretch(dcoSrc,
dimoShadow,
dimoMask,
ulAvec,
(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, dcoSrc, ulAvec));
}
// 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;
// Lock the source and target LDEVs
PDEVOBJ pdoTrg(pSurfTrg()->hdev());
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);
// Deal with target mirroring
vMirror(perclTrg());
// Dispatch the call.
PFN_DrvStretchBlt pfn = PPFNGET(pdoTrg, StretchBlt, pSurfTrg()->flags());
if (jMode == HALFTONE)
{
// Don't call down to driver if it doesn't do halftone.
if (!(dcoTrg.flGraphicsCaps() & GCAPS_HALFTONE))
pfn = (PFN_DrvStretchBlt)EngStretchBlt;
}
// 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));
}
/******************************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 = 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,
&dclevelDefault.ca,
(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 = 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,
&dclevelDefault.ca,
(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
* stupid 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 stupid 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
if ((pSurfTrg->iFormat() == BMF_4RLE) ||
(pSurfTrg->iFormat() == BMF_8RLE))
{
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);
// Send Halftoning to DanielC.
if (iMode == HALFTONE)
{
int iRet = EngHTBlt(psoTrg,
psoSrc,
psoMask,
pco,
pxlo,
pca,
pptlBrushOrg,
prclTrg,
prclSrc,
pptlMask);
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;
//
// Get the LDEV's for the target and source surfaces
//
PDEVOBJ pdoTrg( pSurfTrg->hdev());
PDEVOBJ pdoSrc( pSurfSrc->hdev());
//
// 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;
dbmi.iFormat = pSurfTrg->iFormat();
dbmi.fl = 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.
//
if ( pSurfTrg->flags() & HOOK_SYNCHRONIZE)
{
PDEVOBJ po( pSurfTrg->hdev());
(po.pfnSync())(pSurfTrg->dhpdev(),NULL);
}
//
// 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.
//
if ( pSurfSrc->flags() & HOOK_SYNCHRONIZE)
{
PDEVOBJ po( pSurfSrc->hdev());
(po.pfnSync())(pSurfSrc->dhpdev(),NULL);
}
//
// 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;
pxloIn = pxlo;
prclIn = prclSrc;
}
else
{
DEVBITMAPINFO dbmi;
dbmi.cxBitmap = erclTrim.right - erclTrim.left;
dbmi.cyBitmap = erclTrim.bottom - erclTrim.top;
dbmi.hpal = (HPALETTE) 0;
dbmi.iFormat = pSurfOut->iFormat();
dbmi.fl = 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,
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.
//
if ( pSurfOut->flags() & HOOK_SYNCHRONIZE)
{
PDEVOBJ po( pSurfOut->hdev());
(po.pfnSync())(pSurfOut->dhpdev(),NULL);
}
//
// 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)
) &&
(
(pcoOut == (CLIPOBJ *)NULL) ||
(pcoOut->iDComplexity != DC_COMPLEX)
)
)
{
//
// set clipping for DC_RECT case only, otherwise
// use dst rectangle
//
PRECTL prclClipOut = prclOut;
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()
);
//
// 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;
//return(TRUE);
} 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.
//
//RECTL rclTrim = pdda->rcl;
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
//
cjSpace = sizeof(STRRUN) + sizeof(XRUNLEN) *
((rclTrim.right - rclTrim.left + 3) / 2) + sizeof(DWORD);
if ( ((rclTrim.right - rclTrim.left) > 100000000L) ||
((prun = (STRRUN *) PALLOCNOZ(cjSpace, 'htsG')) == 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;
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();
}
}
//
// Free up the work buffers.
//
VFREEMEM(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);
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
(*PPFNGET(pdoTrg,CopyBits, pSurfTrg->flags())) (pSurfTrg->pSurfobj(),
dimoOut.pSurfobj(),
&eco,
NULL,
&erclDev,
&eptlDev);
#ifdef DBG_STRBLT
if (gflStrBlt & STRBLT_FORMAT)
DbgBreakPoint();
#endif
return(TRUE);
}