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.

568 lines
18 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. % ProcSet for implementing CMap resources.
  16. % When this is run, systemdict is still writable.
  17. % NOTE: Rearranged fonts are not implemented yet.
  18. [
  19. /CMERGE_DEBUG
  20. /USE_CIDCHAR_AS_RANGE
  21. ] {dup where {pop pop} { currentdict exch //false def pop } ifelse} forall
  22. % ---------------- Public operators ---------------- %
  23. /.rewriteTempMapsNotDef {
  24. %
  25. % Before building .CodeMapData from .TempMaps,
  26. % we need to replace dst type codes in the notdef map with the value 3,
  27. % which corresponds to CODE_VALUE_NOTDEF, see gxfcmap.h .
  28. %
  29. CMAPDEBUG { (rewriting TempMapsNotDef\n) print flush } if
  30. .TempMaps 2 get
  31. dup length 0 gt {
  32. 0 get
  33. CMAPDEBUG { (...original...\n) print flush } if
  34. 1 5 2 index length 1 sub {
  35. { 1 index exch get 2 3 put } stopped
  36. { CMAPDEBUG { (cannot rewrite\n) print flush } if }
  37. { CMAPDEBUG { (rewrite\n) print flush } if } ifelse
  38. } for
  39. } if
  40. pop
  41. CMAPDEBUG { (...FINISHED...\n) print } if
  42. } .internalbind def
  43. /.composefontdict { % <name> <cmap|cmapname> <fonts> composefont <name> <font_dict>
  44. 10 dict begin
  45. /CMap 2 index dup type /dicttype ne { /CMap findresource } if def
  46. /FDepVector 1 index cvlit def % temporarily
  47. /Encoding [ 0 1 FDepVector length 1 sub { } for ] def
  48. /FontInfo 1 dict def % for .processToUnicode in pdf_font.ps .
  49. /FDepVector [ 0 1 FDepVector length 1 sub {
  50. % Stack: name cmap[name] fonts /FDepVector [ fonts... i
  51. FDepVector 1 index get
  52. dup type /dicttype ne {
  53. dup /CIDFont resourcestatus {
  54. pop pop /CIDFont
  55. } {
  56. /Font
  57. } ifelse findresource
  58. } if
  59. exch CMap /FontMatrices get dup length 2 index gt {
  60. exch get dup //null eq { pop } { makefont } ifelse
  61. } {
  62. pop pop
  63. } ifelse
  64. } for ] readonly def
  65. /FMapType 9 def
  66. /FontMatrix matrix def
  67. /FontName 3 index def
  68. CMap /WMode .knownget { /WMode exch def } if
  69. /FontType 0 def
  70. pop pop currentdict end
  71. } .internalbind odef
  72. % composefont doesn't appear in CMap files -- it's documented in
  73. % the "PostScript Language Reference Manual Supplement".
  74. /composefont { % <name> <cmap|cmapname> <fonts> composefont <font>
  75. .composefontdict /Font defineresource
  76. } .internalbind def
  77. % ---------------- CMap operators ---------------- %
  78. 40 dict begin
  79. % Our internal .CodeMapData structure closely mirrors the structures
  80. % defined in gxfcmap.h (q.v.). () indicate a string, [] indicate an array,
  81. % ? indicates a Boolean, # indicates an integer, {} for grouping.
  82. % [[[(first) (last) ...]+] % code space ranges
  83. % [[(prefix) (key_size,?is_range,value_type,value_size) (keys...)
  84. % {(values...) | [value ...]} #font_index ]+] % code mappings
  85. % ...]
  86. % <<same>> % notdef mappings
  87. % ]
  88. % FontMatrices is the array of matrices defined by begin/endusematrix.
  89. % All of the arrays and strings are read-only after they have been built.
  90. %
  91. % Note that the code in zfcmap.c that constructs the C structures from
  92. % the PostScript structures has intimate knowledge of the above format.
  93. % ****** NOTE: The code currently only handles "well-behaved" CMaps:
  94. % - CID values only (no bfchars), 16-bit
  95. % - Entries (both code space and map) must be sorted
  96. % - Only the last byte must vary in each map range, except for
  97. % the identity mapping
  98. % ------ Font-level operators ------ %
  99. /begincmap { % - begincmap -
  100. /.CodeMapData [[[]] [[]] [[]]] def
  101. /FontMatrices [] def
  102. /.FontIndex 0 def
  103. /.TempMaps [20 dict 50 dict 50 dict] def
  104. /CodeMap //null def % for .buildcmap
  105. } .internalbind def
  106. /endcmap { % - endcmap -
  107. //.rewriteTempMapsNotDef exec
  108. CMAPDEBUG {
  109. 2 (*** undefined charmap ***)
  110. 1 (*** defined charmap ***)
  111. 0 (*** code space ranges ***)
  112. 3 { =
  113. .TempMaps exch get
  114. 0 1 2 index length 1 sub {
  115. dup //== exec (\t) print
  116. 1 index exch get //== exec
  117. } for
  118. pop
  119. } repeat
  120. } if
  121. /.CodeMapData dup load [ exch
  122. .TempMaps aload pop begin begin begin
  123. {
  124. [ exch aload pop
  125. 0 1 currentdict length 1 sub {
  126. currentdict exch get
  127. } for
  128. ]
  129. end
  130. } forall
  131. ] .endmap def
  132. CMAPDEBUG {
  133. (*** Content of .CodeMapData ***) =
  134. 0 .CodeMapData { exch dup //== exec 1 add exch (\t) print //== exec } forall
  135. pop
  136. } if
  137. currentdict /.TempMaps undef
  138. /FontMatrices FontMatrices .endmap def
  139. } .internalbind def
  140. /.endmap { % <map> .endmap <map>
  141. dup type /arraytype eq {
  142. % This might be a shared read-only array inherited via usecmap.
  143. % Don't try to update its elements if this is the case.
  144. dup wcheck {
  145. 0 1 2 index length 1 sub {
  146. 2 copy 2 copy get .endmap put pop
  147. } for readonly
  148. } if
  149. } {
  150. dup type /stringtype eq { readonly } if
  151. } ifelse
  152. } .internalbind def
  153. /.appendmap { % -mark- <elt> ... <array#> .appendmap -
  154. .TempMaps exch get counttomark 1 add 1 roll
  155. ] 1 index length exch put
  156. } .internalbind def
  157. /begincodespacerange { % <count> begincodespacerange -
  158. pop mark
  159. } .internalbind def
  160. /endcodespacerange { % <code_lo> <code_hi> ... endcodespacerange -
  161. 0 .appendmap
  162. } .internalbind def
  163. /usecmap { % <CMap_name> usecmap -
  164. /CMap findresource dup
  165. % Copy the top level of .CodeMapData
  166. /.CodeMapData exch /.CodeMapData get copyarray def
  167. /FontMatrices exch /FontMatrices get copyarray def
  168. } .internalbind def
  169. /usefont { % <fontID> usefont -
  170. /.FontIndex exch def
  171. } .internalbind def
  172. /beginusematrix { % <fontID> beginusematrix -
  173. FontMatrices wcheck not FontMatrices length 2 index le or {
  174. FontMatrices length 1 index 1 add .max array
  175. dup 0 FontMatrices putinterval
  176. /FontMatrices exch def
  177. } if
  178. } .internalbind def
  179. /endusematrix { % <matrix> endusematrix -
  180. FontMatrices 3 1 roll put
  181. } .internalbind def
  182. % ------ Rearranged font operators ------ %
  183. /beginrearrangedfont { % <font_name> <font*> beginrearrangedfont -
  184. 10 dict begin
  185. /.FontNames exch def
  186. /.FontName exch def
  187. begincmap
  188. } .internalbind def
  189. /endrearrangedfont { % - endrearrangedfont -
  190. (REARRANGED FONTS NOT IMPLEMENTED YET.) = flush
  191. .FontName .FontNames 0 get findfont end definefont pop
  192. } .internalbind def
  193. % ------ Character name/code selector operators ------ %
  194. /beginbfchar { % <count> beginbfchar -
  195. pop mark
  196. } .internalbind def
  197. /endbfchar { % [ <code> <to_code|charname> ... endbfchar
  198. ] [ //true % [<da><ta>] [ true
  199. 3 -1 roll % [ true [<da><ta>]
  200. {
  201. exch {
  202. //false % [ <da> false
  203. } { % [ <da> <ta>
  204. .addbfchar % [ prefix params key value font_index
  205. //true
  206. } ifelse
  207. } forall
  208. pop
  209. 1 .appendmap
  210. } .internalbind def
  211. /beginbfrange { % <count> beginbfrange -
  212. pop mark
  213. } .internalbind def
  214. /endbfrange { % <code_lo> <code_hi> <to_code|(charname*)> ...
  215. % endbfrange -
  216. ] [ 0 % [<da><ta><set>] [ 0
  217. 3 -1 roll % [ 0 [<da><ta><set>]
  218. {
  219. exch % [ <da> 0
  220. { 1 2
  221. {
  222. dup type dup /arraytype eq exch /packedarraytype eq or {
  223. % Array value, split up.
  224. exch pop {
  225. % Stack: code to_code|charname
  226. 1 index exch .addbfchar
  227. % Increment the code. As noted above, we require
  228. % that only the last byte vary, but we still must
  229. % mask it after incrementing, in case the last
  230. % value was 0xff.
  231. % Stack: code prefix params key value fontindex
  232. 6 -1 roll dup length string copy
  233. dup dup length 1 sub 2 copy get 1 add 255 and put
  234. } forall pop
  235. } {
  236. % Single value, handle directly.
  237. .addbfrange
  238. } ifelse
  239. 0
  240. }
  241. } exch get exec
  242. } forall
  243. pop
  244. 1 .appendmap
  245. } .internalbind def
  246. /.addbfchar { % <code> <to_code|charname> .addbfchar
  247. % <prefix> <params> <key> <value> <font_index>
  248. 1 index exch .addbfrange
  249. } .internalbind def
  250. /.addbfrange { % <code_lo> <code_hi> <to_code|charname>
  251. % .addbfrange <<same as .addbfchar>>
  252. 4 string dup 3
  253. 3 index type /nametype eq {
  254. 2 index 2 1 put % dst = CODE_VALUE_GLYPH, see gxfcmap.h .
  255. 4 -1 roll 1 array astore 4 1 roll 4
  256. } {
  257. 2 index 2 2 put % dst = CODE_VALUE_CHARS, see gxfcmap.h .
  258. 3 index length
  259. } ifelse put
  260. % Stack: code_lo code_hi value params
  261. 3 index 3 index eq {
  262. % Single value.
  263. 3 -1 roll pop exch () exch
  264. } {
  265. % Range.
  266. dup 0 4 index length put
  267. dup 1 1 put
  268. 4 2 roll
  269. 1 index dup length 1 sub 0 exch getinterval 5 1 roll % prefix
  270. % Stack: prefix value params code_lo code_hi
  271. concatstrings
  272. 3 -1 roll
  273. } ifelse
  274. .FontIndex
  275. } .internalbind def
  276. % ------ CID selector operators ------ %
  277. /begincidchar { % <count> begincidchar -
  278. pop mark
  279. } .internalbind def
  280. /endcidchar { % <code> <cid> ... endcidchar -
  281. 1 .endmapchars
  282. } .internalbind def
  283. /begincidrange { % <count> begincidrange -
  284. pop mark
  285. } .internalbind def
  286. /endcidrange { % <code_lo> <code_hi> <cid_base> ... endcidrange -
  287. 1 .endmapranges
  288. } .internalbind def
  289. /.endmapchars { % -mark- <code> <cid> ... <map#> .endmapchars -
  290. counttomark 1 add 1 roll
  291. counttomark 2 idiv {
  292. counttomark -2 roll % process in correct order
  293. exch % <cid> <code>
  294. % Construct prefix, params, key, value, font_index
  295. dup length 1 eq { % 1-byte
  296. <00 00 00 02> () % <prefix> <param> <null_key>
  297. } { % N-byte
  298. dup 0 1 getinterval exch % make 1-byte prefix
  299. 4 string dup 0
  300. USE_CIDCHAR_AS_RANGE {
  301. <00 01 00 02> % skelton for param
  302. } {
  303. <00 00 00 02> % skelton for param
  304. } ifelse
  305. putinterval
  306. exch % <prefix> <param> <code>
  307. dup length % <prefix> <param> <code> N
  308. 1 sub % <prefix> <param> <code> N-1
  309. dup % <prefix> <param> <code> N-1 N-1
  310. 3 index % <prefix> <param> <code> N-1 N-1 <param>
  311. exch % <prefix> <param> <code> N-1 <param> N-1
  312. 0 exch % <prefix> <param> <code> N-1 <param> 0 N-1
  313. put % <prefix> <param'> <code> N-1
  314. 1 exch % <prefix> <param'> <code> 1 N-1
  315. getinterval % <prefix> <param'> <key>
  316. USE_CIDCHAR_AS_RANGE {
  317. dup length 2 mul string % <key> <dkey>
  318. dup % <key> <dkey> <dkey>
  319. 2 index % <key> <dkey> <dkey> <key>
  320. 0 exch putinterval % <key> <dkey'>
  321. dup % <key> <dkey'> <dkey'>
  322. 3 -1 roll % <dkey'> <dkey'> <key>
  323. dup length % <dkey'> <dkey'> <key> N-1
  324. exch putinterval % <dkey''>
  325. } if
  326. } ifelse
  327. 4 -1 roll % <prefix> <param'> <key> <cid>
  328. .endmapvalue % <prefix> <param'> <key> <hex_cid> <font_idx>
  329. % prefix params keys value fontindex
  330. counttomark 9 gt { % 2 (or more) ranges (1 range = 5 item)
  331. 4 index 10 index eq % compare prefix
  332. 4 index 10 index eq and % compare params
  333. 1 index 7 index eq and % compare fontindex
  334. {
  335. CMAPDEBUG { (merge! char\n) print } if
  336. pop 4 2 roll pop pop
  337. % prefix params keys value fontindex keys2 value2
  338. 5 -1 roll 3 -1 roll concatstrings
  339. % prefix params value fontindex value2 keys'
  340. 4 -1 roll 3 -1 roll concatstrings
  341. % prefix params fontindex keys' values'
  342. 3 -1 roll
  343. } if
  344. } if % end of 2 (or more) ranges
  345. CMERGE_DEBUG {
  346. ( prefix:) print 4 index =only
  347. ( param:) print 3 index =only
  348. ( key:) print 2 index =only
  349. ( hex_cid:) print 1 index =only
  350. ( font_idx:) print 0 index //== exec flush
  351. } if
  352. } repeat
  353. counttomark 2 add -1 roll .appendmap
  354. } .internalbind def
  355. /.endmapranges { % -mark- <code_lo> <code_hi> <cid_base> ... <map#>
  356. % .endmapranges -
  357. counttomark 1 add 1 roll
  358. counttomark 3 idiv {
  359. counttomark -3 roll % process in correct order
  360. % Construct prefix, params, key_lo, key_hi, value, font_index
  361. 3 1 roll % <cid_base> <code_lo> <code_hi>
  362. % prefix key
  363. % 1-byte code: () .
  364. % 1-byte range: () .
  365. % N-byte code: . (*)
  366. % N-byte range: (*) (*)
  367. dup 2 index eq { % <code_lo> == <code_hi>
  368. % 0: prefix_len for 1-byte code
  369. % 1: prefix_len for N-byte code
  370. dup length 1 eq { 0 } { 1 } ifelse
  371. } { % <code_lo> != <code_hi>
  372. % calculate prefix_len for *-byte range
  373. dup length 1 sub % <cid_base> <code_lo> <code_hi> <code_len-1>
  374. 0 % initial value for N
  375. { % <cid_base> <code_lo> <code_hi> (code_len-1) N
  376. dup 2 index ge { exit } if % if (N >= len - 1) exit
  377. 3 index 1 index get % N-th byte of code_lo
  378. 3 index 2 index get % N-th byte of code_hi
  379. eq { 1 add } { exit } ifelse
  380. } loop
  381. exch pop % discard <code_len-1>
  382. } ifelse
  383. % cid_base code_lo code_hi prefix_len
  384. % Althogh Adobe CPSI with native CID/CMap support accept
  385. % multi-dimensional range specification in notdef & cidrange
  386. % (and CID is calculated as relative position in multi-dimensional
  387. % range), but older CPSI & ATM cannot handle it.
  388. %
  389. % GS accepts such specification, but it's recommended to keep
  390. % from using this feature for notdef & cidrange.
  391. % Following is a disabler of this feature.
  392. % -------------------------------------------------------------
  393. % counttomark 1 add index % get map#
  394. % 0 ne { % if not codespacerange
  395. % 1 index length % get code length
  396. % 1 index % get prefix length
  397. % sub % calculate key length
  398. % 1 gt { % if (key_len > 1),
  399. % (.endmapranges error) = flush
  400. % (multi-dimensional range specification is used out of codespacerange)
  401. % = flush
  402. % (/) =only
  403. % CMapName CMapName length string cvs =only
  404. % (: <) =only
  405. % 2 index (%stdout) (w) file exch writehexstring
  406. % (> <) =only
  407. % 1 index (%stdout) (w) file exch writehexstring
  408. % (>\n) =only flush
  409. % quit
  410. % } if
  411. % } if
  412. % -------------------------------------------------------------
  413. 1 index exch 0 exch getinterval
  414. % cid_base code_lo code_hi prefix
  415. dup length 3 index length exch sub
  416. % cid_base code_lo code_hi prefix range_len
  417. dup 255 gt {
  418. (too long coderange specification for current GS\n) print
  419. /.endmapranges cvx /rangecheck signalerror
  420. } if
  421. <00 01 00 02> 4 string copy % create initialized param
  422. dup 0 4 -1 roll put % put range_len into param
  423. % get key_hi
  424. 3 -1 roll dup length 3 index length dup 3 1 roll sub getinterval
  425. % get key_lo
  426. 4 -1 roll dup length 4 index length dup 3 1 roll sub getinterval
  427. % make "keys" (concatenated key_lo + key_hi)
  428. exch concatstrings
  429. %
  430. 4 -1 roll
  431. .endmapvalue
  432. % See if we can merge with the previous value.
  433. % The prefix, params, and font index must match.
  434. % prefix params keys value fontindex
  435. counttomark 9 gt { % 2 (or more) ranges (1 range = 5 item)
  436. 4 index 10 index eq % compare prefix
  437. 4 index 10 index eq and % compare params
  438. 1 index 7 index eq and % compare fontindex
  439. {
  440. CMAPDEBUG { (merge!\n) print } if
  441. pop 4 2 roll pop pop
  442. % prefix params keys value fontindex keys2 value2
  443. 5 -1 roll 3 -1 roll concatstrings
  444. % prefix params value fontindex value2 keys'
  445. 4 -1 roll 3 -1 roll concatstrings
  446. % prefix params fontindex keys' values'
  447. 3 -1 roll
  448. } if
  449. } if % end of 2 (or more) ranges
  450. } repeat
  451. counttomark 2 add -1 roll .appendmap
  452. } .internalbind def
  453. /.endmapvalue { % <cid> .endmapvalue (hi,lo) .FontIndex
  454. 2 string dup 0 3 index -8 bitshift put % value
  455. dup 1 4 -1 roll 255 and put
  456. .FontIndex % font_index
  457. } .internalbind def
  458. % ------ notdef operators ------ %
  459. /beginnotdefchar { % <count> beginnotdefchar -
  460. pop mark
  461. } .internalbind def
  462. /endnotdefchar { % <code> <cid> ... endnotdefchar -
  463. 2 .endmapchars
  464. } .internalbind def
  465. /beginnotdefrange { % <count> beginnotdefrange -
  466. pop mark
  467. } .internalbind def
  468. /endnotdefrange { % <code_lo> <code_hi> <cid> ... endnotdefrange -
  469. 2 .endmapranges
  470. } .internalbind def
  471. % ---------------- Resource category definition ---------------- %
  472. currentdict end
  473. languagelevel exch 2 .setlanguagelevel
  474. /CMap /Generic /Category findresource dup length dict .copydict
  475. dup /InstanceType /dicttype put
  476. dup /DefineResource {
  477. % The AdobePS5 Windows driver emits code that attempts to
  478. % create CMaps without the required CMapName entry.
  479. % Work around this here.
  480. dup /CMapName known not {
  481. dup wcheck not {
  482. .currentglobal exch dup wcheck .setglobal
  483. dup length dict .copydict exch .setglobal
  484. } if
  485. dup gcheck 2 index gcheck not and {
  486. exch .currentglobal exch //true .setglobal
  487. dup length string copy exch .setglobal exch
  488. } if dup /CMapName 3 index put
  489. } if
  490. % Adobe PS CET 23-25 and others define an almost empty CMap. Tolerate this.
  491. % With the above, we can actually tolerate: /name << >> defineresource
  492. dup /CIDSystemInfo known not {
  493. dup wcheck not {
  494. .currentglobal exch dup wcheck .setglobal
  495. dup length dict .copydict exch .setglobal
  496. } if
  497. dup /CIDSystemInfo [ //null ] put
  498. } if
  499. dup /CodeMap .knownget { //null eq { .buildcmap } if } if
  500. /Generic /Category findresource /DefineResource get exec
  501. } .internalbind put
  502. /Category defineresource pop
  503. % We might have loaded CID font support already.
  504. /CIDInit /ProcSet 2 copy { findresource } //.internalstopped exec
  505. % An interior `stopped' might have reset VM allocation to local.
  506. //true .setglobal
  507. { pop pop 3 -1 roll }
  508. { dup length 4 index length add dict .copydict 4 -1 roll exch .copydict }
  509. ifelse exch defineresource pop
  510. currentdict /.rewriteTempMapsNotDef .undef
  511. .setlanguagelevel