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.
 
 
 
 
 
 

1769 lines
50 KiB

/*++
Copyright (c) 1990-1999 Microsoft Corporation
Module Name:
stretch.c
Abstract:
This module contains all the StretchBlt/BitBlt codes which handle halftoned
sources
[Environment:]
GDI Device Driver - Plotter.
[Notes:]
Revision History:
--*/
#include "raster.h"
#define DW_ALIGN(x) (((DWORD)(x) + 3) & ~(DWORD)3)
#define ROP4_NEED_MASK(Rop4) (((Rop4 >> 8) & 0xFF) != (Rop4 & 0xFF))
#define ROP3_NEED_PAT(Rop3) (((Rop3 >> 4) & 0x0F) != (Rop3 & 0x0F))
#define ROP3_NEED_SRC(Rop3) (((Rop3 >> 2) & 0x33) != (Rop3 & 0x33))
#define ROP3_NEED_DST(Rop3) (((Rop3 >> 1) & 0x55) != (Rop3 & 0x55))
#define ROP4_FG_ROP(Rop4) (Rop4 & 0xFF)
#define ROP4_BG_ROP(Rop4) ((Rop4 >> 8) & 0xFF)
#if DBG
BOOL DbgWhiteRect = FALSE;
BOOL DbgBitBlt = FALSE;
BOOL DbgCopyBits = FALSE;
#define _DBGP(i,x) if (i) { (DbgPrint x); }
#else
#define _DBGP(i,x)
#endif //DBG
#define DELETE_SURFOBJ(pso, phBmp) \
{ \
if (pso) { EngUnlockSurface(pso); pso=NULL; } \
if (*(phBmp)) { EngDeleteSurface((HSURF)*(phBmp)); *(phBmp)=NULL; } \
}
#ifdef WINNT_40 //NT 4.0
#if DBG
BOOL DbgDitherColor = FALSE;
#endif
extern HSEMAPHORE hSemBrushColor;
extern LPDWORD pBrushSolidColor;
#endif //WINNT_40
ROP4 InvertROPs(
ROP4 Rop4
)
/*++
Routine Description:
This function remaps ROPs intended for RGB mode into CMY mode for 8bpp
monochrome printing.
--*/
{
// Rops are remapped for CMY vs RGB rendering by reversing the order of
// the bits in the ROP and inverting the result.
//
if ((Rop4 & 0xff) == ((Rop4 >> 8) & 0xff))
{
ROP4 NewRop = 0;
if (Rop4 & 0x01) NewRop |= 0x8080;
if (Rop4 & 0x02) NewRop |= 0x4040;
if (Rop4 & 0x04) NewRop |= 0x2020;
if (Rop4 & 0x08) NewRop |= 0x1010;
if (Rop4 & 0x10) NewRop |= 0x0808;
if (Rop4 & 0x20) NewRop |= 0x0404;
if (Rop4 & 0x40) NewRop |= 0x0202;
if (Rop4 & 0x80) NewRop |= 0x0101;
NewRop ^= 0xFFFF;
#ifdef DBGROP
if (NewRop != Rop4)
{
DbgPrint ("ROP remapped: %4x -> %4x\n",Rop4,NewRop);
}
#endif
Rop4 = NewRop;
}
/*
if (Rop4 == 0xB8B8) // required for bug 22915
Rop4 = 0xE2E2;
else if (Rop4 == 0x0000) // BLACKNESS
Rop4 = 0xFFFF;
else if (Rop4 == 0xFFFF) // WHITENESS
Rop4 = 0x0000;
else if (Rop4 == 0x8888) // SRCAND, required for bug 36192
Rop4 = 0xEEEE;
else if (Rop4 == 0xEEEE) // SRCPAINT, remap so it differs from SCRAND
Rop4 = 0x8888;
else if (Rop4 == 0xC0C0) // MERGECOPY
Rop4 = 0xFCFC;
else if (Rop4 == 0xFBFB) // PATPAINT
Rop4 = 0x2020;
*/
return Rop4;
}
BOOL DrawWhiteRect(
PDEV *pPDev,
RECTL *pDest,
CLIPOBJ *pco
)
/*++
Routine Description:
This function sends a white rectangle directly to the device if fonts
have been sent to the printer for this band. This is used to clear
the region where an image will be drawn.
Arguments:
pPDev - pointer to PDEV structure
pDest - pointer to destination RECTL
pco - pointer to CLIPOBJ
--*/
{
RECTL rcClip;
BYTE bMask;
BOOL bSendRectFill;
LONG i;
PBYTE pbScanBuf;
BOOL bMore;
DWORD dwMaxRects;
if (DRIVER_DEVICEMANAGED (pPDev)) // Device Managed Surface
return 0;
//
// only send the clearing rectangle if the device supports rectangles,
// text has been downloaded, it is not a complex clip region.
//
if (!(pPDev->fMode & PF_RECT_FILL) ||
!(pPDev->fMode & PF_DOWNLOADED_TEXT) ||
(pco && pco->iDComplexity == DC_COMPLEX && pco->iFComplexity != FC_RECT4) ||
!(COMMANDPTR(pPDev->pDriverInfo,CMD_RECTWHITEFILL)) ||
pPDev->pdmPrivate->dwFlags & DXF_TEXTASGRAPHICS ||
pPDev->fMode2 & PF2_MIRRORING_ENABLED)
{
return 0;
}
//
// if complex clip but FC_RECT4 then there won't be more than 4 rectangles
//
if (pco && pco->iFComplexity == FC_RECT4)
{
if (CLIPOBJ_cEnumStart(pco,TRUE,CT_RECTANGLES,CD_ANY,4) == -1)
return 0;
}
bMore = FALSE;
dwMaxRects = 0;
do
{
//
// clip to printable region or band
//
rcClip.left = MAX(0, pDest->left);
rcClip.top = MAX(0, pDest->top);
rcClip.right = MIN(pPDev->szBand.cx,pDest->right);
rcClip.bottom = MIN(pPDev->szBand.cy,pDest->bottom);
//
// if clip rectangle or complex clip FC_RECT4 we need to apply
// clip rectangle to input rectangle.
//
if (pco)
{
if (pco->iDComplexity == DC_RECT)
{
if (rcClip.left < pco->rclBounds.left)
rcClip.left = pco->rclBounds.left;
if (rcClip.top < pco->rclBounds.top)
rcClip.top = pco->rclBounds.top;
if (rcClip.right > pco->rclBounds.right)
rcClip.right = pco->rclBounds.right;
if (rcClip.bottom > pco->rclBounds.bottom)
rcClip.bottom = pco->rclBounds.bottom;
}
else if (pco->iFComplexity == FC_RECT4)
{
ENUMRECTS eRect;
bMore = CLIPOBJ_bEnum(pco,(ULONG)sizeof(ENUMRECTS),(ULONG *)&eRect);
if (eRect.c != 1)
continue;
if (rcClip.left < eRect.arcl[0].left)
rcClip.left = eRect.arcl[0].left;
if (rcClip.top < eRect.arcl[0].top)
rcClip.top = eRect.arcl[0].top;
if (rcClip.right > eRect.arcl[0].right)
rcClip.right = eRect.arcl[0].right;
if (rcClip.bottom > eRect.arcl[0].bottom)
rcClip.bottom = eRect.arcl[0].bottom;
}
}
//
// At this point we will check whether anything has been directly downloaded to the
// printer (ie text) to see if we need to even bother drawing the erase rectangle.
//
bMask = BGetMask(pPDev, &rcClip);
bSendRectFill = FALSE;
for (i = rcClip.top; i < rcClip.bottom ; i++)
{
if (pPDev->pbScanBuf[i] & bMask)
{
bSendRectFill = TRUE;
break;
}
}
//
// check if we end up with an empty rect.
//
if (bSendRectFill && rcClip.right > rcClip.left && rcClip.bottom > rcClip.top)
{
DRAWPATRECT PatRect;
PatRect.wStyle = 1; // white rectangle
PatRect.wPattern = 0; // pattern not used
PatRect.ptPosition.x = rcClip.left;
PatRect.ptPosition.y = rcClip.top;
PatRect.ptSize.x = rcClip.right - rcClip.left;
PatRect.ptSize.y = rcClip.bottom - rcClip.top;
DrawPatternRect(pPDev,&PatRect);
dwMaxRects++;
_DBGP(DbgWhiteRect,("DrawWhiteRect (%d,%d) (%d,%d)\n",
rcClip.left+pPDev->rcClipRgn.left,
rcClip.top+pPDev->rcClipRgn.top,
rcClip.right+pPDev->rcClipRgn.left,
rcClip.bottom+pPDev->rcClipRgn.top));
}
} while (bMore && dwMaxRects < 4);
return (BOOL)dwMaxRects;
}
LONG
GetBmpDelta(
DWORD SurfaceFormat,
DWORD cx
)
/*++
Routine Description:
This function calculate total bytes needed for a single scan line in the
bitmap according to its format and alignment requirement.
Arguments:
SurfaceFormat - Surface format of the bitmap, this is must one of the
standard format which defined as BMF_xxx
cx - Total Pels per scan line in the bitmap.
Return Value:
The return value is the total bytes in one scan line if it is greater than
zero
Author:
19-Jan-1994 Wed 16:19:39 created -by- Daniel Chou (danielc)
Revision History:
--*/
{
DWORD Delta = cx;
switch (SurfaceFormat) {
case BMF_32BPP:
Delta <<= 5;
break;
case BMF_24BPP:
Delta *= 24;
break;
case BMF_16BPP:
Delta <<= 4;
break;
case BMF_8BPP:
Delta <<= 3;
break;
case BMF_4BPP:
Delta <<= 2;
break;
case BMF_1BPP:
break;
default:
_DBGP(1, ("\nGetBmpDelta: Invalid BMF_xxx format = %ld", SurfaceFormat));
break;
}
Delta = (DWORD)DW_ALIGN((Delta + 7) >> 3);
return((LONG)Delta);
}
SURFOBJ *
CreateBitmapSURFOBJ(
PDEV *pPDev,
HBITMAP *phBmp,
LONG cxSize,
LONG cySize,
DWORD Format
)
/*++
Routine Description:
This function create a bitmap and lock the bitmap to return a SURFOBJ
Arguments:
pPDev - Pointer to our PDEV
phBmp - Pointer the HBITMAP location to be returned for the bitmap
cxSize - CX size of bitmap to be created
cySize - CY size of bitmap to be created
Format - one of BMF_xxx bitmap format to be created
Return Value:
SURFOBJ if sucessful, NULL if failed
Author:
19-Jan-1994 Wed 16:31:50 created -by- Daniel Chou (danielc)
Revision History:
--*/
{
SURFOBJ *pso = NULL;
SIZEL szlBmp;
szlBmp.cx = cxSize;
szlBmp.cy = cySize;
if (*phBmp = EngCreateBitmap(szlBmp,
GetBmpDelta(Format, cxSize),
Format,
BMF_TOPDOWN | BMF_NOZEROINIT,
NULL)) {
if (EngAssociateSurface((HSURF)*phBmp, (HDEV)pPDev->devobj.hEngine, 0)) {
if (pso = EngLockSurface((HSURF)*phBmp)) {
//
// Sucessful lock it down, return it
//
return(pso);
} else {
_DBGP(1, ("\nCreateBmpSurfObj: EngLockSruface(hBmp) failed!"));
}
} else {
_DBGP(1, ("\nCreateBmpSurfObj: EngAssociateSurface() failed!"));
}
} else {
_DBGP(1, ("\nCreateBMPSurfObj: FAILED to create Bitmap Format=%ld, %ld x %ld",
Format, cxSize, cySize));
}
DELETE_SURFOBJ(pso, phBmp);
return(NULL);
}
BOOL
IsHTCompatibleSurfObj(
PAL_DATA *pPD,
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
XLATEOBJ *pxlo
)
/*++
Routine Description:
This function determine if the surface obj is compatble with plotter
halftone output format.
Arguments:
pPD - Pointer to the PAL_DATA
psoDst - Our desitnation format
psoSrc - Source format to be checked againest
pxlo - engine XLATEOBJ for source -> postscript translation
Return Value:
BOOLEAN true if the psoSrc is compatible with halftone output format, if
return value is true, the pDrvHTInfo->pHTXB is a valid trnaslation from
indices to 3 planes
Revision History:
--*/
{
ULONG *pSrcPal = NULL;
UINT SrcBmpFormat;
UINT DstBmpFormat;
UINT cPal;
BOOL Ok = TRUE;
if ((SrcBmpFormat = (UINT)psoSrc->iBitmapFormat) >
(DstBmpFormat = (UINT)psoDst->iBitmapFormat))
{
return(FALSE);
}
if ((!pxlo) || (pxlo->flXlate & XO_TRIVIAL))
{
#ifdef WINNT_40
//
// The palette in NT4 always indexed, so if the the xlate is trivial
// but the Source type is not indexed then we have problem
//
if ((pxlo) &&
((pxlo->iSrcType & (PAL_INDEXED |
PAL_BITFIELDS |
PAL_BGR |
PAL_RGB)) != PAL_INDEXED))
{
return FALSE;
}
#endif
return((BOOL)(SrcBmpFormat == DstBmpFormat));
}
switch (DstBmpFormat)
{
case BMF_1BPP:
case BMF_4BPP:
case BMF_8BPP:
//
// If we cannot get the source palette memory, we will be in the
// loop forever.
//
if ((pPD->wPalGdi > 0) &&
(pxlo->flXlate & XO_TABLE) &&
(cPal = (UINT)pxlo->cEntries))
{
if ((pSrcPal = (ULONG *)MemAlloc(cPal * sizeof(ULONG))))
{
ULONG *pUL;
XLATEOBJ_cGetPalette(pxlo, XO_SRCPALETTE, cPal, pSrcPal);
//
// Assume palette is OK unless we can't find a match
//
pUL = pSrcPal;
while (cPal--)
{
ULONG *pMyPal = pPD->ulPalCol;
ULONG Pal = *pUL++;
UINT j = (UINT)pPD->wPalGdi;
do
{
if (*pMyPal++ == Pal)
break;
} while (--j);
//
// Didn't find matching color so set to FALSE
//
if (j == 0)
{
Ok = FALSE;
break;
}
}
MemFree(pSrcPal);
}
}
else
Ok = FALSE;
break;
case BMF_24BPP:
//
// Since device surface is 24-bpp, we will assume all source OK
//
break;
default:
_DBGP(1, ("\nUnidrv:IsHTCompatibleSurfObj: Invalid Dest format = %ld",
DstBmpFormat));
Ok = FALSE;
break;
}
return(Ok);
}
BOOL
CreateMaskSurface(
SURFOBJ *psoSrc,
SURFOBJ *psoMsk,
ULONG iTransColor
)
/*++
Routine Description:
This function creates a mask surface based on the transparent color of the source surface.
Arguments:
psoMsk - Mask surface to be created
psoSrc - Source format to be checked againest
iTransColor - Transparent color to compare against
Revision History:
--*/
{
BYTE *pSrc;
BYTE *pMsk;
INT iRow,iCol;
union {
BYTE bColor[4];
USHORT sColor[2];
ULONG lColor;
} u;
//
// Check for NULL pointers.
// We dont create mask for 1bpp surface, because the
// mask surface will either be identical to the original
// surface or it will be its inverse. The same
// affect can be achieved by manipulating the pxlo
//
if ( NULL == psoSrc ||
NULL == psoMsk ||
NULL == psoSrc->pvScan0 ||
NULL == psoMsk->pvScan0 ||
psoSrc->iBitmapFormat == BMF_1BPP )
{
ASSERT((FALSE, "Invalid Parameter"));
return FALSE;
}
u.lColor = iTransColor;
for (iRow = 0;iRow < psoSrc->sizlBitmap.cy;iRow++)
{
BYTE Mask = 0xFF;
pSrc = (BYTE *)(psoSrc->pvScan0) + (psoSrc->lDelta * iRow);
pMsk = (BYTE *)(psoMsk->pvScan0) + (psoMsk->lDelta * iRow);
memset(pMsk,0xff,(psoMsk->sizlBitmap.cx+7) >> 3);
if (psoSrc->iBitmapFormat == BMF_8BPP)
{
for (iCol = 0;iCol < psoSrc->sizlBitmap.cx;iCol++)
{
if (*pSrc == u.bColor[0])
{
pMsk[iCol >> 3] &= ~(0x80 >> (iCol & 7));
}
pSrc += 1;
}
}
else if (psoSrc->iBitmapFormat == BMF_16BPP)
{
for (iCol = 0;iCol < psoSrc->sizlBitmap.cx;iCol++)
{
if (*(USHORT *)pSrc == u.sColor[0])
{
pMsk[iCol >> 3] &= ~(0x80 >> (iCol & 7));
}
pSrc += 2;
}
}
else if (psoSrc->iBitmapFormat == BMF_24BPP)
{
for (iCol = 0;iCol < psoSrc->sizlBitmap.cx;iCol++)
{
if (pSrc[0] == u.bColor[0] && pSrc[1] == u.bColor[1] && pSrc[2] == u.bColor[2])
{
pMsk[iCol >> 3] &= ~(0x80 >> (iCol & 7));
}
pSrc += 3;
}
}
else if (psoSrc->iBitmapFormat == BMF_32BPP)
{
for (iCol = 0;iCol < psoSrc->sizlBitmap.cx;iCol++)
{
if (*(ULONG *)pSrc == u.lColor)
{
pMsk[iCol >> 3] &= ~(0x80 >> (iCol & 7));
}
pSrc += 4;
}
}
else if (psoSrc->iBitmapFormat == BMF_4BPP)
{
for (iCol = 0;iCol < psoSrc->sizlBitmap.cx;iCol++)
{
if (((*pSrc >> 4) & 0xf) == u.bColor[0])
{
pMsk[iCol >> 3] &= ~(0x80 >> (iCol & 7));
}
iCol++;
if ((*pSrc & 0xf) == u.bColor[0])
{
pMsk[iCol >> 3] &= ~(0x80 >> (iCol & 7));
}
pSrc += 1;
}
}
}
return TRUE;
}
BOOL
RMBitBlt(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
SURFOBJ *psoMask,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
PRECTL prclDst,
PPOINTL pptlSrc,
PPOINTL pptlMask,
BRUSHOBJ *pbo,
PPOINTL pptlBrush,
ROP4 Rop4
)
/*++
Routine Description:
This function will try to bitblt the source to the destination
Arguments:
per winddi spec.
Return Value:
BOOLEAN
Author:
17-Feb-1993 Wed 12:39:03 created -by- Daniel Chou (danielc)
NOTE: Currently only if SRCCOPY/SRCMASKCOPY will halftone
Revision History:
01-Feb-1994 Tue 21:51:40 updated -by- Daniel Chou (danielc)
Re-written, it now will handle any ROP4 which have soruces involved
either foreground or background. It will half-tone the source first
if it is not compatible with unidrv destiantion format, then it passed
the compatible source to the EngBitBlt()
17-May-1995 Wed 23:08:15 updated -by- Daniel Chou (danielc)
Updated so it will do the brush origin correctly, also speed up by
calling EngStretchBlt directly when SRCCOPY (0xCCCC) is passed.
--*/
{
PDEV *pPDev;
SURFOBJ *psoNewSrc;
HBITMAP hBmpNewSrc;
RECTL rclNewSrc;
RECTL rclOldSrc;
POINTL BrushOrg;
DWORD RopBG;
DWORD RopFG;
BOOL Ok;
pPDev = (PDEV *)psoDst->dhpdev;
// if this isn't a graphics band we will return true
// without doing anything
if (!(pPDev->fMode & PF_ENUM_GRXTXT))
return TRUE;
#ifndef DISABLE_NEWRULES
if (pPDev->pbRulesArray && pPDev->dwRulesCount < (MAX_NUM_RULES-4) &&
Rop4 == 0xF0F0 && pbo && pxlo == NULL &&
(pco == NULL || pco->iDComplexity != DC_COMPLEX || pco->iFComplexity == FC_RECT4) &&
((psoDst->iBitmapFormat != BMF_24BPP &&
pbo->iSolidColor == (ULONG)((PAL_DATA*)(pPDev->pPalData))->iBlackIndex) ||
(psoDst->iBitmapFormat == BMF_24BPP &&
pbo->iSolidColor == 0)))
{
//
// if complexity is rect4 then we could add up to 4 rectangles
//
BOOL bMore = FALSE;
if (pco && pco->iFComplexity == FC_RECT4)
{
if (CLIPOBJ_cEnumStart(pco,TRUE,CT_RECTANGLES,CD_ANY,4) == -1)
goto SkipRules;
}
do
{
PRECTL pRect= &pPDev->pbRulesArray[pPDev->dwRulesCount];
*pRect = *prclDst;
//
// if clip rectangle then clip the rule
//
if (pco)
{
if (pco->iDComplexity == DC_RECT)
{
if (pRect->left < pco->rclBounds.left)
pRect->left = pco->rclBounds.left;
if (pRect->top < pco->rclBounds.top)
pRect->top = pco->rclBounds.top;
if (pRect->right > pco->rclBounds.right)
pRect->right = pco->rclBounds.right;
if (pRect->bottom > pco->rclBounds.bottom)
pRect->bottom = pco->rclBounds.bottom;
}
else if (pco->iFComplexity == FC_RECT4)
{
ENUMRECTS eRect;
bMore = CLIPOBJ_bEnum(pco,(ULONG)sizeof(ENUMRECTS),(ULONG *)&eRect);
if (eRect.c != 1)
{
continue;
}
if (pRect->left < eRect.arcl[0].left)
pRect->left = eRect.arcl[0].left;
if (pRect->top < eRect.arcl[0].top)
pRect->top = eRect.arcl[0].top;
if (pRect->right > eRect.arcl[0].right)
pRect->right = eRect.arcl[0].right;
if (pRect->bottom > eRect.arcl[0].bottom)
pRect->bottom = eRect.arcl[0].bottom;
}
}
if (pRect->left < pRect->right && pRect->top < pRect->bottom)
{
DWORD i;
for (i = 0;i < pPDev->dwRulesCount;i++)
{
PRECTL pRect2= &pPDev->pbRulesArray[i];
//
// test if this rectangle can be combined with another
//
if (pRect->top == pRect2->top &&
pRect->bottom == pRect2->bottom &&
pRect->left <= pRect2->right &&
pRect->right >= pRect2->left)
{
if (pRect2->left > pRect->left)
pRect2->left = pRect->left;
if (pRect2->right < pRect->right)
pRect2->right = pRect->right;
pPDev->dwRulesCount--;
break;
}
else if (pRect->left == pRect2->left &&
pRect->right == pRect2->right &&
pRect->top <= pRect2->bottom &&
pRect->bottom >= pRect2->top)
{
if (pRect2->top > pRect->top)
pRect2->top = pRect->top;
if (pRect2->bottom < pRect->bottom)
pRect2->bottom = pRect->bottom;
pPDev->dwRulesCount--;
break;
}
}
pPDev->dwRulesCount++;
}
} while (bMore && pPDev->dwRulesCount < MAX_NUM_RULES);
return TRUE;
}
SkipRules:
#endif
//
// Send white rectangle to printer to clear any previously
// downloaded text or graphics for PATCOPY and SRCCOPY rops
//
if (Rop4 == 0xF0F0 || Rop4 == 0xCCCC)
DrawWhiteRect(pPDev,prclDst,pco);
//
// We will looked if we need the source, if we do then we check if the
// source is compatible with halftone format, if not then we halftone the
// source and passed the new halftoned source along to the EngBitBlt()
//
psoNewSrc = NULL;
hBmpNewSrc = NULL;
RopBG = ROP4_BG_ROP(Rop4);
RopFG = ROP4_FG_ROP(Rop4);
if (((ROP3_NEED_PAT(RopBG)) ||
(ROP3_NEED_PAT(RopBG))) &&
(pptlBrush)) {
BrushOrg = *pptlBrush;
_DBGP(DbgBitBlt, ("\nRMBitBlt: BrushOrg for pattern PASSED IN as (%ld, %ld)",
BrushOrg.x, BrushOrg.y));
} else {
BrushOrg.x =
BrushOrg.y = 0;
_DBGP(DbgBitBlt, ("\nRMBitBlt: BrushOrg SET by UNIDRV to (0,0), non-pattern"));
}
if (((ROP3_NEED_SRC(RopBG)) ||
(ROP3_NEED_SRC(RopFG))) &&
(!IsHTCompatibleSurfObj((PAL_DATA *)pPDev->pPalData,
psoDst, psoSrc, pxlo)))
{
rclNewSrc.left =
rclNewSrc.top = 0;
rclNewSrc.right = prclDst->right - prclDst->left;
rclNewSrc.bottom = prclDst->bottom - prclDst->top;
rclOldSrc.left = pptlSrc->x;
rclOldSrc.top = pptlSrc->y;
rclOldSrc.right = rclOldSrc.left + rclNewSrc.right;
rclOldSrc.bottom = rclOldSrc.top + rclNewSrc.bottom;
_DBGP(DbgBitBlt, ("\nRMBitBlt: Blt Source=(%ld, %ld)-(%ld, %ld)=%ld x %ld [psoSrc=%ld x %ld]",
rclOldSrc.left, rclOldSrc.top,
rclOldSrc.right, rclOldSrc.bottom,
rclOldSrc.right - rclOldSrc.left,
rclOldSrc.bottom - rclOldSrc.top,
psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy));
_DBGP(DbgBitBlt, ("\nUnidrv!RMBitBlt: DestRect=(%ld, %ld)-(%ld, %ld), BrushOrg = (%ld, %ld)",
prclDst->left, prclDst->top,
prclDst->right, prclDst->bottom,
BrushOrg.x, BrushOrg.y));
//
// If we have a SRCCOPY then call EngStretchBlt directly
//
if (Rop4 == 0xCCCC) {
_DBGP(DbgBitBlt, ("\nUnidrv!RMBitBlt(SRCCOPY): No Clone, call EngStretchBlt() ONLY\n"));
//
// At here, the brush origin guaranteed at (0,0)
//
CheckBitmapSurface(psoDst,prclDst);
return(EngStretchBlt(psoDst,
psoSrc,
psoMask,
pco,
pxlo,
NULL,
&BrushOrg,
prclDst,
&rclOldSrc,
pptlMask,
HALFTONE));
}
//
// Modify the brush origin, because when we blt to the clipped bitmap
// the origin is at bitmap's 0,0 minus the original location
//
BrushOrg.x -= prclDst->left;
BrushOrg.y -= prclDst->top;
_DBGP(DbgBitBlt, ("\nUnidrv!RMBitBlt: BrushOrg Change to (%ld, %ld)",
BrushOrg.x, BrushOrg.y));
_DBGP(DbgBitBlt, ("\nUnidrv!RMBitBlt: Clone SOURCE: from (%ld, %ld)-(%ld, %ld) to (%ld, %ld)-(%ld, %ld)=%ld x %ld\n",
rclOldSrc.left, rclOldSrc.top,
rclOldSrc.right, rclOldSrc.bottom,
rclNewSrc.left, rclNewSrc.top,
rclNewSrc.right, rclNewSrc.bottom,
rclOldSrc.right - rclOldSrc.left,
rclOldSrc.bottom - rclOldSrc.top));
if ((psoNewSrc = CreateBitmapSURFOBJ(pPDev,
&hBmpNewSrc,
rclNewSrc.right,
rclNewSrc.bottom,
psoDst->iBitmapFormat)) &&
(EngStretchBlt(psoNewSrc, // psoDst
psoSrc, // psoSrc
NULL, // psoMask
NULL, // pco
pxlo, // pxlo
NULL, // pca
&BrushOrg, // pptlBrushOrg
&rclNewSrc, // prclDst
&rclOldSrc, // prclSrc
NULL, // pptlmask
HALFTONE))) {
//
// If we cloning sucessful then the pxlo will be NULL because it
// is identities for the halftoned surface to our engine managed
// bitmap
//
psoSrc = psoNewSrc;
pptlSrc = (PPOINTL)&(rclNewSrc.left);
pxlo = NULL;
BrushOrg.x =
BrushOrg.y = 0;
}
else {
_DBGP(1, ("\nUnidrv:RMBitblt: Clone Source to halftone FAILED"));
}
}
//
// Check if we need to clear the bitmap surface. If it hasn't been cleared
// but we are only going to draw a white region on it we can skip the white
// PATCOPY bitblt.
//
if (!(pPDev->fMode & PF_SURFACE_USED) &&
Rop4 == 0xF0F0 && pbo &&
#ifndef DISABLE_NEWRULES
(pPDev->pbRulesArray == NULL || pPDev->dwRulesCount == 0) &&
#endif
((psoDst->iBitmapFormat != BMF_24BPP &&
pbo->iSolidColor == (ULONG)((PAL_DATA*)(pPDev->pPalData))->iWhiteIndex) ||
(psoDst->iBitmapFormat == BMF_24BPP &&
pbo->iSolidColor == 0x00FFFFFF)))
{
_DBGP (DbgBitBlt, ("\nUnidrv:RMBitblt: Skipping white bitblt\n"));
Ok = TRUE;
}
else
{
// test whether to remap rops for 8bpp mono mode
if (pPDev->fMode2 & PF2_INVERTED_ROP_MODE)
{
Rop4 = InvertROPs(Rop4);
}
// set dirty surface flag
CheckBitmapSurface(psoDst,prclDst);
Ok = EngBitBlt(psoDst,
psoSrc,
psoMask,
pco,
pxlo,
prclDst,
pptlSrc,
pptlMask,
pbo,
&BrushOrg,
Rop4);
}
DELETE_SURFOBJ(psoNewSrc, &hBmpNewSrc);
return(Ok);
}
BOOL
RMStretchBlt(
SURFOBJ *psoDest,
SURFOBJ *psoSrc,
SURFOBJ *psoMask,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
COLORADJUSTMENT *pca,
POINTL *pptlBrushOrg,
RECTL *prclDest,
RECTL *prclSrc,
POINTL *pptlMask,
ULONG BltMode
)
/*++
Routine Description:
This function do driver's stretch bitblt, it actually call HalftoneBlt()
to do the actual work
Arguments:
per above
Return Value:
BOOLEAN
Author:
24-Mar-1992 Tue 14:06:18 created -by- Daniel Chou (danielc)
Revision History:
27-Jan-1993 Wed 07:29:00 updated -by- Daniel Chou (danielc)
clean up, so gdi will do the work, we will always doing HALFTONE mode
--*/
{
PDEV *pPDev; /* Our main PDEV */
UNREFERENCED_PARAMETER(BltMode);
pPDev = (PDEV *)psoDest->dhpdev;
// if this isn't a graphics band we will return true
// without doing anything
if (!(pPDev->fMode & PF_ENUM_GRXTXT))
return TRUE;
// test whether we need to clear any device text that
// may be under the graphics
//
DrawWhiteRect(pPDev,prclDest,pco);
// set dirty surface flag since we're drawing in it
CheckBitmapSurface(psoDest,prclDest);
return(EngStretchBlt(psoDest,
psoSrc,
psoMask,
pco,
pxlo,
pca,
pptlBrushOrg,
prclDest,
prclSrc,
pptlMask,
HALFTONE));
}
BOOL
RMStretchBltROP(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
SURFOBJ *psoMask,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
COLORADJUSTMENT *pca,
POINTL *pptlBrushOrg,
RECTL *prclDst,
RECTL *prclSrc,
POINTL *pptlMask,
ULONG iMode,
BRUSHOBJ *pbo,
DWORD rop4
)
/*++
Routine Description:
This function do driver's stretch bitblt, it actually call HalftoneBlt()
to do the actual work
Arguments:
per above
Return Value:
BOOLEAN
--*/
{
#ifndef WINNT_40
PDEV *pPDev; /* Our main PDEV */
pPDev = (PDEV *)psoDst->dhpdev;
// if this isn't a graphics band we will return true
// without doing anything
if (!(pPDev->fMode & PF_ENUM_GRXTXT))
return TRUE;
// test whether we need to clear any device text that
// may be under the graphics, rop must be SRCCOPY
//
if (rop4 == 0xCCCC)
DrawWhiteRect(pPDev,prclDst,pco);
// test whether to remap rops for 8bpp mono mode
//
if (pPDev->fMode2 & PF2_INVERTED_ROP_MODE)
{
rop4 = InvertROPs(rop4);
}
//
// GDI doesn't support Halftoning for StretchBltROP unless the rop is SRCCOPY
// Therefore to fix bug 36192, we will create a new surface to stretchblt with
// halftone and then will bitblt the result to the actual destination with the rop4
//
#ifndef DISABLE_SBR_GDIWORKAROUND
if (rop4 != 0xCCCC && psoMask == NULL &&
ROP3_NEED_SRC(ROP4_FG_ROP(rop4)) &&
psoDst->iBitmapFormat <= BMF_4BPP && psoSrc->iBitmapFormat >= BMF_4BPP)
{
SURFOBJ *psoNewSrc;
HBITMAP hBmpNewSrc;
RECTL rclNewSrc;
POINTL BrushOrg;
BOOL Ok;
DWORD xHTOffset=0;
DWORD yHTOffset=0;
// DbgPrint("StretchBltROP: rop4=%x,iFormat=%d->%d, Dest=%d,%d\n",rop4,psoSrc->iBitmapFormat,psoDst->iBitmapFormat,prclDst->left,prclDst->top);
//
// determine offset into temporary surface to get halftone patterns to align
//
if (pPDev->dwHTPatSize > 0)
{
xHTOffset = prclDst->left % pPDev->dwHTPatSize;
yHTOffset = prclDst->top % pPDev->dwHTPatSize;
}
rclNewSrc.left =
rclNewSrc.top = 0;
rclNewSrc.right = (prclDst->right - prclDst->left) + xHTOffset;
rclNewSrc.bottom = (prclDst->bottom - prclDst->top) + yHTOffset;
//
// Modify the brush origin, because when we blt to the clipped bitmap
// the origin is at bitmap's 0,0 minus the original location
//
BrushOrg.x = -prclDst->left;
BrushOrg.y = -prclDst->top;
if ((psoNewSrc = CreateBitmapSURFOBJ(pPDev,
&hBmpNewSrc,
rclNewSrc.right,
rclNewSrc.bottom,
psoDst->iBitmapFormat)))
{
rclNewSrc.left += xHTOffset;
rclNewSrc.top += yHTOffset;
if ((EngStretchBlt(psoNewSrc, // psoDst
psoSrc, // psoSrc
NULL, // psoMask
NULL, // pco
pxlo, // pxlo
NULL, // pca
pptlBrushOrg, // pptlBrushOrg
&rclNewSrc, // prclDst
prclSrc, // prclSrc
NULL, // pptlmask
HALFTONE)))
{
//
// If we cloning sucessful then the pxlo will be NULL because it
// is identities for the halftoned surface to our engine managed
// bitmap
//
PPOINTL pptlSrc = (PPOINTL)&(rclNewSrc.left);
pxlo = NULL;
BrushOrg.x =
BrushOrg.y = 0;
// set dirty surface flag
CheckBitmapSurface(psoDst,prclDst);
Ok = EngBitBlt(psoDst,
psoNewSrc,
psoMask,
pco,
pxlo,
prclDst,
pptlSrc,
pptlMask,
pbo,
&BrushOrg,
rop4);
DELETE_SURFOBJ(psoNewSrc, &hBmpNewSrc);
if (!Ok)
_DBGP(1,("RMStretchBltROP: Clone bitblt failed\n"));
return Ok;
}
else {
_DBGP(1,("RMStretchBltROP: Clone Source to halftone FAILED\n"));
}
}
DELETE_SURFOBJ(psoNewSrc, &hBmpNewSrc);
}
#endif
// set dirty surface flag since we're drawing in it
CheckBitmapSurface(psoDst,prclDst);
return(EngStretchBltROP(psoDst,
psoSrc,
psoMask,
pco,
pxlo,
pca,
pptlBrushOrg,
prclDst,
prclSrc,
pptlMask,
HALFTONE,
pbo,
rop4));
#else
return TRUE;
#endif
}
BOOL
RMPaint(
SURFOBJ *pso,
CLIPOBJ *pco,
BRUSHOBJ *pbo,
POINTL *pptlBrushOrg,
MIX mix)
/*++
Routine Description:
Implementation of DDI entry point DrvPaint.
Please refer to DDK documentation for more details.
Arguments:
pso - Defines the surface on which to draw
pco - Limits the area to be modified on the Dstination
pbo - Points to a BRUSHOBJ which defined the pattern and colors to fill with
pptlBrushOrg - Specifies the origin of the halftone brush
mix - Defines the foreground and background raster operations to use for
the brush
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
#define MIXCOPYPEN (R2_COPYPEN | (R2_COPYPEN << 8))
#define MIXWHITE (R2_WHITE | (R2_WHITE << 8))
PDEV *pPDev = (PDEV *)pso->dhpdev;
// if this isn't a graphics band we will return true
// without doing anything
if (!(pPDev->fMode & PF_ENUM_GRXTXT))
return TRUE;
//
// Send white rectangle to printer to clear any previously
// downloaded text or graphics for COPYPEN or WHITE rop2's
//
if ((mix == MIXCOPYPEN || mix == MIXWHITE) && pco && pco->iDComplexity == DC_RECT)
{
RECTL rclDst;
rclDst.left = pco->rclBounds.left;
rclDst.top = pco->rclBounds.top;
rclDst.right = pco->rclBounds.right;
rclDst.bottom = pco->rclBounds.bottom;
DrawWhiteRect(pPDev,&rclDst,pco);
}
//
// Check whether to erase surface
//
CheckBitmapSurface(pso,&pco->rclBounds);
//
// Call GDI to do the paint function
//
return EngPaint(pso, pco, pbo, pptlBrushOrg, mix);
}
BOOL
RMCopyBits(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclDst,
POINTL *pptlSrc
)
/*++
Routine Description:
Convert between two bitmap formats
Arguments:
Per Engine spec.
Return Value:
BOOLEAN
Author:
24-Jan-1996 Wed 16:08:57 created -by- Daniel Chou (danielc)
Revision History:
--*/
{
PDEV *pPDev; /* Our main PDEV */
pPDev = (PDEV *)psoDst->dhpdev;
// if this isn't a graphics band we will return true
// without doing anything
if (!(pPDev->fMode & PF_ENUM_GRXTXT))
return TRUE;
// Handle the case which has to be passed to Engine.
//
if (IsHTCompatibleSurfObj((PAL_DATA *)pPDev->pPalData,
psoDst, psoSrc, pxlo) )
{
DrawWhiteRect(pPDev,prclDst,pco);
CheckBitmapSurface(psoDst,prclDst);
return(EngCopyBits(psoDst, psoSrc, pco, pxlo, prclDst, pptlSrc));
}
else {
POINTL ptlBrushOrg;
RECTL rclSrc;
RECTL rclDst;
rclDst = *prclDst;
rclSrc.left = pptlSrc->x;
rclSrc.top = pptlSrc->y;
rclSrc.right = rclSrc.left + (rclDst.right - rclDst.left);
rclSrc.bottom = rclSrc.top + (rclDst.bottom - rclDst.top);
//
// Validate that we only BLT the available source size
//
if ((rclSrc.right > psoSrc->sizlBitmap.cx) ||
(rclSrc.bottom > psoSrc->sizlBitmap.cy)) {
WARNING(("RMCopyBits: Engine passed SOURCE != DEST size, CLIP IT"));
rclSrc.right = psoSrc->sizlBitmap.cx;
rclSrc.bottom = psoSrc->sizlBitmap.cy;
rclDst.right = (LONG)(rclSrc.right - rclSrc.left + rclDst.left);
rclDst.bottom = (LONG)(rclSrc.bottom - rclSrc.top + rclDst.top);
}
ptlBrushOrg.x =
ptlBrushOrg.y = 0;
_DBGP(DbgCopyBits, ("\nUnidrv!RMCopyBits: Format Src=%ld, Dest=%ld, Halftone it\n",
psoSrc->iBitmapFormat, psoDst->iBitmapFormat));
_DBGP(DbgCopyBits, ("\nUnidrv!RMCopyBits: Source Size: (%ld, %ld)-(%ld, %ld) = %ld x %ld\n",
rclSrc.left, rclSrc.top, rclSrc.right, rclSrc.bottom,
rclSrc.right - rclSrc.left, rclSrc.bottom - rclSrc.top));
_DBGP(DbgCopyBits, ("\nUnidrv!RMCopyBits: Dest Size: (%ld, %ld)-(%ld, %ld) = %ld x %ld\n",
rclDst.left, rclDst.top, rclDst.right, rclDst.bottom,
rclDst.right - rclDst.left, rclDst.bottom - rclDst.top));
return(DrvStretchBlt(psoDst,
psoSrc,
NULL,
pco,
pxlo,
NULL,
&ptlBrushOrg,
&rclDst,
&rclSrc,
NULL,
HALFTONE));
}
}
ULONG
RMDitherColor(
DHPDEV dhpdev,
ULONG iMode,
ULONG rgbColor,
ULONG *pulDither
)
/*++
Routine Description:
This is the hooked brush creation function, it ask CreateHalftoneBrush()
to do the actual work.
Arguments:
dhpdev - DHPDEV passed, it is our pDEV
iMode - Not used
rgbColor - Solid rgb color to be used
pulDither - buffer to put the halftone brush.
Return Value:
BOOLEAN
Author:
24-Mar-1992 Tue 14:53:36 created -by- Daniel Chou (danielc)
Revision History:
27-Jan-1993 Wed 07:29:00 updated -by- Daniel Chou (danielc)
clean up, so gdi will do the work.
--*/
{
#ifndef WINNT_40 //NT 5.0
UNREFERENCED_PARAMETER(dhpdev);
UNREFERENCED_PARAMETER(iMode);
UNREFERENCED_PARAMETER(rgbColor);
UNREFERENCED_PARAMETER(pulDither);
return(DCR_HALFTONE);
#else // NT 4.0
DWORD RetVal;
UNREFERENCED_PARAMETER(dhpdev);
UNREFERENCED_PARAMETER(iMode);
UNREFERENCED_PARAMETER(pulDither);
EngAcquireSemaphore(hSemBrushColor);
if (pBrushSolidColor) {
*pBrushSolidColor = (DWORD)(rgbColor & 0x00FFFFFF);
_DBGP(DbgDitherColor, ("\nDrvDitherColor(BRUSH=%08lx)\t\t",
*pBrushSolidColor));
pBrushSolidColor = NULL;
RetVal = DCR_SOLID;
} else {
_DBGP(DbgDitherColor, ("\nDrvDitherColor(HALFTONE=%08lx)\t\t", rgbColor));
RetVal = DCR_HALFTONE;
}
EngReleaseSemaphore(hSemBrushColor);
return(RetVal);
#endif //!WINNT_40
}
BOOL
RMPlgBlt(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
SURFOBJ *psoMask,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
COLORADJUSTMENT *pca,
POINTL *pptlBrushOrg,
POINTFIX *pptfx,
RECTL *prclSrc,
POINTL *pptlMask,
ULONG BltMode
)
/*++
Routine Description:
This function does driver's plgblt.
Arguments:
per above
Return Value:
BOOLEAN
--*/
{
PDEV *pPDev; /* Our main PDEV */
pPDev = (PDEV *)psoDst->dhpdev;
// if this isn't a graphics band we will return true
// without doing anything
if (!(pPDev->fMode & PF_ENUM_GRXTXT))
return TRUE;
//
// test for no rotation, as this is another case the GDI EngPlgBlt call fails
// bug #336711, 3/8/01
//
if (pptfx[0].x == pptfx[2].x && pptfx[0].y == pptfx[1].y && pptfx[0].y < pptfx[2].y)
{
RECTL rclDst;
rclDst.top = pptfx[0].y >> 4;
rclDst.left = pptfx[0].x >> 4;
rclDst.bottom = pptfx[2].y >> 4;
rclDst.right = pptfx[1].x >> 4;
// blt surface into destination
//
CheckBitmapSurface(psoDst,&rclDst);
return EngStretchBlt(psoDst, // psoDst
psoSrc, // psoSrc
psoMask, // psoMask
pco, // pco
pxlo, // pxlo
pca, // pca
pptlBrushOrg, // pptlBrushOrg
&rclDst, // prclDst
prclSrc, // prclSrc
pptlMask, // pptlmask
HALFTONE);
}
// test for 90/270 rotation as GDI's EngPlgBlt sometimes fails if it has to do
// both rotation and scaling. In those case this function will rotate the
// data to an intermediate surface before scaling to the destination surface.
//
if (psoMask == NULL && pptfx[0].x == pptfx[1].x && pptfx[0].y == pptfx[2].y &&
(pPDev->pdmPrivate->iLayout == ONE_UP || psoSrc->iBitmapFormat == BMF_1BPP))
{
SURFOBJ *psoNewSrc = NULL;
HBITMAP hBmpNewSrc = NULL;
RECTL rclNewSrc;
BOOL iRet;
RECTL rclDst;
POINTFIX pFix[3];
rclNewSrc.left =
rclNewSrc.top = 0;
rclNewSrc.bottom = (prclSrc->right - prclSrc->left);
rclNewSrc.right = (prclSrc->bottom - prclSrc->top);
// rotate 90 degrees
//
if (pptfx[2].x < pptfx[0].x)
{
pFix[0].y = pFix[2].y = 0;
pFix[0].x = pFix[1].x = (rclNewSrc.right << 4);
pFix[2].x = 0;
pFix[1].y = (rclNewSrc.bottom << 4);
rclDst.top = pptfx[2].y >> 4;
rclDst.left = pptfx[2].x >> 4;
rclDst.bottom = pptfx[1].y >> 4;
rclDst.right = pptfx[1].x >> 4;
}
// rotate 270 degrees
//
else
{
pFix[0].y = pFix[2].y = (rclNewSrc.bottom << 4);
pFix[0].x = pFix[1].x = 0;
pFix[2].x = (rclNewSrc.right << 4);
pFix[1].y = 0;
rclDst.top = pptfx[1].y >> 4;
rclDst.left = pptfx[1].x >> 4;
rclDst.bottom = pptfx[2].y >> 4;
rclDst.right = pptfx[2].x >> 4;
}
// Only enable EngPlgBlt workaround when scaling up. EngPlgBlt appears to work
// ok when scaling down and it is more efficient in that mode. This also fixes
// the rounding error associated with scaling down (bug #356514).
//
if ((rclNewSrc.right < abs(rclDst.right - rclDst.left) &&
rclNewSrc.bottom < abs(rclDst.bottom - rclDst.top)) ||
psoSrc->iBitmapFormat == BMF_1BPP)
{
/*
#if DBG
DbgPrint("PlgBlt:Src=L%d,T%d,R%d,B%d;Dst=L%d,T%d,R%d,B%d\n",
prclSrc->left,prclSrc->top,prclSrc->right,prclSrc->bottom,
rclDst.left,rclDst.top,rclDst.right,rclDst.bottom);
#endif
*/
// Create an intermediate surface and rotate the source data into
// the surface with no scaling.
//
if ((psoNewSrc = CreateBitmapSURFOBJ(pPDev,
&hBmpNewSrc,
rclNewSrc.right,
rclNewSrc.bottom,
psoSrc->iBitmapFormat)))
{
if ((iRet = EngPlgBlt(psoNewSrc,
psoSrc,
psoMask,
NULL,
NULL,
pca,
pptlBrushOrg,
pFix,
prclSrc,
pptlMask,
BltMode)))
{
// blt new surface into destination
//
if (psoSrc->iBitmapFormat != BMF_1BPP)
{
BltMode = HALFTONE;
}
CheckBitmapSurface(psoDst,&rclDst);
iRet = EngStretchBlt(psoDst, // psoDst
psoNewSrc, // psoSrc
NULL, // psoMask
pco, // pco
pxlo, // pxlo
pca, // pca
pptlBrushOrg, // pptlBrushOrg
&rclDst, // prclDst
&rclNewSrc, // prclSrc
NULL, // pptlmask
BltMode);
}
DELETE_SURFOBJ(psoNewSrc, &hBmpNewSrc);
return iRet;
}
}
}
// set dirty surface flag since we're drawing in it
CheckBitmapSurface(psoDst,NULL);
return(EngPlgBlt(psoDst,
psoSrc,
psoMask,
pco,
pxlo,
pca,
pptlBrushOrg,
pptfx,
prclSrc,
pptlMask,
HALFTONE));
}