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
|