File:  [WindowsNT SDKs] / ntddk / src / print / pscript / escape.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

//--------------------------------------------------------------------------
//
// 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"
#include "enable.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;

FLOAT FixToFloat(FIX);
BOOL  bDoEpsXform(PDEVDATA, PEPSDATA);
extern BOOL bDoClipObj(PDEVDATA, CLIPOBJ *, RECTL *, RECTL *, BOOL *, BOOL *, DWORD);

#define ESC_NOT_SUPPORTED   0xFFFFFFFF
#define ESC_IS_SUPPORTED    0x00000001

//--------------------------------------------------------------------------
// 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.
//--------------------------------------------------------------------------

ULONG DrvEscape (pso, iEsc, cjIn, pvIn, cjOut, pvOut)
SURFOBJ    *pso;
ULONG       iEsc;
ULONG       cjIn;
PVOID       pvIn;
ULONG       cjOut;
PVOID       pvOut;
{
    PDEVDATA    pdev;
    DWORD       cWritten;
    FLOAT       *pfloat;
    LONG        ytmp;
    ULONG       ulRet = ESC_NOT_SUPPORTED;

    // handle each case depending on which escape function is being asked for.

    switch (iEsc)
    {
        case QUERYESCSUPPORT:
            // when querying escape support, the function in question is
            // passed in the ULONG passed in pvIn.

            switch (*(PULONG)pvIn)
            {
                case QUERYESCSUPPORT:
                case PASSTHROUGH:
                case POSTSCRIPT_PASSTHROUGH:
                case GETDEVICEUNITS:
                    return(ESC_IS_SUPPORTED);

                case SETCOPYCOUNT:
                    return(MAX_COPIES);

                default:
                    // return 0 if the escape in question is not supported.

		    return(0);
            }

        case POSTSCRIPT_PASSTHROUGH:
        case PASSTHROUGH:
            // get the pointer to our DEVDATA structure and make sure it is ours.

            pdev = (PDEVDATA) pso->dhpdev;

            if (bValidatePDEV(pdev) == FALSE)
            {
                RIP("PSCRIPT!DrvEscape: invalid pdev.\n");
                SetLastError(ERROR_INVALID_PARAMETER);
                ulRet = 0;
                break;
            }

            // do nothing if the document has been cancelled.

            if (pdev->dwFlags & PDEV_CANCELDOC)
                return(*(LPWORD)pvIn);

            if (iEsc == POSTSCRIPT_PASSTHROUGH)
            {
                // initialize the current graphics state.

                init_cgs(pdev);

                if (pdev->dwFlags & PDEV_WITHINPAGE)
                {
                    ps_restore(pdev, FALSE);
                    pdev->dwFlags &= ~PDEV_WITHINPAGE;
                }

                if (pdev->dwFlags & PDEV_PROCSET)
                {
                    PrintString(pdev, "end\n");
                    pdev->dwFlags &= ~PDEV_PROCSET;
                }
            }

            pdev->dwFlags |= PDEV_RAWDATASENT;

            // just write out what is in the buffer.  do NOT add a
            // header to the output.  that would be wrong.

            bPSFlush(pdev);

            cjIn = (*(LPWORD)pvIn);
            pvIn = (LPVOID)(((LPWORD)pvIn) + 1);

            if (!WritePrinter(pdev->hPrinter, pvIn, cjIn, &cWritten))
            {
                DbgPrint("PSCRIPT!DrvEscape PASSTHROUGH: WritePrinter failed.\n");
                ulRet = 0;
                break;
            }
            else
                ulRet = cWritten;

            break;

        case GETDEVICEUNITS:
            // get the pointer to our DEVDATA structure and make sure it is ours.

            pdev = (PDEVDATA) pso->dhpdev;

            if ((bValidatePDEV(pdev) == FALSE) || (cjOut < (sizeof(LONG) * 4)))
            {
                RIP("PSCRIPT!DrvEscape GETDEVICEUNITS: invalid pdev or cjOut.\n");
                SetLastError(ERROR_INVALID_PARAMETER);
                ulRet = 0;
                break;
            }

            pfloat = (FLOAT *)pvOut;

            // fill in the first two bytes with the resolution we actually
            // send to the printer.

            *pfloat++ =(FLOAT)(pdev->CurForm.imagearea.right -
                               pdev->CurForm.imagearea.left);

            // handle landscape vs portrait.

            ytmp = pdev->CurForm.imagearea.bottom -
                   pdev->CurForm.imagearea.top;

#ifndef LANDSCAPE_270_ROTATE // 90 degree case.
            if ((pdev->psdm.dm.dmFields & DM_ORIENTATION) &&
                (pdev->psdm.dm.dmOrientation == DMORIENT_LANDSCAPE))
                ytmp = -ytmp;
#endif

            *pfloat++ = (FLOAT)ytmp;

            // now fill in the offset of our origin from the upper left
            // corner of the piece of paper.

            *pfloat++ = (FLOAT)pdev->CurForm.imagearea.left;

            ytmp = pdev->CurForm.imagearea.top;

            *pfloat = (FLOAT)ytmp;

            ulRet = TRUE;
            break;

        case SETCOPYCOUNT:
            // the copy count is a DWORD count sitting at pvIn.

            if (!pvIn)
            {
                ulRet = 0;
                break;
            }

            // get the pointer to our DEVDATA structure and make sure it is ours.

            pdev = (PDEVDATA) pso->dhpdev;

            if (bValidatePDEV(pdev) == FALSE)
            {
                RIP("PSCRIPT!DrvEscape: invalid pdev.\n");
                SetLastError(ERROR_INVALID_PARAMETER);
                ulRet = 0;
                break;
            }

            // if user specified zero or one copy, do nothing.  one
            // copy will be printed by default.

            if (*(DWORD *)pvIn <= MIN_COPIES)
            {
                // let the caller know how many copies we will do.

                pdev->cCopies = 1;

                if (pvOut)
                    *(DWORD *)pvOut = pdev->cCopies;

                ulRet = TRUE;
                break;
            }

            // we have a positive number of copies.  let's set a limit.

            pdev->cCopies = min(*(DWORD *)pvIn, MAX_COPIES);

            // let the caller know how many copies we will do.

            if (pvOut)
                *(DWORD *)pvOut = pdev->cCopies;

            ulRet = TRUE;
            break;

        default:
            // if we get to the default case, we have been passed an
            // unsupported escape function number.

            DbgPrint("PSCRIPT!DrvEscape %x ESC_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;
    DWORD       cWritten;
    PEPSDATA    pEpsData;
    BOOL        bRet;
    BOOL        bFirstClipPass;     // TRUE 1st call to bDoClipObj.
    BOOL        bMoreClipping;      // TRUE if more clipping to enumerate.
    BOOL        bClipping;          // TRUE if clipping being done.

    // handle each case depending on which escape function is being asked for.

    switch (iEsc)
    {
        case QUERYESCSUPPORT:
            // when querying escape support, the function in question is
            // passed in the ULONG passed in pvIn.

            switch (*(PULONG)pvIn)
            {
                case QUERYESCSUPPORT:
                case ENCAPSULATED_POSTSCRIPT:
                    return(ESC_IS_SUPPORTED);

                default:
                    // return 0 if the escape in question is not supported.
                    return(0);
            }

        case ENCAPSULATED_POSTSCRIPT:

            // get the pointer to our DEVDATA structure and make sure it is ours.

            pdev = (PDEVDATA) pso->dhpdev;

            if (bValidatePDEV(pdev) == FALSE)
            {
                RIP("PSCRIPT!DrvDrawEscape: invalid pdev.\n");
                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->pntpd->LangLevel < pEpsData->nVersion)
            && !(pdev->pntpd->LangLevel == 0 && pEpsData->nVersion <= 1))
            {
                SetLastError(ERROR_NOT_SUPPORTED);
                return(0);
            }

            // set up the clip path.

            bFirstClipPass = TRUE;
            bMoreClipping = TRUE;

            while (bMoreClipping)
            {
                if (bClipping = bDoClipObj(pdev, pco, NULL, NULL,
                                           &bMoreClipping, &bFirstClipPass,
                                           25))
                    ps_clip(pdev, TRUE);

                // 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))
                {
                    RIP("PSCRIPT!DrvDrawEscape: invalid xform.\n");
                    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.

                bPSFlush(pdev);
                bRet = WritePrinter(pdev->hPrinter,
                                    (PBYTE) pEpsData + sizeof(EPSDATA),
                                    pEpsData->cbData - sizeof(EPSDATA),
                                    &cWritten);
                if (!bRet)
                    DbgPrint("PSCRIPT!DrvDrawEscape ENCAPSULATED_POSTSCRIPT: WritePrinter failed.\n");

                // restore state and cleanup stacks.

                ps_end_eps(pdev);

                if (bClipping)
                    ps_restore(pdev, TRUE);

            }

            return(bRet ? 1 : 0);

        default:
            // if we get to the default case, we have been passed an
            // unsupported escape function number.

            DbgPrint("PSCRIPT!DrvDrawEscape %x ESC_NOT_SUPPORTED.\n", iEsc);

            return(ESC_NOT_SUPPORTED);
    }
}

BOOL bDoEpsXform(pdev, pEpsData)
PDEVDATA  pdev;
PEPSDATA  pEpsData;
{
    PBYTE  pbEps, pbEpsEnd, pbBoundingBox;
    FLOAT  aeBoundingBox[4];        // bl.x, bl.y, tr.x, tr.y
    XFORM  xform;
    PS_FIX psfxM11, psfxM12, psfxM21, psfxM22, psfxdx, psfxdy;
    int    i;
    BOOL   bIsNegative;
    POINTE apteDst[3], apteSrc[3];

    // 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))
        {
            pbBoundingBox += 14;

            // store the bounding box coordinates in aeBoundingBox[].

            for (i = 0; i < 4; i++)
            {
                // initialize bounding box.

                aeBoundingBox[i] = 0.0f;

                // 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')
                {
                    aeBoundingBox[i] = aeBoundingBox[i] * 10.0f
                                        + (FLOAT) (int) (*pbBoundingBox - '0');
                    pbBoundingBox++;
                }

                // get fraction if any.

                if (*pbBoundingBox == '.')
                {
                    FLOAT eDiv;

                    pbBoundingBox++;        // skip '.'

                    eDiv = 10.0f;
                    while (*pbBoundingBox >= '0' && *pbBoundingBox <= '9')
                    {
                        aeBoundingBox[i] += (FLOAT) (int) (*pbBoundingBox - '0')
                                                / eDiv;
                        eDiv *= 10.0f;
                        pbBoundingBox++;
                    }
                }

                if (bIsNegative)
                    aeBoundingBox[i] = aeBoundingBox[i] * -1.0f;
            }
            break;        // got it!
        }
        else
            pbBoundingBox++;

        // look for the '%' character.

    find_bounding_box:

        while (*pbBoundingBox != '%' && pbBoundingBox <= pbEpsEnd)
            pbBoundingBox++;
    }

    if (pbBoundingBox > pbEpsEnd)
    {
        RIP("PSCRIPT!bDoEpsXform: invalid EPS bounding box.\n");
        SetLastError(ERROR_INVALID_PARAMETER);
        return(FALSE);
    }

    // convert the parallelogram to PostScript coordinates (FLOAT, 72dpi).

    apteDst[0].x = XE72DPI(FixToFloat(pEpsData->aptl[0].x));   // left   u0
    apteDst[0].y = YE72DPI(FixToFloat(pEpsData->aptl[0].y));   // top    v0
    apteDst[1].x = XE72DPI(FixToFloat(pEpsData->aptl[1].x));   // right  u1
    apteDst[1].y = YE72DPI(FixToFloat(pEpsData->aptl[1].y));   // top    v1
    apteDst[2].x = XE72DPI(FixToFloat(pEpsData->aptl[2].x));   // left   u2
    apteDst[2].y = YE72DPI(FixToFloat(pEpsData->aptl[2].y));   // bottom v2

    apteSrc[0].x = aeBoundingBox[0];    // left   x0
    apteSrc[0].y = aeBoundingBox[3];    // top    y0
    apteSrc[1].x = aeBoundingBox[2];    // right  x1
    apteSrc[1].y = aeBoundingBox[3];    // top    y1
    apteSrc[2].x = aeBoundingBox[0];    // left   x2
    apteSrc[2].y = aeBoundingBox[1];    // bottom y2

// 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 = (apteDst[1].x - apteDst[0].x) / (apteSrc[1].x - apteSrc[0].x);
    xform.eM12 = (apteDst[1].y - apteDst[0].y) / (apteSrc[1].x - apteSrc[0].x);
    xform.eM21 = (apteDst[2].x - apteDst[0].x) / (apteSrc[2].y - apteSrc[0].y);
    xform.eM22 = (apteDst[2].y - apteDst[0].y) / (apteSrc[2].y - apteSrc[0].y);
    xform.eDx  = apteDst[0].x - xform.eM11 * apteSrc[0].x - xform.eM21 * apteSrc[0].y;
    xform.eDy  = apteDst[0].y - xform.eM12 * apteSrc[0].x - xform.eM22 * apteSrc[0].y;

    // 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);

    PrintString(pdev, "[");
    PrintPSFIX(pdev, 6, psfxM11, psfxM12, psfxM21, psfxM22,
               psfxdx, psfxdy);
    PrintString(pdev, "] concat\n");

    return(TRUE);
}

FLOAT ae16[16] = { 0.0f / 16.0f,  1.0f / 16.0f,  2.0f / 16.0f,  3.0f / 16.0f,
                   4.0f / 16.0f,  5.0f / 16.0f,  6.0f / 16.0f,  7.0f / 16.0f,
                   8.0f / 16.0f,  9.0f / 16.0f, 10.0f / 16.0f, 11.0f / 16.0f,
                  12.0f / 16.0f, 13.0f / 16.0f, 14.0f / 16.0f, 15.0f / 16.0f};

// Convert 28.4 FIX to FLOAT.

FLOAT FixToFloat(FIX fx)
{
    FLOAT e;

    e = (FLOAT) ((LONG) fx >> 4);
    e += ae16[fx & 0xF];

    return(e);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.