You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1044 lines
38 KiB

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