gs_cidcm.ps 17 KB

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