% Copyright (C) 1994 Aladdin Enterprises. All rights reserved. % % This file is part of Aladdin Ghostscript. % % Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author % or distributor accepts any responsibility for the consequences of using it, % or for whether it serves any particular purpose or works at all, unless he % or she says so in writing. Refer to the Aladdin Ghostscript Free Public % License (the "License") for full details. % % Every copy of Aladdin Ghostscript must include a copy of the License, % normally in a plain ASCII text file named PUBLIC. The License grants you % the right to copy, modify and redistribute Aladdin Ghostscript, but only % under certain conditions described in the License. Among other things, the % License requires that the copyright notice and this notice be preserved on % all copies. % The current implementation of setpagedevice is extremely limited. % It is intended only to support a minimal set of keys that common % applications expect to be able to read and set, namely those given % as the value of .pagedevicekeys below. In particular, it does not % support media selection or Policies. It runs the Install procedure % at the appropriate time, but does not save the resulting CTM as the % one for initmatrix or defaultmatrix. languagelevel 1 .setlanguagelevel level2dict begin % setpagedevice ignores all keys other than the ones below; it does not % give an error or invoke Policies for unknown keys. /.pagedevicekeys mark { /BeginPage /EndPage /HWResolution /ImagingBBox /Install /Margins /NumCopies /OutputDevice /PageSize /ProcessColorModel } { dup } forall .dicttomark def /.pagedevicedict % .pagedevicedict { .pagedevicekeys .getdeviceparams .dicttomark } bind def % currentpagedevice just selects the page device keys from the entire % set of device parameters. /currentpagedevice { .currentpagedevice dup length 0 eq { pop currentdevice .pagedevicedict dup .setpagedevice } if } bind odef /.defaultdevicename 0 .getdevice .devicename def % setpagedevice is complex, but nothing compared to its full specification! /setpagedevice { currentpagedevice % Check whether we are changing OutputDevice; % also handle the case where the current device % is not a page device. % Stack: dup /OutputDevice .knownget { % Current device is a page device. 2 index /OutputDevice .knownget { % A specific OutputDevice was requested. 2 copy eq { pop pop null } { exch pop } ifelse } { pop null } ifelse } { % Current device is not a page device. % Use the default device. 1 index /OutputDevice .knownget not { .defaultdevicename } if } ifelse dup null eq { pop } { exch pop finddevice .pagedevicedict } ifelse % Merge the current and requested dictionaries. % Stack: dup length 2 index length add dict copy copy % Construct the new device, and attempt to set its attributes. % Stack: currentdevice .devicename 1 index /OutputDevice get eq { currentdevice } { 1 index /OutputDevice get finddevice } ifelse %**************** We should copy the device here, %**************** but since we can't close the old device, %**************** we don't. This is WRONG. % Stack: %****************copydevice null false % Ignore undefined keys. mark 4 index { 1 index /OutputDevice eq { pop pop } if } forall DEBUG { (Putting.\n) print pstack flush } if .putdeviceparams DEBUG { (Result of putting.\n) print pstack flush } if dup type /nametype eq { % The request failed. % Stack: % ... counttomark 1 add 1 roll cleartomark exch pop exch pop /setpagedevice load exch signalerror } if % The attempt succeeded. Install the new device. % Stack: DEBUG { (Installing.\n) print pstack flush } if pop 2 .endpage { 1 true .outputpage (>>setpagedevice, press to continue<<\n) .confirm } if .setdevice pop dup /Install .knownget { exec } if erasepage initgraphics .setpagedevice .beginpage } odef %**************************************************************** % The remainder of this file contains an implementation of setpagedevice % that is not ready for use yet; we just skip over it. %**************************************************************** (%END) .skipeof % The implementation of setpagedevice is quite complex. Currently, % everything but the media matching algorithm is implemented here. %**************** Need an implementation of currentpagedevice using %**************** .currentpagedevice. % Define the parameters that require special action to merge into the % combined page device dictionary. The procedures are called as follows: % -proc- /.mergespecial mark /InputAttributes { dup null eq { pop null } { 3 copy pop .knownget { dup null eq { pop dup length dict } { dup length 2 index length add dict copy } ifelse } { dup length dict } ifelse copy readonly } ifelse } bind /OutputAttributes 1 index /Policies { 3 copy pop .knownget { dup length 2 index length add dict copy } { dup length dict } ifelse copy readonly } bind .dicttomark readonly def % Define the keys used in input attribute matching. /.inputattrkeys [ /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet ] readonly def % Define the keys used in output attribute matching. /.outputattrkeys [ /OutputType ] readonly def % Define the parameters that should not be presented to the device. % The procedures are called as follows: % -proc- % The procedure leaves all its operands on the stack and returns % true iff the key/value pair should be presented to .putdeviceparams. /.presentspecial mark /Name false /OutputDevice false /InputAttributes false .inputattrkeys { pop { 2 index /InputAttributes get null eq } } forall /OutputAttributes false .outputattrkeys { pop { 2 index /OutputAttributes get null eq } } forall /Install false /BeginPage false /EndPage false /Policies false .dicttomark readonly def % Define the required attributes of all page devices. % We don't include attributes such as PageSize, which all devices % are guaranteed to supply on their own. /.requiredattrs mark /InputAttributes null /OutputAttributes null /Install {.callinstall} bind /BeginPage {.callbeginpage} bind /EndPage {.callendpage} bind /Policies mark /PolicyNotFound 1 /PageSize 0 /PolicyReport {pop} bind .dicttomark readonly .dicttomark readonly def % Define access to device defaults. /.defaultdevicename 0 .getdevice .devicename def /.defaultdeviceparams { finddevice null .getdeviceparams } bind def % Select media (input or output). /.selectmedia % % (these are retained) % .selectmedia { 4 index 4 -1 roll 3 index .matchmedia { 4 index 3 1 roll put pop } { % Adobe's implementations have a "big hairy heuristic" % to choose the set of keys to report as having failed the match. % For the moment, we report any keys that are in the request % and don't have the same value as in the original dictionary. 3 index exch undef { % Stack: 3 index 1 index .knownget { 5 index 2 index .knownget { ne } { pop true } ifelse } { true } ifelse % Stack: ... { 2 copy /rangecheck put } if pop } forall } ifelse } bind def % Apply Policies to any unprocessed failed requests. % As we process each request entry, we replace the error name % in the dictionary with the policy value, % and we remove the key from the dictionary. /.applypolicies % .applypolicies { 1 index /Policies get 1 index { type /integertype eq { pop % already processed } { 2 copy .knownget not { 1 index /PolicyNotFound get } if % Stack: dup 1 ne { % Set errorinfo and signal a configurationerror. % Note that we currently treat all Policy values other than 1 % the same as 0. pop dup 4 index exch get 2 array astore $error /errorinfo 3 -1 roll put cleartomark /setpagedevice load /configurationerror signalerror } { % Ignore the failed request. 3 index 2 index 3 -1 roll put 3 index exch undef } ifelse } ifelse } forall pop } bind def % Try setting the device parameters from the merged request. /.trysetparams % ... <(ignored)> % .trysetparams { true mark 5 index dup { % Stack: .presentspecial 2 index .knownget { exec { 3 -1 roll } { pop pop } ifelse } { 3 -1 roll } ifelse } forall pop DEBUG { (Putting.\n) print pstack flush } if .putdeviceparams DEBUG { (Result of putting.\n) print pstack flush } if } bind def % Finally, define setpagedevice. /setpagedevice { mark exch currentpagedevice % Check whether we are changing OutputDevice; % also handle the case where the current device % is not a page device. % Stack: mark DEBUG { (Checking.\n) print pstack flush } if dup /OutputDevice .knownget { % Current device is a page device. 2 index /OutputDevice .knownget { % A specific OutputDevice was requested. 2 copy eq { pop pop null } { exch pop } ifelse } { pop null } ifelse } { % Current device is not a page device. % Use the default device. 1 index /OutputDevice .knownget not { .defaultdevicename } if } ifelse dup null eq { pop } { exch pop .defaultdeviceparams counttomark 2 idiv .requiredattrs length add dict .requiredattrs exch copy begin counttomark 2 idiv { def } repeat pop currentdict end } ifelse % Merge the current and requested dictionaries. % Stack: mark DEBUG { (Merging.\n) print pstack flush } if exch 1 index dup length 2 index length add dict copy dup 2 index { % stack: .mergespecial 2 index .knownget { exec } if put dup } forall pop % Select input and output media. % Stack: mark DEBUG { (Selecting.\n) print pstack flush } if 0 dict % 1 index /InputAttributes get .inputattrkeys (%MediaSource) cvn .selectmedia 1 index /OutputAttributes get .outputattrkeys (%MediaDestination) cvn .selectmedia .applypolicies % Construct the new device, and attempt to set its attributes. % Stack: mark DEBUG { (Constructing.\n) print pstack flush } if currentdevice .devicename 2 index /OutputDevice get eq { currentdevice } { 1 index /OutputDevice get finddevice } ifelse %**************** We should copy the device here, %**************** but since we can't close the old device, %**************** we don't. This is WRONG. %****************copydevice 2 index /Policies get .trysetparams dup type /nametype eq { % The request failed. % Stack: ... % ... counttomark 4 add -1 roll counttomark 2 idiv { dup 4 -2 roll put } repeat exch pop 3 1 roll % Stack: mark ... 4 2 roll .applypolicies 4 -2 roll .trysetparams % shouldn't fail! dup type /booleantype ne { 2 { counttomark 1 add 1 roll cleartomark } repeat /setpagedevice load exch signalerror } if } if % The attempt succeeded. Install the new device. % Stack: mark ... DEBUG { (Installing.\n) print pstack flush } if pop 2 .endpage { 1 true .outputpage (>>setpagedevice, press to continue<<\n) .confirm } if .setdevice pop 1 index /Install .knownget { exec } if erasepage initgraphics 1 index .setpagedevice .beginpage % Clean up, calling PolicyReport if needed. % Stack: mark ... DEBUG { (Finishing.\n) print pstack flush } if dup length 0 ne { 1 index /Policies get /PolicyReport get counttomark 1 add 2 roll cleartomark exec } { cleartomark } ifelse } odef %END end % level2dict .setlanguagelevel