]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/ghostscript/gs_setpd.ps
etherbcm: handle 64-bit host addresses, use PCIWADDR() instead of PADDR()
[plan9front.git] / sys / lib / ghostscript / gs_setpd.ps
1 %    Copyright (C) 1994, 2000 Aladdin Enterprises.  All rights reserved.
2
3 % This software is provided AS-IS with no warranty, either express or
4 % implied.
5
6 % This software is distributed under license and may not be copied,
7 % modified or distributed except as expressly authorized under the terms
8 % of the license contained in the file LICENSE in this distribution.
9
10 % For more information about licensing, please refer to
11 % http://www.ghostscript.com/licensing/. For information on
12 % commercial licensing, go to http://www.artifex.com/licensing/ or
13 % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 % San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
16 % $Id: gs_setpd.ps,v 1.27 2005/06/09 19:47:18 ray Exp $
17 % The current implementation of setpagedevice has the following limitations:
18 %       - It doesn't attempt to "interact with the user" for Policy = 2.
19
20 languagelevel 1 .setlanguagelevel
21 level2dict begin
22
23 % ---------------- Redefinitions ---------------- %
24
25 % Redefine .beginpage and .endpage so that they call BeginPage and
26 % EndPage respectively if appropriate.
27
28 % We have to guard against the BeginPage procedure not popping its operand.
29 % This is really stupid, but the Genoa CET does it.
30 /.beginpage {           % - .beginpage -
31   .currentshowpagecount {
32     .currentpagedevice pop
33     dup //null ne { /BeginPage .knownget } { pop //false } ifelse {
34                 % Stack: ... pagecount proc
35        count 2 .execn
36                 % Stack: ... ..???.. oldcount
37        count 1 add exch sub { pop } repeat
38     } {
39       pop
40     } ifelse
41   } if
42 } bind odef
43
44 % Guard similarly against EndPage not popping its operand.
45 /.endpage {             % <reason> .endpage <print_bool>
46   .currentshowpagecount {
47     1 index .currentpagedevice pop
48     dup //null ne { /EndPage .knownget } { pop //false } ifelse {
49                 % Stack: ... reason pagecount reason proc
50       count 2 .execn
51                 % Stack: ... ..???.. print oldcount
52       count 2 add exch sub { exch pop } repeat
53     } {
54       pop pop 2 ne
55     } ifelse
56   } {
57     2 ne
58   } ifelse
59 } bind odef
60
61 % Define interpreter callouts for handling gstate-saving operators,
62 % to make sure that they create a page device dictionary for use by
63 % the corresponding gstate-restoring operator.
64 % We'd really like to avoid the cost of doing this, but we don't see how.
65 % The names %gsavepagedevice, %savepagedevice, %gstatepagedevice,
66 % %copygstatepagedevice, and %currentgstatepagedevice are known to the
67 % interpreter.
68
69 (%gsavepagedevice) cvn
70  { currentpagedevice pop gsave
71  } bind def
72
73 (%savepagedevice) cvn
74  { currentpagedevice pop save
75  } bind def
76
77 (%gstatepagedevice) cvn
78  { currentpagedevice pop gstate
79  } bind def
80
81 (%copygstatepagedevice) cvn
82  { currentpagedevice pop copy
83  } bind def
84
85 (%currentgstatepagedevice) cvn
86  { currentpagedevice pop currentgstate
87  } bind def
88
89 % Define interpreter callouts for handling gstate-restoring operators
90 % when the current page device needs to be changed.
91 % The names %grestorepagedevice, %grestoreallpagedevice,
92 % %restorepagedevice, %restore1pagedevice, and %setgstatepagedevice
93 % are known to the interpreter.
94
95 /.installpagedevice
96  {      % Since setpagedevice doesn't create new device objects,
97         % we must (carefully) reinstall the old parameters in
98         % the same device.
99    .currentpagedevice pop //null currentdevice //null .trysetparams
100    dup type /booleantype eq
101     { pop pop }
102     {           % This should never happen!
103       SETPDDEBUG { (Error in .trysetparams!) = pstack flush } if
104       cleartomark pop pop pop
105       /.installpagedevice cvx /rangecheck signalerror
106     }
107    ifelse pop pop
108         % A careful reading of the Red Book reveals that an erasepage
109         % should occur, but *not* an initgraphics.
110    erasepage .beginpage
111  } bind def
112
113 /.uninstallpagedevice
114  { 2 .endpage { .currentnumcopies //false .outputpage } if
115    nulldevice
116  } bind def
117
118 (%grestorepagedevice) cvn
119  { .uninstallpagedevice grestore .installpagedevice
120  } bind def
121
122 (%grestoreallpagedevice) cvn
123  { .uninstallpagedevice grestore .installpagedevice grestoreall
124  } bind def
125
126 (%restore1pagedevice) cvn
127  { .uninstallpagedevice grestore .installpagedevice restore
128  } bind def
129
130 (%restorepagedevice) cvn
131  { .uninstallpagedevice restore .installpagedevice
132  } bind def
133
134 (%setgstatepagedevice) cvn
135  { .uninstallpagedevice setgstate .installpagedevice
136  } bind def
137
138 % Redefine .currentnumcopies so it consults the NumCopies device parameter.
139 /.numcopiesdict mark
140   /NumCopies dup
141 .dicttomark readonly def
142
143 /.currentnumcopies
144  { currentdevice //.numcopiesdict .getdeviceparams
145    dup type /integertype eq
146     { exch pop exch pop }
147     { cleartomark #copies }
148    ifelse
149  } bind odef
150
151 % Redefine .currentpagedevice and .setpagedevice so they convert between
152 % null and a fixed empty directionary.
153 /.nullpagedevice 0 dict readonly def
154 /.currentpagedevice {
155   //.currentpagedevice exch dup //null eq { pop //.nullpagedevice } if exch
156 } bind odef
157 /.setpagedevice {
158   dup //.nullpagedevice eq { pop //null } if //.setpagedevice
159 } bind odef
160
161 % ---------------- Auxiliary definitions ---------------- %
162
163 % Define the required attributes of all page devices, and their default values.
164 % We don't include attributes such as .MediaSize, which all devices
165 % are guaranteed to supply on their own.
166 /.defaultpolicies mark
167   /PolicyNotFound 1
168   /PageSize 0
169   /PolicyReport {
170     dup /.LockSafetyParams known {
171         % Only possible error is invalidaccess
172       /setpagedevice .systemvar /invalidaccess signalerror
173     }
174     if
175     pop
176   } bind
177 .dicttomark readonly def
178 % Note that the values of .requiredattrs are executed, not just fetched.
179 /.requiredattrs mark
180   /PageDeviceName //null
181   /PageOffset [0 0] readonly
182 % We populate InputAttributes with all of the known page sizes 
183 % followed by a dummy media type that handles pages of any size.
184 % This will create some duplicates, but that only slightly slows
185 % down the media selection (loop is in zmedia2.c).
186 %
187 % Some PostScript creators assume that slot 0 is the default media
188 % size and some can't handle a non-standard 4-element array which
189 % is a 'range' type page size (always put last).
190 %
191 % Real Devices that can only handle specific page sizes will override this.
192   /InputAttributes {
193     mark
194     % First put the device's default page size in slot 0
195     % This satifies those that have devices built with a4 as the default
196     0 mark /PageSize currentdevice /PageSize gsgetdeviceprop .dicttomark
197     statusdict /.pagetypenames get {
198       counttomark 1 sub 2 idiv exch mark exch /PageSize exch
199       % stack: mark --dict-- --dict-- ... key mark /PageSize pagetypename
200       % see note above about pagetype executable array contents.
201       load dup 0 get exch 1 get 2 array astore .dicttomark
202     } forall
203     % If NORANGEPAGESIZE is defined, (-dNORANGEPAGESIZE), then don't add
204     % the 'match any' PageSize entry
205     systemdict /NORANGEPAGESIZE known not {
206       % Add one last entry which is the 4 element range array (non-standard)
207       counttomark 2 idiv 
208         % PageSize with either dimension 0 will be detected in
209         % match_page_size, so we can allow it here
210       mark /PageSize [0 dup 16#7ffff dup] .dicttomark
211     } if
212     .dicttomark
213   }
214   (%MediaSource) 0
215   /OutputAttributes {
216     mark 0 mark .dicttomark readonly .dicttomark
217   }
218   (%MediaDestination) 0
219   /Install {{.callinstall}} bind
220   /BeginPage {{.callbeginpage}} bind
221   /EndPage {{.callendpage}} bind
222   /Policies .defaultpolicies
223   /ImagingBBox //null           % default value
224   /UseCIEColor /.getuseciecolor load
225 .dicttomark readonly def
226
227 % Define currentpagedevice so it creates the dictionary on demand if needed,
228 % adding all the required entries defined just above.
229 % We have to deal specially with entries that the driver may change
230 % on its own.
231 /.dynamicppkeys mark
232   /.MediaSize dup               % because it changes when PageSize is set
233   /PageCount dup
234   /Colors dup
235   /BitsPerPixel dup
236   /ColorValues dup
237 .dicttomark readonly def
238 /.makecurrentpagedevice {       % - .makecurrentpagedevice <dict>
239   currentdevice //null .getdeviceparams
240         % Make the dictionary large enough to add defaulted entries.
241   counttomark 2 idiv .requiredattrs length add dict
242   counttomark 2 idiv { dup 4 2 roll put } repeat exch pop
243         % Add any missing required attributes.
244         % Make a writable and (if possible) local copy of any default
245         % dictionaries, to work around a bug in the output of WordPerfect,
246         % which assumes that these dictionaries are writable and local.
247   .currentglobal exch dup gcheck .setglobal
248   .requiredattrs {
249     2 index 2 index known {
250       1 index /Policies eq {
251         % Merge policies from the device driver with defaults
252         2 index             % <<>> /key value <<>>
253         3 2 roll get        % <<>> value <<policies>>
254         exch {                
255           2 index 2 index known { 
256             pop pop
257           } { 
258             2 index 3 1 roll put
259           } ifelse
260         } forall
261         pop
262       } {
263         pop pop
264       } ifelse
265     } {
266       exec 2 index 3 1 roll put
267     } ifelse
268   } forall exch .setglobal
269   dup .setpagedevice
270 } bind def
271 /currentpagedevice {
272   .currentpagedevice {
273     dup length 0 eq {
274       pop .makecurrentpagedevice
275     } {
276                 % If any of the dynamic keys have changed,
277                 % we must update the page device dictionary.
278       currentdevice //.dynamicppkeys .getdeviceparams .dicttomark {
279                 % Stack: current key value
280             2 index 2 index .knownget { 1 index ne } { //true } ifelse
281              { 2 index wcheck not
282                 {       % This is the first entry being updated.
283                         % Copy the dictionary to make it writable.
284                   3 -1 roll
285                   currentglobal 1 index dup gcheck currentglobal and setglobal
286                   length dict
287                   exch setglobal
288                   .copydict
289                   3 1 roll
290                 }
291                if
292                2 index 3 1 roll put
293              }
294              { pop pop
295              }
296             ifelse
297       } forall
298       % If the device is the distiller device, update distillerparams that
299       % may have been changed by setdistillerparams
300       currentdevice .devicename /pdfwrite eq {
301         currentdistillerparams {
302               % Stack: current key value
303           2 index 2 index .knownget { 1 index ne } { //true } ifelse
304           { 2 index 3 1 roll put } { pop pop } ifelse
305         } forall
306       } if
307                 % If the dictionary was global and is now local, copy
308                 % any global subsidiary dictionaries to local VM.  This
309                 % too is to work around the Word Perfect bug (see above).
310       dup gcheck not {
311         dup {
312           dup type /dicttype eq { dup gcheck } { //false } ifelse {
313                 % Copy-on-write, see above.
314             2 index wcheck not {
315               3 -1 roll dup length dict .copydict
316               3 1 roll
317             } if
318             .copytree 2 index 3 1 roll put
319           } {
320             pop pop
321           } ifelse
322         } forall
323       } if
324                 % We would like to do a .setpagedevice so we don't keep
325                 % re-creating the dictionary.  Unfortunately, the effect
326                 % of this is that if any dynamic key changes (PageCount
327                 % in particular), we will do the equivalent of a
328                 % setpagedevice at the next restore or grestore.
329                 % Therefore, we make the dictionary read-only, but
330                 % we don't store it away.  I.e., NOT:
331                 % dup wcheck { .setpagedevice .currentpagedevice pop } if
332       readonly
333     } ifelse
334   } if
335 } bind odef
336
337 % Copy a dictionary recursively.
338 /.copytree {    % <dict> .copytree <dict'>
339   dup length dict exch {
340     dup type /dicttype eq { .copytree } if 2 index 3 1 roll put
341   } forall
342 } bind def
343
344 % The implementation of setpagedevice is quite complex.  Currently,
345 % everything but the media matching algorithm is implemented here.
346
347 % By default, we only present the requested changes to the device,
348 % but there are some parameters that require special merging action.
349 % Define those parameters here, with the procedures that do the merging.
350 % The procedures are called as follows:
351 %       <merged> <key> <new_value> -proc- <merged> <key> <new_value'>
352 /.mergespecial mark
353   /InputAttributes
354    { dup //null eq
355       { pop //null
356       }
357       { 3 copy pop .knownget
358          { dup //null eq
359             { pop dup length dict }
360             { dup length 2 index length add dict .copydict }
361            ifelse
362          }
363          { dup length dict
364          }
365         ifelse .copydict readonly
366       }
367      ifelse
368    } bind
369   /OutputAttributes 1 index
370   /Policies
371     { 3 copy pop .knownget
372        { dup length 2 index length add dict .copydict }
373        { dup length dict }
374       ifelse copy readonly
375     } bind
376 .dicttomark readonly def
377
378 % Define the keys used in input attribute matching.
379 /.inputattrkeys [
380   /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet /ManualFeed
381         % The following are documented in Adobe's supplement for v2017.
382   /LeadingEdge /MediaClass
383 ] readonly def
384 % Define other keys used in media selection.
385 /.inputselectionkeys [
386   /MediaPosition /Orientation
387 ] readonly def
388
389 % Define the keys used in output attribute matching.
390 /.outputattrkeys [
391   /OutputType
392 ] readonly def
393
394 % Define all the parameters that should always be copied to the merged
395 % dictionary.
396 /.copiedkeys [
397   /OutputDevice
398   .mergespecial { pop } forall
399   .inputattrkeys aload pop
400   .inputselectionkeys aload pop
401   .outputattrkeys aload pop
402 ] readonly def
403
404 % Define the parameters that should not be presented to the device.
405 % The procedures are called as follows:
406 %       <merged> <key> <value> -proc-
407 % The procedure leaves all its operands on the stack and returns
408 % true iff the key/value pair should be presented to .putdeviceparams.
409 /.presentspecial mark
410   .dynamicppkeys { pop //false } forall
411                         % We must ignore an explicit request for .MediaSize,
412                         % because media matching always handles this.
413   /.MediaSize //false
414   /Name //false
415   /OutputDevice //false
416   /PageDeviceName //false
417   /PageOffset //false
418   /PageSize //false             % obsolete alias for .MediaSize
419   /InputAttributes //false
420   .inputattrkeys
421     { dup /PageSize eq
422        { pop }
423        { { 2 index /InputAttributes .knownget { //null eq } { //true } ifelse } }
424       ifelse
425     }
426   forall
427   .inputselectionkeys { //false } forall
428   /OutputAttributes //false
429   .outputattrkeys
430     { { 2 index /OutputAttributes .knownget { //null eq } { //true } ifelse } }
431   forall
432   /Install //false
433   /BeginPage //false
434   /EndPage //false
435   /Policies //false
436         % Our extensions:
437   /HWColorMap
438     {                   % HACK: don't transmit the color map, because
439                         % window systems can change the color map on their own
440                         % incrementally.  Someday we'll have a better
441                         % solution for this....
442       //false
443     }
444   /ViewerPreProcess //false
445   /ImagingBBox //false  % This prevents the ImagingBBox value in the setpagedevice
446                         % from affecting the device's ImagingBBox parameter, but
447                         % does retain a 'shadow' copy at the PostScript level.
448                         % This is done for Adobe compatibility since Adobe does
449                         % render marks outside the ImagingBBox (and QuarkXpress
450                         % relies on it).
451 .dicttomark readonly def
452
453 % Define access to device defaults.
454 /.defaultdeviceparams
455  { finddevice //null .getdeviceparams
456  } bind def
457
458 % Select media (input or output).  The hard work is done in an operator:
459 %       <pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true
460 %       <pagedict> <attrdict> <policydict> <keys> .matchmedia false
461 %       <pagedict> null <policydict> <keys> .matchmedia null true
462 /.selectmedia           % <orig> <request> <merged> <failed>     <-- retained
463                         %   <attrdict> <policydict> <attrkeys> <mediakey>
464                         %   .selectmedia
465  { 5 index 5 -2 roll 4 index .matchmedia
466                 % Stack: orig request merged failed attrkeys mediakey
467                 %   (key true | false)
468     { 4 index 3 1 roll put pop
469     }
470     {   % Adobe's implementations have a "big hairy heuristic"
471         % to choose the set of keys to report as having failed the match.
472         % For the moment, we report any keys that are in the request
473         % and don't have the same value as in the original dictionary.
474       5 index 1 index .knownget
475        { 4 index 3 1 roll put }
476        { 3 index exch .undef }
477       ifelse
478        {        % Stack: <orig> <request> <merged> <failed> <attrkey>
479          3 index 1 index .knownget
480           { 5 index 2 index .knownget { ne } { pop //true } ifelse }
481           { //true }
482          ifelse         % Stack: ... <failed> <attrkey> <report>
483           { 2 copy /rangecheck put }
484          if pop
485        }
486       forall
487     }
488    ifelse
489  } bind def
490
491 % Apply Policies to any unprocessed failed requests.
492 % As we process each request entry, we replace the error name
493 % in the <failed> dictionary with the policy value,
494 % and we replace the key in the <merged> dictionary with its prior value
495 % (or remove it if it had no prior value).
496 /.policyprocs mark
497 % These procedures are called with the following on the stack:
498 %   <orig> <merged> <failed> <Policies> <key> <policy>
499 % They are expected to consume the top 2 operands.
500 % NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize)
501 % the same as 0, i.e., we signal an error.
502   0 {           % Set errorinfo and signal a configurationerror.
503         pop dup 4 index exch get 2 array astore
504         $error /errorinfo 3 -1 roll put
505         cleartomark
506         /setpagedevice load /configurationerror signalerror
507   } bind
508   1 {           % Roll back the failed request to its previous status.
509 SETPDDEBUG { (Rolling back.) = pstack flush } if
510         3 index 2 index 3 -1 roll put
511         4 index 1 index .knownget
512          { 4 index 3 1 roll put }
513          { 3 index exch .undef }
514         ifelse
515   } bind
516   7 {           % For PageSize only, just impose the request.
517         1 index /PageSize eq
518          { pop pop 1 index /PageSize 7 put }
519          { .policyprocs 0 get exec }
520         ifelse
521   } bind
522 .dicttomark readonly def
523 /.applypolicies         % <orig> <merged> <failed> .applypolicies
524                         %   <orig> <merged'> <failed'>
525  { 1 index /Policies get 1 index
526     { type /integertype eq
527        { pop            % already processed
528        }
529        { 2 copy .knownget not { 1 index /PolicyNotFound get } if
530                         % Stack: <orig> <merged> <failed> <Policies> <key>
531                         %   <policy>
532          .policyprocs 1 index .knownget not { .policyprocs 0 get } if exec
533        }
534       ifelse
535     }
536    forall pop
537  } bind def
538
539 % Prepare to present parameters to the device, by spreading them onto the
540 % operand stack and removing any that shouldn't be presented.
541 /.prepareparams         % <params> .prepareparams -mark- <key1> <value1> ...
542  { mark exch dup
543     {                   % Stack: -mark- key1 value1 ... merged key value
544       .presentspecial 2 index .knownget
545        { exec { 3 -1 roll } { pop pop } ifelse }
546        { 3 -1 roll }
547       ifelse
548     }
549    forall pop
550  } bind def
551
552 % Put device parameters without resetting currentpagedevice.
553 % (.putdeviceparams clears the current page device.)
554 /.putdeviceparamsonly   % <device> <Policies|null> <require_all> -mark-
555                         %   <key1> <value1> ... .putdeviceparamsonly
556                         % On success: <device> <eraseflag>
557                         % On failure: <device> <Policies|null> <req_all> -mark-
558                         %   <key1> <error1> ...
559  { .currentpagedevice
560     { counttomark 4 add 1 roll .putdeviceparams
561       dup type /booleantype eq { 3 } { counttomark 5 add } ifelse -1 roll
562       .setpagedevice
563     }
564     { pop .putdeviceparams
565     }
566    ifelse
567  } bind def
568
569 % Try setting the device parameters from the merged request.
570 /.trysetparams          % <merged> <(ignored)> <device> <Policies>
571                         %   .trysetparams
572  { //true 4 index .prepareparams
573                         % Add the computed .MediaSize.
574                         % Stack: merged (ignored) device Policies -true-
575                         %   -mark- key1 value1 ...
576    counttomark 5 add index .computemediasize
577    exch pop exch pop /.MediaSize exch
578 SETPDDEBUG { (Putting.) = pstack flush } if
579    .putdeviceparamsonly
580 SETPDDEBUG { (Result of putting.) = pstack flush } if
581  } bind def
582
583 % Compute the media size and initial matrix from a merged request (after
584 % media selection).
585 /.computemediasize      % <request> .computemediasize
586                         %   <request> <matrix> <[width height]>
587  { dup /PageSize get                                    % requested page size
588    1 index /InputAttributes get
589      2 index (%MediaSource) get get /PageSize get       % media size
590                                                         % (may be a range)
591    2 index /Policies get
592      dup /PageSize .knownget
593       { exch pop } { /PolicyNotFound get } ifelse       % PageSize policy,
594                                                         % affects scaling
595    3 index /Orientation .knownget not { //null } if
596    4 index /RollFedMedia .knownget not { //false } if
597    matrix .matchpagesize not {
598                 % This is a "can't happen" condition!
599      /setpagedevice load /rangecheck signalerror
600    } if
601    2 array astore
602  } bind def
603
604 % ---------------- setpagedevice itself ---------------- %
605
606 /setpagedevice
607  {              % We mustn't pop the argument until the very end,
608                 % so that the pseudo-operator machinery can restore the stack
609                 % if an error occurs.
610    mark 1 index currentpagedevice
611
612                 % Check whether we are changing OutputDevice;
613                 % also handle the case where the current device
614                 % is not a page device.
615                 % Stack: mark <request> <current>
616 SETPDDEBUG { (Checking.) = pstack flush } if
617
618    dup /OutputDevice .knownget
619     {           % Current device is a page device.
620       2 index /OutputDevice .knownget
621        {        % A specific OutputDevice was requested.
622          2 copy eq
623           { pop pop //null }
624           { exch pop }
625          ifelse
626        }
627        { pop //null
628        }
629       ifelse
630     }
631     {           % Current device is not a page device.
632                 % Use the default device.
633       1 index /OutputDevice .knownget not { .defaultdevicename } if
634     }
635    ifelse
636    dup //null eq
637     { pop
638     }
639     { exch pop .defaultdeviceparams
640                 % In case of duplicate keys, .dicttomark takes the entry
641                 % lower on the stack, so we can just append the defaults here.
642       .requiredattrs { exec } forall .dicttomark
643     }
644    ifelse
645
646                 % Check whether a viewer wants to intervene.
647                 % We must check both the request (which takes precedence)
648                 % and the current dictionary.
649                 % Stack: mark <request> <orig>
650    exch dup /ViewerPreProcess .knownget
651     { exec }
652     { 1 index /ViewerPreProcess .knownget { exec } if }
653    ifelse exch
654
655                 % Construct a merged request from the actual request plus
656                 % any keys that should always be propagated.
657                 % Stack: mark <request> <orig>
658 SETPDDEBUG { (Merging.) = pstack flush } if
659
660    exch 1 index length 1 index length add dict
661    .copiedkeys
662     {           % Stack: <orig> <request> <merged> <key>
663       3 index 1 index .knownget { 3 copy put pop } if pop
664     }
665    forall
666                 % Stack: <orig> <request> <merged>
667    dup 2 index
668     {           % stack: <orig> <request> <merged> <merged> <rkey> <rvalue>
669       .mergespecial 2 index .knownget { exec } if
670       put dup
671     }
672    forall pop
673                 % Hack: if FIXEDRESOLUTION is true, discard any attempt to
674                 % change HWResolution.
675    FIXEDRESOLUTION { dup /HWResolution .undef } if
676                 % Hack: if FIXEDMEDIA is true, discard any attempt to change
677                 % PageSize or HWSize.
678    FIXEDMEDIA
679     { dup /PageSize 4 index /PageSize get put
680       dup /HWSize 4 index /HWSize get put
681     } if
682                 % Hack: to work around some files that take a PageSize
683                 % from InputAttributes and impose it, discard any attempt
684                 % to set PageSize to a 4-element value.
685                 % Stack: mark <orig> <request> <merged>
686     dup /PageSize .knownget {
687       length 2 ne {
688         dup /PageSize 4 index /PageSize get put
689       } if
690     } if
691
692                 % Select input and output media.
693                 % Stack: mark <orig> <request> <merged>
694 SETPDDEBUG { (Selecting.) = pstack flush } if
695
696    0 dict       % <failed>
697    1 index /InputAttributes .knownget
698     { 2 index /Policies get
699       .inputattrkeys (%MediaSource) cvn .selectmedia
700     } if
701    1 index /OutputAttributes .knownget
702     { 2 index /Policies get
703       .outputattrkeys (%MediaDestination) cvn .selectmedia
704      } if
705    3 -1 roll 4 1 roll           % temporarily swap orig & request
706    .applypolicies
707    3 -1 roll 4 1 roll           % swap back
708
709                 % Construct the new device, and attempt to set its attributes.
710                 % Stack: mark <orig> <request> <merged> <failed>
711 SETPDDEBUG { (Constructing.) = pstack flush } if
712
713    currentdevice .devicename 2 index /OutputDevice get eq
714     { currentdevice }
715     { 1 index /OutputDevice get finddevice }
716    ifelse
717                 %**************** We should copy the device here,
718                 %**************** but since we can't close the old device,
719                 %**************** we don't.  This is WRONG.
720         %****************copydevice
721    2 index /Policies get
722    .trysetparams
723    dup type /booleantype ne
724     {           % The request failed.
725                 % Stack: ... <orig> <request> <merged> <failed> <device>
726                 %   <Policies> true mark <name> <errorname> ...
727 SETPDDEBUG { (Recovering.) = pstack flush } if
728       counttomark 4 add index
729       counttomark 2 idiv { dup 4 -2 roll put } repeat
730       pop pop pop
731                 % Stack: mark ... <orig> <request> <merged> <failed> <device>
732                 %   <Policies>
733       6 2 roll 3 -1 roll 4 1 roll
734       .applypolicies
735       3 -1 roll 4 1 roll 6 -2 roll
736       .trysetparams             % shouldn't fail!
737       dup type /booleantype ne
738        { 2 { counttomark 1 add 1 roll cleartomark } repeat
739          /setpagedevice load exch signalerror
740        }
741       if
742     }
743    if
744
745                 % The attempt succeeded.  Install the new device.
746                 % Stack: mark ... <merged> <failed> <device> <eraseflag>
747 SETPDDEBUG { (Installing.) = pstack flush } if
748
749    pop 2 .endpage
750     { 1 //true .outputpage
751       (>>setpagedevice, press <return> to continue<<\n) .confirm
752     }
753    if
754                 % .setdevice clears the current page device!
755    .currentpagedevice pop exch
756    .setdevice pop
757    .setpagedevice
758
759                 % Implement UseCIEColor directly if this is a LL3 system.
760                 % The color substitution feature is now implemented in
761                 % the interpreter, and this is used as an optimization.
762                 %
763                 % NB: This shoud be the only use of the .setuseciecolor
764                 %     operator anywhere.
765                 %
766                 % If UseCIEColor is transitioned to false, set some
767                 % color space other than /DeviceGray, to insure that
768                 % initgraphics will actually perform a setcolorspace
769                 % operation (there is an optimization in setcolorspace
770                 % that does nothing if the operand and current color
771                 % spaces are the same, and UseCIEColor is false).
772
773     /.setuseciecolor where
774       {
775         pop 1 index /UseCIEColor .knownget
776           {
777             dup .setuseciecolor not
778               { /DeviceRGB setcolorspace }
779             if
780           }
781         if
782       }
783     if
784
785                 % Merge the request into the current page device,
786                 % unless we're changing the OutputDevice.
787                 % Stack: mark ... <merged> <failed>
788    exch currentpagedevice dup length 2 index length add dict
789                 % Stack: mark ... <failed> <merged> <current> <newdict>
790    2 index /OutputDevice .knownget {
791      2 index /OutputDevice .knownget not { //null } if eq
792    } {
793      //true
794    } ifelse {
795                 % Same OutputDevice, merge the dictionaries.
796      .copydict
797    } {
798                 % Different OutputDevice, discard the old dictionary.
799      exch pop
800    } ifelse .copydict
801                 % Initialize the default matrix, taking media matching
802                 % into account.
803    .computemediasize pop initmatrix concat
804    dup /PageOffset .knownget
805     {           % Translate by the given number of 1/72" units in device X/Y.
806       dup 0 get exch 1 get
807       2 index /HWResolution get dup 1 get exch 0 get
808       4 -1 roll mul 72 div   3 1 roll mul 72 div
809       idtransform translate
810     }
811    if
812                 % We must install the new page device dictionary
813                 % before calling the Install procedure.
814   dup .setpagedevice
815   .setdefaulthalftone   % Set the default screen before calling Install.
816   dup /Install .knownget {
817     { .execinstall } stopped { .postinstall stop } { .postinstall } ifelse
818   } {
819     .postinstall
820   } ifelse
821 } odef
822
823 % We break out the code after calling the Install procedure into a
824 % separate procedure, since it is executed even if Install causes an error.
825 % By making .execinstall a separate operator procedure, we get the stacks
826 % restored if it fails.
827
828 /.execinstall {         % <proc> .execinstall -
829         % Because the interpreter optimizes tail calls, we can't just let
830         % the body of this procedure be 'exec', because that would lose
831         % the stack protection that is the whole reason for having the
832         % procedure in the first place.  We hack this by adding a couple
833         % of extra tokens to ensure that the operator procedure is still
834         % on the stack during the exec.
835   exec
836   0 pop % See above.
837 } odef
838 /.postinstall {         % mark ... <failed> <merged> .postinstall -
839    matrix currentmatrix .setdefaultmatrix
840                 % Erase and initialize the page.
841    initgraphics
842    currentoverprint //false setoverprint 1 setcolor
843    .fillpage
844    0 setcolor setoverprint
845    .beginpage
846
847                 % Clean up, calling PolicyReport if needed.
848                 % Stack: mark ... <failed> <merged>
849 SETPDDEBUG { (Finishing.) = pstack flush } if
850
851    exch dup length 0 ne
852     { 1 index /Policies get /PolicyReport get
853       counttomark 1 add 2 roll cleartomark
854       exec
855     }
856     { cleartomark
857     }
858    ifelse pop
859
860 } odef
861
862 end                             % level2dict
863 .setlanguagelevel