Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1873 lines
57 KiB

/******************************Module*Header*******************************\
* Module Name: plgblt.cxx
*
* This contains the API and DDI entry points to the graphics engine
* for PlgBlt and EngPlgBlt.
*
* Created: 21-Oct-1990 14:15:53
* Author: Donald Sidoroff [donalds]
*
* Copyright (c) 1990-1999 Microsoft Corporation
\**************************************************************************/
#include "precomp.hxx"
#include "rotate.hxx"
/******************************Public*Routine******************************\
* GrePlgBlt
*
* API for blting to a parallelogram from a rectangle.
*
* History:
* Tue 02-Jun-1992 -by- Patrick Haluptzok [patrickh]
* fix clipping bugs
*
* 21-Mar-1992 -by- Donald Sidoroff [donalds]
* Rewrote it.
*
* Wed 15-Jan-1992 -by- Patrick Haluptzok [patrickh]
* Add mask support
*
* 26-Mar-1991 -by- Patrick Haluptzok patrickh
* Wrote it.
\**************************************************************************/
BOOL GrePlgBlt(
HDC hdcTrg,
LPPOINT pptlTrg,
HDC hdcSrc,
int xSrc,
int ySrc,
int cxSrc,
int cySrc,
HBITMAP hbmMask,
int xMask,
int yMask,
DWORD crBackColor
)
{
GDITraceHandle3(GrePlgBlt, "(%X, %p, %X, %d, %d, %d, %d, %X, %d, %d, %X)\n", (va_list)&hdcTrg, hdcTrg, hdcSrc, hbmMask);
BLTRECORD blt;
ULONG ulAvec;
// Lock the DC's, no optimization is made for same surface
DCOBJ dcoTrg(hdcTrg);
DCOBJ dcoSrc(hdcSrc);
if (!dcoTrg.bValid() || !dcoSrc.bValid())
{
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return(FALSE);
}
if (dcoTrg.bStockBitmap())
{
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return(FALSE);
}
// Lock the surface and the Rao region
DEVLOCKBLTOBJ dlo(dcoTrg, dcoSrc);
if (!dlo.bValid())
{
return(dcoTrg.bFullScreen() || dcoSrc.bFullScreen());
}
if (!dcoTrg.bValidSurf() || !dcoSrc.bValidSurf() || !dcoSrc.pSurface()->bReadable())
{
ULONG ulDirty = dcoTrg.pdc->ulDirty();
if ( ulDirty & DC_BRUSH_DIRTY)
{
GreDCSelectBrush (dcoTrg.pdc,dcoTrg.pdc->hbrush());
}
ulDirty = dcoSrc.pdc->ulDirty();
if ( ulDirty & DC_BRUSH_DIRTY)
{
GreDCSelectBrush (dcoSrc.pdc,dcoSrc.pdc->hbrush());
}
// I wanted to cheat, but InfoDCs need the right answer here...
if ((dcoTrg.dctp() == DCTYPE_INFO) || !dcoSrc.bValidSurf())
{
if (dcoTrg.fjAccum())
{
blt.pxoTrg()->vInit(dcoTrg,WORLD_TO_DEVICE);
if (!blt.TrgPlg(pptlTrg))
{
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
return(FALSE);
}
// Complete the parallelogram and find the extrema.
blt.vExtrema();
// Get the bounding rectangle
ERECTL erclBnd;
blt.vBound(&erclBnd);
dcoTrg.vAccumulate(erclBnd);
}
}
// 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 unless there is no
// destination surface.
if( !dcoSrc.bDisplay() )
{
return( dcoTrg.pSurface() == NULL );
}
}
if (dcoTrg.bDisplay() && !dcoTrg.bRedirection() && dcoSrc.bValidSurf() && !dcoSrc.bDisplay() && !UserScreenAccessCheck())
{
SAVE_ERROR_CODE(ERROR_ACCESS_DENIED);
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());
// Initialize the color translation object.
//
// No ICM with PlgBlt(), so pass NULL color transform to XLATEOBJ.
if (!blt.pexlo()->bInitXlateObj(NULL, // 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 PlgBlt\n");
return(FALSE);
}
blt.flSet(BLTREC_PXLO);
blt.pbo(NULL);
// Set the source rectangle.
if (blt.pxoSrc()->bRotation() || !blt.Src(xSrc, ySrc, cxSrc, cySrc))
{
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
return(FALSE);
}
// Deal with the mask if provided
if (hbmMask == (HBITMAP) 0)
{
blt.pSurfMsk((SURFACE *) NULL);
blt.rop(0x0000CCCC);
ulAvec = AVEC_S;
}
else
{
SURFREF soMsk((HSURF) hbmMask);
if (!soMsk.bValid())
{
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return(FALSE);
}
soMsk.vKeepIt();
blt.pSurfMsk((SURFACE *) soMsk.ps);
blt.rop(0x0000AACC);
ulAvec = AVEC_NEED_MASK | AVEC_S;
blt.flSet(BLTREC_MASK_NEEDED | BLTREC_MASK_LOCKED);
if (
(blt.pSurfMsk()->iType() != STYPE_BITMAP) ||
(blt.pSurfMsk()->iFormat() != BMF_1BPP)
)
{
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return(FALSE);
}
blt.Msk(xMask, yMask);
}
// We must first transform the target. We might be rotating because of
// the transform or the specified parallelogram.
if (!blt.TrgPlg(pptlTrg))
{
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
return(FALSE);
}
// If the parallelogram is rotated, skewed or has fractional endpoints
// send the call to bRotate.
if (blt.bRotated())
{
return(blt.bRotate(dcoTrg, dcoSrc, ulAvec, dcoTrg.pdc->jStretchBltMode()));
}
// 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()));
}
return(blt.bBitBlt(dcoTrg, dcoSrc, ulAvec));
}
BOOL
APIENTRY
NtGdiPlgBlt(
HDC hdcTrg,
LPPOINT pptlTrg,
HDC hdcSrc,
int xSrc,
int ySrc,
int cxSrc,
int cySrc,
HBITMAP hbmMask,
int xMask,
int yMask,
DWORD crBackColor
)
{
GDITraceHandle3(NtGdiPlgBlt, "(%X, %p, %X, %d, %d, %d, %d, %X, %d, %d, %X)\n", (va_list)&hdcTrg, hdcTrg, hdcSrc, hbmMask);
BOOL bRet;
POINT aptDst[3];
__try
{
ProbeForRead(pptlTrg, sizeof(aptDst), sizeof(DWORD));
RtlMoveMemory(aptDst, pptlTrg, sizeof(aptDst));
pptlTrg = aptDst;
bRet = TRUE;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
// SetLastError(GetExceptionCode());
bRet = FALSE;
}
if (bRet)
{
bRet = GrePlgBlt(hdcTrg, pptlTrg, hdcSrc, xSrc, ySrc, cxSrc, cySrc,
hbmMask, xMask, yMask, crBackColor);
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL BLTRECORD::bRotate(dcoTrg, dcoSrc, ulAvec)
*
* Do a rotate blt from the blt record
*
* History:
* 21-Mar-1992 -by- Donald Sidoroff [donalds]
* Rewrote it.
\**************************************************************************/
BOOL
BLTRECORD::bRotate(
DCOBJ& dcoTrg,
DCOBJ& dcoSrc,
ULONG ulAvec,
BYTE jMode
)
{
//
// Complete the parallelogram and find the extrema
//
vExtrema();
//
// We might be here on behalf of MaskBlt and need to rotate the mask
// before we do a pattern only blt.
//
BOOL bReturn;
if (!(ulAvec & AVEC_NEED_SOURCE))
{
vOrder(perclMask());
if (MIRRORED_DC(dcoTrg.pdc)) {
LONG x = aptlMask[0].x;
aptlMask[0].x = aptlMask[1].x;
aptlMask[1].x = x;
}
//
// 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 there is a mask, rotate it.
//
if ((ulAvec & AVEC_NEED_MASK) && !bRotate(dimoMask, (ULONG) jMode))
{
return(FALSE);
}
//
// Since this is going to bBitBlt, we need to create a target rectangle.
//
vBound(perclTrg());
//
// Create a region from the parallelogram and select it into the
// clipping pipeline. This is to make sure no bits are altered
// outside when BitBlt is called.
//
if (!bCreateRegion(dcoTrg, aptfxTrg))
{
return(FALSE);
}
bReturn = bBitBlt(dcoTrg, dcoSrc, ulAvec);
//
// Remember to clean up after ourselves!
//
dcoTrg.pdc->prgnAPI(NULL);
return(bReturn);
}
//
// Make the source rectangle well ordered remembering all the flips.
//
vOrder(perclSrc());
perclMask()->vOrder();
if (MIRRORED_DC(dcoTrg.pdc)) {
int x = aptlMask[0].x;
aptlMask[0].x = aptlMask[1].x;
aptlMask[1].x = x;
}
//
// 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);
}
}
//
// 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);
}
//
// We might be here with a ROP, again on behalf of MaskBlt. If it
// isn't one of the basic PlgBlt rops, create a rotated shadow and mask
// and call BitBlt to finish the job for us.
//
if ((rop4 != 0x0000CCCC) && (rop4 != 0x0000AACC))
{
SURFMEM dimoMask;
SURFMEM dimoShadow;
// WINBUG #263939 3-5-2000 bhouse Watchdog timeout problems
// We suspend the watchdog here ... GDI is brain dead and will
// create a temporary shadow surface the size of the destination
// mapping. This is crazy when the destination mapping far excceeds
// the actual size of the destination. Maybe one day we will
// re-write this brain dead code.... I'm not holding my breadth.
PDEVOBJ pdoTrg(pSurfTrg()->hdev());
if(pdoTrg.bDisplayPDEV())
GreSuspendWatch(pdoTrg.ppdev, WD_DEVLOCK);
bReturn = bRotate(dcoSrc, dimoShadow, dimoMask, ulAvec, (ULONG) jMode);
if(pdoTrg.bDisplayPDEV())
GreResumeWatch(pdoTrg.ppdev, WD_DEVLOCK);
if(!bReturn)
return(FALSE);
//
// Since this is going to bBitBlt, we need to create a target rectangle.
//
vBound(perclTrg());
//
// Create a region from the parallelogram and select it into the
// clipping pipeline. This is to make sure no bits are altered
// outside when BitBlt is called.
//
if (!bCreateRegion(dcoTrg, aptfxTrg))
{
return(FALSE);
}
bReturn = bBitBlt(dcoTrg, dcoSrc, ulAvec);
//
// Remember to clean up after ourselves!
//
dcoTrg.pdc->prgnAPI(NULL);
return(bReturn);
}
//
// Get the bounding rectangle
//
ERECTL erclBound;
vBound(&erclBound);
//
// Adjust bounds for inclusive/inclusive
//
erclBound.right += 1;
erclBound.bottom += 1;
//
// Accumulate bounds. We can do this before knowing if the operation is
// successful because bounds can be loose.
//
if (dcoTrg.fjAccum())
{
dcoTrg.vAccumulate(erclBound);
}
//
// With a fixed DC origin we can change parallelogram and rectangle to
// SCREEN coordinates
//
vOffset(dcoTrg.eptlOrigin());
*perclSrc() += dcoSrc.eptlOrigin();
erclBound += dcoTrg.eptlOrigin();
//
// Compute the clipping complexity and maybe reduce the exclusion rectangle.
//
ECLIPOBJ eco(dcoTrg.prgnEffRao(), erclBound);
//
// 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 pdoTrg(pSurfTrg()->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);
}
//
// Handle target mirroring
//
vMirror(aptfxTrg);
//
// Inc the target surface uniqueness
//
INC_SURF_UNIQ(pSurfTrg());
return((*PPFNGET(pdoTrg, PlgBlt, pSurfTrg()->flags()))(
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(),
aptfxTrg,
perclSrc(),
aptlMask,
jMode));
}
/******************************Public*Routine******************************\
* BOOL BLTRECORD::bRotate(dimo, iMode)
*
* Rotate just the mask.
*
* History:
* 23-Mar-1992 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
BOOL BLTRECORD::bRotate(
SURFMEM& dimo,
ULONG iMode)
{
ERECTL erclTrg;
vBound(&erclTrg);
// Fill in the bitmap info.
DEVBITMAPINFO dbmi;
dbmi.iFormat = BMF_1BPP;
dbmi.cxBitmap = erclTrg.right - erclTrg.left;
dbmi.cyBitmap = erclTrg.bottom - erclTrg.top;
dbmi.hpal = (HPALETTE) 0;
dbmi.fl = pSurfMskOut()->bUMPD() ? UMPD_SURFACE : 0;
dimo.bCreateDIB(&dbmi, (VOID *) NULL);
if (!dimo.bValid())
{
return(FALSE);
}
// Build a shadow parallelogram.
POINTFIX aptfxShadow[4];
aptfxShadow[0].x = aptfxTrg[0].x - FIX_FROM_LONG(erclTrg.left);
aptfxShadow[0].y = aptfxTrg[0].y - FIX_FROM_LONG(erclTrg.top);
aptfxShadow[1].x = aptfxTrg[1].x - FIX_FROM_LONG(erclTrg.left);
aptfxShadow[1].y = aptfxTrg[1].y - FIX_FROM_LONG(erclTrg.top);
aptfxShadow[2].x = aptfxTrg[2].x - FIX_FROM_LONG(erclTrg.left);
aptfxShadow[2].y = aptfxTrg[2].y - FIX_FROM_LONG(erclTrg.top);
aptfxShadow[3].x = aptfxTrg[3].x - FIX_FROM_LONG(erclTrg.left);
aptfxShadow[3].y = aptfxTrg[3].y - FIX_FROM_LONG(erclTrg.top);
// Take care of mirroring.
vMirror(aptfxShadow);
// Call EngPlgBlt to rotate the mask.
EPOINTL ptl(0,0);
if (!EngPlgBlt(
dimo.pSurfobj(),
pSurfMskOut()->pSurfobj(),
(SURFOBJ *) NULL,
(CLIPOBJ *) NULL,
NULL,
NULL,
(POINTL *)&ptl,
aptfxShadow,
perclMask(),
(POINTL *) NULL,
iMode)
)
return(FALSE);
// Release the previous pSurfMask, tell ~BLTRECORD its gone and put the
// new DIB in its place. Remember to adjust the mask origin.
flState &= ~BLTREC_MASK_LOCKED;
pSurfMsk()->vAltUnlockFast();
pSurfMsk((SURFACE *) dimo.ps);
aptlMask[0].x = 0;
aptlMask[0].y = 0;
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL BLTRECORD::bRotate(dcoSrc, dimoShadow, dimoMask, ulAvec, iMode)
*
* Rotate the shadow and mask.
*
* History:
* 24-Mar-1992 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
BOOL
BLTRECORD::bRotate(
DCOBJ& dcoSrc,
SURFMEM& dimoShadow,
SURFMEM& dimoMask,
ULONG ulAvec,
ULONG iMode
)
{
// If there is a mask, rotate it.
if ((ulAvec & AVEC_NEED_MASK) && !bRotate(dimoMask, iMode))
{
return(FALSE);
}
ERECTL erclTrg;
vBound(&erclTrg);
// Fill in the bitmap info.
DEVBITMAPINFO dbmi;
dbmi.cxBitmap = erclTrg.right - erclTrg.left;
dbmi.cyBitmap = erclTrg.bottom - erclTrg.top;
dbmi.hpal = (HPALETTE) 0;
dbmi.iFormat = pSurfSrc()->iFormat();
dbmi.fl = pSurfSrc()->bUMPD() ? UMPD_SURFACE : 0;
dimoShadow.bCreateDIB(&dbmi, (VOID *) NULL);
if (!dimoShadow.bValid())
{
return(FALSE);
}
// Build a shadow parallelogram.
POINTFIX aptfxShadow[4];
aptfxShadow[0].x = aptfxTrg[0].x - FIX_FROM_LONG(erclTrg.left);
aptfxShadow[0].y = aptfxTrg[0].y - FIX_FROM_LONG(erclTrg.top);
aptfxShadow[1].x = aptfxTrg[1].x - FIX_FROM_LONG(erclTrg.left);
aptfxShadow[1].y = aptfxTrg[1].y - FIX_FROM_LONG(erclTrg.top);
aptfxShadow[2].x = aptfxTrg[2].x - FIX_FROM_LONG(erclTrg.left);
aptfxShadow[2].y = aptfxTrg[2].y - FIX_FROM_LONG(erclTrg.top);
aptfxShadow[3].x = aptfxTrg[3].x - FIX_FROM_LONG(erclTrg.left);
aptfxShadow[3].y = aptfxTrg[3].y - FIX_FROM_LONG(erclTrg.top);
// Take care of mirroring.
vMirror(aptfxShadow);
// 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);
// Rotate the bits to the DIB.
EPOINTL ptl(0,0);
if (!EngPlgBlt(
dimoShadow.pSurfobj(),
pSurfSrc()->pSurfobj(),
(SURFOBJ *) NULL,
(CLIPOBJ *) NULL,
NULL,
NULL,
(POINTL *)&ptl,
aptfxShadow,
perclSrc(),
(POINTL *) NULL,
iMode)
)
{
return(FALSE);
}
// Update the source surface and set the source rectangle for
// BitBlt or MaskBlt.
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******************************\
* BOOL BLTRECORD::bRotated()
*
* Checks if the target parallelogram is skewed or rotated.
*
* History:
* 25-Mar-1992 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
BOOL BLTRECORD::bRotated()
{
// Test for rotation or skew.
if (
((aptfxTrg[1].y - aptfxTrg[0].y) != 0) ||
((aptfxTrg[2].x - aptfxTrg[0].x) != 0)
)
{
return(TRUE);
}
// We might have fractional endpoints. If so, we still need to call
// bRotate since StretchBlt at the DDI takes integer coordinates.
if (
(aptfxTrg[0].x & 0x0f) || (aptfxTrg[0].y & 0x0f) ||
(aptfxTrg[1].x & 0x0f) || (aptfxTrg[1].y & 0x0f) ||
(aptfxTrg[2].x & 0x0f) || (aptfxTrg[2].y & 0x0f)
)
{
return(TRUE);
}
// OK, we don't have to call bRotate. Set up the target rectangle and
// return FALSE.
aptlTrg[0].x = LONG_FLOOR_OF_FIX(aptfxTrg[0].x);
aptlTrg[0].y = LONG_FLOOR_OF_FIX(aptfxTrg[0].y);
aptlTrg[1].x = LONG_FLOOR_OF_FIX(aptfxTrg[1].x);
aptlTrg[1].y = LONG_FLOOR_OF_FIX(aptfxTrg[2].y);
return(FALSE);
}
/******************************Public*Routine******************************\
* VOID BLTRECORD::vExtrema()
*
* Complete the parallelogram and find the extrema. Uses ChuckWh's trick.
*
* History:
* 28-Jan-1993 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
VOID BLTRECORD::vExtrema()
{
aptfxTrg[3].x = aptfxTrg[1].x + aptfxTrg[2].x - aptfxTrg[0].x;
aptfxTrg[3].y = aptfxTrg[1].y + aptfxTrg[2].y - aptfxTrg[0].y;
iLeft = (aptfxTrg[1].x > aptfxTrg[0].x) == (aptfxTrg[1].x > aptfxTrg[3].x);
iTop = (aptfxTrg[1].y > aptfxTrg[0].y) == (aptfxTrg[1].y > aptfxTrg[3].y);
}
/******************************Public*Routine******************************\
* VOID BLTRECORD::vBound(percl)
*
* Make a well ordered bounding rectangle from the parallelogram
*
* History:
* 28-Jan-1993 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
VOID BLTRECORD::vBound(ERECTL *percl)
{
percl->left = LONG_CEIL_OF_FIX(aptfxTrg[iLeft].x);
percl->top = LONG_CEIL_OF_FIX(aptfxTrg[iTop].y);
percl->right = LONG_CEIL_OF_FIX(aptfxTrg[iLeft ^ 3].x);
percl->bottom = LONG_CEIL_OF_FIX(aptfxTrg[iTop ^ 3].y);
// Make it well ordered!
percl->vOrder();
}
/******************************Public*Routine******************************\
* VOID BLTRECORD::vMirror(pptfx)
*
* Flip the parallelogram according to the mirroring flags
*
* History:
* 24-Mar-1992 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
VOID BLTRECORD::vMirror(POINTFIX *pptfx)
{
FIX fx;
if (flState & BLTREC_MIRROR_X)
{
fx = pptfx[1].x, pptfx[1].x = pptfx[0].x, pptfx[0].x = fx;
fx = pptfx[1].y, pptfx[1].y = pptfx[0].y, pptfx[0].y = fx;
fx = pptfx[3].x, pptfx[3].x = pptfx[2].x, pptfx[2].x = fx;
fx = pptfx[3].y, pptfx[3].y = pptfx[2].y, pptfx[2].y = fx;
}
if (flState & BLTREC_MIRROR_Y)
{
fx = pptfx[2].x, pptfx[2].x = pptfx[0].x, pptfx[0].x = fx;
fx = pptfx[2].y, pptfx[2].y = pptfx[0].y, pptfx[0].y = fx;
fx = pptfx[3].x, pptfx[3].x = pptfx[1].x, pptfx[1].x = fx;
fx = pptfx[3].y, pptfx[3].y = pptfx[1].y, pptfx[1].y = fx;
}
}
/******************************Public*Routine******************************\
* BOOL BLTRECORD::bCreateRegion(dco, pptfx)
*
* Create a region from the parallelogram and add it to the clipping
* pipeline.
*
* History:
* 24-Mar-1992 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
BOOL BLTRECORD::bCreateRegion(
DCOBJ& dco,
POINTFIX *pptfx
)
{
// First, take care of any mirroring that might have occured.
vMirror(pptfx);
// Create a path
PATHMEMOBJ pmo;
if (!pmo.bValid())
{
return(FALSE);
}
// Create a parallelogram in drawing order.
POINTL aptl[4];
aptl[0].x = pptfx[0].x;
aptl[0].y = pptfx[0].y;
aptl[1].x = pptfx[1].x;
aptl[1].y = pptfx[1].y;
aptl[2].x = pptfx[3].x;
aptl[2].y = pptfx[3].y;
aptl[3].x = pptfx[2].x;
aptl[3].y = pptfx[2].y;
// Construct a path around the parallelogram
if (!pmo.bMoveTo((EXFORMOBJ *) NULL, &aptl[0]))
{
return(FALSE);
}
if (!pmo.bPolyLineTo((EXFORMOBJ *) NULL, &aptl[1], 3))
{
return(FALSE);
}
// Create a region from it.
prmo()->vCreate(pmo, ALTERNATE);
if (!prmo()->bValid())
{
return(FALSE);
}
// Tell ~BLTRECORD it has something to clean up.
flState |= BLTREC_PRO;
// Select the region into the DC's clipping pipeline. This will dirty
// the Rao so it gets merged in when bCompute is called.
dco.pdc->prgnAPI(prmo()->prgnGet());
return(TRUE);
}
#ifdef DBG_PLGBLT
LONG gflPlgBlt = PLGBLT_ENABLE;
VOID vShowRect(
CHAR *psz,
RECTL *prcl)
{
if (gflPlgBlt & PLGBLT_RECTS)
{
DbgPrint("%s [(%ld,%ld) (%ld,%ld)]\n",
psz, prcl->left, prcl->top, prcl->right, prcl->bottom);
}
#endif
/******************************Public*Routine******************************\
* EngPlgBlt
*
* This does parallelogram bltting. This gets called to PlgBlt between
* two engine managed surfaces or if the driver has chosen not to handle
* EngPlgBlt.
*
* The API passes in prclSrc which is the rectangle on the left, and
* also passes in 3 points which define A,B,C of the paralellogram on the
* right. The points are assumed to be in that order A,B,C.
* The lower-left of the src rect goes to the third point, the upper-left of
* the src rect goes to the first point, and the upper-right of the source
* rect goes to the second point.
*
* NOTE! The source rectangle MUST BE WELL ORDERED IN DEVICE SPACE.
*
* A-----B B A----------------B
* | | / \ | |
* | | ---> / \ | |
* | | / \ or | |
* C-----D A \ | |
* \ D | |
* \ / | |
* \ / | |
* \ / | |
* C C----------------D
*
*
* This call returns TRUE for success, FALSE for ERROR.
*
* History:
* 27-Jul-1992 -by- Donald Sidoroff [donalds]
* Wrote.
\**************************************************************************/
BOOL
EngPlgBlt(
SURFOBJ *psoTrg,
SURFOBJ *psoSrc,
SURFOBJ *psoMsk,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
COLORADJUSTMENT *pca,
POINTL *pptlBrushOrg,
POINTFIX *pptfx,
RECTL *prcl,
POINTL *pptl,
ULONG iMode)
{
PSURFACE pSurfTrg = SURFOBJ_TO_SURFACE(psoTrg);
PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE(psoSrc);
PSURFACE pSurfMsk = SURFOBJ_TO_SURFACE(psoMsk);
BOOL bRet = FALSE;
//
// Added HALFTONE support if iMode passed in is HALFTONE.
// This is to ensure n-up printing on PCL printers
// will look decent.
// Note that we are currently not supporting HALFTONE
// if there is mask. [lingyunw]
//
BOOL bHalftone = ((iMode == HALFTONE) && !pSurfMsk);
//
// Prevent bad driver call backs
//
if ((iMode == 0) || (iMode > MAXSTRETCHBLTMODE))
{
WARNING1("EngPlgBlt: Unsupported iMode\n");
return(FALSE);
}
//
// Can't PlgBlt to an RLE
// Can't PlgBlt 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 ))
{
WARNING("EngPlgBlt: Unsupported source/target\n");
return(FALSE);
}
//
// We may need to do a WHITEONBLACK or BLACKONWHITE from a monochrome source.
// Find out and set the bogusity flag.
//
BOOL bBogus = (
(iMode < COLORONCOLOR) &&
(pSurfMsk == (SURFACE *) NULL) &&
((pSurfSrc->iFormat() == BMF_1BPP) ||
(pSurfTrg->iFormat() == BMF_1BPP))
);
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;
POINTFIX aptfxOut[4];
POINTFIX *pptfxOut;
ECLIPOBJ ecoOut;
CLIPOBJ *pcoOut;
ERECTL erclDev;
EPOINTL eptlDev;
XLATEOBJ *pxloOut;
RGNMEMOBJTMP rmoOut;
ERECTL erclTrim(0, 0, pSurfSrc->sizl().cx, pSurfSrc->sizl().cy);
//
// Multimon negative offset case
//
if ((pdoSrc.bValid()) && (pdoSrc.bPrimary(pSurfSrc) && (pdoSrc.bMetaDriver())))
{
erclTrim += *pdoSrc.pptlOrigin();
}
//
// 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. We will also create a target DIB if we need to do
// the evil BLACKONWHITE or WHITEONBLACK modes.
//
if ( !bBogus &&
(pSurfTrg->iType() == STYPE_BITMAP) &&
(pSurfTrg->hsurf() != pSurfSrc->hsurf()) &&
!bHalftone )
{
pSurfOut = pSurfTrg;
pptfxOut = pptfx;
pcoOut = pco;
}
else
{
aptfxOut[0] = pptfx[0];
aptfxOut[1] = pptfx[1];
aptfxOut[2] = pptfx[2];
aptfxOut[3].x = pptfx[1].x + pptfx[2].x - pptfx[0].x;
aptfxOut[3].y = pptfx[1].y + pptfx[2].y - pptfx[0].y;
//
// Compute the extrema
//
int iLeft = (aptfxOut[1].x > aptfxOut[0].x) == (aptfxOut[1].x > aptfxOut[3].x);
int iTop = (aptfxOut[1].y > aptfxOut[0].y) == (aptfxOut[1].y > aptfxOut[3].y);
if (aptfxOut[iLeft].x > aptfxOut[iLeft ^ 3].x)
{
iLeft ^= 3;
}
if (aptfxOut[iTop].y > aptfxOut[iTop ^ 3].y)
{
iTop ^= 3;
}
//
// This will be the area we copy dimoOut to in the target surface.
//
erclDev.left = LONG_FLOOR_OF_FIX(aptfxOut[iLeft].x) - 1;
erclDev.top = LONG_FLOOR_OF_FIX(aptfxOut[iTop].y) - 1;
erclDev.right = LONG_CEIL_OF_FIX(aptfxOut[iLeft ^ 3].x) + 1;
erclDev.bottom = LONG_CEIL_OF_FIX(aptfxOut[iTop ^ 3].y) + 1;
//
// Trim to the target surface.
//
ERECTL erclTrg(0, 0, pSurfTrg->sizl().cx, pSurfTrg->sizl().cy);
//
// Multimon negative offset case
//
if ((pdoTrg.bValid()) && (pdoTrg.bPrimary(pSurfTrg) && (pdoTrg.bMetaDriver())))
{
erclTrg += *pdoTrg.pptlOrigin();
}
erclDev *= erclTrg;
//
// If we have nothing left, we're done.
//
if (erclDev.bEmpty())
{
return(TRUE);
}
//
// If we are only here on possible overlap, test for misses
//
if ( !bBogus &&
(pSurfTrg->iType() == STYPE_BITMAP) &&
(!bHalftone) &&
( (erclDev.left > prcl->right) ||
(erclDev.right < prcl->left) ||
(erclDev.top > prcl->bottom) ||
(erclDev.bottom < prcl->top) ) )
{
pSurfOut = pSurfTrg;
pptfxOut = pptfx;
pcoOut = pco;
}
else
{
// Compute the adjusted parallelogram in the temporary surface.
aptfxOut[0].x -= FIX_FROM_LONG(erclDev.left);
aptfxOut[0].y -= FIX_FROM_LONG(erclDev.top);
aptfxOut[1].x -= FIX_FROM_LONG(erclDev.left);
aptfxOut[1].y -= FIX_FROM_LONG(erclDev.top);
aptfxOut[2].x -= FIX_FROM_LONG(erclDev.left);
aptfxOut[2].y -= FIX_FROM_LONG(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 = pSurfTrg->bUMPD() ? UMPD_SURFACE : 0;
//
// If this is a bogus call, build a monochrome target.
//
if (bBogus)
{
dbmi.iFormat = BMF_1BPP;
}
else if (bHalftone)
{
//
// if HALFTONE, make the target same format as source
// so latter on we can stretch with HALFTONE
//
dbmi.iFormat = pSurfSrc->iFormat();
}
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;
rmoOut.vSet((RECTL *) &erclDev);
ecoOut.vSetup(rmoOut.prgnGet(), erclDev, CLIP_FORCE);
//
// Synchronize with the device driver before touching the device surface.
//
pdoTrg.vSync(psoTrg,NULL,0);
//
// If there is a mask, copy the actual target to the temporary.
//
if (pSurfMsk != (SURFACE *) NULL)
{
(*PPFNGET(pdoTrg,CopyBits,pSurfTrg->flags()))(
dimoOut.pSurfobj(),
pSurfTrg->pSurfobj(),
(CLIPOBJ *) NULL,
&xloIdent,
&erclDev,
&eptlDev);
}
//
// If we are doing BLACKONWHITE or WHITEONBLACK we need to
// initialize the DIB appropriately.
//
if (bBogus)
{
if (!EngEraseSurface(dimoOut.pSurfobj(),
&erclDev,
iMode == BLACKONWHITE ? ~0L : 0L))
return(FALSE);
}
//
// Point to the new target.
//
pSurfOut = dimoOut.ps;
pptfxOut = &aptfxOut[0];
pcoOut = &ecoOut;
if ((bBogus && (pSurfSrc->iFormat() == BMF_1BPP)) || bHalftone)
{
pxloOut = pxlo;
pxlo = NULL;
}
else
{
pxloOut = &xloIdent;
}
}
}
//
// Synchronize with the device driver before touching the device surface.
//
pdoSrc.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.
//
erclTrim *= *prcl;
// WINBUG #263939 3-5-2000 bhouse Watchdog timeout problems
// We suspend the watchdog here ... This code is just brain
// dead and for various scenarios can cause us to hang within GDI
// giving false positive WatchDog timeouts. Maybe one day we will
// re-write this brain dead code.... I'm not holding my breadth.
if(pdoTrg.bValid() && pdoTrg.bDisplayPDEV())
GreSuspendWatch(pdoTrg.ppdev, WD_DEVLOCK);
if(pdoSrc.bValid() && pdoSrc.bDisplayPDEV())
GreSuspendWatch(pdoSrc.ppdev, WD_DEVLOCK);
//
// If we have nothing left, we're done.
//
if (erclTrim.bEmpty())
{
bRet = TRUE;
}
else
{
//
// 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 (! ((pSurfSrc->iType() != STYPE_BITMAP) ||
(pSurfSrc->iFormat() == BMF_4RLE) ||
(pSurfSrc->iFormat() == BMF_8RLE) )
)
{
pSurfIn = pSurfSrc;
pxloIn = pxlo;
prclIn = prcl;
}
else
{
DEVBITMAPINFO dbmi;
dbmi.cxBitmap = erclTrim.right - erclTrim.left + 1;
dbmi.cyBitmap = erclTrim.bottom - erclTrim.top + 1;
dbmi.hpal = (HPALETTE) 0;
dbmi.iFormat = pSurfOut->iFormat();
dbmi.fl = pSurfSrc->bUMPD() ? UMPD_SURFACE : 0;
dimoIn.bCreateDIB(&dbmi, (VOID *) NULL);
if (!dimoIn.bValid())
{
bRet = FALSE;
goto exit;
}
// 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 = prcl->left - erclTrim.left;
rclIn.top = prcl->top - erclTrim.top;
rclIn.right = prcl->right - erclTrim.left;
rclIn.bottom = prcl->bottom - erclTrim.top;
pSurfIn = dimoIn.ps;
pxloIn = NULL;
prclIn = &rclIn;
// Adjust the trimmed source origin and extent
erclTrim.right -= erclTrim.left;
erclTrim.bottom -= erclTrim.top;
erclTrim.left = 0;
erclTrim.top = 0;
}
// Synchronize with the device driver before touching the device surface.
{
PDEVOBJ po(pSurfOut->hdev());
po.vSync(pSurfOut->pSurfobj(),NULL,0);
}
//
// Initialize the DDA
//
PLGDDA *pdda = (PLGDDA *)PALLOCMEM(sizeof(PLGDDA),'addG');
if (pdda)
{
if (!bInitPlgDDA(pdda, (RECTL *) &erclTrim, prclIn, pptfxOut))
{
bRet = TRUE;
}
else
{
PFN_PLGREAD pfnRead = apfnRead[pSurfIn->iFormat()];
PFN_PLGWRITE pfnWrite;
PLGRUN *prun;
LONG cjSpace = lSizeDDA(pdda) * (erclTrim.right - erclTrim.left + 2);
if (bBogus)
{
pdda->bOverwrite = TRUE;
pfnWrite = apfnBogus[iMode];
}
else
{
pdda->bOverwrite = FALSE;
pfnWrite = apfnWrite[pSurfOut->iFormat()];
}
if (prun = (PLGRUN *) PALLOCMEM(cjSpace,'addG'))
{
BYTE *pjSrc = (BYTE *) pSurfIn->pvScan0() + pSurfIn->lDelta() * erclTrim.top;
BYTE *pjMask;
POINTL ptlMask;
if (pSurfMsk == (SURFACE *) NULL)
{
pjMask = (BYTE *) NULL;
}
else
{
ptlMask.x = erclTrim.left - prclIn->left + pptl->x;
ptlMask.y = erclTrim.top - prclIn->top + pptl->y;
pjMask = (BYTE *) pSurfMsk->pvScan0() + pSurfMsk->lDelta() * ptlMask.y;
}
// See if we can accelerate anything.
if ((pxloIn != NULL) && (pxloIn->flXlate & XO_TRIVIAL))
{
pxloIn = NULL;
}
//
// force DDA into clipping to destination surface!, this can be
// removed once dda doesn't go negatice!
//
if ((pcoOut == NULL) || (pcoOut->iDComplexity == DC_TRIVIAL))
{
ERECTL erclDest(0,0,pSurfOut->sizl().cx,pSurfOut->sizl().cy);
rmoOut.vSet((RECTL *) &erclDest);
ecoOut.vSetup(rmoOut.prgnGet(), erclDest, CLIP_FORCE);
pcoOut = &ecoOut;
}
//
// make sure it doesn't have a empty rectangle
//
if ((pcoOut->rclBounds.left < pcoOut->rclBounds.right) &&
(pcoOut->rclBounds.top < pcoOut->rclBounds.bottom))
{
for (LONG yRow = erclTrim.top; yRow < erclTrim.bottom; yRow++)
{
pdda->dsX = pdda->ds;
(*pfnWrite)(prun,
(*pfnRead)(pdda,
prun,
pjSrc,
pjMask,
pxloIn,
erclTrim.left,
erclTrim.right,
ptlMask.x),
pSurfOut,
pcoOut);
vAdvYDDA(pdda);
pjSrc += pSurfIn->lDelta();
if (pjMask != (BYTE *) NULL)
{
pjMask += pSurfMsk->lDelta();
}
}
VFREEMEM(prun);
//
// See if we have drawn on the actual output surface.
//
if (pSurfOut == pSurfTrg)
{
bRet = TRUE;
}
else
{
BOOL bTmpRet = FALSE;
//
// If the source rectangle was reduced, then we have to
// create a mask for the target, so only the actual pels
// effected by the PlgBlt will be altered on the target.
SURFMEM dimoMask;
SURFACE *pSurfMask;
if (((prcl->right - prcl->left) == erclTrim.right) &&
((prcl->bottom - prcl->top) == erclTrim.bottom) )
{
pSurfMask = (SURFACE *) NULL;
bTmpRet = TRUE;
}
else
{
DEVBITMAPINFO dbmi;
dbmi.cxBitmap = erclDev.right + 1;
dbmi.cyBitmap = erclDev.bottom + 1;
dbmi.hpal = (HPALETTE) 0;
dbmi.iFormat = BMF_1BPP;
dbmi.fl = pSurfTrg->bUMPD() ? UMPD_SURFACE : 0;
dimoMask.bCreateDIB(&dbmi, (VOID *) NULL);
if (dimoMask.bValid())
{
SURFMEM dimoTrim;
dbmi.cxBitmap = erclTrim.right;
dbmi.cyBitmap = erclTrim.bottom;
dbmi.hpal = (HPALETTE) 0;
dbmi.iFormat = BMF_1BPP;
dbmi.fl = pSurfTrg->bUMPD() ? UMPD_SURFACE : 0;
dimoTrim.bCreateDIB(&dbmi, (VOID *) NULL);
RGNMEMOBJTMP rmoMask;
if (dimoTrim.bValid() &&
rmoMask.bValid() )
{
rmoMask.vSet((RECTL *) &erclDev);
ECLIPOBJ ecoMask(rmoMask.prgnGet(), erclDev, CLIP_FORCE);
//
// Initialize the two bitmaps and call EngPlgBlt to create a pel
// perfect mask for the reduced call.
//
if (EngEraseSurface(dimoMask.pSurfobj(),
&erclDev,
0L) &&
EngEraseSurface(dimoTrim.pSurfobj(),
&erclTrim,
(ULONG)~0L) &&
EngPlgBlt(dimoMask.pSurfobj(),
dimoTrim.pSurfobj(),
(SURFOBJ *) NULL,
&ecoMask,
NULL,
(COLORADJUSTMENT *) NULL,
(POINTL *) NULL,
pptfxOut,
prclIn,
(POINTL *) NULL,
COLORONCOLOR) )
{
pSurfMask = dimoMask.ps;
bTmpRet = TRUE;
}
}
}
}
// If we had to draw the target on a shadow, we need to copy it to the
// actual surface. Since we don't clip to the shadow buffer, we need
// to merge the parallelogram into the clipobj and clip against this
// and call BitBlt.
PATHMEMOBJ pmo;
if (bTmpRet &&
pmo.bValid())
{
//
// Create a parallelogram in drawing order.
//
POINTL aptl[4];
aptl[0].x = pptfx[0].x;
aptl[0].y = pptfx[0].y;
aptl[1].x = pptfx[1].x;
aptl[1].y = pptfx[1].y;
aptl[2].x = pptfx[1].x + pptfx[2].x - pptfx[0].x;
aptl[2].y = pptfx[1].y + pptfx[2].y - pptfx[0].y;;
aptl[3].x = pptfx[2].x;
aptl[3].y = pptfx[2].y;
//
// Construct a path around the parallelogram
//
if ( (pmo.bMoveTo((EXFORMOBJ *) NULL, &aptl[0])) &&
(pmo.bPolyLineTo((EXFORMOBJ *) NULL, &aptl[1], 3)) )
{
//
// Create a regions from it.
//
RGNMEMOBJTMP rmo(pmo, ALTERNATE);
RGNMEMOBJTMP rmoTrg;
if ( (rmo.bValid()) &&
(rmoTrg.bValid()) )
{
//
// Merge the region we just constructed with the clip region.
//
if ( ((pco == (CLIPOBJ *) NULL) &&
(rmoTrg.bCopy(rmo))) ||
((pco != (CLIPOBJ *) NULL) &&
(rmoTrg.bMerge(rmo,
*((ECLIPOBJ *)pco),
gafjRgnOp[RGN_AND]))) )
{
ERECTL ercl;
rmoTrg.vGet_rcl(&ercl);
// If we have a clipobj,
// make sure that the bounds are
// tight to the destination rectangle
// and there is intersection.
if ((pco == NULL) ||
bIntersect(&ercl, &pco->rclBounds, &ercl))
{
ECLIPOBJ eco(rmoTrg.prgnGet(), ercl, CLIP_FORCE);
if (!eco.erclExclude().bEmpty())
{
//
// 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;
//
// Inc the target surface uniqueness
//
INC_SURF_UNIQ(pSurfTrg);
if (!bHalftone)
{
(*(pSurfTrg->pfnBitBlt()))(
pSurfTrg->pSurfobj(),
dimoOut.pSurfobj(),
pSurfMask->pSurfobj(),
&eco,
pxloOut,
&erclDev,
&eptlDev,
&eptlDev,
(BRUSHOBJ *) NULL,
(POINTL *) NULL,
pSurfMask == (SURFACE *) NULL ? 0x0000CCCC : 0x0000AACC);
}
else
{
POINTL ptlBrushOrg;
ERECTL erclSrc(0, 0,
erclDev.right-erclDev.left,
erclDev.bottom-erclDev.top);
ptlBrushOrg.x=0; ptlBrushOrg.y=0;
(*PPFNGET(pdoTrg, StretchBlt, pSurfTrg->flags()))(
pSurfTrg->pSurfobj(),
dimoOut.pSurfobj(),
pSurfMask->pSurfobj(),
&eco,
pxloOut,
NULL,
&ptlBrushOrg,
&erclDev,
&erclSrc,
&eptlDev,
HALFTONE);
}
}
}
bRet = TRUE;
}
}
}
}
}
}
else
{
VFREEMEM(prun);
}
}
}
VFREEMEM(pdda);
}
}
exit:
if(pdoTrg.bValid() && pdoTrg.bDisplayPDEV())
GreResumeWatch(pdoTrg.ppdev, WD_DEVLOCK);
if(pdoSrc.bValid() && pdoSrc.bDisplayPDEV())
GreResumeWatch(pdoSrc.ppdev, WD_DEVLOCK);
return bRet;
}