Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
 
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
 
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
 
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
 
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
 
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