gs_cmap.ps 17 KB

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