home *** CD-ROM | disk | FTP | other *** search
/ Mixa 155: Dogs / MIXA 155: Dogs.iso / pc / Viewer / BROWSER(W) / フィルタ / PDF / LIB / gs_cidcm.ps < prev    next >
Encoding:
Text File  |  2002-10-29  |  17.8 KB  |  483 lines

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