gs_cmap.ps 14 KB

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