Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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