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.
 
 
 
 
 
 

1389 lines
32 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
header.c
Abstract:
Functions for generating PostScript output headers
[Environment:]
Win32 subsystem, PostScript driver
Revision History:
11/26/90 -kentse-
Created it.
09/20/95 -davidx-
Rewrote most of the functions for selecting form/tray,
resolution, and device features.
mm/dd/yy -author-
description
--*/
#include "pscript.h"
// Forward declaration of local functions
VOID SetResolution(PDEVDATA, DWORD, WORD);
VOID SetTimeoutValues(PDEVDATA);
VOID SetLandscape(PDEVDATA, BOOL, PSREAL, PSREAL);
VOID PsSelectCustomPageSize(PDEVDATA);
VOID HandlePublicDevmodeOptions(PDEVDATA);
PINPUTSLOT MatchFormToTray(PDEVDATA, BOOL*);
BOOL
bOutputHeader(
PDEVDATA pdev
)
/*++
Routine Description:
Send PostScript output header to the printer
Arguments:
pdev - Pointer to our DEVDATA
Return Value:
TRUE if successful, FALSE otherwise
--*/
{
CHAR *pstr;
HPPD hppd = pdev->hppd;
ENG_TIME_FIELDS localtime;
//
// Process information in the public devmode fields and map it to printer
// feature selections. This must be called before PsSelectPrinterFeatures.
//
HandlePublicDevmodeOptions(pdev);
//
// Spit out job control stuff at the beginning of a job if necessary
//
if (! bPageIndependence(pdev) &&
! (pdev->dm.dmPrivate.dwFlags & PSDEVMODE_NO_JOB_CONTROL))
{
if (PpdSupportsProtocol(hppd, PROTOCOL_PJL)) {
// Universal exit language
if (hppd->pJclBegin != NULL) {
psputs(pdev, hppd->pJclBegin);
} else {
DBGMSG(DBG_LEVEL_TERSE, "No JCLBegin code.\n");
psputs(pdev, "\033%-12345X");
}
// If the printer uses PJL commands to set resolution,
// then do it before the job.
SetResolution(pdev, pdev->dm.dmPublic.dmPrintQuality, RESTYPE_JCL);
// Select printer specific features - JCLSetup
PsSelectPrinterFeatures(pdev, ODS_JCLSETUP);
// if the printer supports job switching, put the printer into
// postscript mode now.
if (hppd->pJclToPs != NULL) {
psputs(pdev, hppd->pJclToPs);
} else {
DBGMSG(DBG_LEVEL_TERSE, "No JCLToPSInterpreter code.\n");
psputs(pdev, "@PJL ENTER LANGUAGE=POSTSCRIPT\n");
}
} else if (PpdSupportsProtocol(hppd, PROTOCOL_SIC)) {
// directly call pswrite to output the necessary escape commands.
// psputs will NOT output '\000'.
pswrite(pdev, "\033\133\113\030\000\006\061\010\000\000\000\000\000", 13);
pswrite(pdev, "\000\000\000\000\000\000\000\000\004\033\133\113\003", 13);
pswrite(pdev, "\000\006\061\010\004", 5);
} else if (pdev->dm.dmPrivate.dwFlags & PSDEVMODE_CTRLD_BEFORE) {
// send a ^D before the job
pswrite(pdev, "\004", 1);
}
}
psputs(pdev, "%!PS-Adobe-3.0\n");
// output the title of the document.
if (pdev->pwstrDocName) {
CHAR buf[128];
CopyUnicode2Str(buf, pdev->pwstrDocName, 128);
psprintf(pdev, "%%%%Title: %s\n", buf);
} else
psputs(pdev, "%%Title: Untitled Document\n");
// let the world know who we are.
psputs(pdev, "%%Creator: Windows NT 4.0\n");
// print the date and time of creation.
EngQueryLocalTime(&localtime);
psprintf(pdev, "%%%%CreationDate: %d:%d %d/%d/%d\n",
localtime.usHour,
localtime.usMinute,
localtime.usMonth,
localtime.usDay,
localtime.usYear);
if (! (pdev->dwFlags & PDEV_EPSPRINTING_ESCAPE))
psputs(pdev, "%%Pages: (atend)\n");
// mark the bounding box of the document.
psputs(pdev, "%%BoundingBox: ");
psprintf(pdev, "%d %d %d %d\n",
PSREAL2INT(pdev->CurForm.ImageArea.left),
PSREAL2INT(pdev->CurForm.ImageArea.bottom),
PSREAL2INT(pdev->CurForm.ImageArea.right),
PSREAL2INT(pdev->CurForm.ImageArea.top));
if (pdev->cCopies > 1)
psprintf(pdev, "%%%%Requirements: numcopies(%d) collate\n", pdev->cCopies);
DscLanguageLevel(pdev, pdev->hppd->dwLangLevel);
DscOutputFontComments(pdev, FALSE);
// we are done with the comments portion of the document.
psputs(pdev, "%%EndComments\n");
// If the printer uses exitserver commands to set
// resolution, then do it before any other PS code.
SetResolution(pdev, pdev->dm.dmPublic.dmPrintQuality, RESTYPE_EXITSERVER);
// define our procedure set.
if (!(pdev->dwFlags & PDEV_EPSPRINTING_ESCAPE)) {
psputs(pdev, "%%BeginProlog\n");
DownloadNTProcSet(pdev, TRUE);
psputs(pdev, "%%EndProlog\n");
}
// do the device setup.
psputs(pdev, "%%BeginSetup\n");
// set job and wait timeout values
SetTimeoutValues(pdev);
// Set number of copies
psprintf(pdev, "/#copies %d def\n", pdev->cCopies);
// Select printer specific features - DocumentSetup and AnySetup
PsSelectPrinterFeatures(pdev, ODS_DOCSETUP|ODS_ANYSETUP);
// The implemention of EPSPRINTING escape here just follows Win31
if ((pdev->dwFlags & PDEV_EPSPRINTING_ESCAPE) &&
(pdev->dm.dmPublic.dmOrientation == DMORIENT_LANDSCAPE))
{
SetLandscape(pdev, TRUE, pdev->CurForm.PaperSize.height, pdev->CurForm.PaperSize.width);
}
//
// Invert the default transfer function if Negative Output option is selected
//
if (pdev->dm.dmPrivate.dwFlags & PSDEVMODE_NEG) {
psputs(pdev, "[currenttransfer /exec load {1 exch sub} /exec load] cvx settransfer\n");
}
psputs(pdev, "%%EndSetup\n");
// the form-tray information has already been sent for the first page.
pdev->dwFlags &= ~PDEV_RESETPDEV;
return(TRUE);
}
BOOL
bSendDeviceSetup(
PDEVDATA pdev
)
/*++
Routine Description:
Send page setup code to the printer. This is called at the
beginning of every page.
Arguments:
pdev - Pointer to our DEVDATA structure
Return Value:
TRUE if successful, FALSE if error
--*/
{
PSTR pstr;
HPPD hppd = pdev->hppd;
//
// Clear the current page if Negative Output option is selected
//
if (pdev->dm.dmPrivate.dwFlags & PSDEVMODE_NEG) {
psputs(pdev, "gsave clippath 1 setgray fill grestore\n");
}
// Rotate 90 degrees counterclockwise for normal landscape
// or 90 degrees clockwise for rotated landscape
if (pdev->dm.dmPublic.dmOrientation == DMORIENT_LANDSCAPE) {
SetLandscape(pdev,
(pdev->dm.dmPrivate.dwFlags & PSDEVMODE_LSROTATE) != 0,
pdev->CurForm.PaperSize.height,
pdev->CurForm.PaperSize.width);
}
if (pdev->dm.dmPrivate.dwFlags & PSDEVMODE_MIRROR) {
psprintf(pdev,
"%f %f translate -1 1 scale\n",
pdev->CurForm.ImageArea.right - pdev->CurForm.ImageArea.left,
0);
}
/* Translate origin to upper left corner a la GDI */
psprintf(pdev, "%f %f translate ",
pdev->CurForm.ImageArea.left,
pdev->CurForm.ImageArea.top);
/* Flip y-axis to point downwards and scale from points to dpi */
psprintf(pdev, "%d %d div dup neg scale\n", 72, pdev->dm.dmPublic.dmPrintQuality);
/* Snap to pixel */
psputs(pdev,
"0 0 transform .25 add round .25 sub exch .25 add "
"round .25 sub exch itransform translate\n");
return TRUE;
}
BOOL
bSendPSProcSet(
PDEVDATA pdev,
ULONG ulPSid
)
/*++
Routine Description:
Load the specified procset from the resource file and
then output it to printer.
Arguments:
pdev Pointer to DEVDATA structure
ulPSid Resource ID of the procset
Return Value:
TRUE if successful. FALSE otherwise.
--*/
{
PVOID pres;
ULONG size;
if (pdev->dwFlags & PDEV_CANCELDOC)
return FALSE;
// Retrieve the specified procset from resource file
pres = EngFindResource(pdev->hModule, ulPSid, PSPROC, &size);
if (pres == NULL || size == 0) {
DBGERRMSG("EngFindResource");
pdev->dwFlags |= PDEV_CANCELDOC;
return FALSE;
}
// Output the procset to printer
return pswrite(pdev, pres, size);
}
VOID
DownloadNTProcSet(
PDEVDATA pdev,
BOOL bEhandler
)
/*++
Routine Description:
Output NT procset to the printer.
Arguments:
pdev Pointer to DEVDATA structure
bEhandler Wheter to output error handler
Return Value:
NONE
--*/
{
#if _NOT_USED_
// Download our error handler if we are told to.
if (bEhandler && (pdev->dm.dmPrivate.dwFlags & PSDEVMODE_EHANDLER)) {
bSendPSProcSet(pdev, PSPROC_EHANDLER);
}
#endif
bSendPSProcSet(pdev, PSPROC_HEADER);
}
VOID
PsSelectFormAndTray(
PDEVDATA pdev
)
/*++
Routine Description:
This function pick the tray for a particular form selected, depends on
the user request in the UI
Arguments:
pdev - Pointer to our PDEVDATA
Return Value:
NONE
--*/
{
BOOL IsManual;
PINPUTSLOT pInputSlot;
HPPD hppd = pdev->hppd;
PSTR pstr;
// If a valid input slot is specified, then we'll instruct
// the printer to draw paper from that slot. Otherwise,
// we'll tell printer to select input slot based on paper size.
IsManual = FALSE;
pInputSlot = NULL;
if ((pdev->dm.dmPublic.dmFields & DM_DEFAULTSOURCE) &&
(pdev->dm.dmPublic.dmDefaultSource != DMBIN_FORMSOURCE))
{
DWORD SlotNum, cInputSlots;
SlotNum = pdev->dm.dmPublic.dmDefaultSource;
cInputSlots = UIGROUP_CountOptions(hppd->pInputSlots);
if (SlotNum == DMBIN_MANUAL || SlotNum == DMBIN_ENVMANUAL) {
// Manual feed is requested
IsManual = TRUE;
} else if (SlotNum >= DMBIN_USER && SlotNum < DMBIN_USER+cInputSlots) {
// A valid input slot is requested
pInputSlot = (PINPUTSLOT)
LISTOBJ_FindIndexed(
(PLISTOBJ) hppd->pInputSlots->pUiOptions,
SlotNum - DMBIN_USER);
}
} else if (pdev->CurForm.FormName[0] != NUL) {
// No input slot is specifically requested. Go through
// the form to tray assignment table and find the input
// slot matching the requested form.
pInputSlot = MatchFormToTray(pdev, &IsManual);
}
if (IsManual) {
// If manual feed feature is requested, then
// generate PostScript code to enable it.
PsSelectManualFeed(pdev, TRUE);
} else {
// Disable manual feed if it's currently enabled
PsSelectManualFeed(pdev, FALSE);
if (pInputSlot != NULL) {
// If an input slot is designated, then generate
// PostScript code to select it.
DscBeginFeature(pdev, "InputSlot ");
psprintf(pdev, "%s\n", pInputSlot->pName);
if (pInputSlot->pInvocation != NULL)
psputs(pdev, pInputSlot->pInvocation);
DscEndFeature(pdev);
}
}
if (IsCustomPrinterForm(& pdev->CurForm)) {
// If the custom page size is requested, then generate
// appropriate PostScript code to send to the printer.
DscBeginFeature(pdev, "CustomPageSize\n");
PsSelectCustomPageSize(pdev);
DscEndFeature(pdev);
} else if (pInputSlot == NULL || pInputSlot->bReqPageRgn) {
BOOL bRegion;
PMEDIAOPTION pMediaOption;
// If an input slot was selected and it doesn't require
// PageRegion, then we are done. Otherwise, we need to
// generate either PageRegion or PageSize code (depending
// on whether a tray was selected).
bRegion = IsManual || (pInputSlot != NULL);
DscBeginFeature(pdev, bRegion ? "PageRegion" : "PageSize");
psprintf(pdev, " %s\n", pdev->CurForm.PaperName);
// Find the invocation string to send to the printer
pMediaOption = (PMEDIAOPTION)
LISTOBJ_FindIndexed(
(PLISTOBJ) hppd->pPageSizes->pUiOptions,
pdev->CurForm.featureIndex);
if (pMediaOption != NULL) {
pstr = bRegion ?
pMediaOption->pPageRgnCode :
pMediaOption->pPageSizeCode;
if (pstr != NULL) {
psputs(pdev, pstr);
}
}
DscEndFeature(pdev);
}
}
VOID
PsSelectManualFeed(
PDEVDATA pdev,
BOOL bManual
)
/*++
Routine Description:
Enable or disable manual feed feature on the printer.
Arguments:
bManual TRUE to enable manual feed and FALSE to disable it
Return Value:
NONE
--*/
{
PSTR pstr;
// Check if the manual feed feature is already
// in the requested state.
if (bManual != ((pdev->dwFlags & PDEV_MANUALFEED) != 0)) {
// Generate PostScript to send to the printer
// and enclosed within a stopped context.
DscBeginFeature(pdev, "ManualFeed ");
psprintf(pdev, "%s\n", bManual ? "True" : "False");
if ((pstr = PpdFindManualFeedCode(pdev->hppd, bManual)) != NULL) {
psputs(pdev, pstr);
}
DscEndFeature(pdev);
// Set or clear the manual feed flag in DEVDATA
if (bManual)
pdev->dwFlags |= PDEV_MANUALFEED;
else
pdev->dwFlags &= ~PDEV_MANUALFEED;
}
}
PINPUTSLOT
MatchFormToTray(
PDEVDATA pdev,
BOOL *pbManual
)
/*++
Routine Description:
description-of-function
Arguments:
pdev Pointer to DEVDATA structure
pbManual Pointer to a boolean variable for indicating
whether the form is in the manual feed tray
Return Value:
Pointer to input slot object. NULL if the form is not assigned
to any input slot or if it's in the manual feed tray.
--*/
{
FORM_TRAY_TABLE pFormTrayTable, pNextEntry;
PWSTR pFormName, pSlotName, pPrinterForm;
BOOL IsDefTray;
PINPUTSLOT pInputSlot = NULL;
PWSTR pManualSlotName;
// Get the name of manual feed slot
pManualSlotName = STDSTR_SLOT_MANUAL;
*pbManual = FALSE;
// Read form-to-tray assignment table from registry
pNextEntry = pFormTrayTable = CurrentFormTrayTable(pdev->hPrinter);
if (pFormTrayTable == NULL) {
DBGMSG(DBG_LEVEL_WARNING,
"Failed to read form-to-tray assignment table.\n");
} else {
while (*pNextEntry != NUL) {
// Extract information from the current table entry
// and move on to the next entry
pNextEntry = EnumFormTrayTable(
pNextEntry,
& pSlotName,
& pFormName,
& pPrinterForm,
& IsDefTray);
// If a form is in more than one tray, then IsDefTray
// may or may not be set. But if form is in only one
// tray, then IsDefTray will always be set.
if (IsDefTray && wcscmp(pFormName, pdev->CurForm.FormName) == EQUAL_STRING) {
if (wcscmp(pSlotName, pManualSlotName) == EQUAL_STRING) {
*pbManual = TRUE;
} else {
CHAR SlotName[MAX_OPTION_NAME];
// Find the INPUTSLOT object corresponding
// to the input slot name
CopyUnicode2Str(SlotName, pSlotName, MAX_OPTION_NAME);
pInputSlot = PpdFindInputSlot(pdev->hppd, SlotName);
if (pInputSlot == NULL) {
DBGMSG1(DBG_LEVEL_WARNING,
"No such input slot: %ws.\n",
pSlotName);
}
}
break;
}
}
// Free the memory occupied by form-to-tray assignment table
FreeFormTrayTable(pFormTrayTable);
}
return pInputSlot;
}
VOID
PsSelectCustomPageSize(
PDEVDATA pdev
)
/*++
Routine Description:
Generate PostScript code to select custom page size
on the printer.
Arguments:
pdev Pointer to DEVDATA structure
Return Value:
NONE
--*/
{
PSREAL params[MAXPCP];
INT index;
HPPD hppd = pdev->hppd;
PSREAL xlen, ylen;
// Sanity check: if no custom page size invocation is provided,
// simply return with emitting anything.
if (hppd->pCustomSizeCode == NULL) {
DBGMSG(DBG_LEVEL_WARNING,
"No invocation string for custom page size.\n");
return;
}
// Generate parameters for custom page size invocation
// Sort them according to the order specified in PPD file
for (index=0; index < MAXPCP; index++)
params[index] = 0;
// Figure out size of the physical page along x- and y-axis
//
// Undo the effect of AdjustForLandscape here:
// in landscape mode, CurForm.PaperSize.width and
// and CurForm.PaperSize.height were swapped.
if (pdev->CurForm.bLandscape) {
xlen = pdev->CurForm.PaperSize.height;
ylen = pdev->CurForm.PaperSize.width;
} else {
xlen = pdev->CurForm.PaperSize.width;
ylen = pdev->CurForm.PaperSize.height;
}
if (! hppd->bCutSheet) {
PSREAL maxWidth, maxHeight, tmpPsreal;
// For roll-fed devices, choose orientation 0 or 1
// depending on whether width is bigger than height
maxWidth = hppd->maxMediaWidth -
hppd->customParam[PCP_WIDTHOFFSET].minVal;
maxHeight = hppd->maxMediaHeight -
hppd->customParam[PCP_HEIGHTOFFSET].minVal;
if (xlen <= ylen && ylen <= maxWidth && xlen <= maxHeight) {
// Use orientation 0: ylen is used as width parameter
// and xlen is used as height parameter
if (hppd->customParam[PCP_ORIENTATION].minVal > 0) {
DBGMSG(DBG_LEVEL_ERROR,
"Device does not support orientation 0.\n");
}
tmpPsreal = xlen;
xlen = ylen;
ylen = tmpPsreal;
} else {
// Use orientation 1
if (hppd->customParam[PCP_ORIENTATION].maxVal < 1) {
DBGMSG(DBG_LEVEL_ERROR,
"Device does not support orientation 1.\n");
}
params[hppd->customParam[PCP_ORIENTATION].dwOrder - 1] = 1;
}
}
params[hppd->customParam[PCP_WIDTH].dwOrder - 1] = xlen;
params[hppd->customParam[PCP_HEIGHT].dwOrder - 1] = ylen;
// Use minimum width and height offsets
params[hppd->customParam[PCP_WIDTHOFFSET].dwOrder - 1] =
hppd->customParam[PCP_WIDTHOFFSET].minVal;
params[hppd->customParam[PCP_HEIGHTOFFSET].dwOrder - 1] =
hppd->customParam[PCP_HEIGHTOFFSET].minVal;
// Emit custom page size parameters and invocation string
for (index=0; index < MAXPCP; index++)
psprintf(pdev, "%f ", params[index]);
psputs(pdev, hppd->pCustomSizeCode);
psputs(pdev, "\n");
}
VOID
HandlePublicDevmodeOptions(
PDEVDATA pdev
)
/*++
Routine Description:
Process information in the public devmode fields and map it
to appropriate printer feature selections
Arguments:
pdev - Points to our DEVDATA structure
Return Value:
NONE
--*/
{
HPPD hppd = pdev->hppd;
PDEVMODE pdmPublic = &pdev->dm.dmPublic;
PBYTE pdmOptions = pdev->dm.dmPrivate.options;
PUIGROUP pUiGroup;
WORD index;
//
// Process resolution information in the public devmode fields
//
if (pdmPublic->dmPrintQuality > 0 &&
hppd->wResType == RESTYPE_NORMAL &&
(pUiGroup = hppd->pResOptions))
{
PRESOPTION pResOption;
for (pResOption = (PRESOPTION) pUiGroup->pUiOptions, index = 0;
pResOption != NULL;
pResOption = pResOption->pNext, index++)
{
if (atol(pResOption->pName) == pdmPublic->dmPrintQuality) {
pdmOptions[pUiGroup->featureIndex] = (BYTE) index;
break;
}
}
}
//
// Process duplex information in the public devmode fields
//
if ((pdmPublic->dmFields & DM_DUPLEX) &&
(pUiGroup = hppd->pDuplex) &&
LISTOBJ_FindItemIndex((PLISTOBJ) pUiGroup->pUiOptions,
MapDevModeDuplexOption(pdmPublic->dmDuplex),
&index))
{
pdmOptions[pUiGroup->featureIndex] = (BYTE) index;
}
//
// Process collation information in the public devmode fields
//
if ((pdmPublic->dmFields & DM_COLLATE) &&
(pUiGroup = hppd->pCollate) &&
LISTOBJ_FindItemIndex((PLISTOBJ) pUiGroup->pUiOptions,
(pdmPublic->dmDuplex == DMCOLLATE_TRUE) ? "True" : "False",
&index))
{
pdmOptions[pUiGroup->featureIndex] = (BYTE) index;
}
//
// HACK: Insert a faked PageSize option so that PsSelectFormAndTray gets called
// at the right place in the output. This is not perfect. But since the logic for
// selecting paper and input slot is complicated, this is the safest solution for now.
//
if (pUiGroup = hppd->pPageSizes)
pdmOptions[pUiGroup->featureIndex] = 0;
if (pUiGroup = hppd->pManualFeed)
pdmOptions[pUiGroup->featureIndex] = OPTION_INDEX_ANY;
if (pUiGroup = hppd->pInputSlots)
pdmOptions[pUiGroup->featureIndex] = OPTION_INDEX_ANY;
}
VOID
SetResolution(
PDEVDATA pdev,
DWORD res,
WORD restype)
/*++
Routine Description:
Generate commands to set printer resolution.
Arguments:
pdev pointer to device data
res desired resolution
bPJL TRUE this is called at the beginning of a job
FALSE if this called during the setup section
Return Value:
NONE
--*/
{
HPPD hppd = pdev->hppd;
PRESOPTION pResOption;
// We only need to do something when the requested
// resolution type matches what the printer can do
if (restype != hppd->wResType)
return;
// Check if the desired resolution is supported
pResOption = PpdFindResolution(hppd, res);
// Ignore if the desired resolution is not found
if (pResOption == NULL) {
DBGMSG1(DBG_LEVEL_TERSE,
"No invocation string for resolution option: %d.\n", res);
return;
}
switch (restype) {
case RESTYPE_NORMAL: // Use normal PS code
if (pResOption->pInvocation == NULL) {
DBGMSG(DBG_LEVEL_ERROR, "Failed to set resolution.");
} else {
DscBeginFeature(pdev, "Resolution ");
psprintf(pdev, "%d\n", res);
psputs(pdev, pResOption->pInvocation);
DscEndFeature(pdev);
}
break;
case RESTYPE_JCL: // Use JCL code
if (! PpdSupportsProtocol(hppd,PROTOCOL_PJL) ||
pResOption->pJclCode == NULL)
{
DBGMSG(DBG_LEVEL_ERROR,
"Cannot set resolution using PJL commands.\n");
} else {
psputs(pdev, pResOption->pJclCode);
}
break;
case RESTYPE_EXITSERVER: // Use exitserver code
if (pResOption->pSetResCode == NULL) {
DBGMSG(DBG_LEVEL_ERROR, "Failed to set resolution.");
} else {
PSTR password = hppd->pPassword ? hppd->pPassword : "0";
psputs(pdev, "%%BeginExitServer: ");
psputs(pdev, password);
psprintf(pdev, "\n%%%%Resolution: %d\n", res);
psputs(pdev, password);
psputs(pdev, "\n");
psputs(pdev, pResOption->pSetResCode);
psputs(pdev, "\n%%EndExitServer\n");
}
break;
}
}
VOID
SetTimeoutValues(
PDEVDATA pdev
)
/*++
Routine Description:
Output code to printer to set job and wait timeout values
Arguments:
pdev Pointer to DEVDATA structure
Return Value:
NONE
--*/
{
psprintf(pdev, "[{%d\n", pdev->pPrinterData->dwJobTimeout);
psputs(pdev,
"/languagelevel where{pop languagelevel 2 ge}{false}ifelse\n"
"{1 dict dup/JobTimeout 4 -1 roll put setuserparams}\n"
"{statusdict/setjobtimeout get exec}ifelse\n"
"}stopped cleartomark\n");
psprintf(pdev, "[{%d\n", pdev->pPrinterData->dwWaitTimeout);
psputs(pdev,
"/languagelevel where{pop languagelevel 2 ge}{false}ifelse\n"
"{1 dict dup/WaitTimeout 4 -1 roll put setuserparams}\n"
"{statusdict/waittimeout 3 -1 roll put}ifelse\n"
"}stopped cleartomark\n");
}
VOID
SetLandscape(
PDEVDATA pdev,
BOOL bMinus90,
PSREAL width,
PSREAL height
)
/*++
Routine Description:
Generate PostScript code to rotation the coordinate system
to landscape mode.
Arguments:
pdev - Pointer to DEVDATA structure
bMinus90 - TRUE to rotation -90 degree FALSE to rotation 90 degree
width, height - Physical width and height of the paper
(as seen in normal portraint mode)
Return Value:
NONE
--*/
{
// xlen and ylen are 24.8 fixed-point numbers
if (bMinus90) {
psprintf(pdev, "-90 rotate -%f 0 translate\n", height);
} else {
psprintf(pdev, "90 rotate 0 -%f translate\n", width);
}
}
BOOL
PrepareFeatureData(
PDEVDATA pdev
)
/*++
Routine Description:
Prepare data for handling printer specific feature
Arguments:
pdev - Pointer to our DEVDATA structure
Return Value:
TRUE if successful, FALSE otherwise
--*/
{
PPACKEDORDERDEP pOrderDep;
PFEATUREDATA pFeatureData;
BYTE options[MAX_PRINTER_OPTIONS];
WORD index, cOptions;
HPPD hppd;
ASSERT(pdev->cSelectedFeature == 0 &&
pdev->pFeatureData == NULL);
// Allocate memory to hold printer specific feature data
memset(options, OPTION_INDEX_ANY, sizeof(options));
hppd = pdev->hppd;
cOptions = hppd->cDocumentStickyFeatures +
hppd->cPrinterStickyFeatures;
ASSERT(cOptions <= MAX_PRINTER_OPTIONS)
if (hppd->cDocumentStickyFeatures != pdev->dm.dmPrivate.wOptionCount &&
hppd->cPrinterStickyFeatures != pdev->pPrinterData->wOptionCount)
{
DBGMSG(DBG_LEVEL_ERROR, "Invalid option count.\n");
}
memcpy(options, pdev->dm.dmPrivate.options, hppd->cDocumentStickyFeatures);
memcpy(&options[hppd->cDocumentStickyFeatures],
pdev->pPrinterData->options,
hppd->cPrinterStickyFeatures);
pdev->pFeatureData = HEAPALLOC(pdev->hheap, cOptions * sizeof(FEATUREDATA));
if (pdev->pFeatureData == NULL) {
DBGERRMSG("MEMALLOC");
return FALSE;
}
// Collect printer specific feature data
pFeatureData = pdev->pFeatureData;
for (index=0; index < cOptions; index++) {
if (options[index] != OPTION_INDEX_ANY) {
pOrderDep = PpdFindOrderDep(hppd, index, options[index]);
if (pOrderDep != NULL &&
(pOrderDep->section & (ODS_PROLOG | ODS_EXITSERVER)))
{
// Prolog and ExitServer are treated the same as DocSetup
DBGMSG(DBG_LEVEL_WARNING, "Prolog and ExitServer section encountered.\n");
pFeatureData->section = ODS_DOCSETUP;
pFeatureData->order = pOrderDep->order;
} else if (pOrderDep == NULL) {
// If a feature has no corresponding OrderDependency entry,
// assume it goes to the end of DocumentSetup section.
pFeatureData->section = ODS_DOCSETUP;
pFeatureData->order = MAXPSREAL;
} else {
pFeatureData->section = pOrderDep->section;
pFeatureData->order = pOrderDep->order;
}
pFeatureData->feature = index;
pFeatureData->option = options[index];
pFeatureData++;
}
}
// Sort printer specific feature data using OrderDependency.
// Since the number of features is very small (usually less
// than a handful), we don't have to be too concerned with
// sorting speed here.
if (pdev->cSelectedFeature = (WORD) (pFeatureData - pdev->pFeatureData)) {
cOptions = pdev->cSelectedFeature;
pFeatureData = pdev->pFeatureData;
for (index=0; index < cOptions-1; index++) {
WORD n, m = index;
for (n=index+1; n < cOptions; n++) {
if (pFeatureData[n].order < pFeatureData[m].order)
m = n;
}
if (m != index) {
FEATUREDATA featureData;
featureData = pFeatureData[index];
pFeatureData[index] = pFeatureData[m];
pFeatureData[m] = featureData;
}
}
}
return TRUE;
}
BOOL
NeedPageSetupSection(
PDEVDATA pdev
)
/*++
Routine Description:
Determine whether we need to have a PageSetup section
to support device specific features.
Arguments:
pdev - Pointer to our DEVDATA structure
Return Value:
TRUE if a PageSetup section is needed. FALSE if not.
--*/
{
WORD index;
// Prepare data for handling printer specific feature
// if it's not done already.
if (pdev->pFeatureData == NULL) {
if (! PrepareFeatureData(pdev)) {
DBGERRMSG("PrepareFeatureData");
return FALSE;
}
}
// Check if any of the requested features should appear in
// PageSetup section.
for (index=0; index < pdev->cSelectedFeature; index++) {
if (pdev->pFeatureData[index].section == ODS_PAGESETUP)
return TRUE;
}
return FALSE;
}
VOID
PsSelectPrinterFeatures(
PDEVDATA pdev,
WORD section
)
/*++
Routine Description:
Select printer specific feature to appear in a
given section.
Arguments:
pdev - Pointer to our DEVDATA structure
section - DSC section we're currently in
Return Value:
NONE
--*/
{
WORD index;
PFEATUREDATA pFeatureData;
PUIGROUP pUiGroup;
PUIOPTION pUiOption;
//
// Prepare data for handling printer specific feature if it's not done already.
//
if (!pdev->pFeatureData && !PrepareFeatureData(pdev)) {
DBGERRMSG("PrepareFeatureData");
return;
}
//
// For each requested feature, check if it should be sent to
// the printer in the current DSC section.
//
for (index = 0, pFeatureData = pdev->pFeatureData;
index < pdev->cSelectedFeature;
index ++, pFeatureData++)
{
//
// Find the UIOPTION object corresponding to the requested feature/selection.
//
// HACK: PageSize feature is handled differently here because it involves
// lots of legacy stuff which we don't want to touch at this point.
//
if (! (pFeatureData->section & section))
continue;
if (pdev->hppd->pPageSizes &&
pdev->hppd->pPageSizes->featureIndex == pFeatureData->feature)
{
PsSelectFormAndTray(pdev);
} else if (PpdFindFeatureSelection(
pdev->hppd,
pFeatureData->feature,
pFeatureData->option,
&pUiGroup,
&pUiOption))
{
DBGMSG1(DBG_LEVEL_VERBOSE, "Feature: %s\n", pUiGroup->pName);
DBGMSG1(DBG_LEVEL_VERBOSE, "Selection: %s\n", pUiOption->pName);
//
// If we're not in JCLSetup section, then enclose the feature
// invocation in a mark/cleartomark pair.
//
if (section != ODS_JCLSETUP) {
DscBeginFeature(pdev, pUiGroup->pName);
psprintf(pdev, " %s\n", pUiOption->pName);
}
if (pUiOption->pInvocation)
psputs(pdev, pUiOption->pInvocation);
if (section != ODS_JCLSETUP)
DscEndFeature(pdev);
}
}
}