1 % Copyright (C) 2000 artofcode LLC. All rights reserved.
3 % This software is provided AS-IS with no warranty, either express or
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.
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.
16 % $Id: gs_cidcm.ps,v 1.12 2004/10/25 15:11:37 igor Exp $
17 % Extending Font resource category with CIDFont-CMap fonts.
19 languagelevel 2 .setlanguagelevel currentglobal true setglobal
22 % In the comments below, 'CSI' is an abbreviation/acronym for CIDSystemInfo.
23 % We pre-scan resource files to retrieve the CSI from them.
24 % First we define a hidden procset .prs_dict containing
25 % necessary variables and procedures.
26 % Then we redefine the old /Font category using this procset.
28 % We maintain internal caches for the CSI values retrieved from
29 % resource files. This supposes that document doesn't uninstall
30 % resource files. To disable caching, set enable_cache to false.
32 % We assume that names starting with '.prs' do not appear in resource files.
33 % If this causes any problem, this prefix should be systematically changed
34 % in this file. ('prs' is an abbreviation for 'prescan'.)
38 % Define local variables :
40 /.prs_dict currentdict def % self-reference (constant)
41 /.prs_empty 0 dict readonly def
42 /path_buffer 8192 string def
43 /name_buffer 1024 string def
44 /minus (-) 0 get def % character code constant for '-'
45 /period (.) 0 get def % character code constant for '.'
46 /CMap 10 dict def % CSI cache for CMaps
47 /CIDFont 10 dict def % CSI cache for CIDFonts
48 /enable_cache true def % set false to disable cache
50 % The folloving variables are just placeholders for ones to be set
52 /.prsFile 0 def % file to prescan
53 /.prsResult 0 def % result of prescan
54 /.prsDictCount 0 def % save the dictionary stack depth
56 % Define a dummy CIDInit procset to use while pre-scanning :
62 /usecmap {pop} bind def
65 [ /begincodespacerange /endcodespacerange /beginnotdefchar /endnotdefchar
66 /beginnotdefrange /endnotdefrange /begincidchar /endcidchar /begincidrange
67 /endcidrange /endcmap /usefont /StartData
75 % Define a local 'findresource' for pre-scanning :
76 % (it returns the dummy CIDInit instead of the regular CIDInit ProcSet)
78 /findresource { % <InstName> <CatName> findresource <inst>
79 2 copy /ProcSet eq exch % /InstName /CatName bool /InstName
81 pop pop //DummyCIDInit
87 % Define procedures for pre-scanning :
89 /StopIfCSIDefined { % - StopIfCSIDefined -
91 % Check if the dictionary stack contains a dictionary containing /CIDSystemInfo.
92 % The search is limited to the top .prsDictCount dictionaries in the stack.
93 % If so, retrieve the CSI, and execute stop to terminate the pre-scanning of the file.
94 % Otherwise, do nothing, so the pre-scanning continues.
96 countdictstack //.prs_dict /.prsDictCount get sub dup {
97 currentdict /CIDSystemInfo .knownget {
98 //.prs_dict exch /.prsResult exch put
107 /PrescanFile { % - PrescanFile -
108 { //.prs_dict /.prsFile get token {
109 dup type % token type
110 dup /nametype eq exch /operatortype eq or {
113 //StopIfCSIDefined exec
122 /GetCIDSystemInfoFromFile { % <file> GetCIDSystemInfoFromFile <CSI>
124 % This procedure reads resource files with 'token',
125 % executing the tokens untill /CIDSystemInfo appears to be defined.
126 % Normally the resource file creates a new dictionary on
127 % dictionary stack and defines /CIDSystemInfo in it.
129 % Returns an empty dictionary if no CIDSystemInfo is found.
131 RESMPDEBUG { (cidcm GetCIDSystemInfoFromFile beg) = } if
134 /.prsResult //.prs_empty def
135 /.prsDictCount countdictstack def
136 RESMPDEBUG { (cidcm GetCIDSystemInfoFromFile will PrescanFile.) = } if
137 { //PrescanFile } stopped pop
138 //.prs_dict /.prsResult get
140 RESMPDEBUG { (cidcm GetCIDSystemInfoFromFile end) = } if
143 /GetCIDSystemInfo { % <InstName> <CatName> GetCIDSystemInfo <CSI>
145 % Retrieve CSI, using caches.
147 RESMPDEBUG { (cidcm GetCIDSystemInfo beg) = } if
148 /Category findresource begin % /InstName
152 FindResource /CIDSystemInfo .knownget not {
156 currentdict /GetCIDSystemInfoFromMap .knownget {
159 dup type /nametype eq
161 RESMPDEBUG { (cidcm GetCIDSystemInfo got a name.) = } if
162 //.prs_dict Category get % /InstName CSIs
165 RESMPDEBUG { (cidcm GetCIDSystemInfo from cache.) = } if
168 RESMPDEBUG { (cidcm GetCIDSystemInfo from file.) = } if
169 exch % CSIs /InstName
170 dup //path_buffer ResourceFileName % CSIs /InstName (path)
171 RESMPDEBUG { (cidcm GetCIDSystemInfo from file ) print dup = } if
172 currentglobal exch true setglobal % CSIs /InstName g (path)
173 mark exch % CSIs /InstName g [ (path)
174 { (r) file % CSIs /InstName g [ file
175 //GetCIDSystemInfoFromFile exec % CSIs /InstName g [ CSI
177 cleartomark //.prs_empty
180 } ifelse % CSIs /InstName g CSI
181 exch setglobal % CSIs /InstName CSI
182 dup 4 1 roll % CSI CSIs /InstName CSI
185 (cidcm GetCIDSystemInfo got from file : <<) print
186 dup { exch //=string cvs print ( ) print
187 //=string cvs print ( ) print
198 RESMPDEBUG { (cidcm GetCIDSystemInfo end) = } if
201 /IsCompatibleCSI { % <CSI-M> <CSI-F> IsCompatibleCSI <bool>
203 % The CSI in a CIDFont may be an array, a dict, or null.
204 % If it is an array, it must be of 1 element, which is a dict.
205 % In this case the dict is used for testing the compatibility.
206 % Two dicts are compatible iff they contain same /Ordering and /Registry.
209 { dup type /arraytype eq {
215 dup type /dicttype ne {
217 } if % CSI-F <<CSI-M>>
218 exch % <<CSI-M>> CSI-F
219 dup type /dicttype ne {
221 } if % <<CSI-M>> <<CSI-F>>
222 true % <<CSI-M>> <<CSI-F>> bEQ
223 [/Registry /Ordering] {
224 2 index 1 index .knownget not {
226 } if % <<CSI-M>> <<CSI-F>> bEQ /key vF
227 exch % <<CSI-M>> <<CSI-F>> bEQ vF /key
228 4 index exch .knownget not {
230 } if % <<CSI-M>> <<CSI-F>> bEQ vF vM
231 eq and % <<CSI-M>> <<CSI-F>> bEQ
233 exch pop exch pop % bEQ
238 /IsWellComposed { % <CIDFontName> <CMapName> IsWellComposed <bool>
240 % Check if the given CIDFont and CMap have compatible CSIs.
241 exch % /CMapName /CIDFontName
242 /CIDFont //GetCIDSystemInfo exec % /CMapName CSI-F
243 dup type /dicttype eq {
245 exch % CSI-F /CMapName
246 /CMap //GetCIDSystemInfo exec % CSI-F CSI-M
247 //IsCompatibleCSI exec % bool
256 /IsComposedFont { % <FontName> IsComposedFont <CIDFontName> <CMapName> true
257 % <FontName> IsComposedFont false
259 % Check if the given font name may be decomposed into CIDFont.CMap, CIDFont-CMap
260 % or into CIDFont--CMap, such that CIDFont and CMap have compatible CSIs.
262 dup type /stringtype ne {
265 { dup length 2 sub -1 1 {
267 2 copy get dup //minus eq exch //period eq or {
268 2 copy 2 copy % (FontName) i (FontName) i (FontName) i
269 2 copy get //minus eq {
270 2 copy 1 sub get //minus eq {
273 } if % (FontName) i (FontName) i (FontName) i0
274 0 exch getinterval cvn % (FontName) i (FontName) i /CIDFontName
275 3 1 roll % (FontName) i /CIDFontName (FontName) i
276 1 add dup % (FontName) i /CIDFontName (FontName) i1 i1
277 5 index length % (FontName) i /CIDFontName (FontName) i1 i1 l
278 exch sub getinterval cvn % (FontName) i /CIDFontName /CMapName
279 2 copy //IsWellComposed exec { % (FontName) i /CIDFontName /CMapName
280 4 2 roll pop pop % /CIDFontName /CMapName
286 } ifelse % (FontName)
292 /ComposeName { % <CIDFont> <CMap> <scr> ComposeName <CIDFont-CMap>
293 dup dup 5 2 roll % (scr) (scr) /CIDFont /CMap (scr)
294 3 2 roll exch cvs length dup % (scr) (scr) /CMap l0 l0
295 4 -1 roll exch //minus put % (scr) /CMap l0
296 1 add dup % (scr) /CMap l1 l1
297 3 index dup length % (scr) /CMap l1 l1 (scr) L
298 2 index sub % (scr) /CMap l1 l1 (scr) LT
299 3 2 roll % (scr) /CMap l1 (scr) LT l1
300 exch getinterval % (scr) /CMap l1 (scrT)
301 3 2 roll exch cvs length % (scr) l1 l2
302 add 0 exch getinterval % (CIDFont-CMap)
305 % Redefine the /Font category with CIDFont-CMap construction :
307 % The following code supposes that the following names are not
308 % defined in the old /Font category dictionary :
309 % /IsComposedFont, /IsWellComposed .
312 /Font /Category findresource dup length dict copy begin
314 /FindResource { % <InstName> FindResource <inst>
315 dup //ResourceStatus exec {
316 pop pop //FindResource exec
318 dup //IsComposedFont exec { % /FontName /CIDFontName /CMapName
319 exch [ exch ] composefont % inst
326 /ResourceStatus { % <InstName> ResourceStatus <nStatus> <nSize> true
327 % <InstName> ResourceStatus false
328 dup //ResourceStatus exec {
329 3 2 roll pop true % nStatus nSize true
331 //IsComposedFont exec { % /CIDFontName /CMapName
332 /CMap resourcestatus { % /CIDFontName nStatusM nSizeM
333 exch pop exch % nSizeM /CIDFontName
334 /CIDFont resourcestatus { % nSizeM nStatusF nSizeF
335 exch pop % nSizeF nSizeM
345 2 exch true % nStatus nSize true
347 pop pop pop false % work around buggy resource file
350 pop pop pop false % work around buggy resource file
358 /ResourceForAll { % <template> <proc> <scratch> ResourceForAll -
360 % We suppose that the resourceforall procedure does not
361 % define or install new fonts, CMaps, and/or CIDFonts.
363 % First we create 3 temporary dictionaries to store temporary data
364 % about fonts, CMaps and CIDFonts.
365 % These dictionaries must be created dynamically, to allow for a possible
366 % recursive call to resourceforall from the resourceforall procedure.
367 currentglobal false setglobal
368 20 dict 20 dict 20 dict
370 4 -1 roll setglobal % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
372 % Store resource identifiers into local dictionaries
373 % A resource instance can have a key that is not a name or a string. In this
374 % case, resourceforall passes the key directly to proc instead of copying it
375 % into the scratch string. This case can arise only for a resource instance
376 % defined in virtual memory by a previous defineresource
378 % Discard non-string keys of CIDFont and CMap because <CIDFontName>- -<CMapName>
379 % is only defined for names.
381 { /.DisableResourceOrdering pop % gs_resmp accesses this through execstack - don't remove !
383 5 index [ 2 index {exch //null put} aload pop ] cvx bind 5 index //ResourceForAll exec
385 (*) [ 3 index {exch dup type /stringtype eq { cvn dup put } { pop pop } ifelse } aload pop
386 ] cvx bind 5 index /CMap resourceforall
388 (*) [ 4 index {exch dup type /stringtype eq { cvn dup put } { pop pop } ifelse } aload pop
389 ] cvx bind 5 index /CIDFont resourceforall
392 } loop % This loop is a pattern for execstack_lookup - don't remove !
394 %% Make the list of fonts in the form (/Name status) :
396 % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
399 //ResourceStatus exec {
400 pop 2 index % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>> /Name nStatus <<Font>>
401 3 1 roll put % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
405 } forall % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
407 %% Add CIDFont-CMap to it (filtering duplicates) :
411 3 1 roll % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap /CIDFont /CMap
412 6 index //ComposeName exec % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap (Font)
413 dup 8 index .stringmatch {
414 cvn % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap /Font
415 dup 4 index exch known {
418 2 index % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap /Font /CIDFont
419 4 2 roll % (templ) proc (scr) <<CMap>> <<Font>> /Font /CIDFont /CIDFont /CMap
420 //IsWellComposed exec {
421 exch 2 index exch 2 put % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont
429 dup % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CIDFont
431 pop pop % (templ) proc (scr) <<CMap>> <<Font>>
432 } forall % (templ) proc (scr) <<CMap>> <<Font>>
433 exch pop % (templ) proc (scr) <<Font>>
434 4 3 roll pop % proc (scr) <<Font>>
436 % Make the enumerator and apply it :
437 /MappedCategoryRedefiner /ProcSet findresource /MakeResourceEnumerator get exec exec
442 currentdict end /Font exch /Category defineresource pop
444 setglobal .setlanguagelevel