gs_setpd.ps 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. % Copyright (C) 1994, 2000 Aladdin Enterprises. All rights reserved.
  2. %
  3. % This file is part of AFPL Ghostscript.
  4. %
  5. % AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
  6. % distributor accepts any responsibility for the consequences of using it, or
  7. % for whether it serves any particular purpose or works at all, unless he or
  8. % she says so in writing. Refer to the Aladdin Free Public License (the
  9. % "License") for full details.
  10. %
  11. % Every copy of AFPL Ghostscript must include a copy of the License, normally
  12. % in a plain ASCII text file named PUBLIC. The License grants you the right
  13. % to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14. % conditions described in the License. Among other things, the License
  15. % requires that the copyright notice and this notice be preserved on all
  16. % copies.
  17. % $Id: gs_setpd.ps,v 1.8.2.1 2002/01/25 06:33:09 rayjj Exp $
  18. % The current implementation of setpagedevice has the following limitations:
  19. % - It doesn't attempt to "interact with the user" for Policy = 2.
  20. languagelevel 1 .setlanguagelevel
  21. level2dict begin
  22. % ---------------- Redefinitions ---------------- %
  23. % Redefine .beginpage and .endpage so that they call BeginPage and
  24. % EndPage respectively if appropriate.
  25. % We have to guard against the BeginPage procedure not popping its operand.
  26. % This is really stupid, but the Genoa CET does it.
  27. /.beginpage { % - .beginpage -
  28. .currentshowpagecount {
  29. .currentpagedevice pop
  30. dup null ne { /BeginPage .knownget } { pop false } ifelse {
  31. % Stack: ... pagecount proc
  32. count 2 .execn
  33. % Stack: ... ..???.. oldcount
  34. count 1 add exch sub { pop } repeat
  35. } {
  36. pop
  37. } ifelse
  38. } if
  39. } bind odef
  40. % Guard similarly against EndPage not popping its operand.
  41. /.endpage { % <reason> .endpage <print_bool>
  42. .currentshowpagecount {
  43. 1 index .currentpagedevice pop
  44. dup null ne { /EndPage .knownget } { pop false } ifelse {
  45. % Stack: ... reason pagecount reason proc
  46. count 2 .execn
  47. % Stack: ... ..???.. print oldcount
  48. count 2 add exch sub { exch pop } repeat
  49. } {
  50. pop pop 2 ne
  51. } ifelse
  52. } {
  53. 2 ne
  54. } ifelse
  55. } bind odef
  56. % Define interpreter callouts for handling gstate-saving operators,
  57. % to make sure that they create a page device dictionary for use by
  58. % the corresponding gstate-restoring operator.
  59. % We'd really like to avoid the cost of doing this, but we don't see how.
  60. % The names %gsavepagedevice, %savepagedevice, %gstatepagedevice,
  61. % %copygstatepagedevice, and %currentgstatepagedevice are known to the
  62. % interpreter.
  63. (%gsavepagedevice) cvn
  64. { currentpagedevice pop gsave
  65. } bind def
  66. (%savepagedevice) cvn
  67. { currentpagedevice pop save
  68. } bind def
  69. (%gstatepagedevice) cvn
  70. { currentpagedevice pop gstate
  71. } bind def
  72. (%copygstatepagedevice) cvn
  73. { currentpagedevice pop copy
  74. } bind def
  75. (%currentgstatepagedevice) cvn
  76. { currentpagedevice pop currentgstate
  77. } bind def
  78. % Define interpreter callouts for handling gstate-restoring operators
  79. % when the current page device needs to be changed.
  80. % The names %grestorepagedevice, %grestoreallpagedevice,
  81. % %restorepagedevice, %restore1pagedevice, and %setgstatepagedevice
  82. % are known to the interpreter.
  83. /.installpagedevice
  84. { % Since setpagedevice doesn't create new device objects,
  85. % we must (carefully) reinstall the old parameters in
  86. % the same device.
  87. .currentpagedevice pop null currentdevice null .trysetparams
  88. dup type /booleantype eq
  89. { pop pop }
  90. { % This should never happen!
  91. DEBUG { (Error in .trysetparams!) = pstack flush } if
  92. cleartomark pop pop pop
  93. /.installpagedevice cvx /rangecheck signalerror
  94. }
  95. ifelse pop pop
  96. % A careful reading of the Red Book reveals that an erasepage
  97. % should occur, but *not* an initgraphics.
  98. erasepage .beginpage
  99. } bind def
  100. /.uninstallpagedevice
  101. { 2 .endpage { .currentnumcopies false .outputpage } if
  102. nulldevice
  103. } bind def
  104. (%grestorepagedevice) cvn
  105. { .uninstallpagedevice grestore .installpagedevice
  106. } bind def
  107. (%grestoreallpagedevice) cvn
  108. { .uninstallpagedevice grestore .installpagedevice grestoreall
  109. } bind def
  110. (%restore1pagedevice) cvn
  111. { .uninstallpagedevice grestore .installpagedevice restore
  112. } bind def
  113. (%restorepagedevice) cvn
  114. { .uninstallpagedevice restore .installpagedevice
  115. } bind def
  116. (%setgstatepagedevice) cvn
  117. { .uninstallpagedevice setgstate .installpagedevice
  118. } bind def
  119. % Redefine .currentnumcopies so it consults the NumCopies device parameter.
  120. /.numcopiesdict mark
  121. /NumCopies dup
  122. .dicttomark readonly def
  123. /.currentnumcopies
  124. { currentdevice //.numcopiesdict .getdeviceparams
  125. dup type /integertype eq
  126. { exch pop exch pop }
  127. { cleartomark #copies }
  128. ifelse
  129. } bind odef
  130. % Redefine .currentpagedevice and .setpagedevice so they convert between
  131. % null and a fixed empty directionary.
  132. /.nullpagedevice 0 dict readonly def
  133. /.currentpagedevice {
  134. //.currentpagedevice exch dup null eq { pop //.nullpagedevice } if exch
  135. } bind odef
  136. /.setpagedevice {
  137. dup //.nullpagedevice eq { pop null } if //.setpagedevice
  138. } bind odef
  139. % ---------------- Auxiliary definitions ---------------- %
  140. % Define the required attributes of all page devices, and their default values.
  141. % We don't include attributes such as .MediaSize, which all devices
  142. % are guaranteed to supply on their own.
  143. /.defaultpolicies mark
  144. /PolicyNotFound 1
  145. /PageSize 0
  146. /PolicyReport {
  147. dup /.LockSafetyParams known {
  148. % Only possible error is invalidaccess
  149. /setpagedevice .systemvar /invalidaccess signalerror
  150. }
  151. if
  152. pop
  153. } bind
  154. .dicttomark readonly def
  155. % Note that the values of .requiredattrs are executed, not just fetched.
  156. /.requiredattrs mark
  157. /PageDeviceName null
  158. /PageOffset [0 0] readonly
  159. % We define InputAttributes and OutputAttributes with a single
  160. % dummy media type that handles pages of any size.
  161. % Devices that care will override this.
  162. /InputAttributes {
  163. mark 0
  164. % Since sizes match within 5 user units, we need to set the smallest
  165. % PageSize to 6 units so that [0 0] will fail.
  166. mark /PageSize [6 dup 16#7ffff dup] .dicttomark
  167. .dicttomark
  168. }
  169. (%MediaSource) 0
  170. /OutputAttributes {
  171. mark 0 mark .dicttomark readonly .dicttomark
  172. }
  173. (%MediaDestination) 0
  174. /Install {{.callinstall}} bind
  175. /BeginPage {{.callbeginpage}} bind
  176. /EndPage {{.callendpage}} bind
  177. /Policies .defaultpolicies
  178. .dicttomark readonly def
  179. % Define currentpagedevice so it creates the dictionary on demand if needed,
  180. % adding all the required entries defined just above.
  181. % We have to deal specially with entries that the driver may change
  182. % on its own.
  183. /.dynamicppkeys mark
  184. /.MediaSize dup % because it changes when PageSize is set
  185. /PageCount dup
  186. .dicttomark readonly def
  187. /.makecurrentpagedevice { % - .makecurrentpagedevice <dict>
  188. currentdevice null .getdeviceparams
  189. % Make the dictionary large enough to add defaulted entries.
  190. counttomark 2 idiv .requiredattrs length add dict
  191. counttomark 2 idiv { dup 4 2 roll put } repeat exch pop
  192. % Add any missing required attributes.
  193. % Make a writable and (if possible) local copy of any default
  194. % dictionaries, to work around a bug in the output of WordPerfect,
  195. % which assumes that these dictionaries are writable and local.
  196. .currentglobal exch dup gcheck .setglobal
  197. .requiredattrs {
  198. 2 index 2 index known {
  199. pop pop
  200. } {
  201. exec 2 index 3 1 roll put
  202. } ifelse
  203. } forall exch .setglobal
  204. dup .setpagedevice
  205. } bind def
  206. /currentpagedevice {
  207. .currentpagedevice {
  208. dup length 0 eq {
  209. pop .makecurrentpagedevice
  210. } {
  211. % If any of the dynamic keys have changed,
  212. % we must update the page device dictionary.
  213. currentdevice //.dynamicppkeys .getdeviceparams .dicttomark {
  214. % Stack: current key value
  215. 2 index 2 index .knownget { 1 index ne } { true } ifelse
  216. { 2 index wcheck not
  217. { % This is the first entry being updated.
  218. % Copy the dictionary to make it writable.
  219. 3 -1 roll dup length dict .copydict
  220. 3 1 roll
  221. }
  222. if
  223. 2 index 3 1 roll put
  224. }
  225. { pop pop
  226. }
  227. ifelse
  228. } forall
  229. % If the dictionary was global and is now local, copy
  230. % any global subsidiary dictionaries to local VM. This
  231. % too is to work around the Word Perfect bug (see above).
  232. dup gcheck not {
  233. dup {
  234. dup type /dicttype eq { dup gcheck } { false } ifelse {
  235. % Copy-on-write, see above.
  236. 2 index wcheck not {
  237. 3 -1 roll dup length dict .copydict
  238. 3 1 roll
  239. } if
  240. .copytree 2 index 3 1 roll put
  241. } {
  242. pop pop
  243. } ifelse
  244. } forall
  245. } if
  246. % We would like to do a .setpagedevice so we don't keep
  247. % re-creating the dictionary. Unfortunately, the effect
  248. % of this is that if any dynamic key changes (PageCount
  249. % in particular), we will do the equivalent of a
  250. % setpagedevice at the next restore or grestore.
  251. % Therefore, we make the dictionary read-only, but
  252. % we don't store it away. I.e., NOT:
  253. % dup wcheck { .setpagedevice .currentpagedevice pop } if
  254. readonly
  255. } ifelse
  256. } if
  257. } bind odef
  258. % Copy a dictionary recursively.
  259. /.copytree { % <dict> .copytree <dict'>
  260. dup length dict exch {
  261. dup type /dicttype eq { .copytree } if 2 index 3 1 roll put
  262. } forall
  263. } bind def
  264. % The implementation of setpagedevice is quite complex. Currently,
  265. % everything but the media matching algorithm is implemented here.
  266. % By default, we only present the requested changes to the device,
  267. % but there are some parameters that require special merging action.
  268. % Define those parameters here, with the procedures that do the merging.
  269. % The procedures are called as follows:
  270. % <merged> <key> <new_value> -proc- <merged> <key> <new_value'>
  271. /.mergespecial mark
  272. /InputAttributes
  273. { dup null eq
  274. { pop null
  275. }
  276. { 3 copy pop .knownget
  277. { dup null eq
  278. { pop dup length dict }
  279. { dup length 2 index length add dict .copydict }
  280. ifelse
  281. }
  282. { dup length dict
  283. }
  284. ifelse .copydict readonly
  285. }
  286. ifelse
  287. } bind
  288. /OutputAttributes 1 index
  289. /Policies
  290. { 3 copy pop .knownget
  291. { dup length 2 index length add dict .copydict }
  292. { dup length dict }
  293. ifelse copy readonly
  294. } bind
  295. .dicttomark readonly def
  296. % Define the keys used in input attribute matching.
  297. /.inputattrkeys [
  298. /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet
  299. % The following are documented in Adobe's supplement for v2017.
  300. /LeadingEdge /MediaClass
  301. ] readonly def
  302. % Define other keys used in media selection.
  303. /.inputselectionkeys [
  304. /MediaPosition /Orientation
  305. ] readonly def
  306. % Define the keys used in output attribute matching.
  307. /.outputattrkeys [
  308. /OutputType
  309. ] readonly def
  310. % Define all the parameters that should always be copied to the merged
  311. % dictionary.
  312. /.copiedkeys [
  313. /OutputDevice
  314. .mergespecial { pop } forall
  315. .inputattrkeys aload pop
  316. .inputselectionkeys aload pop
  317. .outputattrkeys aload pop
  318. ] readonly def
  319. % Define the parameters that should not be presented to the device.
  320. % The procedures are called as follows:
  321. % <merged> <key> <value> -proc-
  322. % The procedure leaves all its operands on the stack and returns
  323. % true iff the key/value pair should be presented to .putdeviceparams.
  324. /.presentspecial mark
  325. .dynamicppkeys { pop false } forall
  326. % We must ignore an explicit request for .MediaSize,
  327. % because media matching always handles this.
  328. /.MediaSize false
  329. /Name false
  330. /OutputDevice false
  331. /PageDeviceName false
  332. /PageOffset false
  333. /PageSize false % obsolete alias for .MediaSize
  334. /InputAttributes false
  335. .inputattrkeys
  336. { dup /PageSize eq
  337. { pop }
  338. { { 2 index /InputAttributes .knownget { null eq } { true } ifelse } }
  339. ifelse
  340. }
  341. forall
  342. .inputselectionkeys { false } forall
  343. /OutputAttributes false
  344. .outputattrkeys
  345. { { 2 index /OutputAttributes .knownget { null eq } { true } ifelse } }
  346. forall
  347. /Install false
  348. /BeginPage false
  349. /EndPage false
  350. /Policies false
  351. % Our extensions:
  352. /HWColorMap
  353. { % HACK: don't transmit the color map, because
  354. % window systems can change the color map on their own
  355. % incrementally. Someday we'll have a better
  356. % solution for this....
  357. false
  358. }
  359. /ViewerPreProcess false
  360. .dicttomark readonly def
  361. % Define access to device defaults.
  362. /.defaultdeviceparams
  363. { finddevice null .getdeviceparams
  364. } bind def
  365. % Select media (input or output). The hard work is done in an operator:
  366. % <pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true
  367. % <pagedict> <attrdict> <policydict> <keys> .matchmedia false
  368. % <pagedict> null <policydict> <keys> .matchmedia null true
  369. /.selectmedia % <orig> <request> <merged> <failed> <-- retained
  370. % <attrdict> <policydict> <attrkeys> <mediakey>
  371. % .selectmedia
  372. { 5 index 5 -2 roll 4 index .matchmedia
  373. % Stack: orig request merged failed attrkeys mediakey
  374. % (key true | false)
  375. { 4 index 3 1 roll put pop
  376. }
  377. { % Adobe's implementations have a "big hairy heuristic"
  378. % to choose the set of keys to report as having failed the match.
  379. % For the moment, we report any keys that are in the request
  380. % and don't have the same value as in the original dictionary.
  381. 5 index 1 index .knownget
  382. { 4 index 3 1 roll put }
  383. { 3 index exch .undef }
  384. ifelse
  385. { % Stack: <orig> <request> <merged> <failed> <attrkey>
  386. 3 index 1 index .knownget
  387. { 5 index 2 index .knownget { ne } { pop true } ifelse }
  388. { true }
  389. ifelse % Stack: ... <failed> <attrkey> <report>
  390. { 2 copy /rangecheck put }
  391. if pop
  392. }
  393. forall
  394. }
  395. ifelse
  396. } bind def
  397. % Apply Policies to any unprocessed failed requests.
  398. % As we process each request entry, we replace the error name
  399. % in the <failed> dictionary with the policy value,
  400. % and we replace the key in the <merged> dictionary with its prior value
  401. % (or remove it if it had no prior value).
  402. /.policyprocs mark
  403. % These procedures are called with the following on the stack:
  404. % <orig> <merged> <failed> <Policies> <key> <policy>
  405. % They are expected to consume the top 2 operands.
  406. % NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize)
  407. % the same as 0, i.e., we signal an error.
  408. 0 { % Set errorinfo and signal a configurationerror.
  409. pop dup 4 index exch get 2 array astore
  410. $error /errorinfo 3 -1 roll put
  411. cleartomark
  412. /setpagedevice load /configurationerror signalerror
  413. } bind
  414. 1 { % Roll back the failed request to its previous status.
  415. DEBUG { (Rolling back.) = pstack flush } if
  416. 3 index 2 index 3 -1 roll put
  417. 4 index 1 index .knownget
  418. { 4 index 3 1 roll put }
  419. { 3 index exch .undef }
  420. ifelse
  421. } bind
  422. 7 { % For PageSize only, just impose the request.
  423. 1 index /PageSize eq
  424. { pop pop 1 index /PageSize 7 put }
  425. { .policyprocs 0 get exec }
  426. ifelse
  427. } bind
  428. .dicttomark readonly def
  429. /.applypolicies % <orig> <merged> <failed> .applypolicies
  430. % <orig> <merged'> <failed'>
  431. { 1 index /Policies get 1 index
  432. { type /integertype eq
  433. { pop % already processed
  434. }
  435. { 2 copy .knownget not { 1 index /PolicyNotFound get } if
  436. % Stack: <orig> <merged> <failed> <Policies> <key>
  437. % <policy>
  438. .policyprocs 1 index .knownget not { .policyprocs 0 get } if exec
  439. }
  440. ifelse
  441. }
  442. forall pop
  443. } bind def
  444. % Prepare to present parameters to the device, by spreading them onto the
  445. % operand stack and removing any that shouldn't be presented.
  446. /.prepareparams % <params> .prepareparams -mark- <key1> <value1> ...
  447. { mark exch dup
  448. { % Stack: -mark- key1 value1 ... merged key value
  449. .presentspecial 2 index .knownget
  450. { exec { 3 -1 roll } { pop pop } ifelse }
  451. { 3 -1 roll }
  452. ifelse
  453. }
  454. forall pop
  455. } bind def
  456. % Put device parameters without resetting currentpagedevice.
  457. % (.putdeviceparams clears the current page device.)
  458. /.putdeviceparamsonly % <device> <Policies|null> <require_all> -mark-
  459. % <key1> <value1> ... .putdeviceparamsonly
  460. % On success: <device> <eraseflag>
  461. % On failure: <device> <Policies|null> <req_all> -mark-
  462. % <key1> <error1> ...
  463. { .currentpagedevice
  464. { counttomark 4 add 1 roll .putdeviceparams
  465. dup type /booleantype eq { 3 } { counttomark 5 add } ifelse -1 roll
  466. .setpagedevice
  467. }
  468. { pop .putdeviceparams
  469. }
  470. ifelse
  471. } bind def
  472. % Try setting the device parameters from the merged request.
  473. /.trysetparams % <merged> <(ignored)> <device> <Policies>
  474. % .trysetparams
  475. { true 4 index .prepareparams
  476. % Add the computed .MediaSize.
  477. % Stack: merged (ignored) device Policies -true-
  478. % -mark- key1 value1 ...
  479. counttomark 5 add index .computemediasize
  480. exch pop exch pop /.MediaSize exch
  481. DEBUG { (Putting.) = pstack flush } if
  482. .putdeviceparamsonly
  483. DEBUG { (Result of putting.) = pstack flush } if
  484. } bind def
  485. % Compute the media size and initial matrix from a merged request (after
  486. % media selection).
  487. /.computemediasize % <request> .computemediasize
  488. % <request> <matrix> <[width height]>
  489. { dup /PageSize get % requested page size
  490. 1 index /InputAttributes get
  491. 2 index (%MediaSource) get get /PageSize get % media size
  492. % (may be a range)
  493. 2 index /Policies get
  494. dup /PageSize .knownget
  495. { exch pop } { /PolicyNotFound get } ifelse % PageSize policy,
  496. % affects scaling
  497. 3 index /Orientation .knownget not { null } if
  498. 4 index /RollFedMedia .knownget not { false } if
  499. matrix .matchpagesize not {
  500. % This is a "can't happen" condition!
  501. /setpagedevice load /rangecheck signalerror
  502. } if
  503. 2 array astore
  504. } bind def
  505. % ---------------- setpagedevice itself ---------------- %
  506. /setpagedevice
  507. { % We mustn't pop the argument until the very end,
  508. % so that the pseudo-operator machinery can restore the stack
  509. % if an error occurs.
  510. mark 1 index currentpagedevice
  511. % Check whether we are changing OutputDevice;
  512. % also handle the case where the current device
  513. % is not a page device.
  514. % Stack: mark <request> <current>
  515. DEBUG { (Checking.) = pstack flush } if
  516. dup /OutputDevice .knownget
  517. { % Current device is a page device.
  518. 2 index /OutputDevice .knownget
  519. { % A specific OutputDevice was requested.
  520. 2 copy eq
  521. { pop pop null }
  522. { exch pop }
  523. ifelse
  524. }
  525. { pop null
  526. }
  527. ifelse
  528. }
  529. { % Current device is not a page device.
  530. % Use the default device.
  531. 1 index /OutputDevice .knownget not { .defaultdevicename } if
  532. }
  533. ifelse
  534. dup null eq
  535. { pop
  536. }
  537. { exch pop .defaultdeviceparams
  538. % In case of duplicate keys, .dicttomark takes the entry
  539. % lower on the stack, so we can just append the defaults here.
  540. .requiredattrs { exec } forall .dicttomark
  541. }
  542. ifelse
  543. % Check whether a viewer wants to intervene.
  544. % We must check both the request (which takes precedence)
  545. % and the current dictionary.
  546. % Stack: mark <request> <orig>
  547. exch dup /ViewerPreProcess .knownget
  548. { exec }
  549. { 1 index /ViewerPreProcess .knownget { exec } if }
  550. ifelse exch
  551. % Construct a merged request from the actual request plus
  552. % any keys that should always be propagated.
  553. % Stack: mark <request> <orig>
  554. DEBUG { (Merging.) = pstack flush } if
  555. exch 1 index length 1 index length add dict
  556. .copiedkeys
  557. { % Stack: <orig> <request> <merged> <key>
  558. 3 index 1 index .knownget { 3 copy put pop } if pop
  559. }
  560. forall
  561. % Stack: <orig> <request> <merged>
  562. dup 2 index
  563. { % stack: <orig> <request> <merged> <merged> <rkey> <rvalue>
  564. .mergespecial 2 index .knownget { exec } if
  565. put dup
  566. }
  567. forall pop
  568. % Hack: if FIXEDRESOLUTION is true, discard any attempt to
  569. % change HWResolution.
  570. FIXEDRESOLUTION { dup /HWResolution .undef } if
  571. % Hack: if FIXEDMEDIA is true, discard any attempt to change
  572. % PageSize or HWSize.
  573. FIXEDMEDIA
  574. { dup /PageSize 4 index /PageSize get put
  575. dup /HWSize 4 index /HWSize get put
  576. } if
  577. % Hack: to work around some files that take a PageSize
  578. % from InputAttributes and impose it, discard any attempt
  579. % to set PageSize to a 4-element value.
  580. % Stack: mark <orig> <request> <merged>
  581. dup /PageSize .knownget {
  582. length 2 ne {
  583. dup /PageSize 4 index /PageSize get put
  584. } if
  585. } if
  586. % Select input and output media.
  587. % Stack: mark <orig> <request> <merged>
  588. DEBUG { (Selecting.) = pstack flush } if
  589. 0 dict % <failed>
  590. 1 index /InputAttributes .knownget
  591. { 2 index /Policies get
  592. .inputattrkeys (%MediaSource) cvn .selectmedia
  593. } if
  594. 1 index /OutputAttributes .knownget
  595. { 2 index /Policies get
  596. .outputattrkeys (%MediaDestination) cvn .selectmedia
  597. } if
  598. 3 -1 roll 4 1 roll % temporarily swap orig & request
  599. .applypolicies
  600. 3 -1 roll 4 1 roll % swap back
  601. % Construct the new device, and attempt to set its attributes.
  602. % Stack: mark <orig> <request> <merged> <failed>
  603. DEBUG { (Constructing.) = pstack flush } if
  604. currentdevice .devicename 2 index /OutputDevice get eq
  605. { currentdevice }
  606. { 1 index /OutputDevice get finddevice }
  607. ifelse
  608. %**************** We should copy the device here,
  609. %**************** but since we can't close the old device,
  610. %**************** we don't. This is WRONG.
  611. %****************copydevice
  612. 2 index /Policies get
  613. .trysetparams
  614. dup type /booleantype ne
  615. { % The request failed.
  616. % Stack: ... <orig> <request> <merged> <failed> <device>
  617. % <Policies> true mark <name> <errorname> ...
  618. DEBUG { (Recovering.) = pstack flush } if
  619. counttomark 4 add index
  620. counttomark 2 idiv { dup 4 -2 roll put } repeat
  621. pop pop pop
  622. % Stack: mark ... <orig> <request> <merged> <failed> <device>
  623. % <Policies>
  624. 6 2 roll 3 -1 roll 4 1 roll
  625. .applypolicies
  626. 3 -1 roll 4 1 roll 6 -2 roll
  627. .trysetparams % shouldn't fail!
  628. dup type /booleantype ne
  629. { 2 { counttomark 1 add 1 roll cleartomark } repeat
  630. /setpagedevice load exch signalerror
  631. }
  632. if
  633. }
  634. if
  635. % The attempt succeeded. Install the new device.
  636. % Stack: mark ... <merged> <failed> <device> <eraseflag>
  637. DEBUG { (Installing.) = pstack flush } if
  638. pop 2 .endpage
  639. { 1 true .outputpage
  640. (>>setpagedevice, press <return> to continue<<\n) .confirm
  641. }
  642. if
  643. % .setdevice clears the current page device!
  644. .currentpagedevice pop exch
  645. .setdevice pop
  646. .setpagedevice
  647. % Merge the request into the current page device,
  648. % unless we're changing the OutputDevice.
  649. % Stack: mark ... <merged> <failed>
  650. exch currentpagedevice dup length 2 index length add dict
  651. % Stack: mark ... <failed> <merged> <current> <newdict>
  652. 2 index /OutputDevice .knownget {
  653. 2 index /OutputDevice .knownget not { null } if eq
  654. } {
  655. true
  656. } ifelse {
  657. % Same OutputDevice, merge the dictionaries.
  658. .copydict
  659. } {
  660. % Different OutputDevice, discard the old dictionary.
  661. exch pop
  662. } ifelse .copydict
  663. % Initialize the default matrix, taking media matching
  664. % into account.
  665. .computemediasize pop initmatrix concat
  666. dup /PageOffset .knownget
  667. { % Translate by the given number of 1/72" units in device X/Y.
  668. dup 0 get exch 1 get
  669. 2 index /HWResolution get dup 1 get exch 0 get
  670. 4 -1 roll mul 72 div 3 1 roll mul 72 div
  671. idtransform translate
  672. }
  673. if
  674. % We must install the new page device dictionary
  675. % before calling the Install procedure.
  676. dup .setpagedevice
  677. .setdefaultscreen % Set the default screen before calling Install.
  678. dup /Install .knownget {
  679. { .execinstall } stopped { .postinstall stop } { .postinstall } ifelse
  680. } {
  681. .postinstall
  682. } ifelse
  683. } odef
  684. % We break out the code after calling the Install procedure into a
  685. % separate procedure, since it is executed even if Install causes an error.
  686. % By making .execinstall a separate operator procedure, we get the stacks
  687. % restored if it fails.
  688. /.execinstall { % <proc> .execinstall -
  689. % Because the interpreter optimizes tail calls, we can't just let
  690. % the body of this procedure be 'exec', because that would lose
  691. % the stack protection that is the whole reason for having the
  692. % procedure in the first place. We hack this by adding a couple
  693. % of extra tokens to ensure that the operator procedure is still
  694. % on the stack during the exec.
  695. exec
  696. 0 pop % See above.
  697. } odef
  698. /.postinstall { % mark ... <failed> <merged> .postinstall -
  699. matrix currentmatrix .setdefaultmatrix
  700. % Erase and initialize the page.
  701. erasepage initgraphics
  702. .beginpage
  703. % Clean up, calling PolicyReport if needed.
  704. % Stack: mark ... <failed> <merged>
  705. DEBUG { (Finishing.) = pstack flush } if
  706. exch dup length 0 ne
  707. { 1 index /Policies get /PolicyReport get
  708. counttomark 1 add 2 roll cleartomark
  709. exec
  710. }
  711. { cleartomark
  712. }
  713. ifelse pop
  714. } odef
  715. end % level2dict
  716. .setlanguagelevel