gs_cidcm.ps 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. % Copyright (C) 2000 artofcode LLC. 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_cidcm.ps,v 1.5 2001/07/01 08:55:34 igorm Exp $
  18. % Extending Font resource category with CIDFont-CMap fonts.
  19. languagelevel 2 .setlanguagelevel currentglobal true setglobal
  20. % In the comments below, 'CSI' is an abbreviation/acronym for CIDSystemInfo.
  21. % We pre-scan resource files to retrieve the CSI from them.
  22. % First we define a hidden procset .prs_dict containing
  23. % necessary variables and procedures.
  24. % Then we redefine the old /Font category using this procset.
  25. % We maintain internal caches for the CSI values retrieved from
  26. % resource files. This supposes that document doesn't uninstall
  27. % resource files. To disable caching, set enable_cache to false.
  28. % We suppose that names starting with '.prs' do not appear in resource files.
  29. % If this causes any problem, this prefix should be systematically changed
  30. % in this file. ('prs' is an abbreviation for 'prescan'.)
  31. 25 dict begin
  32. % Define local variables :
  33. /.prs_dict currentdict def % self-reference (constant)
  34. /.prs_empty 0 dict readonly def
  35. /path_buffer 255 string def
  36. /name_buffer 255 string def
  37. /minus (-) 0 get def % character code constant for '-'
  38. /period (.) 0 get def % character code constant for '.'
  39. /CMap 10 dict def % CSI cache for CMaps
  40. /CIDFont 10 dict def % CSI cache for CIDFonts
  41. /enable_cache true def % set false to disable cache
  42. % The folloving variables are just placeholders for ones to be set
  43. % dynamically :
  44. /.prsFile 0 def % file to prescan
  45. /.prsResult 0 def % result of prescan
  46. /.prsDictCount 0 def % save the dictionary stack depth
  47. % Define a dummy CIDInit procset to use while pre-scanning :
  48. /DummyCIDInit 15 dict
  49. begin
  50. /begincmap {} def
  51. /usecmap {pop} bind def
  52. {stop} bind
  53. [ /begincodespacerange /endcodespacerange /beginnotdefchar /endnotdefchar
  54. /beginnotdefrange /endnotdefrange /begincidchar /endcidchar /begincidrange
  55. /endcidrange /endcmap /usefont /StartData
  56. ] {
  57. 1 index def
  58. } bind forall
  59. pop
  60. currentdict end def
  61. % Define a local 'findresource' for pre-scanning :
  62. % (it returns the dummy CIDInit instead of the regular CIDInit ProcSet)
  63. /findresource { % <InstName> <CatName> findresource <inst>
  64. 2 copy /ProcSet eq exch % /InstName /CatName bool /InstName
  65. /CIDInit eq and {
  66. pop pop //DummyCIDInit
  67. } {
  68. //findresource exec
  69. } ifelse
  70. } bind def
  71. % Define procedures for pre-scanning :
  72. /StopIfCSIDefined { % - StopIfCSIDefined -
  73. % Check if the dictionary stack contains a dictionary containing /CIDSystemInfo.
  74. % The search is limited to the top .prsDictCount dictionaries in the stack.
  75. % If so, retrieve the CSI, and execute stop to terminate the pre-scanning of the file.
  76. % Otherwise, do nothing, so the pre-scanning continues.
  77. countdictstack //.prs_dict /.prsDictCount get sub dup {
  78. currentdict /CIDSystemInfo .knownget {
  79. //.prs_dict exch /.prsResult exch put
  80. stop
  81. } if
  82. currentdict exch end
  83. } repeat {
  84. begin
  85. } repeat
  86. } bind def
  87. /PrescanFile { % - PrescanFile -
  88. { //.prs_dict /.prsFile get token {
  89. dup type % token type
  90. dup /nametype eq exch /operatortype eq or {
  91. dup xcheck {
  92. exec
  93. //StopIfCSIDefined exec
  94. } if
  95. } if
  96. } {
  97. stop
  98. } ifelse
  99. } loop
  100. } bind odef
  101. /GetCIDSystemInfoFromFile { % <file> GetCIDSystemInfoFromFile <CSI>
  102. % This procedure reads resource files with 'token',
  103. % executing the tokens untill /CIDSystemInfo appears to be defined.
  104. % Normally the resource file creates a new dictionary on
  105. % dictionary stack and defines /CIDSystemInfo in it.
  106. %
  107. % Returns an empty dictionary if no CIDSystemInfo is found.
  108. //.prs_dict begin
  109. /.prsFile exch def
  110. /.prsResult //.prs_empty def
  111. /.prsDictCount countdictstack def
  112. { //PrescanFile } stopped pop
  113. //.prs_dict /.prsResult get
  114. end
  115. } bind def
  116. /GetCIDSystemInfo { % <InstName> <CatName> GetCIDSystemInfo <CSI>
  117. % Retrieve CSI, using caches.
  118. 2 copy resourcestatus {
  119. pop 2 lt {
  120. findresource /CIDSystemInfo .knownget not {
  121. //.prs_empty
  122. } if
  123. } {
  124. dup //.prs_dict exch get % /InstName /CatName CSIs
  125. dup 3 index known
  126. //enable_cache and {
  127. exch pop exch get % CSI
  128. } {
  129. 3 1 roll % CSIs /InstName /CatName
  130. /Category findresource begin % CSIs /InstName
  131. dup //path_buffer ResourceFileName % CSIs /InstName (path)
  132. end
  133. currentglobal exch true setglobal % CSIs /InstName g
  134. mark exch % CSIs /InstName g [ (path)
  135. { (r) file % CSIs /InstName g [ file
  136. //GetCIDSystemInfoFromFile exec % CSIs /InstName g [ CSI
  137. } stopped {
  138. cleartomark //.prs_empty
  139. } {
  140. exch pop
  141. } ifelse % CSIs /InstName g CSI
  142. exch setglobal % CSIs /InstName CSI
  143. dup 4 1 roll % CSI CSIs /InstName CSI
  144. put % CSI
  145. } ifelse
  146. } ifelse
  147. } {
  148. pop pop //.prs_empty
  149. } ifelse
  150. } bind def
  151. /IsCompatibleCSI { % <CSI-M> <CSI-F> IsCompatibleCSI <bool>
  152. % The CSI in a CIDFont may be an array, a dict, or null.
  153. % If it is an array, it must be of 1 element, which is a dict.
  154. % In this case the dict is used for testing the compatibility.
  155. % Two dicts are compatible iff they contain same /Ordering and /Registry.
  156. exch % CSI-F CSI-M
  157. { dup type /arraytype eq {
  158. dup length 1 ne {
  159. pop pop false exit
  160. } if
  161. 0 get
  162. } if % CSI-F CSI-M
  163. dup type /dicttype ne {
  164. pop pop false exit
  165. } if % CSI-F <<CSI-M>>
  166. exch % <<CSI-M>> CSI-F
  167. dup type /dicttype ne {
  168. pop pop false exit
  169. } if % <<CSI-M>> <<CSI-F>>
  170. true % <<CSI-M>> <<CSI-F>> bEQ
  171. [/Registry /Ordering] {
  172. 2 index 1 index .knownget not {
  173. 1234567
  174. } if % <<CSI-M>> <<CSI-F>> bEQ /key vF
  175. exch % <<CSI-M>> <<CSI-F>> bEQ vF /key
  176. 4 index exch .knownget not {
  177. 7654321
  178. } if % <<CSI-M>> <<CSI-F>> bEQ vF vM
  179. eq and % <<CSI-M>> <<CSI-F>> bEQ
  180. } forall
  181. exch pop exch pop % bEQ
  182. exit
  183. } loop
  184. } bind def
  185. /IsComposedOK { % <CIDFontName> <CMapName> IsComposedOK <bool>
  186. % Check if the given CIDFont and CMap have compatible CSIs.
  187. exch % /CMapName /CIDFontName
  188. /CIDFont //GetCIDSystemInfo exec % /CMapName CSI-F
  189. dup type /dicttype eq {
  190. dup length 0 ne {
  191. exch % CSI-F /CMapName
  192. /CMap //GetCIDSystemInfo exec % CSI-F CSI-M
  193. //IsCompatibleCSI exec % bool
  194. } {
  195. pop pop false
  196. } ifelse
  197. } {
  198. pop pop false
  199. } ifelse
  200. } bind def
  201. /IsComposedFont { % <FontName> IsComposedFont <CIDFontName> <CMapName> true
  202. % <FontName> IsComposedFont false
  203. % Check if the given font name may be decomposed into CIDFont.CMap, CIDFont-CMap
  204. % or into CIDFont--CMap, such that CIDFont and CMap have compatible CSIs.
  205. % FontName
  206. dup type /stringtype ne {
  207. //name_buffer cvs
  208. } if % (FontName)
  209. { dup length 2 sub -1 1 {
  210. % (FontName) i
  211. 2 copy get dup //minus eq exch //period eq or {
  212. 2 copy 2 copy % (FontName) i (FontName) i (FontName) i
  213. 2 copy get //minus eq {
  214. 2 copy 1 sub get //minus eq {
  215. 1 sub
  216. } if
  217. } if % (FontName) i (FontName) i (FontName) i0
  218. 0 exch getinterval cvn % (FontName) i (FontName) i /CIDFontName
  219. 3 1 roll % (FontName) i /CIDFontName (FontName) i
  220. 1 add dup % (FontName) i /CIDFontName (FontName) i1 i1
  221. 5 index length % (FontName) i /CIDFontName (FontName) i1 i1 l
  222. exch sub getinterval cvn % (FontName) i /CIDFontName /CMapName
  223. 2 copy //IsComposedOK exec { % (FontName) i /CIDFontName /CMapName
  224. 4 2 roll pop pop % /CIDFontName /CMapName
  225. stop
  226. } if
  227. pop pop pop
  228. } {
  229. pop
  230. } ifelse % (FontName)
  231. } for
  232. pop
  233. } stopped
  234. } bind def
  235. /ComposeName { % <CIDFont> <CMap> <scr> ComposeName <CIDFont-CMap>
  236. dup dup 5 2 roll % (scr) (scr) /CIDFont /CMap (scr)
  237. 3 2 roll exch cvs length dup % (scr) (scr) /CMap l0 l0
  238. 4 -1 roll exch //minus put % (scr) /CMap l0
  239. 1 add dup % (scr) /CMap l1 l1
  240. 3 index dup length % (scr) /CMap l1 l1 (scr) L
  241. 2 index sub % (scr) /CMap l1 l1 (scr) LT
  242. 3 2 roll % (scr) /CMap l1 (scr) LT l1
  243. exch getinterval % (scr) /CMap l1 (scrT)
  244. 3 2 roll exch cvs length % (scr) l1 l2
  245. add 0 exch getinterval % (CIDFont-CMap)
  246. } bind def
  247. % Define a few procedure templates to be modified dynamically :
  248. currentpacking false setpacking
  249. /BindAux { % <proc> BindAux <proc>
  250. 0 exec
  251. } bind def
  252. /EnumerateFontNames { % - EnumerateFontNames ...
  253. % This is a pattern for enumeration procedure to be built dynamically,
  254. % using Bind with a temporary dictionary.
  255. % The following names will be replaced with specific objects
  256. % during Bind : en_local_dict, scr, proc, Fonts, Category .
  257. end % Category
  258. {
  259. 0 1 2 {
  260. en_local_dict exch /status exch put
  261. Fonts {
  262. en_local_dict /status get eq {
  263. scr cvs % ... (Font)
  264. proc exec %
  265. } {
  266. pop
  267. } ifelse % ...
  268. } forall
  269. } for % ...
  270. } stopped
  271. Category begin
  272. { stop } if
  273. } bind def
  274. setpacking
  275. /Bind { % <proc> Bind <proc>
  276. % Make a copy of the given procedure, binding in the values of all names
  277. % defined in currentdict.
  278. % Caution : this code cannot handle procedures that were already
  279. % bound recursively.
  280. dup length array copy
  281. dup length 1 sub -1 0 {
  282. 2 copy get % {precopy} i {elem}
  283. dup dup type /arraytype eq exch xcheck and {
  284. % {precopy} i {elem}
  285. //BindAux exec % {precopy} i {elem_copy}
  286. 2 index 3 1 roll put % {precopy}
  287. } {
  288. dup dup type /nametype eq exch xcheck and {
  289. % {precopy} i {elem}
  290. currentdict exch .knownget {
  291. 2 index 3 1 roll put % {precopy}
  292. } {
  293. pop
  294. } ifelse
  295. } {
  296. pop pop
  297. } ifelse
  298. } ifelse % {precopy}
  299. } for % {copy}
  300. cvx
  301. } bind def
  302. //BindAux 0 //Bind put % bind the recursive call in 'Bind'.
  303. % Redefine the /Font category with CIDFont-CMap construction :
  304. % The following code supposes that the following names are not
  305. % defined in the old /Font category dictionary :
  306. % /IsComposedFont, /Bind, /IsComposedOK, /EnumerateFontNames .
  307. /Font /Category findresource dup length dict copy begin
  308. /FindResource { % <InstName> FindResource <inst>
  309. dup //ResourceStatus exec {
  310. pop pop //FindResource exec
  311. } {
  312. dup //IsComposedFont exec { % /FontName /CIDFontName /CMapName
  313. exch [ exch ] composefont % inst
  314. } {
  315. //FindResource exec
  316. } ifelse
  317. } ifelse
  318. } bind def
  319. /ResourceStatus { % <InstName> ResourceStatus <nStatus> <nSize> true
  320. % <InstName> ResourceStatus false
  321. dup //ResourceStatus exec {
  322. 3 2 roll pop true % nStatus nSize true
  323. } {
  324. //IsComposedFont exec { % /CIDFontName /CMapName
  325. /CMap resourcestatus { % /CIDFontName nStatusM nSizeM
  326. exch pop exch % nSizeM /CIDFontName
  327. /CIDFont resourcestatus { % nSizeM nStatusF nSizeF
  328. exch pop % nSizeF nSizeM
  329. dup 0 ge {
  330. exch dup 0 ge {
  331. add
  332. } {
  333. exch pop
  334. } ifelse
  335. } {
  336. pop
  337. } ifelse % nSize
  338. 2 exch true % nStatus nSize true
  339. } {
  340. pop pop pop false % work around buggy resource file
  341. } ifelse
  342. } {
  343. pop pop pop false % work around buggy resource file
  344. } ifelse
  345. } {
  346. false
  347. } ifelse
  348. } ifelse
  349. } bind def
  350. /ResourceForAll { % <template> <proc> <scratch> ResourceForAll -
  351. % We suppose that the resourceforall procedure does not
  352. % define or install new fonts, CMaps, and/or CIDFonts.
  353. % First we create 3 temporary dictionaries to store temporary data
  354. % about fonts, CMaps and CIDFonts.
  355. % These dictionaries must be created dynamically, to allow for a possible
  356. % recursive call to resourceforall from the resourceforall procedure.
  357. currentglobal false setglobal
  358. 20 dict 20 dict 20 dict
  359. 4 -1 roll setglobal % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
  360. % Store resource names into local dictionaries :
  361. 5 index [ 2 index {exch cvn dup put} aload pop ] cvx 5 index //ResourceForAll exec
  362. (*) [ 3 index {exch cvn dup put} aload pop ] cvx 5 index /CMap resourceforall
  363. (*) [ 4 index {exch cvn dup put} aload pop ] cvx 5 index /CIDFont resourceforall
  364. %% Make the list of fonts in the form (/Name status) :
  365. % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
  366. dup {
  367. //ResourceStatus exec {
  368. pop 2 index % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>> /Name nStatus <<Font>>
  369. 3 1 roll put % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
  370. } {
  371. pop
  372. } ifelse
  373. } forall % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
  374. %% Add CIDFont-CMap to it (filtering duplicates) :
  375. 3 2 roll {
  376. 3 index {
  377. 3 1 roll % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap /CIDFont /CMap
  378. 6 index //ComposeName exec % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap (Font)
  379. dup 8 index .stringmatch {
  380. cvn % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap /Font
  381. dup 4 index exch known {
  382. pop pop
  383. } {
  384. 2 index % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap /Font /CIDFont
  385. 4 2 roll % (templ) proc (scr) <<CMap>> <<Font>> /Font /CIDFont /CIDFont /CMap
  386. //IsComposedOK exec {
  387. exch 2 index exch 2 put % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont
  388. } {
  389. exch pop
  390. } ifelse
  391. } ifelse
  392. } {
  393. pop pop
  394. } ifelse
  395. dup % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CIDFont
  396. } forall
  397. pop pop % (templ) proc (scr) <<CMap>> <<Font>>
  398. } forall % (templ) proc (scr) <<CMap>> <<Font>>
  399. exch pop % (templ) proc (scr) <<Font>>
  400. % Build the enumeration procedure :
  401. % Since the resourceforall procedure may leave values on the operand stack,
  402. % we cannot simply store the enumerator's local data on the stack.
  403. % We also cannot use a static dictionary to store local variables,
  404. % because of possible recursion in the resourceforall procedure.
  405. % To work around this, we create a copy of the enumeration procedure and
  406. % bind it dynamically with a temporary dictionary, which contains
  407. % local variables for the currently executing instance of resourceforall.
  408. currentdict
  409. 6 dict begin % the temporary dictionary
  410. /Category exch def
  411. /Fonts exch def
  412. /scr exch def
  413. /proc exch def
  414. /en_local_dict currentdict def
  415. //EnumerateFontNames //Bind exec % (templ) Enumerator
  416. /status 0 def % variable for the current status to enumerate - do not Bind with it !
  417. end
  418. exch pop % Enumerator
  419. % Do the enumeration :
  420. exec
  421. } bind def
  422. currentdict end /Font exch /Category defineresource pop
  423. end
  424. setglobal .setlanguagelevel