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.
 
 
 
 
 
 

779 lines
21 KiB

//--------------------------------------------------------------------------
//
// Module Name: ESCAPE.C
//
// Brief Description: This module contains the PSCRIPT driver's Escape
// functions and related routines.
//
// Author: Kent Settle (kentse)
// Created: 08-Feb-1991
//
// Copyright (c) 1991 - 1992 Microsoft Corporation
//
// This routine contains routines to handle the various Escape functions.
//--------------------------------------------------------------------------
#include "pscript.h"
// DrawEscape to output encapsulated PostScript data.
typedef struct tagEPSDATA
{
DWORD cbData; // Size of the structure and EPS data in bytes.
DWORD nVersion; // Language level, e.g. 1 for level 1 PostScript.
POINTL aptl[3]; // Output parallelogram in 28.4 FIX device coords.
// This is followed by the EPS data.
} EPSDATA, *PEPSDATA;
#define CLIP_SAVE 0
#define CLIP_RESTORE 1
#define CLIP_INCLUSIVE 2
BOOL bDoEpsXform(PDEVDATA, PEPSDATA);
VOID FlushFonts(PDEVDATA);
#define ESC_NOT_SUPPORTED 0
#define ESC_IS_SUPPORTED 1
//--------------------------------------------------------------------------
// ULONG DrvEscape (pso, iEsc, cjIn, pvIn, cjOut, pvOut)
// SURFOBJ *pso;
// ULONG iEsc;
// ULONG cjIn;
// PVOID pvIn;
// ULONG cjOut;
// PVOID pvOut;
//
// This entry point serves more than one function call. The particular
// function depends on the value of the iEsc parameter.
//
// In general, the DrvEscape functions will be device specific functions
// that don't belong in a device independent DDI. This entry point is
// optional for all devices.
//
// Parameters:
// pso
// Identifies the surface that the call is directed to.
//
// iEsc
// Specifies the particular function to be performed. The meaning of
// the remaining arguments depends on this parameter. Allowed values
// are as follows.
//
// ESC_QUERYESCSUPPORT
// Asks if the driver supports a particular escape function. The
// escape function number is a ULONG pointed to by pvIn. A non-zero
// value should be returned if the function is supported. cjIn has a
// value of 4. The arguments cjOut and pvOut are ignored.
//
// ESC_PASSTHROUGH
// Passes raw device data to the device driver. The number of BYTEs of
// raw data is indicated by cjIn. The data is pointed to by pvIn. The
// arguments cjOut and pvOut are ignored. Returns the number of BYTEs
// written if the function is successful. Otherwise, it returns zero
// and logs an error code.
// cjIn
// The size, in BYTEs, of the data buffer pointed to by pvIn.
//
// pvIn
// The input data for the call. The format of the input data depends
// on the function specified by iEsc.
//
// cjOut
// The size, in BYTEs, of the output data buffer pointed to by pvOut.
// The driver must never write more than this many BYTEs to the output
// buffer.
//
// pvOut
// The output buffer for the call. The format of the output data depends
// on the function specified by iEsc.
//
// Returns:
// Depends on the function specified by iEsc. In general, the driver should
// return 0xFFFFFFFF if an unsupported function is called.
//
// History:
// 02-Feb-1991 -by- Kent Settle (kentse)
// Wrote it.
//--------------------------------------------------------------------------
/* private escapes for WOW to deal with incompatible apps */
#define IGNORESTARTPAGE 0x7FFFFFFF
#define NOFIRSTSAVE 0x7FFFFFFE
#define ADDMSTT 0x7FFFFFFD
ULONG isSupported(ULONG iEsc)
{
if (iEsc == QUERYESCSUPPORT ||
iEsc == SETCOPYCOUNT ||
iEsc == CLIP_TO_PATH ||
iEsc == BEGIN_PATH ||
iEsc == END_PATH ||
iEsc == PASSTHROUGH ||
iEsc == POSTSCRIPT_PASSTHROUGH ||
iEsc == POSTSCRIPT_DATA ||
iEsc == POSTSCRIPT_IGNORE ||
iEsc == GETDEVICEUNITS ||
iEsc == DOWNLOADHEADER ||
iEsc == GETTECHNOLOGY ||
iEsc == EPSPRINTING ||
iEsc == IGNORESTARTPAGE ||
iEsc == NOFIRSTSAVE ||
iEsc == ADDMSTT)
return ESC_IS_SUPPORTED;
else
return ESC_NOT_SUPPORTED;
}
ULONG DrvEscape (SURFOBJ *pso,
ULONG iEsc,
ULONG cjIn,
PVOID pvIn,
ULONG cjOut,
PVOID pvOut)
{
PDEVDATA pdev;
FLOAT * pfloat;
FLOATOBJ floatobj;
PSRECT * prect;
ULONG ulRet = (ULONG) TRUE;
TRACEDDIENTRY("DrvEscape");
if (isSupported(iEsc) != ESC_IS_SUPPORTED) return ESC_NOT_SUPPORTED;
/* Process query-type escapes */
if (iEsc == QUERYESCSUPPORT) {
// !!! Note: Some apps pass in DWORD and other apps pass in WORD.
// In order to keep everyone happy, we only look at a 16-bit word.
// This should be fine even if the app passes in a DWORD (whose
// upper 16-bit should always be 0).
iEsc = * (PWORD) pvIn;
return (iEsc == SETCOPYCOUNT) ? MAX_COPIES : isSupported(iEsc) ;
}
if (iEsc == GETTECHNOLOGY) {
if (!pvOut || cjOut <= strlen("PostScript")) {
SETLASTERROR(ERROR_INVALID_PARAMETER);
return 0;
}
strcpy (pvOut, "PostScript");
return (ULONG) TRUE;
}
/* Check pdev before processing non-query type of escapes */
pdev = (PDEVDATA) pso->dhpdev;
if (!bValidatePDEV(pdev)) {
DBGERRMSG("bValidatePDEV");
SETLASTERROR(ERROR_INVALID_PARAMETER);
return 0;
}
switch (iEsc) {
case IGNORESTARTPAGE:
pdev->dwFlags |= PDEV_IGNORE_STARTPAGE;
break;
case NOFIRSTSAVE:
pdev->dwFlags |= PDEV_NOFIRSTSAVE;
break;
case ADDMSTT:
pdev->dwFlags |= PDEV_ADDMSTT;
break;
case DOWNLOADHEADER:
if (pso->dhsurf) DownloadNTProcSet(pdev, FALSE);
if (pvOut) strcpy(pvOut, PROCSETNAME);
break;
case POSTSCRIPT_IGNORE:
if (!cjIn || !pvIn) {
SETLASTERROR(ERROR_INVALID_PARAMETER);
return 0;
}
if (*(WORD *) pvIn)
pdev->dwFlags |= PDEV_IGNORE_GDI;
else
pdev->dwFlags &= ~PDEV_IGNORE_GDI;
break;
case POSTSCRIPT_DATA:
case PASSTHROUGH:
case POSTSCRIPT_PASSTHROUGH:
//
// Validate input buffer and byte count
//
if (cjIn < sizeof(WORD) || (INT) cjIn < *((PWORD) pvIn) + sizeof(WORD)) {
DBGMSG(DBG_LEVEL_ERROR, "Bad byte count for PASSTHROUGH escapes!\n");
SETLASTERROR(ERROR_INVALID_PARAMETER);
ulRet = (ULONG) SP_ERROR;
break;
}
// do nothing if the document has been cancelled.
if (pdev->dwFlags & PDEV_CANCELDOC)
return(*(LPWORD)pvIn);
if (iEsc == POSTSCRIPT_PASSTHROUGH) {
if (!(pdev->dwFlags & PDEV_PROCSET) &&
!(pdev->dwFlags & PDEV_RAWBEFOREPROCSET))
{
pdev->dwFlags |= PDEV_RAWBEFOREPROCSET;
}
//
// HACK: Clear any procset and font information when we see a pass through
//
if (pdev->dwFlags & PDEV_RAWBEFOREPROCSET) {
pdev->dwFlags &= ~(PDEV_UTILSSENT | PDEV_BMPPATSENT | PDEV_IMAGESENT);
FlushFonts(pdev);
}
init_cgs(pdev);
//
// HACK: Workaround for Corel Xara
//
pdev->cgs.ulColor = NOT_SOLID_COLOR;
} else if (!(pdev->dwFlags & PDEV_PROCSET)) {
/* send prolog, for compatibility with some win31 apps */
bOutputHeader(pdev);
pdev->dwFlags |= PDEV_PROCSET;
// hack for XPress.
// Push NTPROCSET and define 2 dummy procedures
if (pdev->dwFlags & PDEV_IGNORE_STARTPAGE)
psputs(pdev,
PROCSETNAME
" begin /RS {dumbsave restore} def"
"/SS {/dumbsave save def} def SS\n");
}
cjIn = (*(LPWORD)pvIn);
pvIn = (LPVOID)(((LPWORD)pvIn) + 1);
if (! pswrite(pdev, pvIn, cjIn))
ulRet = (ULONG) SP_ERROR;
else
ulRet = cjIn;
break;
case GETDEVICEUNITS:
if (!pvOut) return 0;
pfloat = (FLOAT *)pvOut;
prect = &pdev->CurForm.ImageArea;
// We are assuming FLOAT and LONG have the same size.
// Make sure that's indeed that case.
ASSERT(sizeof(FLOAT) == sizeof(LONG));
// 1st 2 numbers are dimensions of imageable area in driver units
FLOATOBJ_SetLong(&floatobj,
PSRealToPixel(
prect->right - prect->left,
pdev->dm.dmPublic.dmPrintQuality));
*((LONG *)pfloat) = FLOATOBJ_GetFloat(&floatobj);
pfloat++;
FLOATOBJ_SetLong(&floatobj,
PSRealToPixel(
prect->top - prect->bottom,
pdev->dm.dmPublic.dmPrintQuality));
*((LONG *)pfloat) = FLOATOBJ_GetFloat(&floatobj);
pfloat++;
/* 3rd & 4th are origin offsets applied by driver */
if (pdev->dwFlags & PDEV_WITHINPAGE) {
FLOATOBJ_SetLong(&floatobj,
PSRealToPixel(
prect->left,
pdev->dm.dmPublic.dmPrintQuality));
*((LONG *)pfloat) = FLOATOBJ_GetFloat(&floatobj);
pfloat++;
FLOATOBJ_SetLong(&floatobj,
PSRealToPixel(
pdev->CurForm.PaperSize.height - prect->top,
pdev->dm.dmPublic.dmPrintQuality));
*((LONG *)pfloat) = FLOATOBJ_GetFloat(&floatobj);
} else {
/* no offset if outside of start/endpage */
*pfloat++ = (FLOAT) 0.0;
*pfloat = (FLOAT) 0.0;
}
ulRet = TRUE;
break;
case SETCOPYCOUNT:
// the copy count is a DWORD count sitting at pvIn.
if (!pvIn)
{
ulRet = (ULONG) SP_ERROR;
break;
}
// we have a positive number of copies. let's set a limit.
pdev->cCopies = min(*(DWORD *)pvIn, MAX_COPIES);
if (pdev->cCopies < 1) pdev->cCopies = 1;
// let the caller know how many copies we will do.
if (pvOut)
*(DWORD *)pvOut = pdev->cCopies;
break;
case CLIP_TO_PATH:
if (!pvIn) {
SETLASTERROR(ERROR_INVALID_PARAMETER);
return 0;
}
switch (*(WORD *) pvIn) {
case CLIP_SAVE:
ps_save(pdev, TRUE, FALSE);
ps_newpath(pdev);
break;
case CLIP_RESTORE:
ps_restore(pdev, TRUE, FALSE);
break;
case CLIP_INCLUSIVE:
ps_clip(pdev, FALSE);
break;
default:
return 0;
}
break;
case BEGIN_PATH:
psputs(pdev, "/s {} def /e {} def\n");
pdev->dwFlags |= PDEV_INSIDE_PATHESCAPE;
break;
case END_PATH:
psputs(pdev, "/s /stroke ld /e /eofill ld\n");
pdev->dwFlags &= ~PDEV_INSIDE_PATHESCAPE;
break;
case EPSPRINTING:
if ((pvIn) && (*(WORD *)pvIn))
pdev->dwFlags |= PDEV_EPSPRINTING_ESCAPE;
else
pdev->dwFlags &= ~PDEV_EPSPRINTING_ESCAPE;
break;
default:
// if we get to the default case, we have been passed an
// unsupported escape function number.
DBGMSG1(DBG_LEVEL_ERROR, "DrvEscape 0x%x not supported.\n", iEsc);
ulRet = ESC_NOT_SUPPORTED;
break;
}
return(ulRet);
}
//--------------------------------------------------------------------------
// ULONG DrvDrawEscape(
// SURFOBJ *pso,
// ULONG iEsc,
// CLIPOBJ *pco,
// RECTL *prcl,
// ULONG cjIn,
// PVOID pvIn);
//
// Supports the ESCAPSULATED_POSTSCRIPT escape.
//
// History:
// Sat May 08 13:27:52 1993 -by- Hock San Lee [hockl]
// Wrote it.
//--------------------------------------------------------------------------
ULONG DrvDrawEscape(
SURFOBJ *pso,
ULONG iEsc,
CLIPOBJ *pco,
RECTL *prcl,
ULONG cjIn,
PVOID pvIn)
{
PDEVDATA pdev;
PEPSDATA pEpsData;
BOOL bRet;
BOOL bClipping; // TRUE if clipping being done.
TRACEDDIENTRY("DrvDrawEscape");
// handle each case depending on which escape function is being asked for.
switch (iEsc) {
case QUERYESCSUPPORT:
// !!! Note: Some apps pass in DWORD and other apps pass in WORD.
// In order to keep everyone happy, we only look at a 16-bit word.
// This should be fine even if the app passes in a DWORD (whose
// upper 16-bit should always be 0).
switch (*(PWORD)pvIn) {
case QUERYESCSUPPORT:
case ENCAPSULATED_POSTSCRIPT:
return ESC_IS_SUPPORTED;
default:
return ESC_NOT_SUPPORTED;
}
case ENCAPSULATED_POSTSCRIPT:
// get the pointer to our DEVDATA structure and make sure it is ours.
pdev = (PDEVDATA) pso->dhpdev;
if (bValidatePDEV(pdev) == FALSE)
{
DBGERRMSG("bValidatePDEV");
SETLASTERROR(ERROR_INVALID_PARAMETER);
return(0);
}
// get the encapsulated PostScript data.
pEpsData = (PEPSDATA) pvIn;
// make sure that the driver can handle the eps language level.
if ((pdev->hppd->dwLangLevel < pEpsData->nVersion)
&& !(pdev->hppd->dwLangLevel == 0 && pEpsData->nVersion <= 1))
{
SETLASTERROR(ERROR_NOT_SUPPORTED);
return(0);
}
// set up the clip path.
bClipping = bDoClipObj(pdev, pco, NULL, NULL);
// prepare for the included EPS data.
ps_begin_eps(pdev);
// set up the transform needed to map the EPS to the device
// parallelogram.
// We ignore prcl here and assume that it is at (0,0).
if (!bDoEpsXform(pdev, pEpsData))
{
DBGERRMSG("bDoEpsXform");
SETLASTERROR(ERROR_INVALID_PARAMETER);
ps_end_eps(pdev);
return(0);
}
// write out the EPS data. The EPS data is assumed to begin
// with %%BeginDocument as recommanded in the DSC version 3.0
// by Adobe.
bRet = pswrite(pdev,
(PBYTE) pEpsData + sizeof(EPSDATA),
pEpsData->cbData - sizeof(EPSDATA));
// restore state and cleanup stacks.
ps_end_eps(pdev);
if (bClipping)
ps_restore(pdev, TRUE, FALSE);
return(bRet ? 1 : 0);
default:
// if we get to the default case, we have been passed an
// unsupported escape function number.
DBGMSG1(DBG_LEVEL_ERROR,
"DrvDrawEscape 0x%x not supported.\n",
iEsc);
return(ESC_NOT_SUPPORTED);
}
}
// Calculate n / (f1 - f2), where f1 and f2 point to FLOATOBJ's
// and n is a 28.4 fixed-point number
VOID
CalcFormula1(
FLOAT * pResult,
LONG n,
PFLOATOBJ f1,
PFLOATOBJ f2
)
{
FLOATOBJ num, denom;
FLOATOBJ_SetLong(&num, n);
denom = *f1;
FLOATOBJ_Sub(&denom, f2);
FLOATOBJ_MulLong(&denom, 16);
FLOATOBJ_Div(&num, &denom);
*((LONG *)pResult) = FLOATOBJ_GetFloat(&num);
}
// Calculate n - mx * x - my * y, where n is a 28.4 fixed-point number,
// mx and my are floating-pointing numbers, and x and y point to FLOATOBJ's
VOID
CalcFormula2(
FLOAT * pResult,
LONG n,
FLOAT mx,
PFLOATOBJ x,
FLOAT my,
PFLOATOBJ y
)
{
FLOATOBJ f1, f2;
FLOATOBJ_SetLong(&f1, n);
FLOATOBJ_DivFloat(&f1, (FLOAT) 16.0);
FLOATOBJ_SetFloat(&f2, mx);
FLOATOBJ_Mul(&f2, x);
FLOATOBJ_Sub(&f1, &f2);
FLOATOBJ_SetFloat(&f2, my);
FLOATOBJ_Mul(&f2, y);
FLOATOBJ_Sub(&f1, &f2);
*((LONG *)pResult) = FLOATOBJ_GetFloat(&f1);
}
BOOL bDoEpsXform(pdev, pEpsData)
PDEVDATA pdev;
PEPSDATA pEpsData;
{
PBYTE pbEps, pbEpsEnd, pbBoundingBox;
XFORM xform;
PS_FIX psfxM11, psfxM12, psfxM21, psfxM22, psfxdx, psfxdy;
int i;
BOOL bIsNegative;
FLOATOBJ aeBoundingBox[4];
// look for the string %%BoundingBox:
pbEps = (PBYTE) pEpsData + sizeof(EPSDATA);
pbEpsEnd = (PBYTE) pEpsData + pEpsData->cbData - 1;
pbBoundingBox = pbEps;
while (pbBoundingBox <= pbEpsEnd)
{
if (memcmp(pbBoundingBox, "%%BoundingBox:", 14) == EQUAL_STRING) {
pbBoundingBox += 14;
// store the bounding box coordinates in aeBoundingBox[].
for (i = 0; i < 4; i++)
{
// initialize bounding box.
FLOATOBJ_SetFloat(&aeBoundingBox[i], (FLOAT) 0.0);
// skip white space.
while (*pbBoundingBox == ' ' || *pbBoundingBox == '\t')
pbBoundingBox++;
// get sign.
if (*pbBoundingBox == '-')
{
pbBoundingBox++;
bIsNegative = TRUE;
}
else
bIsNegative = FALSE;
// if this is not an integer, it may be an (atend) and
// the bounding box is at the end of the EPS data.
if (!(*pbBoundingBox >= '0' && *pbBoundingBox <= '9' ||
*pbBoundingBox == '.'))
{
goto find_bounding_box;
}
// get integer.
while (*pbBoundingBox >= '0' && *pbBoundingBox <= '9')
{
FLOATOBJ_MulFloat(&aeBoundingBox[i], (FLOAT) 10.0);
FLOATOBJ_AddLong(&aeBoundingBox[i], *pbBoundingBox - '0');
pbBoundingBox++;
}
// get fraction if any.
if (*pbBoundingBox == '.') {
LONG scale, fraction;
INT digits;
FLOATOBJ tmpfloat;
pbBoundingBox++; // skip '.'
digits = 5; // max precision
scale = 1;
fraction = 0;
while (*pbBoundingBox >= '0' && *pbBoundingBox <= '9') {
if (digits-- > 0) {
fraction = 10 * fraction + (*pbBoundingBox - '0');
scale *= 10;
}
pbBoundingBox++;
}
FLOATOBJ_SetLong(&tmpfloat, fraction);
FLOATOBJ_DivLong(&tmpfloat, scale);
FLOATOBJ_Add(&aeBoundingBox[i], &tmpfloat);
}
if (bIsNegative) {
FLOATOBJ_MulFloat(&aeBoundingBox[i], (FLOAT) -1.0);
}
}
break; // got it!
}
else
pbBoundingBox++;
// look for the '%' character.
find_bounding_box:
while (*pbBoundingBox != '%' && pbBoundingBox <= pbEpsEnd)
pbBoundingBox++;
}
if (pbBoundingBox > pbEpsEnd)
{
DBGMSG(DBG_LEVEL_ERROR, "Invalid EPS bounding box.\n");
SETLASTERROR(ERROR_INVALID_PARAMETER);
return(FALSE);
}
// convert the parallelogram to PostScript coordinates (FLOAT, 72dpi).
#define u0 pEpsData->aptl[0].x // left
#define v0 pEpsData->aptl[0].y // top
#define u1 pEpsData->aptl[1].x // right
#define v1 pEpsData->aptl[1].y // top
#define u2 pEpsData->aptl[2].x // left
#define v2 pEpsData->aptl[2].y // bottom
#define x0 &aeBoundingBox[0] // left
#define y0 &aeBoundingBox[3] // top
#define x1 &aeBoundingBox[2] // right
#define y1 &aeBoundingBox[3] // top
#define x2 &aeBoundingBox[0] // left
#define y2 &aeBoundingBox[1] // bottom
// Here is the transform equation from source EPS parallelogram
// [(x0,y0) (x1,y1) (x2,y2)] to the device parallelogram
// [(u0,v0) (u1,v1) (u2,v2)]:
//
// (u) (u0) [(x) (x0)]
// ( ) = ( ) + M * [( ) - ( )]
// (v) (v0) [(y) (y0)]
//
// where
//
// [(u1-u0)/(x1-x0) (u2-u0)/(y2-y0)]
// M = [ ]
// [(v1-v0)/(x1-x0) (v2-v0)/(y2-y0)]
// xform.eM11 = (u1 - u0) / (x1 - x0);
// xform.eM12 = (v1 - v0) / (x1 - x0);
// xform.eM21 = (u2 - u0) / (y2 - y0);
// xform.eM22 = (v2 - v0) / (y2 - y0);
// xform.eDx = u0 - xform.eM11 * x0 - xform.eM21 * y0;
// xform.eDy = v0 - xform.eM12 * x0 - xform.eM22 * y0;
// We are assuming FLOAT and LONG have the same size.
// Make sure that's indeed that case.
ASSERT(sizeof(FLOAT) == sizeof(LONG));
CalcFormula1(&xform.eM11, u1 - u0, x1, x0);
CalcFormula1(&xform.eM12, v1 - v0, x1, x0);
CalcFormula1(&xform.eM21, u2 - u0, y2, y0);
CalcFormula1(&xform.eM22, v2 - v0, y2, y0);
CalcFormula2(&xform.eDx, u0, xform.eM11, x0, xform.eM21, y0);
CalcFormula2(&xform.eDy, v0, xform.eM12, x0, xform.eM22, y0);
// output the transform.
psfxM11 = ETOPSFX(xform.eM11);
psfxM12 = ETOPSFX(xform.eM12);
psfxM21 = ETOPSFX(xform.eM21);
psfxM22 = ETOPSFX(xform.eM22);
psfxdx = ETOPSFX(xform.eDx);
psfxdy = ETOPSFX(xform.eDy);
psputs(pdev, "[");
psputfix(pdev, 6, psfxM11, psfxM12, psfxM21, psfxM22, psfxdx, psfxdy);
psputs(pdev, "] concat\n");
return(TRUE);
}