|
|
/*++
Copyright (c) 1996-1999 Microsoft Corporation
Module Name:
escape.c
Abstract:
Implementation of escape related DDI entry points: DrvEscape
Environment:
Windows NT Unidrv driver
Revision History:
10/14/96 -amandan- Initial framework.
03/31/97 -zhanw- Added OEM customization support
--*/
#include "unidrv.h"
// define DPRECT if you want to enable DRAWPATTERNRECT escape feature
#define DPRECT
typedef struct _POINTS { short x; short y; } POINTs;
typedef struct _SHORTDRAWPATRECT { // use 16-bit POINT structure
POINTs ptPosition; POINTs ptSize; WORD wStyle; WORD wPattern; } SHORTDRAWPATRECT, *PSHORTDRAWPATRECT;
ULONG DrvEscape( SURFOBJ *pso, ULONG iEsc, ULONG cjIn, PVOID *pvIn, ULONG cjOut, PVOID *pvOut )
/*++
Routine Description:
Implementation of DDI entry point DrvEscape. Please refer to DDK documentation for more details.
Arguments:
pso - Describes the surface the call is directed to iEsc - Specifies a query cjIn - Specifies the size in bytes of the buffer pointed to by pvIn pvIn - Points to input data buffer cjOut - Specifies the size in bytes of the buffer pointed to by pvOut pvOut - Points to the output buffer
Return Value:
Depends on the query specified by iEsc parameter
--*/
{
#define pbIn ((BYTE *)pvIn)
#define pdwIn ((DWORD *)pvIn)
#define pdwOut ((DWORD *)pvOut)
PDEV *pPDev; ULONG ulRes = 0;
VERBOSE(("Entering DrvEscape: iEsc = %d...\n", iEsc)); ASSERT(pso);
pPDev = (PDEV *) pso->dhpdev;
ASSERT_VALID_PDEV(pPDev);
//
// use driver managed surface
//
if (pPDev->pso) pso = pPDev->pso;
//
// Handle OEM hooks
//
HANDLE_OEMHOOKS(pPDev, EP_OEMEscape, PFN_OEMEscape, ULONG, (pso, iEsc, cjIn, pvIn, cjOut, pvOut));
HANDLE_VECTORHOOKS(pPDev, EP_OEMEscape, VMEscape, ULONG, (pso, iEsc, cjIn, pvIn, cjOut, pvOut));
switch( iEsc ) { case QUERYESCSUPPORT:
//
// Check if the specified escape code is supported
//
if (pvIn != NULL || cjIn >= sizeof(DWORD)) { switch( *pdwIn ) {
case QUERYESCSUPPORT: case PASSTHROUGH: //
// Always support these escapes
//
ulRes = 1; break;
case SETCOPYCOUNT: ulRes = pPDev->dwMaxCopies > 1; break;
#ifndef WINNT_40 // NT5
case DRAWPATTERNRECT: if ((pPDev->fMode & PF_RECT_FILL) && (pPDev->dwMinGrayFill < pPDev->dwMaxGrayFill) && (pPDev->pdmPrivate->iLayout == ONE_UP) && (!(pPDev->pdm->dmFields & DM_TTOPTION) || pPDev->pdm->dmTTOption != DMTT_BITMAP) && !(pPDev->fMode2 & PF2_MIRRORING_ENABLED) && !(pPDev->pdmPrivate->dwFlags & DXF_TEXTASGRAPHICS)) // else, only black fill
{ if (pPDev->fMode & PF_RECTWHITE_FILL) ulRes = 2; else ulRes = 1; } break; #endif // !WINNT_40
} } break;
case PASSTHROUGH: //
// QFE fix: NT4 TTY driver compatibility.
// There is an application that sends FF by itself.
// We don't want to send Form Feed if application calls DrvEscape.
//
if (pPDev->bTTY) { pPDev->fMode2 |= PF2_PASSTHROUGH_CALLED_FOR_TTY; }
if( pvIn == NULL || cjIn < sizeof(WORD) ) { SetLastError( ERROR_INVALID_PARAMETER ); ERR(("DrvEscape(PASSTHROUGH): Bad input parameters\n")); } else {
//
// Win 3.1 actually uses the first 2 bytes as a count of the
// number of bytes following!!!! So, the following union
// allows us to copy the data to an aligned field that
// we use. And thus we ignore cjIn!
//
union { WORD wCount; BYTE bCount[ 2 ]; } u;
u.bCount[ 0 ] = pbIn[ 0 ]; u.bCount[ 1 ] = pbIn[ 1 ];
if( u.wCount && cjIn >= (ULONG)(u.wCount + sizeof(WORD)) ) {
ulRes = WriteSpoolBuf( pPDev, pbIn + 2, u.wCount ); } else { SetLastError( ERROR_INVALID_DATA ); ERR(("DrvEscape: Bad data in PASSTRHOUGH.\n")); } } break;
case SETCOPYCOUNT:
if( pdwIn && *pdwIn > 0 ) { pPDev->sCopies = (SHORT)*pdwIn;
//
// Check whether the copy count is in printer range
//
if( pPDev->sCopies > (SHORT)pPDev->dwMaxCopies ) pPDev->sCopies = (SHORT)pPDev->dwMaxCopies;
if( pdwOut ) *pdwOut = pPDev->sCopies;
ulRes = 1; }
break;
case DRAWPATTERNRECT: { #ifndef WINNT_40
typedef struct _DRAWPATRECTP { DRAWPATRECT DrawPatRect; XFORMOBJ *pXFormObj; } DRAWPATRECTP, *PDRAWPATRECTP; if (pvIn == NULL || (cjIn != sizeof(DRAWPATRECT) && cjIn != sizeof(DRAWPATRECTP))) #else
if( pvIn == NULL || cjIn != sizeof(DRAWPATRECT)) #endif
{ if (pvIn && cjIn == sizeof(SHORTDRAWPATRECT)) // check for Win3.1 DRAWPATRECT size
{ DRAWPATRECT dpr; PSHORTDRAWPATRECT psdpr = (PSHORTDRAWPATRECT)pvIn;
if (pPDev->fMode & PF_ENUM_GRXTXT) { //
// Some apps (Access 2.0, AmiPro 3.1, etc.) do use the 16-bit
// POINT version of DRAWPATRECT structure. Have to be compatible
// with these apps.
//
dpr.ptPosition.x = (LONG)psdpr->ptPosition.x; dpr.ptPosition.y = (LONG)psdpr->ptPosition.y; dpr.ptSize.x = (LONG)psdpr->ptSize.x; dpr.ptSize.y = (LONG)psdpr->ptSize.y; dpr.wStyle = psdpr->wStyle; dpr.wPattern = psdpr->wPattern;
ulRes = DrawPatternRect(pPDev, &dpr); } } else { SetLastError( ERROR_INVALID_PARAMETER ); ERR(("DrvEscape(DRAWPATTERNRECT): Bad input parameters.\n")); } } else if (pPDev->fMode & PF_ENUM_GRXTXT) { DRAWPATRECT dpr = *(PDRAWPATRECT)pvIn; #ifndef WINNT_40 // NT 5.0
if (pPDev->pdmPrivate->iLayout != ONE_UP && cjIn == sizeof(DRAWPATRECTP)) { XFORMOBJ *pXFormObj = ((PDRAWPATRECTP)pvIn)->pXFormObj; POINTL PTOut[2],PTIn[2]; PTIn[0].x = dpr.ptPosition.x + pPDev->rcClipRgn.left; PTIn[0].y = dpr.ptPosition.y + pPDev->rcClipRgn.top; PTIn[1].x = PTIn[0].x + dpr.ptSize.x; PTIn[1].y = PTIn[0].y + dpr.ptSize.y; if (!XFORMOBJ_bApplyXform(pXFormObj, XF_LTOL, 2, PTIn, PTOut)) { ERR (("DrvEscape(DRAWPATTERNRECT): XFORMOBJ_bApplyXform failed.\n")); break; } dpr.ptPosition.x = PTOut[0].x; dpr.ptSize.x = PTOut[1].x - PTOut[0].x; if (dpr.ptSize.x < 0) { dpr.ptPosition.x += dpr.ptSize.x; dpr.ptSize.x = -dpr.ptSize.x; } else if (dpr.ptSize.x == 0) dpr.ptSize.x = 1;
dpr.ptPosition.y = PTOut[0].y; dpr.ptSize.y = PTOut[1].y - PTOut[0].y; if (dpr.ptSize.y < 0) { dpr.ptPosition.y += dpr.ptSize.y; dpr.ptSize.y = -dpr.ptSize.y; } else if (dpr.ptSize.y == 0) dpr.ptSize.y = 1; } #endif // !WINNT_40
// Test whether to force minimum size = 2 pixels
//
if (pPDev->fMode & PF_SINGLEDOT_FILTER) { if (dpr.ptSize.y < 2) dpr.ptSize.y = 2; if (dpr.ptSize.x < 2) dpr.ptSize.x = 2; } ulRes = DrawPatternRect(pPDev, &dpr); } else ulRes = 1; // no need for GDI to take any action
break; // case DRAWPATTERNRECT
} default: SetLastError( ERROR_INVALID_FUNCTION ); break;
}
return ulRes; }
ULONG DrawPatternRect( PDEV *pPDev, PDRAWPATRECT pPatRect) /*++
Routine Description: Implementation of DRAWPATTERNECT escape. Note that it is PCL-specific.
Arguments: pPDev - the driver's PDEV pPatRect - the DRAWPATRECT structure from the app
Return Value: 1 if successful. Otherwise, 0. --*/ { WORD wPattern, wStyle; RECTL rcClip; COMMAND *pCmd; ULONG ulRes = 0;
if (!(pPDev->fMode & PF_RECT_FILL)) return 0;
wStyle = pPatRect->wStyle; if (!((wStyle+1) & 3)) // same as (wStyle < 0 || wStyle > 2)
return 0; // we support only solid fill
// Reset the brush, before downloading rule unless we are going to use
// a white rectangle command
if (wStyle != 1) GSResetBrush(pPDev);
//
// clip to printable region
//
rcClip.left = MAX(0, pPatRect->ptPosition.x); rcClip.top = MAX(0, pPatRect->ptPosition.y); rcClip.right = MIN(pPDev->szBand.cx, pPatRect->ptPosition.x + pPatRect->ptSize.x); rcClip.bottom = MIN(pPDev->szBand.cy, pPatRect->ptPosition.y + pPatRect->ptSize.y); //
// check if we end up with an empty rect. If not, put down the rule.
//
if (rcClip.right > rcClip.left && rcClip.bottom > rcClip.top) { DWORD dwXSize,dwYSize; //
// Move to the starting position. rcClip is in device units to
// which we must add the offset of the band origin
//
XMoveTo(pPDev, rcClip.left+pPDev->rcClipRgn.left, MV_GRAPHICS); YMoveTo(pPDev, rcClip.top+pPDev->rcClipRgn.top, MV_GRAPHICS);
//
// The RectFill commands expect master units.
//
dwXSize = pPDev->dwRectXSize; pPDev->dwRectXSize = (rcClip.right - rcClip.left) * pPDev->ptGrxScale.x; dwYSize = pPDev->dwRectYSize; pPDev->dwRectYSize = (rcClip.bottom - rcClip.top) * pPDev->ptGrxScale.y;
//
// check whether the rectangle size is different and update if necessary
//
if (dwXSize != pPDev->dwRectXSize || (!(COMMANDPTR(pPDev->pDriverInfo,CMD_RECTBLACKFILL)) && !(COMMANDPTR(pPDev->pDriverInfo,CMD_RECTGRAYFILL)))) { WriteChannel(pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_SETRECTWIDTH)); } if (dwYSize != pPDev->dwRectYSize || (!(COMMANDPTR(pPDev->pDriverInfo,CMD_RECTBLACKFILL)) && !(COMMANDPTR(pPDev->pDriverInfo,CMD_RECTGRAYFILL)))) { WriteChannel(pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_SETRECTHEIGHT)); } //
// range-check the pattern based upon the kind of rule.
//
switch (wStyle) { case 0: //
// black fill, which is max gray fill unless CmdRectBlackFill exists
//
if (pCmd = COMMANDPTR(pPDev->pDriverInfo,CMD_RECTBLACKFILL)) WriteChannel(pPDev, pCmd); else { pPDev->dwGrayPercentage = pPDev->dwMaxGrayFill; WriteChannel(pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_RECTGRAYFILL)); } ulRes = 1; break;
case 1: //
// White (erase) fill
//
if (pCmd = COMMANDPTR(pPDev->pDriverInfo,CMD_RECTWHITEFILL)) { WriteChannel(pPDev, pCmd); ulRes = 1; } break;
case 2: //
// Shaded gray fill.
//
// If 100% black use black rectangle fill anyway
//
if (pPatRect->wPattern == 100 && (pCmd = COMMANDPTR(pPDev->pDriverInfo,CMD_RECTBLACKFILL))) { WriteChannel(pPDev, pCmd); } // If 0% black use white rectangle fill
//
else if (pPatRect->wPattern == 0 && (pCmd = COMMANDPTR(pPDev->pDriverInfo,CMD_RECTWHITEFILL))) { WriteChannel(pPDev, pCmd); } //
// Check for the gray range.
//
else { if ((wPattern = pPatRect->wPattern) < (WORD)pPDev->dwMinGrayFill) wPattern = (WORD)pPDev->dwMinGrayFill; if (wPattern > (WORD)pPDev->dwMaxGrayFill) wPattern = (WORD)pPDev->dwMaxGrayFill; pPDev->dwGrayPercentage = (DWORD)wPattern; WriteChannel(pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_RECTGRAYFILL)); } ulRes = 1; break; }
//
// update internal coordinates, if necessary. BUG_BUG, do we really need cx/cyafterfill in PDEV?
//
if (ulRes == 1) { if (pPDev->cxafterfill == CXARF_AT_RECT_X_END) XMoveTo(pPDev, pPatRect->ptSize.x, MV_GRAPHICS | MV_UPDATE | MV_RELATIVE);
if (pPDev->cyafterfill == CYARF_AT_RECT_Y_END) YMoveTo(pPDev, pPatRect->ptSize.y, MV_GRAPHICS | MV_UPDATE | MV_RELATIVE); if (wStyle != 1) { INT i; BYTE ubMask = BGetMask(pPDev,&rcClip); for (i = rcClip.top;i < rcClip.bottom;i++) pPDev->pbScanBuf[i] |= ubMask; } } } // if (!IsRectEmpty(&rcClip))
return ulRes; }
|