mirror of https://github.com/lianthony/NT4.0
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.
1321 lines
35 KiB
1321 lines
35 KiB
//--------------------------------------------------------------------------
|
|
//
|
|
// 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"
|
|
|
|
extern LONG iHipot(LONG, LONG);
|
|
|
|
|
|
|
|
VOID
|
|
ps_setrgbcolor(
|
|
PDEVDATA pdev,
|
|
PSRGB *prgb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Select a new color into the current graphics state
|
|
|
|
Arguments:
|
|
|
|
pdev - Points to our DEVDATA structure
|
|
prgb - Specifies the new color to be selected
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
if (pdev->dm.dmPrivate.dwFlags & PSDEVMODE_BLACK) {
|
|
|
|
// If monochrome flag is set, map all non-white colors to black
|
|
|
|
if (*((ULONG *) prgb) == RGB_WHITE)
|
|
psputs(pdev, "1 g\n");
|
|
else
|
|
psputs(pdev, "0 g\n");
|
|
|
|
} else if (pdev->cgs.ulColor != *((ULONG *) prgb)) {
|
|
|
|
PS_FIX psfxRed, psfxGreen, psfxBlue;
|
|
|
|
// Save the new color in the current graphics state structure.
|
|
|
|
pdev->cgs.ulColor = *((ULONG *) prgb);
|
|
|
|
// Convert RGB values from integers in the range of 0-255
|
|
// to 24.8 fixed-point values:
|
|
// fixValue = (rgbValue << 8) / 255
|
|
//
|
|
// Here, we use a simpler formula here to achieve similar results.
|
|
|
|
psfxRed = prgb->red;
|
|
if (psfxRed > 128) psfxRed++;
|
|
|
|
psfxGreen = prgb->green;
|
|
if (psfxGreen > 128) psfxGreen++;
|
|
|
|
psfxBlue = prgb->blue;
|
|
if (psfxBlue > 128) psfxBlue++;
|
|
|
|
if (pdev->dm.dmPublic.dmColor == DMCOLOR_COLOR) {
|
|
|
|
// If all color components have equal value, just output a
|
|
// gray scale value. Otherwise, output the RGB value.
|
|
|
|
if (psfxRed == psfxGreen && psfxRed == psfxBlue) {
|
|
psprintf(pdev, "%f g\n", psfxRed);
|
|
} else {
|
|
psprintf(pdev, "%f %f %f r\n", psfxRed, psfxGreen, psfxBlue);
|
|
}
|
|
|
|
} else {
|
|
|
|
// Convert RGB color to grayscale using NTSC formula
|
|
// and output the grayscale value to the printer.
|
|
|
|
psprintf(pdev, "%f g\n", RgbToGray(psfxRed, psfxGreen, psfxBlue));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// 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;
|
|
{
|
|
psputs(pdev, "n\n");
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// BOOL ps_save(pdev, bgsave, bFontSave)
|
|
// PDEVDATA pdev;
|
|
// BOOL bgsave;
|
|
// BOOL bFontSave;
|
|
//
|
|
// 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.
|
|
// 21Oct94 un-wrote it pingw
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL ps_save(pdev, bgsave, bFontSave)
|
|
PDEVDATA pdev;
|
|
BOOL bgsave;
|
|
BOOL bFontSave;
|
|
{
|
|
CGS *pcgs;
|
|
CGS *pNew;
|
|
|
|
// save the current graphics state in a linked list.
|
|
|
|
// allocate the new element of the linked list.
|
|
|
|
if (!(pNew = HEAPALLOC(pdev->hheap, sizeof(CGS)))) {
|
|
|
|
DBGERRMSG("HEAPALLOC");
|
|
return(FALSE);
|
|
}
|
|
|
|
// save the current graphics state in our new element.
|
|
memcpy(pNew, &pdev->cgs, sizeof(CGS));
|
|
|
|
/* push pNew on linked list */
|
|
pNew->pcgsNext = pdev->pcgsSave;
|
|
pdev->pcgsSave = pNew;
|
|
|
|
// output save command to printer.
|
|
|
|
if (bgsave) {
|
|
|
|
pdev->cgs.dwFlags |= CGS_GSAVE;
|
|
psputs(pdev, "gs\n");
|
|
|
|
} else {
|
|
|
|
pdev->cgs.dwFlags &= ~CGS_GSAVE;
|
|
|
|
psprintf(pdev, "%s /%s save put\n",
|
|
PROCSETNAME, bFontSave ? "FontSV" : "PageSV");
|
|
|
|
if (! (pdev->cgs.pFontFlags =
|
|
BitArrayDuplicate(pdev->hheap, pdev->cgs.pFontFlags)))
|
|
{
|
|
DBGERRMSG("BitArrayDuplicate");
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
void FlushFonts(PDEVDATA pdev)
|
|
{
|
|
DLFONT *pDLFont;
|
|
DWORD i;
|
|
PCGS pcgs;
|
|
|
|
pcgs = &pdev->cgs;
|
|
|
|
// if any downloaded fonts currently exist, free up their memory.
|
|
pDLFont = pdev->pDLFonts;
|
|
for (i = 0; i < pdev->cDownloadedFonts; i++) {
|
|
|
|
if (pDLFont->phgVector) {
|
|
HEAPFREE(pdev->hheap, pDLFont->phgVector);
|
|
}
|
|
|
|
pDLFont++;
|
|
}
|
|
// initialize the DLFONT array.
|
|
memset(pdev->pDLFonts, 0, sizeof(DLFONT) * pdev->cDownloadedFonts);
|
|
|
|
// This seems to be an overkill! We should restore to the same state
|
|
// when the font-restore was done instead of flushing everything.
|
|
// Leave it alone for now to minimize risks.
|
|
|
|
BitArrayClearAll(pcgs->pFontFlags);
|
|
|
|
pdev->cDownloadedFonts = 0;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// BOOL ps_restore()
|
|
|
|
// This routine is called by the driver to restore a previously saved
|
|
// 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.
|
|
// 21Oct94 un-wrote it pingw
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL ps_restore(pdev, bgrestore, bFontRestore)
|
|
PDEVDATA pdev;
|
|
BOOL bgrestore;
|
|
BOOL bFontRestore;
|
|
{
|
|
CGS *pcgsTmp;
|
|
|
|
// If doing a page restore, then force a font restore first
|
|
|
|
if (! bgrestore && ! bFontRestore &&
|
|
pdev->cDownloadedFonts > 0 && ! ps_restore(pdev, FALSE, TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Guard against stack underflow
|
|
|
|
if (! pdev->pcgsSave) {
|
|
|
|
DBGMSG(DBG_LEVEL_ERROR, "Graphics state stack underflow\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (bgrestore) {
|
|
|
|
// grestore
|
|
|
|
if (! (pdev->cgs.dwFlags & CGS_GSAVE)) {
|
|
|
|
DBGMSG(DBG_LEVEL_ERROR, "grestore without matching gsave\n");
|
|
return FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
// restore (page or font) - Find the first non-gsaved graphics
|
|
// state object on the stack. This is to deal with unbalanced
|
|
// gsave/grestore pairs.
|
|
|
|
while (pdev->cgs.dwFlags & CGS_GSAVE) {
|
|
|
|
DBGMSG(DBG_LEVEL_ERROR, "gsave without matching grestore\n");
|
|
if (! ps_restore(pdev, TRUE, FALSE))
|
|
return FALSE;
|
|
}
|
|
|
|
if (! pdev->pcgsSave)
|
|
return FALSE;
|
|
|
|
// Free up memory occupied by PS font flags
|
|
|
|
if (pdev->cgs.pFontFlags) {
|
|
|
|
HEAPFREE(pdev->hheap, pdev->cgs.pFontFlags);
|
|
pdev->cgs.pFontFlags = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// Pop off the current graphics state and restore the saved one
|
|
|
|
pcgsTmp = pdev->pcgsSave;
|
|
pdev->cgs = *pcgsTmp;
|
|
pdev->pcgsSave = pcgsTmp->pcgsNext;
|
|
HEAPFREE(pdev->hheap, pcgsTmp);
|
|
|
|
if (bgrestore)
|
|
psputs(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) {
|
|
|
|
psputs(pdev, "Adobe_WinNT_Driver_Gfx dup /terminate get exec\n");
|
|
pdev->dwFlags &= ~(PDEV_UTILSSENT|PDEV_BMPPATSENT|PDEV_IMAGESENT);
|
|
}
|
|
|
|
if (bFontRestore) {
|
|
psputs(pdev, "FontSV restore\n");
|
|
FlushFonts(pdev);
|
|
} else {
|
|
psputs(pdev, "PageSV 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(PDEVDATA pdev, BOOL bWinding)
|
|
{
|
|
if (bWinding)
|
|
psputs(pdev, "clip\n");
|
|
else
|
|
psputs(pdev, "eoclip\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(PDEVDATA pdev, PRECTL prectl, BOOL doclip)
|
|
{
|
|
// output the box command to the printer.
|
|
|
|
psputint(pdev, 4,
|
|
prectl->right - prectl->left,
|
|
prectl->bottom - prectl->top,
|
|
prectl->left,
|
|
prectl->top);
|
|
if (doclip)
|
|
psputs(pdev, " CB\n");
|
|
else
|
|
psputs(pdev, " B\n");
|
|
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// 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;
|
|
{
|
|
psprintf(pdev, "%d %d M\n", pptl->x, pptl->y);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// 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.
|
|
|
|
psputs(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;
|
|
|
|
pcgs = &pdev->cgs;
|
|
|
|
pcgs->dwFlags = 0;
|
|
|
|
memset(&pcgs->lineattrs, 0, sizeof (LINEATTRS));
|
|
pcgs->lineattrs.fl = LA_GEOMETRIC;
|
|
pcgs->lineattrs.iJoin = JOIN_MITER;
|
|
pcgs->lineattrs.iEndCap = ENDCAP_BUTT;
|
|
pcgs->lineattrs.eMiterLimit = (FLOAT) 10.0;
|
|
|
|
pcgs->psfxLineWidth = 0;
|
|
|
|
pcgs->ulColor = RGB_BLACK;
|
|
|
|
/* It is not necessary to reset font at initgraphics, but does not hurt */
|
|
pcgs->lidFont = 0;
|
|
pcgs->fontsubFlag = FALSE;
|
|
pcgs->szFont[0] = '\0';
|
|
|
|
memset(&pcgs->FontXform, 0, sizeof (XFORM));
|
|
pcgs->FontXform.eM11 = (FLOAT) 1.0;
|
|
pcgs->FontXform.eM22 = (FLOAT) 1.0;
|
|
pcgs->fwdEmHeight = 0;
|
|
memset(&pcgs->GeoLineXform, 0, sizeof (XFORM));
|
|
pcgs->GeoLineXform.eM11 = (FLOAT) 1.0;
|
|
pcgs->GeoLineXform.eM22 = (FLOAT) 1.0;
|
|
pcgs->psfxScaleFactor = LTOPSFX(10L);
|
|
memset(&pcgs->FontRemap, 0, sizeof (FREMAP));
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// VOID ps_stroke(pdev)
|
|
// PDEVDATA pdev;
|
|
//
|
|
// This routine is called to stroke 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_stroke(PDEVDATA pdev)
|
|
{
|
|
psputs(pdev, "s\n");
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// 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;
|
|
{
|
|
// output the lineto command.
|
|
|
|
psprintf(pdev, "%d %d L\n", pptl->x, pptl->y);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// 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;
|
|
{
|
|
// output the curveto command, then update the current position
|
|
// to be the last point on the curve.
|
|
|
|
psputint(pdev, 6,
|
|
pptl->x, pptl->y, pptl1->x, pptl1->y,
|
|
pptl2->x, pptl2->y);
|
|
psputs(pdev, " c\n");
|
|
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// 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;
|
|
{
|
|
|
|
if (flFillMode & FP_WINDINGMODE)
|
|
{
|
|
// output the PostScript fill command to do a winding mode fill.
|
|
|
|
psputs(pdev, "f\n");
|
|
}
|
|
else
|
|
{
|
|
// output the PostScript eofill command to do an even odd, or
|
|
// alternate fill.
|
|
|
|
psputs(pdev, "e\n");
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// 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;
|
|
{
|
|
psputs(pdev, "cp\n");
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// 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.
|
|
|
|
psprintf(pdev, "%f sl\n", psfxLineWidth);
|
|
}
|
|
|
|
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;
|
|
FLOATOBJ flo;
|
|
PFLOAT_LONG pfl1, pfl2;
|
|
|
|
// 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;
|
|
}
|
|
|
|
psprintf(pdev, "%d j\n", iJoin);
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
psprintf(pdev, "%d setlinecap\n", iEndCap);
|
|
}
|
|
|
|
// a miter limit less than one does not make sense. rather than
|
|
// returning an error in this case, just default to one.
|
|
|
|
FLOATOBJ_SetFloat(&flo, plineattrs->eMiterLimit);
|
|
if (FLOATOBJ_LessThanLong(&flo, 1))
|
|
plineattrs->eMiterLimit = (FLOAT) 1.0;
|
|
|
|
// update the miter limit value, if it differs from the old one.
|
|
|
|
FLOATOBJ_SetFloat(&flo, plineattrs->eMiterLimit);
|
|
FLOATOBJ_SubFloat(&flo, pdev->cgs.lineattrs.eMiterLimit);
|
|
|
|
if (! FLOATOBJ_EqualLong(&flo, 0)) {
|
|
|
|
// 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);
|
|
psprintf(pdev, "%f setmiterlimit\n", psfxMiterLimit);
|
|
}
|
|
|
|
// 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);
|
|
|
|
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.
|
|
|
|
psprintf(pdev, "%f sl\n", psfxWidth);
|
|
}
|
|
|
|
// 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.
|
|
|
|
FLOATOBJ_SetFloat(&flo, plineattrs->elStyleState.e);
|
|
FLOATOBJ_SubFloat(&flo, pdev->cgs.lineattrs.elStyleState.e);
|
|
|
|
bDiffer = (plineattrs->cstyle != pdev->cgs.lineattrs.cstyle) ||
|
|
! FLOATOBJ_EqualLong(&flo, 0);
|
|
|
|
if (!bDiffer)
|
|
{
|
|
pfl1 = plineattrs->pstyle;
|
|
pfl2 = pdev->cgs.lineattrs.pstyle;
|
|
|
|
#if DBG
|
|
|
|
if ((plineattrs->cstyle == 0) && (plineattrs->pstyle != NULL))
|
|
{
|
|
DBGMSG(DBG_LEVEL_ERROR, "cstyle = 0, but pstyle != NULL.\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
#endif
|
|
|
|
for (i = 0; i < plineattrs->cstyle; i++)
|
|
{
|
|
FLOATOBJ_SetFloat(&flo, pfl1->e);
|
|
FLOATOBJ_SubFloat(&flo, pfl2->e);
|
|
pfl1++;
|
|
pfl2++;
|
|
|
|
if (! FLOATOBJ_EqualLong(&flo, 0))
|
|
{
|
|
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))
|
|
psputs(pdev, "[]0 sd\n");
|
|
else // not a solid line.
|
|
{
|
|
psputs(pdev, "[");
|
|
|
|
pfl1 = plineattrs->pstyle;
|
|
|
|
for (i = 0; i < plineattrs->cstyle; i++)
|
|
{
|
|
psfxStyle = ETOPSFX(pfl1->e);
|
|
pfl1++;
|
|
|
|
psprintf(pdev, "%f ", psfxStyle);
|
|
}
|
|
|
|
psputs(pdev, "]");
|
|
|
|
// output the style state in user coordinates.
|
|
|
|
psfxStyle = ETOPSFX(plineattrs->elStyleState.e);
|
|
|
|
psprintf(pdev, "%f sd\n", psfxStyle);
|
|
}
|
|
|
|
// something in the lineattrs may have changed, update the cgs.
|
|
|
|
if (pdev->cgs.lineattrs.pstyle) {
|
|
HEAPFREE(pdev->hheap, pdev->cgs.lineattrs.pstyle);
|
|
}
|
|
|
|
pdev->cgs.lineattrs = *plineattrs;
|
|
|
|
// allocate space to copy the style array to.
|
|
|
|
pfl1 = (PFLOAT_LONG)
|
|
HEAPALLOC(pdev->hheap, sizeof(FLOAT_LONG)*plineattrs->cstyle);
|
|
|
|
if (pfl1 == NULL) {
|
|
DBGERRMSG("HEAPALLOC");
|
|
return(FALSE);
|
|
}
|
|
|
|
// copy the style array itself.
|
|
|
|
pdev->cgs.lineattrs.pstyle = pfl1;
|
|
memcpy(pfl1, plineattrs->pstyle,
|
|
sizeof(FLOAT_LONG) * plineattrs->cstyle);
|
|
}
|
|
}
|
|
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);
|
|
|
|
// 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.
|
|
|
|
psprintf(pdev, "%f sl\n", psfxWidth);
|
|
}
|
|
|
|
// 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.
|
|
|
|
psputs(pdev, "[1] ");
|
|
psfxStyle = LTOPSFX(plineattrs->elStyleState.l);
|
|
|
|
psprintf(pdev, "%f sd\n", psfxStyle);
|
|
}
|
|
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)
|
|
{
|
|
pfl1 = plineattrs->pstyle;
|
|
pfl2 = pdev->cgs.lineattrs.pstyle;
|
|
|
|
#if DBG
|
|
|
|
if ((plineattrs->cstyle == 0) && (plineattrs->pstyle != NULL))
|
|
{
|
|
DBGMSG(DBG_LEVEL_ERROR,
|
|
"cstyle = 0, but pstyle != NULL.\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
#endif
|
|
|
|
for (i = 0; i < plineattrs->cstyle; i++)
|
|
{
|
|
if (pfl1->l != pfl2->l)
|
|
{
|
|
bDiffer = TRUE;
|
|
break;
|
|
}
|
|
pfl1++;
|
|
pfl2++;
|
|
}
|
|
}
|
|
|
|
// 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))
|
|
psputs(pdev, "[]0 sd\n");
|
|
else // not a solid line.
|
|
{
|
|
psputs(pdev, "[");
|
|
|
|
pfl1 = plineattrs->pstyle;
|
|
|
|
// get style scaling factor.
|
|
|
|
psfxScale = LTOPSFX(pdev->dm.dmPublic.dmPrintQuality/25);
|
|
|
|
for (i = 0; i < plineattrs->cstyle; i++)
|
|
{
|
|
psfxStyle = pfl1->l * psfxScale;
|
|
pfl1++;
|
|
|
|
psprintf(pdev, "%f ", psfxStyle);
|
|
}
|
|
|
|
psputs(pdev, "]");
|
|
psfxStyle = plineattrs->elStyleState.l * psfxScale;
|
|
|
|
psprintf(pdev, "%f sd\n", psfxStyle);
|
|
}
|
|
|
|
// allocate space to copy the style array to.
|
|
|
|
pfl1 = (PFLOAT_LONG) HEAPALLOC(
|
|
pdev->hheap, sizeof(FLOAT_LONG)*plineattrs->cstyle);
|
|
|
|
if (pfl1 == NULL) {
|
|
DBGERRMSG("HEAPALLOC");
|
|
return(FALSE);
|
|
}
|
|
|
|
// something in the lineattrs may have changed, update the cgs.
|
|
|
|
if (pdev->cgs.lineattrs.pstyle) {
|
|
HEAPFREE(pdev->hheap, pdev->cgs.lineattrs.pstyle);
|
|
}
|
|
|
|
pdev->cgs.lineattrs.fl = plineattrs->fl;
|
|
pdev->cgs.lineattrs.elWidth = plineattrs->elWidth;
|
|
pdev->cgs.lineattrs.cstyle = plineattrs->cstyle;
|
|
pdev->cgs.lineattrs.elStyleState = plineattrs->elStyleState;
|
|
|
|
// copy the style array itself.
|
|
|
|
pdev->cgs.lineattrs.pstyle = pfl1;
|
|
memcpy(pfl1, plineattrs->pstyle,
|
|
sizeof(FLOAT_LONG)*plineattrs->cstyle);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
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.
|
|
|
|
psprintf(pdev, "CM %f %f scale\n", psfxM11, psfxM22);
|
|
|
|
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.
|
|
|
|
psputs(pdev, "CM [");
|
|
psputfix(pdev, 6,
|
|
psfxM11, psfxM12, psfxM21, psfxM22, psfxdx, psfxdy);
|
|
psputs(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)
|
|
{
|
|
psputs(pdev, *ppsz++);
|
|
psputs(pdev, "\n");
|
|
}
|
|
|
|
pdev->cgs.dwFlags |= CGS_EPS_PROC;
|
|
}
|
|
|
|
psputs(pdev, "BeginEPSF\n");
|
|
}
|
|
|
|
VOID ps_end_eps(pdev)
|
|
PDEVDATA pdev;
|
|
{
|
|
if (!(pdev->cgs.dwFlags & CGS_EPS_PROC)) {
|
|
DBGMSG(DBG_LEVEL_ERROR, "EndEPSF not defined.\n");
|
|
}
|
|
|
|
psputs(pdev, "EndEPSF\n");
|
|
}
|
|
|
|
LONG
|
|
ETOPSFX(
|
|
FLOAT x
|
|
)
|
|
|
|
{
|
|
FLOATOBJ f;
|
|
|
|
FLOATOBJ_SetFloat(&f, x);
|
|
FLOATOBJ_MulFloat(&f, (FLOAT) 256.0);
|
|
return FLOATOBJ_GetLong(&f);
|
|
}
|
|
|