home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 April / PCWorld_2001-04_cd.bin / Software / Vyzkuste / gs / gs650w32.exe / gs6.50 / lib / gs_cidcm.ps < prev    next >
Text File  |  2000-12-05  |  18KB  |  488 lines

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