henesyinit from p9fd787fda5 years agoHistory
748 lines · 23.2 KB · Text
RawDownload
%    Copyright (C) 1994, 1996, 1997, 1998, 1999 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. % $Id: gs_setpd.ps,v 1.1 2000/03/09 08:40:40 lpd Exp $% The current implementation of setpagedevice has the following limitations:%	- It doesn't attempt to "interact with the user" for Policy = 2. languagelevel 1 .setlanguagelevellevel2dict begin % ---------------- Redefinitions ---------------- % % Redefine .beginpage and .endpage so that they call BeginPage and% EndPage respectively if appropriate. % We have to guard against the BeginPage procedure not popping its operand.% This is really stupid, but the Genoa CET does it./.beginpage {		% - .beginpage -  .currentshowpagecount {    .currentpagedevice pop    dup null ne { /BeginPage .knownget } { pop false } ifelse {		% Stack: ... pagecount proc       count 2 .execn		% Stack: ... ..???.. oldcount       count 1 add exch sub { pop } repeat    } {      pop    } ifelse  } if} bind odef % Guard similarly against EndPage not popping its operand./.endpage {		% <reason> .endpage <print_bool>  .currentshowpagecount {    1 index .currentpagedevice pop    dup null ne { /EndPage .knownget } { pop false } ifelse {		% Stack: ... reason pagecount reason proc      count 2 .execn		% Stack: ... ..???.. print oldcount      count 2 add exch sub { exch pop } repeat    } {      pop pop 2 ne    } ifelse  } {    2 ne  } ifelse} bind odef % Define interpreter callouts for handling gstate-saving operators,% to make sure that they create a page device dictionary for use by% the corresponding gstate-restoring operator.% We'd really like to avoid the cost of doing this, but we don't see how.% The names %gsavepagedevice, %savepagedevice, %gstatepagedevice,% %copygstatepagedevice, and %currentgstatepagedevice are known to the% interpreter. (%gsavepagedevice) cvn { currentpagedevice pop gsave } bind def (%savepagedevice) cvn { currentpagedevice pop save } bind def (%gstatepagedevice) cvn { currentpagedevice pop gstate } bind def (%copygstatepagedevice) cvn { currentpagedevice pop copy } bind def (%currentgstatepagedevice) cvn { currentpagedevice pop currentgstate } bind def % Define interpreter callouts for handling gstate-restoring operators% when the current page device needs to be changed.% The names %grestorepagedevice, %grestoreallpagedevice,% %restorepagedevice, and %setgstatepagedevice are known to the interpreter. /.installpagedevice {	% Since setpagedevice doesn't create new device objects,	% we must (carefully) reinstall the old parameters in	% the same device.   .currentpagedevice pop null currentdevice null .trysetparams   dup type /booleantype eq    { pop pop }    {		% This should never happen!      DEBUG { (Error in .trysetparams!) = pstack flush } if      cleartomark pop pop pop      /.installpagedevice cvx /rangecheck signalerror    }   ifelse pop pop	% A careful reading of the Red Book reveals that an erasepage	% should occur, but *not* an initgraphics.   erasepage .beginpage } bind def /.uninstallpagedevice { 2 .endpage { .currentnumcopies false .outputpage } if   nulldevice } bind def (%grestorepagedevice) cvn { .uninstallpagedevice grestore .installpagedevice } bind def (%grestoreallpagedevice) cvn { .uninstallpagedevice grestore .installpagedevice grestoreall } bind def (%restorepagedevice) cvn { .uninstallpagedevice grestore .installpagedevice restore } bind def (%setgstatepagedevice) cvn { .uninstallpagedevice setgstate .installpagedevice } bind def % Redefine .currentnumcopies so it consults the NumCopies device parameter./.numcopiesdict mark  /NumCopies dup.dicttomark readonly def /.currentnumcopies { currentdevice //.numcopiesdict .getdeviceparams   dup type /integertype eq    { exch pop exch pop }    { cleartomark #copies }   ifelse } bind odef % Redefine .currentpagedevice and .setpagedevice so they convert between% null and a fixed empty directionary./.nullpagedevice 0 dict readonly def/.currentpagedevice {  //.currentpagedevice exch dup null eq { pop //.nullpagedevice } if exch} bind odef/.setpagedevice {  dup //.nullpagedevice eq { pop null } if //.setpagedevice} bind odef % ---------------- Auxiliary definitions ---------------- % % Define the required attributes of all page devices, and their default values.% We don't include attributes such as .MediaSize, which all devices% are guaranteed to supply on their own./.defaultpolicies mark  /PolicyNotFound 1  /PageSize 0  /PolicyReport {pop} bind.dicttomark readonly def% Note that the values of .requiredattrs are executed, not just fetched./.requiredattrs mark  /PageDeviceName null  /PageOffset [0 0] readonly% We define InputAttributes and OutputAttributes with a single% dummy media type that handles pages of any size.% Devices that care will override this.  /InputAttributes {    mark 0	% Since sizes match within 5 user units, we need to set the smallest	% PageSize to 6 units so that [0 0] will fail.    mark /PageSize [6 dup 16#7ffff dup] .dicttomark    .dicttomark  }  (%MediaSource) 0  /OutputAttributes {    mark 0 mark .dicttomark readonly .dicttomark  }  (%MediaDestination) 0  /Install {{.callinstall}} bind  /BeginPage {{.callbeginpage}} bind  /EndPage {{.callendpage}} bind  /Policies .defaultpolicies.dicttomark readonly def % Define currentpagedevice so it creates the dictionary on demand if needed,% adding all the required entries defined just above.% We have to deal specially with entries that the driver may change% on its own./.dynamicppkeys mark  /.MediaSize dup		% because it changes when PageSize is set  /PageCount dup.dicttomark readonly def/.makecurrentpagedevice {	% - .makecurrentpagedevice <dict>  currentdevice null .getdeviceparams	% Make the dictionary large enough to add defaulted entries.  counttomark 2 idiv .requiredattrs length add dict  counttomark 2 idiv { dup 4 2 roll put } repeat exch pop	% Add any missing required attributes.	% Make a writable and (if possible) local copy of any default	% dictionaries, to work around a bug in the output of WordPerfect,	% which assumes that these dictionaries are writable and local.  .currentglobal exch dup gcheck .setglobal  .requiredattrs {    2 index 2 index known {      pop pop    } {      exec 2 index 3 1 roll put    } ifelse  } forall exch .setglobal  dup .setpagedevice} bind def/currentpagedevice {  .currentpagedevice {    dup length 0 eq {      pop .makecurrentpagedevice    } {		% If any of the dynamic keys have changed,		% we must update the page device dictionary.      currentdevice //.dynamicppkeys .getdeviceparams .dicttomark {		% Stack: current key value	    2 index 2 index .knownget { 1 index ne } { true } ifelse	     { 2 index wcheck not		{	% This is the first entry being updated.			% Copy the dictionary to make it writable.		  3 -1 roll dup length dict .copydict		  3 1 roll		}	       if	       2 index 3 1 roll put	     }	     { pop pop	     }	    ifelse      } forall		% If the dictionary was global and is now local, copy		% any global subsidiary dictionaries to local VM.  This		% too is to work around the Word Perfect bug (see above).      dup gcheck not {	dup {	  dup type /dicttype eq { dup gcheck } { false } ifelse {		% Copy-on-write, see above.	    2 index wcheck not {	      3 -1 roll dup length dict .copydict	      3 1 roll	    } if	    .copytree 2 index 3 1 roll put	  } {	    pop pop	  } ifelse	} forall      } if		% We would like to do a .setpagedevice so we don't keep		% re-creating the dictionary.  Unfortunately, the effect		% of this is that if any dynamic key changes (PageCount		% in particular), we will do the equivalent of a		% setpagedevice at the next restore or grestore.		% Therefore, we make the dictionary read-only, but		% we don't store it away.  I.e., NOT:		% dup wcheck { .setpagedevice .currentpagedevice pop } if      readonly    } ifelse  } if} bind odef % Copy a dictionary recursively./.copytree {	% <dict> .copytree <dict'>  dup length dict exch {    dup type /dicttype eq { .copytree } if 2 index 3 1 roll put  } forall} bind def % The implementation of setpagedevice is quite complex.  Currently,% everything but the media matching algorithm is implemented here. % By default, we only present the requested changes to the device,% but there are some parameters that require special merging action.% Define those parameters here, with the procedures that do the merging.% The procedures are called as follows:%	<merged> <key> <new_value> -proc- <merged> <key> <new_value'>/.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 .copydict }	   ifelse	 }	 { dup length dict	 }        ifelse .copydict readonly      }     ifelse   } bind  /OutputAttributes 1 index  /Policies    { 3 copy pop .knownget       { dup length 2 index length add dict .copydict }       { dup length dict }      ifelse copy readonly    } bind.dicttomark readonly def % Define the keys used in input attribute matching./.inputattrkeys [  /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet	% The following are documented in Adobe's supplement for v2017.  /LeadingEdge /MediaClass] readonly def% Define other keys used in media selection./.inputselectionkeys [  /MediaPosition /Orientation] readonly def % Define the keys used in output attribute matching./.outputattrkeys [  /OutputType] readonly def % Define all the parameters that should always be copied to the merged% dictionary./.copiedkeys [  /OutputDevice  .mergespecial { pop } forall  .inputattrkeys aload pop  .inputselectionkeys aload pop  .outputattrkeys aload pop] readonly def % Define the parameters that should not be presented to the device.% The procedures are called as follows:%	<merged> <key> <value> -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  .dynamicppkeys { pop false } forall			% We must ignore an explicit request for .MediaSize,			% because media matching always handles this.  /.MediaSize false  /Name false  /OutputDevice false  /PageDeviceName false  /PageOffset false  /PageSize false		% obsolete alias for .MediaSize  /InputAttributes false  .inputattrkeys    { dup /PageSize eq       { pop }       { { 2 index /InputAttributes .knownget { null eq } { true } ifelse } }      ifelse    }  forall  .inputselectionkeys { false } forall  /OutputAttributes false  .outputattrkeys    { { 2 index /OutputAttributes .knownget { null eq } { true } ifelse } }  forall  /Install false  /BeginPage false  /EndPage false  /Policies false	% Our extensions:  /HWColorMap    {			% HACK: don't transmit the color map, because			% window systems can change the color map on their own			% incrementally.  Someday we'll have a better			% solution for this....      false    }  /ViewerPreProcess false.dicttomark readonly def % Define access to device defaults./.defaultdeviceparams { finddevice null .getdeviceparams } bind def % Select media (input or output).  The hard work is done in an operator:%	<pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true%	<pagedict> <attrdict> <policydict> <keys> .matchmedia false%	<pagedict> null <policydict> <keys> .matchmedia null true/.selectmedia		% <orig> <request> <merged> <failed>     <-- retained			%   <attrdict> <policydict> <attrkeys> <mediakey>			%   .selectmedia { 5 index 5 -2 roll 4 index .matchmedia		% Stack: orig request merged failed attrkeys mediakey		%   (key true | false)    { 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.      5 index 1 index .knownget       { 4 index 3 1 roll put }       { 3 index exch .undef }      ifelse       {	% Stack: <orig> <request> <merged> <failed> <attrkey>	 3 index 1 index .knownget	  { 5 index 2 index .knownget { ne } { pop true } ifelse }	  { true }	 ifelse		% Stack: ... <failed> <attrkey> <report>	  { 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 <failed> dictionary with the policy value,% and we replace the key in the <merged> dictionary with its prior value% (or remove it if it had no prior value)./.policyprocs mark% These procedures are called with the following on the stack:%   <orig> <merged> <failed> <Policies> <key> <policy>% They are expected to consume the top 2 operands.% NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize)% the same as 0, i.e., we signal an error.  0 {		% Set errorinfo and signal a configurationerror.	pop dup 4 index exch get 2 array astore	$error /errorinfo 3 -1 roll put	cleartomark	/setpagedevice load /configurationerror signalerror  } bind  1 {		% Roll back the failed request to its previous status.DEBUG { (Rolling back.) = pstack flush } if	3 index 2 index 3 -1 roll put	4 index 1 index .knownget	 { 4 index 3 1 roll put }	 { 3 index exch .undef }	ifelse  } bind  7 {		% For PageSize only, just impose the request.	1 index /PageSize eq	 { pop pop 1 index /PageSize 7 put }	 { .policyprocs 0 get exec }	ifelse  } bind.dicttomark readonly def/.applypolicies		% <orig> <merged> <failed> .applypolicies			%   <orig> <merged'> <failed'> { 1 index /Policies get 1 index    { type /integertype eq       { pop		% already processed       }       { 2 copy .knownget not { 1 index /PolicyNotFound get } if			% Stack: <orig> <merged> <failed> <Policies> <key>			%   <policy>	 .policyprocs 1 index .knownget not { .policyprocs 0 get } if exec       }      ifelse    }   forall pop } bind def % Prepare to present parameters to the device, by spreading them onto the% operand stack and removing any that shouldn't be presented./.prepareparams		% <params> .prepareparams -mark- <key1> <value1> ... { mark exch dup    {			% Stack: -mark- key1 value1 ... merged key value      .presentspecial 2 index .knownget       { exec { 3 -1 roll } { pop pop } ifelse }       { 3 -1 roll }      ifelse    }   forall pop } bind def % Put device parameters without resetting currentpagedevice.% (.putdeviceparams clears the current page device.)/.putdeviceparamsonly	% <device> <Policies|null> <require_all> -mark-			%   <key1> <value1> ... .putdeviceparamsonly			% On success: <device> <eraseflag>			% On failure: <device> <Policies|null> <req_all> -mark-			%   <key1> <error1> ... { .currentpagedevice    { counttomark 4 add 1 roll .putdeviceparams      dup type /booleantype eq { 3 } { counttomark 5 add } ifelse -1 roll      .setpagedevice    }    { pop .putdeviceparams    }   ifelse } bind def % Try setting the device parameters from the merged request./.trysetparams		% <merged> <(ignored)> <device> <Policies>

Lines 1–500 of 748.