% Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved. % % This file is part of GNU Ghostscript. % % GNU Ghostscript is distributed in the hope that it will be useful, but % WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to % anyone for the consequences of using it or for whether it serves any % particular purpose or works at all, unless he says so in writing. Refer % to the GNU Ghostscript General Public License for full details. % % The current implementation of setpagedevice has the following problems: % - It doesn't save the CTM after the Install procedure as the % one for initmatrix or defaultmatrix. % - It doesn't interact properly with gsave/grestore. % - It doesn't do the automatic 90 degree rotation if the PageSize % dimensions need to be swapped. % - It doesn't handle Policy values other than 1 or non-1. languagelevel 1 .setlanguagelevel level2dict begin % Define currentpagedevice so it creates the dictionary on demand if needed. % The only entry we add automatically is Policies. /currentpagedevice { .currentpagedevice dup length 0 eq { pop currentdevice null .getdeviceparams % In case of duplicate keys, .dicttomark takes the entry % lower on the stack, so we can just append the defaults here. /Policies .defaultpolicies .dicttomark dup .setpagedevice } if } bind odef % The implementation of setpagedevice is quite complex. Currently, % everything but the media matching algorithm is implemented here. % 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, and their default values. % We don't include attributes such as PageSize, which all devices % are guaranteed to supply on their own. /.defaultpolicies mark /PolicyNotFound 1 /PageSize 0 /PolicyReport {pop} bind .dicttomark readonly def /.requiredattrs mark /InputAttributes mark 0 0 dict .dicttomark /OutputAttributes mark 0 0 dict .dicttomark /Install {.callinstall} bind /BeginPage {.callbeginpage} bind /EndPage {.callendpage} bind /Policies .defaultpolicies .dicttomark readonly def % Define access to device defaults. /.defaultdevicename 0 .getdevice .devicename def /.defaultdeviceparams { finddevice null .getdeviceparams } bind def % Select media (input or output). The hard work is done in an operator: % .matchmedia true % .matchmedia false % null .matchmedia null true /.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 % In case of duplicate keys, .dicttomark takes the entry % lower on the stack, so we can just append the defaults here. .requiredattrs { } forall .dicttomark } 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 .knownget { .inputattrkeys (%MediaSource) cvn .selectmedia } if 1 index /OutputAttributes .knownget { .outputattrkeys (%MediaDestination) cvn .selectmedia } if .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: ... true mark % ... counttomark 5 add -1 roll counttomark 2 idiv { dup 4 -2 roll put } repeat exch pop 4 1 roll pop % 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 % level2dict .setlanguagelevel