File:  [WindowsNT SDKs] / ntddk / src / print / pscript / pslayer.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:  PSLAYER.C
//
// Brief Description:  This module contains the PSCRIPT driver's layer
// of PostScript translation routines.
//
// Author:  Kent Settle (kentse)
// Created: 17-Dec-1990
//
// Copyright (c) 1990 - 1992 Microsoft Corporation
//
// This module contains routines to handle the outputting of the PostScript
// language commands to the output channel.  One of the main functions of
// this pslayer is to help provide device independence, by shielding the
// output of the actual device resolution.  The NT PostScript driver will
// output all PostScript commands in POINTS space; that is 72 dots per inch.
// This is the default user coordinates for ALL PostScript printers, so we
// will use it.  As far as the DDI is concerned, it only knows of the actual
// device resolution.  This pslayer will convert between device coordinates
// and the PostScript user coordinates.
//
// Coordinates will be output to the device using PS_FIX (24.8) numbers.
// It may be useful, therefore to note the following relations using
// PS_FIX numbers.  PS_FIX / LONG = PS_FIX.  LONG * PS_FIX = PS_FIX.
// (PS_FIX * PS_FIX) >> 8 = PS_FIX.
//--------------------------------------------------------------------------

#include "pscript.h"
#include <memory.h>
#include "enable.h"

extern LONG iHipot(LONG, LONG);

//--------------------------------------------------------------------------
// VOID ps_setrgbcolor(pdev, pbgr)
// PDEVDATA        pdev;
// BGR_PAL_ENTRY  *pbgr;
//
// This routine is called by the driver to set the current color.  PostScript
// printers only know about the current color.    For example, if you are
// printing text in red and lines in blue, and you alternate printing text
// and a line, you also have to set the current color each time.
//
// For black and white devices the RGB color is converted to a gray scale
// between 0.0 (black) and 1.0 (white).
//
// Parameters:
//   pdev:
//     pointer to DEVDATA structure.
//
//   lColor:
//     RGB value of new color.
//
// Returns:
//   This function returns no value.
//
// History:
//   17-Dec-1990     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------


VOID ps_setrgbcolor(pdev, pbgr)
PDEVDATA        pdev;
BGR_PAL_ENTRY  *pbgr;
{
    PS_FIX psfxRed, psfxGreen, psfxBlue;
    PS_FIX psfxGray;

    // if the all colors to black flag is set, set all colors, except
    // white to black.

    if (pdev->psdm.dwFlags & PSDEVMODE_BLACK)
    {
        // if the last color was non-white and the new color is non-white,
        // or the last color was white and the new color is white, then
        // we want to leave the color alone.

        if (((pdev->cgs.ulColor != RGB_WHITE) && (*(ULONG *)pbgr != RGB_WHITE)) ||
            ((pdev->cgs.ulColor == RGB_WHITE) && (*(ULONG *)pbgr == RGB_WHITE)))
            return;

        // the color must be updated in the printer.

        if (*(ULONG *)pbgr == RGB_WHITE)
            PrintString(pdev, "1 g\n");
        else
            PrintString(pdev, "0 g\n");
    }
    else if (pdev->cgs.ulColor != *(ULONG *)pbgr)
    {
        // save the new color in the current graphics state structure.

        pdev->cgs.ulColor = *(ULONG *)pbgr;

        if (pdev->psdm.dm.dmColor == DMCOLOR_COLOR)
        {
            // each color component must be output to the printer
            // in the range from 0.0 to 1.0, so normalize to this
            // range by dividing by 255.

            psfxRed = LTOPSFX((ULONG)pbgr->bgrRed) / 255;
            psfxGreen = LTOPSFX((ULONG)pbgr->bgrGreen) / 255;
            psfxBlue = LTOPSFX((ULONG)pbgr->bgrBlue) / 255;

            // if each of the color components is equal, just output a
            // gray scale.  otherwise, output the RGB value.

	    if ((psfxRed == psfxGreen) && (psfxRed == psfxBlue))
	    {
		PrintPSFIX(pdev, 1, psfxRed);
                PrintString(pdev, " g\n");
	    }
	    else
	    {
		PrintPSFIX(pdev, 3, psfxRed, psfxGreen, psfxBlue);;
                PrintString(pdev, " r\n");
	    }
        }
        else
        {
            // convert the RGB color to a gray scale and output to the
            // printer.

            psfxGray = psfxRGBtoGray(pbgr);
	    PrintPSFIX(pdev, 1, psfxGray);
            PrintString(pdev, " g\n");
        }
    }
}


//--------------------------------------------------------------------------
// VOID ps_newpath(pdev)
// PDEVDATA    pdev;
//
// This routine is called by the driver to issue a newpath command to
// the printer.
//
// Parameters:
//   pdev:
//     pointer to DEVDATA structure.
//
// Returns:
//   This function returns no value.
//
// History:
//   18-Dec-1990     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

VOID ps_newpath(pdev)
PDEVDATA    pdev;
{
    if (pdev->cgs.dwFlags & CGS_PATHEXISTS)
    {
	PrintString(pdev, "n\n");

        // indicate that no path exists in the printer.

        pdev->cgs.dwFlags &= ~CGS_PATHEXISTS;
    }
}


//--------------------------------------------------------------------------
// BOOL ps_save(pdev, bgsave)
// PDEVDATA	pdev;
// BOOL	bgsave;
//
// This routine is called by the driver to save the current graphics state.
//
// Parameters:
//   pdev:
//     pointer to DEVDATA structure.
//
//   bgsave:
//     TRUE if to perform gsave instead of save.
//
// Returns:
//   This function returns no value.
//
// History:
//   18-Dec-1990     -by-     Kent Settle     (kentse)
//  Wrote it.
//   06-Nov-1991    -by-    Kent Settle     [kentse]
//  Rewrote it using linked list.
//--------------------------------------------------------------------------

BOOL ps_save(pdev, bgsave)
PDEVDATA	pdev;
BOOL 	bgsave;
{
    CGS    *pcgs;
    CGS    *pNew;
    DLFONT *pDLFont;

    // save the current graphics state in a linked list.

    // get pointer to beginning of gsave linked list.

    pcgs = pdev->pcgsSave;

    // move to the last entry in the list.

    if (pcgs)
    {
	while(pcgs->pcgsNext)
	    pcgs = pcgs->pcgsNext;
    }

    // allocate the new element of the linked list.

    if (!(pNew = (PCGS)HeapAlloc(pdev->hheap, 0, sizeof(CGS))))
    {
        RIP("PSCRIPT!ps_save: HeapAlloc for pNew failed.\n");
	return(FALSE);
    }

    // save the current graphics state in our new element.

    memcpy(pNew, &pdev->cgs, sizeof(CGS));

    // allocate a new set of DLFONT structures, then copy the existing ones
    // to the new ones.

    if (!(pNew->pDLFonts = (DLFONT *)HeapAlloc(pdev->hheap, 0,
                                              sizeof(DLFONT) * (pdev->iDLFonts + 1))))
    {
        RIP("PSCRIPT!ps_save: HeapAlloc for pDLFonts failed.\n");
        HeapFree(pdev->hheap, 0, (PVOID)pNew);
        return(FALSE);
    }

    pDLFont = pNew->pDLFonts;

    memcpy(pDLFont, pdev->cgs.pDLFonts, sizeof(DLFONT) * (pdev->iDLFonts));

    // clear out the last entry.

    pDLFont += pdev->iDLFonts;
    memset(pDLFont, 0, sizeof(DLFONT));

    // if this is first element in the list, set the pointer in our
    // pdev, else update list to point to new element.

    if (!pcgs)
	pdev->pcgsSave = pNew;
    else
	pcgs->pcgsNext = pNew;

    // initialize pointers in new element.

    pNew->pcgsPrev = pcgs;  // NULL if first gsave.
    pNew->pcgsNext = NULL;

    // output save command to printer.

    if (bgsave)
	PrintString(pdev, "gs\n");
    else
	PrintString(pdev, "save\n");

    return(TRUE);
}


//--------------------------------------------------------------------------
// BOOL ps_restore(pdev, bgrestore)
// PDEVDATA	pdev;
// BOOL	bgrestore;
//
// This routine is called by the driver to restore a previously saved
// graphics state.
//
// Parameters:
//   pdev:
//     pointer to DEVDATA structure.
//
// Returns:
//   This function returns no value.
//
// History:
//   18-Dec-1990     -by-     Kent Settle     (kentse)
//  Wrote it.
//   06-Nov-1991    -by-    Kent Settle     [kentse]
//  Rewrote it using linked list.
//   15-Feb-1993    -by-    Rob Kiesler
//  If a restore is being performed, reset pdev flags indicating that
//  the Adobe PS utility, pattern, and image procsets have been downloaded.
//--------------------------------------------------------------------------

BOOL ps_restore(pdev, bgrestore)
PDEVDATA	pdev;
BOOL 	bgrestore;
{
    CGS    *pcgs;
    CGS    *pcgsTmp;
    DLFONT *pDLFont;

    // restore the current graphics state from the last element
    // of the graphics state save linked list.

    // get pointer to the linked list.

    pcgs = pdev->pcgsSave;

    // find the last element of the list.

    while (pcgs->pcgsNext)
	pcgs = pcgs->pcgsNext;

    // we are about to copy the last saved CGS from the linked list into the
    // current CGS.  therefore, we must free up memory used in the CGS before
    // we clobber the pointers.

    if  (pdev->cgs.pDLFonts)
    {
        // point to the last DLFONT structure.  this will have been filled
        // in iff we have hit our downloaded font threshold.  if it is filled
        // in, free up the hglyph vector.

        pDLFont = pdev->cgs.pDLFonts;
        pDLFont += pdev->iDLFonts;

        if (pDLFont->phgVector)
            HeapFree(pdev->hheap, 0, (PVOID)pDLFont->phgVector);

        HeapFree(pdev->hheap, 0, (PVOID)pdev->cgs.pDLFonts);
    }

    // restore the current graphics state.

    memcpy(&pdev->cgs, pcgs, sizeof(CGS));

    // back up one element, and free up the last element of the list.

    if (!(pcgsTmp = pcgs->pcgsPrev))
    {
	// restored back to original state.  clear out pointer to
	// linked list.

	pdev->pcgsSave = (CGS *)NULL;
    }
    else
    {
	// mark the current element as the last in the list.

	pcgsTmp->pcgsNext = (PCGS)NULL;
    }

    // free up the save CGS.

    HeapFree(pdev->hheap, 0, (PVOID)pcgs);

    if (bgrestore)
	PrintString(pdev, "gr\n");
    else
    {
      //
      // If the Adobe PS Utilites were downloaded, clean up after
      // them before blowing them away with the restore.
      //
      if (pdev->dwFlags & PDEV_UTILSSENT)
      {
         PrintString(pdev, "Adobe_WinNT_Driver_Gfx dup /terminate get exec\n");
         pdev->dwFlags &= ~(PDEV_UTILSSENT | PDEV_BMPPATSENT | PDEV_IMAGESENT);
      }
      PrintString(pdev, "restore\n");

    }

    return(TRUE);
}


//--------------------------------------------------------------------------
// VOID ps_clip(pdev, bWinding)
// PDEVDATA	pdev;
// BOOL	bWinding;
//
// This routine is called by the driver to intersect the current path with
// the clipping path and make this the nwe clipping path.  The winding
// number rule is used to determine the area clipped, if bWinding is TRUE.
//
// Parameters:
//   pdev:
//     pointer to DEVDATA structure.
//
// Returns:
//   This function returns no value.
//
// History:
//   13-Feb-1991     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

VOID ps_clip(pdev, bWinding)
PDEVDATA    pdev;
BOOL	    bWinding;
{
    // output the clip command to the printer, then output a newpath
    // command, since the clip command does not destroy the path in the
    // printer.

    if (bWinding)
	PrintString(pdev, "clip n\n");
    else
	PrintString(pdev, "eoclip n\n");

    // indicate that the path no longer exists.

    pdev->cgs.dwFlags &= ~CGS_PATHEXISTS;
}


//--------------------------------------------------------------------------
// VOID ps_show(pdev, pstro, flAccel, pdata)
// PDEVDATA    pdev;
// STROBJ     *pstro;
// FLONG       flAccel;
// TEXTDATA   *pdata;
//
// This routine is called by the driver to intersect the current path with
// the clipping path and make this the nwe clipping path.  The winding
// number rule is used to determine the area clipped, if bWinding is TRUE.
//
// Parameters:
//   pdev:
//     pointer to DEVDATA structure.
//
// Returns:
//   This function returns no value.
//
// History:
//   13-Feb-1991     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

VOID ps_show(pdev, pstro, flAccel, pdata)
PDEVDATA    pdev;
STROBJ     *pstro;
FLONG       flAccel;
TEXTDATA   *pdata;
{
    // close the string and send out the show command, abreviated
    // by 't', or our version of the fixed pitched horizontal
    // show command 'H', or the proportional horizontal show
    // command 'h', or the fixed pitched vertical show command 'V',
    // or the proportional vertical show command 'v'.

    if ((flAccel == 0) || (flAccel & SO_FLAG_DEFAULT_PLACEMENT) ||
        (pstro->cGlyphs == 1))
        PrintString(pdev, ")t\n");
    else if (flAccel & SO_HORIZONTAL)
    {
        if (pstro->ulCharInc)
            PrintString(pdev, ")H\n");
        else
        {
            if (pdata->bJustification)
            {
                // if we calculated the text justification, and it turns
                // out the the justification widths are zero, just to
                // a reguluar show command, otherwise it is time for
                // awidthshow.

                if ((pdata->ptSpace.x == 0) && (pdata->ptNonSpace.x == 0))
                    PrintString(pdev, ")t\n");
                else
                    PrintString(pdev, ")aw\n");
            }
            else
                PrintString(pdev, ")h\n");
        }
    }
    else
    {
        if (pstro->ulCharInc)
            PrintString(pdev, ")V\n");
        else
            PrintString(pdev, ")v\n");
    }
}


//--------------------------------------------------------------------------
// VOID ps_box(pdev, prectl)
// PDEVDATA    pdev;
// PRECTL    prectl;
//
// This routine is called by the driver to send box drawing commands to
// the printer.
//
// Parameters:
//   pdev:
//     Pointer to DEVDATA structure.
//
//   prectl:
//     Pointer to RECTL defining the box.
//
// Returns:
//   This function returns no value.
//
// History:
//   13-Feb-1991     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

VOID ps_box(pdev, prectl)
PDEVDATA pdev;
PRECTL     prectl;
{
    RECTPSFX   rectpsfx;

    // output the box command to the printer.  remember to convert
    // between device resolution and PostScript user coordinates.

    // get a local copy of the rectangle, turn it into FIX numbers,
    // flip over the y coordinates since 0,0 is upper left under NT, and
    // 0,0 is lower left under PostScript.

    rectpsfx.xLeft = X72DPI(prectl->left);
    rectpsfx.yBottom = Y72DPI(prectl->bottom);
    rectpsfx.xRight = X72DPI(prectl->right);
    rectpsfx.yTop = Y72DPI(prectl->top);

    PrintPSFIX(pdev, 4, rectpsfx.xLeft, rectpsfx.yTop,
	       rectpsfx.xRight, rectpsfx.yBottom);
    PrintString(pdev, " box\n");

    // indicate that a path now exists.

    pdev->cgs.dwFlags |= CGS_PATHEXISTS;
}


//--------------------------------------------------------------------------
// VOID ps_moveto(pdev, pptl)
// PDEVDATA    pdev;
// PPOINTL    pptl;
//
// This routine is called by the driver to update the current position
// in the printer.
//
// Parameters:
//   pdev:
//     Pointer to DEVDATA structure.
//
//   pptl:
//     Pointer to PPOINTL defining new current position.
//
// Returns:
//   This function returns no value.
//
// History:
//   26-Apr-1991     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

VOID ps_moveto(pdev, pptl)
PDEVDATA     pdev;
PPOINTL      pptl;
{
    POINTPSFX  ptpsfx;

    // output the moveto command if new position is different from
    // the old position.  remember to flip from top to bottom, since
    // under NT 0,0 is top left, and under PostScript 0,0 is bottom left.
    // also, we should output a moveto command even if we are at the
    // current location, if a path does not exist.

    if ((pptl->x != pdev->cgs.ptlCurPos.x) ||
        (pptl->y != pdev->cgs.ptlCurPos.y) ||
        (!(pdev->cgs.dwFlags & CGS_PATHEXISTS)))
    {
	ptpsfx.x = X72DPI(pptl->x);
	ptpsfx.y = Y72DPI(pptl->y);

        // output PostScript user coordinates to the printer.

	PrintPSFIX(pdev, 2, ptpsfx.x, ptpsfx.y);
        PrintString(pdev, " M\n");

        // save the new current position in device coordinates.

        pdev->cgs.ptlCurPos = *pptl;

        // state that a path now exists in the printer.

        pdev->cgs.dwFlags |= CGS_PATHEXISTS;
    }
}


//--------------------------------------------------------------------------
// VOID ps_showpage(pdev)
// PDEVDATA    pdev;
//
// This routine issues a showpage command to the printer, and resets
// the current graphics state (which is done in the printer by the
// showpage command).
//
// Parameters:
//   pdev:
//     Pointer to DEVDATA structure.
//
// Returns:
//   This function returns no value.
//
// History:
//   01-May-1991     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

VOID ps_showpage(pdev)
PDEVDATA    pdev;
{
    // output the eject command to the printer.

    PrintString(pdev, "showpage\n");

    init_cgs(pdev);
}


//--------------------------------------------------------------------------
// VOID init_cgs(pdev)
// PDEVDATA    pdev;
//
// This routine is called to reset the current graphics state.
//
// Parameters:
//   pdev:
//     Pointer to DEVDATA structure.
//
// Returns:
//   This function returns no value.
//
// History:
//   01-May-1991     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

VOID init_cgs(pdev)
PDEVDATA    pdev;
{
    PCGS    pcgs;
    DWORD   i;
    DLFONT *pDLFont, *pDLFontSave;

    pcgs = &pdev->cgs;

    // save pointer to DLFONT structures.

    pDLFont = pdev->cgs.pDLFonts;
    pDLFontSave = pDLFont;

    // if any downloaded fonts currently exist, free up their memory.

    if (pDLFont)
    {
        for (i = 0; i < pcgs->cDownloadedFonts; i++)
        {
            if (pDLFont->phgVector)
                HeapFree(pdev->hheap, 0, (PVOID)pDLFont->phgVector);

            pDLFont++;
        }
    }

    // clear all the softfont downloading bits, if any softfonts.

    if (pcgs->pSFArray)
	memset(pcgs->pSFArray, 0, ((pdev->cSoftFonts + 7) / 8));

    // initialize the entire structure to zero, then fill in the
    // elements we care about.

    memset(pcgs, 0, sizeof(CGS));

    pcgs->lineattrs.fl = LA_GEOMETRIC;
    pcgs->lineattrs.iJoin = JOIN_MITER;
    pcgs->lineattrs.iEndCap = ENDCAP_BUTT;
    pcgs->psfxLineWidth = 0;
    pcgs->lineattrs.eMiterLimit = (FLOAT)10.0;
    pcgs->ulColor = RGB_BLACK;
    pcgs->FontXform.eM11 = (float)1.0;
    pcgs->FontXform.eM22 = (float)1.0;
    pcgs->GeoLineXform.eM11 = (float)1.0;
    pcgs->GeoLineXform.eM22 = (float)1.0;
    pcgs->psfxScaleFactor = LTOPSFX(10L);

    // restore pointer to DLFONT structures.

    pcgs->pDLFonts = pDLFontSave;
}


//--------------------------------------------------------------------------
// VOID ps_stroke(pdev, pbo, pptl)
// PDEVDATA    pdev;
// BRUSHOBJ   *pbo;
// PPOINTL     pptl;
//
// This routine is called to stroke the current path.
//
// Parameters:
//   pdev:
//     Pointer to DEVDATA structure.
//
//   pbo:
//     Pointer to BRUSHOBJ to use for stroking.
//
//   pptl:
//     Pointer to POINTL to use for brush origin.
//
// Returns:
//   This function returns no value.
//
// History:
//   03-May-1991     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

VOID ps_stroke(pdev, pbo, pptl)
PDEVDATA    pdev;
BRUSHOBJ   *pbo;
PPOINTL     pptl;
{
    UNREFERENCED_PARAMETER(pptl);

    // stroke the path if it exists.

    if (pdev->cgs.dwFlags & CGS_PATHEXISTS)
    {
        //!!! check into a path buffer.  - kentse.

	PrintString(pdev, "s\n");
    }
#if DBG
    else
        DbgPrint("PSCRIPT!ps_stroke: stroking a non-existent path.\n");
#endif

    // the path gets destroyed in the printer, when it is stroked, so
    // mark it as such.

    pdev->cgs.dwFlags &= ~CGS_PATHEXISTS;
}


//--------------------------------------------------------------------------
// VOID ps_lineto(pdev, pptl)
// PDEVDATA    pdev;
// PPOINTL    pptl;
//
// This routine is called by the driver to output a lineto command, as
// well as update the current position.
//
// Parameters:
//   pdev:
//     Pointer to DEVDATA structure.
//
//   pptl:
//     Pointer to PPOINTL defining new current position.
//
// Returns:
//   This function returns no value.
//
// History:
//   03-May-1991     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

VOID ps_lineto(pdev, pptl)
PDEVDATA     pdev;
PPOINTL      pptl;
{
    POINTPSFX   ptpsfx;

    // output the lineto command and set the new current position in
    // the printer.  remember to flip from top to bottom, since
    // under NT 0,0 is top left, and under PostScript 0,0 is bottom left.

    if ((pptl->x != pdev->cgs.ptlCurPos.x) ||
        (pptl->y != pdev->cgs.ptlCurPos.y))
    {
	ptpsfx.x = X72DPI(pptl->x);
	ptpsfx.y = Y72DPI(pptl->y);

        // output the lineto command using PostScript user coordinates,
        // then update the current position.

	PrintPSFIX(pdev, 2, ptpsfx.x, ptpsfx.y);
        PrintString(pdev, " L\n");

        // save the new current position in device coordinates.

        pdev->cgs.ptlCurPos = *pptl;

        // mark that we do indeed have a path.

        pdev->cgs.dwFlags |= CGS_PATHEXISTS;
    }
}


//--------------------------------------------------------------------------
// VOID ps_curveto(pdev, pptl, pptl1, pptl2)
// PDEVDATA  pdev;
// PPOINTL   pptl;
// PPOINTL   pptl1;
// PPOINTL   pptl2;
//
// This routine is called by the driver to output a curveto command as well
// as update the current position.
//
// Parameters:
//   pdev:
//     Pointer to DEVDATA structure.
//
//   pptl, pptl1, pptl2:
//     Pointer to PPOINTLs defining the bezier curve to output.
//
// Returns:
//   This function returns no value.
//
// History:
//   03-May-1991     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

VOID ps_curveto(pdev, pptl, pptl1, pptl2)
PDEVDATA     pdev;
PPOINTL      pptl;
PPOINTL      pptl1;
PPOINTL      pptl2;
{
    POINTPSFX   ptpsfx;
    POINTPSFX   ptpsfx1;
    POINTPSFX   ptpsfx2;

    // output the curveto command and set the new current position in
    // the printer.  remember to flip from top to bottom, since
    // under NT 0,0 is top left, and under PostScript 0,0 is bottom left.

    ptpsfx.x = X72DPI(pptl->x);
    ptpsfx.y = Y72DPI(pptl->y);
    ptpsfx1.x = X72DPI(pptl1->x);
    ptpsfx1.y = Y72DPI(pptl1->y);
    ptpsfx2.x = X72DPI(pptl2->x);
    ptpsfx2.y = Y72DPI(pptl2->y);

    // output the curveto command using PostScript user coordinates,
    // then update the current position to be the last point on the curve.

    PrintPSFIX(pdev, 6, ptpsfx.x, ptpsfx.y, ptpsfx1.x, ptpsfx1.y,
	       ptpsfx2.x, ptpsfx2.y);
    PrintString(pdev, " c\n");

    // save the new current position in device coordinates.

    pdev->cgs.ptlCurPos = *pptl2;

    // mark that we do indeed have a path.

    pdev->cgs.dwFlags |= CGS_PATHEXISTS;

    return;
}


//--------------------------------------------------------------------------
// VOID ps_fill(pdev, flFillMode)
// PDEVDATA  pdev;
// FLONG     flFillMode;
//
// This routine is called by the driver to output a fill command to
// the printer.
//
// Parameters:
//   pdev:
//     Pointer to DEVDATA structure.
//
// Returns:
//   This function returns no value.
//
// History:
//   03-May-1991     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

VOID ps_fill(pdev, flFillMode)
PDEVDATA pdev;
FLONG    flFillMode;
{
    // output the fill command if we have an existing path.

    if (pdev->cgs.dwFlags & CGS_PATHEXISTS)
    {
        //!!! check into path buffer.  - kentse.

        if (flFillMode & FP_WINDINGMODE)
        {
            // output the PostScript fill command to do a winding mode fill.

	    PrintString(pdev, "f\n");
        }
        else
        {
            // output the PostScript eofill command to do an even odd, or
            // alternate fill.

	    PrintString(pdev, "e\n");
        }

        // the fill operator deletes the path, so mark it as such.

        pdev->cgs.dwFlags &= ~CGS_PATHEXISTS;
    }
#if DBG
    else
        DbgPrint("PSCRIPT!ps_fill: filling non-existent path.\n");
#endif
}


//--------------------------------------------------------------------------
// VOID ps_closepath(pdev)
// PDEVDATA    pdev;
//
// This routine is called to close the current path.
//
// Parameters:
//   pdev:
//     Pointer to DEVDATA structure.
//
// Returns:
//   This function returns no value.
//
// History:
//   03-May-1991     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

VOID ps_closepath(pdev)
PDEVDATA    pdev;
{
    // if a path exists, close it.

    if (pdev->cgs.dwFlags & CGS_PATHEXISTS)
	PrintString(pdev, "cp\n");
}


//--------------------------------------------------------------------------
// PS_FIX psfxRGBtoGray(pbgr)
// BGR_PAL_ENTRY  *pbgr;
//
// This routine is called to convert an RGB value to a gray scale.
//
// Parameters:
//   ppe:
//     pointer to PALETTEENTRY color to convert.
//
// Returns:
//   This function returns PS_FIX gray scale value.
//
// History:
//   21-May-1991     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------


PS_FIX psfxRGBtoGray(pbgr)
BGR_PAL_ENTRY  *pbgr;
{
    PS_FIX  psfxRed, psfxGreen, psfxBlue, psfxGray;

    // The gray value is computed as a normalized average of the
    // three color components.  The resultant gray level should
    // range from 0.0 to 1.0

    psfxRed = (ULONG)pbgr->bgrRed * PSFXPERCENT_RED;
    psfxGreen = (ULONG)pbgr->bgrGreen * PSFXPERCENT_GREEN;
    psfxBlue = (ULONG)pbgr->bgrBlue * PSFXPERCENT_BLUE;

    psfxGray = (PS_FIX)((psfxRed + psfxGreen + psfxBlue) / 255);

    return (psfxGray);
}


//--------------------------------------------------------------------------
// VOID ps_setlinewidth(pdev, psfxLineWidth)
// PDEVDATA     pdev;
// PS_FIX       psfxLineWidth;
//
// This routine is called by the driver to set the current geometric linewidth.
// The line width is specified in USER coordinates (1/72 inch).
//
// Parameters:
//   pdev:
//     pointer to DEVDATA structure.
//
//   psfxLineWidth:
//     linewidth to set.
//
// Returns:
//   This function returns no value.
//
// History:
//   05-July-1991       -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

VOID ps_setlinewidth(pdev, psfxLineWidth)
PDEVDATA        pdev;
PS_FIX          psfxLineWidth;
{
    // only update the linewidth if the new value differs from the old.

    if (pdev->cgs.psfxLineWidth != psfxLineWidth)
    {
        // update the linewidth in our current graphics state.

        pdev->cgs.psfxLineWidth = psfxLineWidth;

        // update the printer's linewidth.

	PrintPSFIX(pdev, 1, psfxLineWidth);
        PrintString(pdev, " sl\n");
    }

    return;
}


//--------------------------------------------------------------------------
// BOOL ps_setlineattrs(pdev, plineattrs, pxo)
// PDEVDATA    pdev;
// PLINEATTRS  plineattrs;
// XFORMOBJ   *pxo;
//
// This routine is called by the driver to set the current line attributes.
//
// Parameters:
//   pdev:
//     pointer to DEVDATA structure.
//
//   plineattrs:
//     line attributes to set.
//
// Returns:
//   This function returns no value.
//
// History:
//   19-Mar-1992        -by-    Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

BOOL ps_setlineattrs(pdev, plineattrs, pxo)
PDEVDATA    pdev;
PLINEATTRS  plineattrs;
XFORMOBJ   *pxo;
{
    ULONG   iJoin;
    ULONG   iEndCap;
    PS_FIX  psfxMiterLimit;
    PS_FIX  psfxStyle, psfxScale;
    PS_FIX  psfxWidth;
    BOOL    bDiffer;
    DWORD   i;
    FLOAT  *pfloat1;
    FLOAT  *pfloat2;
    LONG   *plong1;
    LONG   *plong2;

    // there are several line attributes which have meaning for a
    // geometric line, but not for a cosmetic.  set each of them, if
    // necessary.

    if (plineattrs->fl & LA_GEOMETRIC)
    {
        // update the line join value, if it differs from the old one.

        if (plineattrs->iJoin != pdev->cgs.lineattrs.iJoin)
        {
            // update the line join value in our current graphics state.

            pdev->cgs.lineattrs.iJoin = plineattrs->iJoin;

            // update the printer's line join.

            switch (plineattrs->iJoin)
            {
                case JOIN_BEVEL:
                    iJoin = PSCRIPT_JOIN_BEVEL;
                    break;

                case JOIN_ROUND:
                    iJoin = PSCRIPT_JOIN_ROUND;
                    break;

                default:
                    iJoin = PSCRIPT_JOIN_MITER;
                    break;
            }

            PrintDecimal(pdev, 1, iJoin);
            PrintString(pdev, " j\n");
        }

        // update the end cap value, if it differs from the old one.

        if (plineattrs->iEndCap != pdev->cgs.lineattrs.iEndCap)
        {
            // update the end cap value in our current graphics state.

            pdev->cgs.lineattrs.iEndCap = plineattrs->iEndCap;

            // update the printer's end cap value.

            switch (plineattrs->iEndCap)
            {
                case ENDCAP_SQUARE:
                    iEndCap = PSCRIPT_ENDCAP_SQUARE;
                    break;

                case ENDCAP_ROUND:
                    iEndCap = PSCRIPT_ENDCAP_ROUND;
                    break;

                default:
                    iEndCap = PSCRIPT_ENDCAP_BUTT;
                    break;
            }

            PrintDecimal(pdev, 1, iEndCap);
            PrintString(pdev, " setlinecap\n");
        }

        // a miter limit less than one does not make sense.  rather than
        // returning an error in this case, just default to one.

        plineattrs->eMiterLimit = max(plineattrs->eMiterLimit, (FLOAT)1.0);

        // update the miter limit value, if it differs from the old one.

        if (plineattrs->eMiterLimit != pdev->cgs.lineattrs.eMiterLimit)
        {
            // update the miter limit value in our current graphics state.

            pdev->cgs.lineattrs.eMiterLimit = plineattrs->eMiterLimit;

            // update the printer's miter limit value.

            psfxMiterLimit = ETOPSFX(plineattrs->eMiterLimit);
            PrintPSFIX(pdev, 1, psfxMiterLimit);
            PrintString(pdev, " setmiterlimit\n");
        }

        // update the geometric line width, if it differs from the old one.
        // we use pdev->cgs.psfxLineWidth to check against rather than
        // pdev->cgs.lineattrs.elWidth.e since we need to set the line width
        // at times in the driver when we do not have access to the
        // current transform to go from WORLD to DEVICE coordinates.

        psfxWidth = (ETOPSFX(plineattrs->elWidth.e) * PS_RESOLUTION) /
                    pdev->psdm.dm.dmPrintQuality;

        if (psfxWidth != pdev->cgs.psfxLineWidth)
        {
            // update the line width value in our current graphics state.

            pdev->cgs.psfxLineWidth = psfxWidth;

            // update the printer's linewidth.  the linewidth is specified
            // in user coordinates.

            PrintPSFIX(pdev, 1, psfxWidth);
            PrintString(pdev, " sl\n");
        }

        // time to deal with the line style.  note:  we don't want to output
        // the style code unless something about the style has actually
        // changed.  specifically, only if the cStyle, elStyleState, or any element
        // of the array has changed will we output the code to change the
        // style.

        bDiffer = FALSE;    // assume style the same.

        if ((plineattrs->cstyle != pdev->cgs.lineattrs.cstyle) ||
            (plineattrs->elStyleState.e != pdev->cgs.lineattrs.elStyleState.e))
            bDiffer = TRUE;

        if (!bDiffer)
        {
            pfloat1 = (FLOAT *)plineattrs->pstyle;
            pfloat2 = (FLOAT *)pdev->cgs.lineattrs.pstyle;

#if DBG
            if ((plineattrs->cstyle == 0) && (plineattrs->pstyle != NULL))
            {
                RIP("PSCRIPT!ps_setlineattrs: cstyle == 0, but pstyle != NULL.\n");
                return(FALSE);
            }
#endif

            for (i = 0; i < plineattrs->cstyle; i++)
            {
                if (*pfloat1++ != *pfloat2++)
                {
                    bDiffer = TRUE;
                    break;
                }
            }
        }

        // now change the line style in the printer, if something about
        // it has changed.

        if (bDiffer)
        {
            // handle the solid line case.

            if ((plineattrs->pstyle == NULL) || (plineattrs->cstyle == 0))
                PrintString(pdev, "[]0 sd\n");
            else    // not a solid line.
            {
                PrintString(pdev, "[");

                pfloat1 = (FLOAT *)plineattrs->pstyle;

                for (i = 0; i < plineattrs->cstyle; i++)
                {
                    psfxStyle = LTOPSFX((ETOL(*pfloat1++)) * PS_RESOLUTION) /
			        pdev->psdm.dm.dmPrintQuality;

                    PrintPSFIX(pdev, 1, psfxStyle);
                    PrintString(pdev, " ");
                }

                PrintString(pdev, "]");

                // output the style state in user coordinates.

                psfxStyle = LTOPSFX((ETOL(plineattrs->elStyleState.e)) * PS_RESOLUTION) /
		                    pdev->psdm.dm.dmPrintQuality;

                PrintPSFIX(pdev, 1, psfxStyle);
                PrintString(pdev, " sd\n");
            }

            // something in the lineattrs may have changed, update the cgs.

            if (pdev->cgs.lineattrs.pstyle)
                HeapFree(pdev->hheap, 0, (PVOID)pdev->cgs.lineattrs.pstyle);

            pdev->cgs.lineattrs = *plineattrs;

            // allocate space to copy the style array to.

            if (!(pfloat1 = (FLOAT *)HeapAlloc(pdev->hheap, 0,
                                     sizeof(FLOAT) * plineattrs->cstyle)))
            {
                RIP("PSCRIPT!ps_setlineattrs: HeapAlloc for pfloat1 failed.\n");
                return(FALSE);
            }

            // copy the style array itself.

            pfloat2 = (FLOAT *)plineattrs->pstyle;
            pdev->cgs.lineattrs.pstyle = (PFLOAT_LONG)pfloat1;

            for (i = 0; i < plineattrs->cstyle; i++)
                *pfloat1++ = *pfloat2++;
        }
    }
    else    // cosmetic lines.
    {
        // now handle cosmetic lines.  iJoin, iEndCap and eMiterLimit make
        // no sense for cosmetic lines, so we won't worry about them.

        psfxWidth = LTOPSFX(plineattrs->elWidth.l * PS_RESOLUTION) /
	                    pdev->psdm.dm.dmPrintQuality;

        // update the cosmetic line width, if it differs from the old one.
        // we use pdev->cgs.psfxLineWidth to check against rather than
        // pdev->cgs.lineattrs.elWidth.e since we need to set the line width
        // at times in the driver when we do not have access to the
        // current transform to go from WORLD to DEVICE coordinates.

        if (psfxWidth != pdev->cgs.psfxLineWidth)
        {
            // update the line width value in our current graphics state.

            pdev->cgs.psfxLineWidth = psfxWidth;

            // update the printer's linewidth.  the linewidth is specified
            // in user coordinates.

            PrintPSFIX(pdev, 1, psfxWidth);
            PrintString(pdev, " sl\n");
        }

        // the LA_ALTERNATE linestyle is a special cosmetic line style, where
        // every other pel is on.  well, if we have a printer with 2500 dpi,
        // do we really want every other pel on?  i don't think so.  so,
        // for now at least, we will simply turn on every other user coordinate
        // pel.

        if (plineattrs->fl & LA_ALTERNATE)
        {
//!!! perhaps we really want to do a .5 setgray.  what about color.  -kentse.

            PrintString(pdev, "[1] ");
            psfxStyle = LTOPSFX(plineattrs->elStyleState.l * PS_RESOLUTION) /
                                pdev->psdm.dm.dmPrintQuality;

            PrintPSFIX(pdev, 1, psfxStyle);
            PrintString(pdev, " sd\n");
        }
        else
        {
            // time to deal with the line style.  note:  we don't want to output
            // the style code unless something about the style has actually
            // changed.  specifically, only if the cStyle, elStyleState, or any element
            // of the array has changed will we output the code to change the
            // style.

            bDiffer = FALSE;    // assume style the same.

            if ((plineattrs->cstyle != pdev->cgs.lineattrs.cstyle) ||
                (plineattrs->elStyleState.l != pdev->cgs.lineattrs.elStyleState.l))
                bDiffer = TRUE;

            if (!bDiffer)
            {
                plong1 = (LONG *)plineattrs->pstyle;
                plong2 = (LONG *)pdev->cgs.lineattrs.pstyle;

#if DBG
                if ((plineattrs->cstyle == 0) && (plineattrs->pstyle != NULL))
                {
                    RIP("PSCRIPT!ps_setlineattrs: cstyle == 0, but pstyle != NULL.\n");
                    return(FALSE);
                }
#endif

                for (i = 0; i < plineattrs->cstyle; i++)
                {
                    if (*plong1++ != *plong2++)
                    {
                        bDiffer = TRUE;
                        break;
                    }
                }
            }

            // now change the line style in the printer, if something about
            // it has changed.

            if (bDiffer)
            {
                // handle the solid line case.

                if ((plineattrs->pstyle == NULL) || (plineattrs->cstyle == 0))
                    PrintString(pdev, "[]0 sd\n");
                else    // not a solid line.
                {
                    PrintString(pdev, "[");

                    plong1 = (LONG *)plineattrs->pstyle;

                    // get style scaling factor.

                    psfxScale = LTOPSFX(pdev->psdm.dm.dmPrintQuality / 25);
                    psfxScale = (psfxScale * PS_RESOLUTION) /
                                pdev->psdm.dm.dmPrintQuality;

                    for (i = 0; i < plineattrs->cstyle; i++)
                    {
                        psfxStyle = (*plong1++) * psfxScale;

                        PrintPSFIX(pdev, 1, psfxStyle);
                        PrintString(pdev, " ");
                    }

                    PrintString(pdev, "]");
                    psfxStyle = plineattrs->elStyleState.l * psfxScale;

                    PrintPSFIX(pdev, 1, psfxStyle);
                    PrintString(pdev, " sd\n");
                }

                // something in the lineattrs may have changed, update the cgs.

                if (pdev->cgs.lineattrs.pstyle)
                    HeapFree(pdev->hheap, 0, (PVOID)pdev->cgs.lineattrs.pstyle);

                pdev->cgs.lineattrs = *plineattrs;

                // allocate space to copy the style array to.

                if (!(plong1 = (LONG *)HeapAlloc(pdev->hheap, 0,
                                         sizeof(LONG) * plineattrs->cstyle)))
                {
                    RIP("PSCRIPT!ps_setlineattrs: HeapAlloc for plong1 failed.\n");
                    return(FALSE);
                }

                // copy the style array itself.

                plong2 = (LONG *)plineattrs->pstyle;
                pdev->cgs.lineattrs.pstyle = (PFLOAT_LONG)plong1;

                for (i = 0; i < plineattrs->cstyle; i++)
                    *plong1++ = *plong2++;
            }
        }

    }

    return(TRUE);
}


//--------------------------------------------------------------------------
// VOID ps_geolinexform(pdev, plineattrs, pxo)
// PDEVDATA    pdev;
// PLINEATTRS  plineattrs;
// XFORMOBJ   *pxo;
//
// This routine is called by the driver to set the current line attributes.
//
// Parameters:
//   pdev:
//     pointer to DEVDATA structure.
//
//   plineattrs:
//     line attributes to set.
//
// Returns:
//   This function returns no value.
//
// History:
//   12-Mar-1993        -by-    Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

VOID ps_geolinexform(pdev, plineattrs, pxo)
PDEVDATA    pdev;
PLINEATTRS  plineattrs;
XFORMOBJ   *pxo;
{
    ULONG   ulComplexity;
    PS_FIX  psfxM11, psfxM12, psfxM21, psfxM22, psfxdx, psfxdy;

    // update the printer's geometric line width.  the line width
    // is given in WORLD coordinates for a geometric line.  it needs
    // to be transformed into DEVICE space.

    ulComplexity = XFORMOBJ_iGetXform(pxo, &pdev->cgs.GeoLineXform);

    // assume no transform will be done.

    pdev->cgs.dwFlags &= ~CGS_GEOLINEXFORM;

    switch(ulComplexity)
    {
        case GX_IDENTITY:
            // there will be nothing to do in this case.

            break;

        case GX_SCALE:
            // output scale command, rather than entire transform.

            psfxM11 = ETOPSFX(pdev->cgs.GeoLineXform.eM11);

            psfxM22 = ETOPSFX(pdev->cgs.GeoLineXform.eM22);

            // save the current CTM, then output the scale command.
            // DrvStrokePath and DrvStrokeAndFillPath are
            // responsible for restoring the CTM.

            PrintString(pdev, "CM ");
            PrintPSFIX(pdev, 2, psfxM11, psfxM22);
            PrintString(pdev, " scale\n");

            pdev->cgs.dwFlags |= CGS_GEOLINEXFORM;

            break;

        default:
            // output a general transform.

            psfxM11 = ETOPSFX(pdev->cgs.GeoLineXform.eM11);

            psfxM12 = ETOPSFX(pdev->cgs.GeoLineXform.eM12);

            psfxM21 = ETOPSFX(pdev->cgs.GeoLineXform.eM21);

            psfxM22 = ETOPSFX(pdev->cgs.GeoLineXform.eM22);

            psfxdx = ETOPSFX(pdev->cgs.GeoLineXform.eDx);

            psfxdy = ETOPSFX(pdev->cgs.GeoLineXform.eDy);

            // save the current CTM, then output the concat command.
            // DrvStrokePath and DrvStrokeAndFillPath are
            // responsible for restoring the CTM.

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

            pdev->cgs.dwFlags |= CGS_GEOLINEXFORM;

            break;
    }
}

//--------------------------------------------------------------------------
// VOID ps_begin_eps(pdev)
// VOID ps_end_eps(pdev)
//
// These routines are called by the driver to issue commands to bracket EPS
// files to the printer.  They conform to the Guidelines for Importing EPS
// Files version 3.0 by Adobe.
//
// Parameters:
//   pdev:
//     pointer to DEVDATA structure.
//
// Returns:
//   None.
//
// History:
//   Sat May 08 15:15:01 1993  	-by-	Hock San Lee	[hockl]
//  Wrote it.
//--------------------------------------------------------------------------

PSZ apszEPSProc[] =
    {
    "/BeginEPSF {/b4_Inc_state save def /dict_count countdictstack def",
    "/op_count count 1 sub def userdict begin /showpage {} def",
    "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin",
    "10 setmiterlimit [] 0 setdash newpath",
    "/languagelevel where {pop languagelevel 1 ne",
    "{false setstrokeadjust false setoverprint} if } if } bind def",
    "/EndEPSF {count op_count sub {pop} repeat",
    "countdictstack dict_count sub {end} repeat b4_Inc_state restore} bind def",
    NULL
    };

VOID ps_begin_eps(pdev)
PDEVDATA    pdev;
{
    PSZ        *ppsz;

    // emit the EPS procedures if necessary.

    if (!(pdev->cgs.dwFlags & CGS_EPS_PROC))
    {
        ppsz = apszEPSProc;
        while (*ppsz)
        {
            PrintString(pdev, *ppsz++);
            PrintString(pdev, "\n");
        }

        pdev->cgs.dwFlags |= CGS_EPS_PROC;
    }

    PrintString(pdev, "BeginEPSF\n");
}

VOID ps_end_eps(pdev)
PDEVDATA    pdev;
{
    if (!(pdev->cgs.dwFlags & CGS_EPS_PROC))
    {
        RIP("PSCRIPT!ps_end_eps: EndEPSF not defined.\n");
    }

    PrintString(pdev, "EndEPSF\n");
}

unix.superglobalmegacorp.com

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