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