home *** CD-ROM | disk | FTP | other *** search
/ jppd.dyndns.org / jppd.dyndns.org.tar / jppd.dyndns.org / QUERYPRO / Impressora_PDF / converter.exe / GPLGS / gs_ttf.ps < prev    next >
Text File  |  2004-08-05  |  43KB  |  1,343 lines

  1. %    Copyright (C) 1996-2003 artofcode LLC.  All rights reserved.
  2. % This software is provided AS-IS with no warranty, either express or
  3. % implied.
  4. % This software is distributed under license and may not be copied,
  5. % modified or distributed except as expressly authorized under the terms
  6. % of the license contained in the file LICENSE in this distribution.
  7. % For more information about licensing, please refer to
  8. % http://www.ghostscript.com/licensing/. For information on
  9. % commercial licensing, go to http://www.artifex.com/licensing/ or
  10. % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  11. % San Rafael, CA  94903, U.S.A., +1(415)492-9861.
  12.  
  13. % $Id: gs_ttf.ps,v 1.28.2.5 2004/08/04 15:20:10 ray Exp $
  14. % Support code for direct use of TrueType fonts.
  15. % (Not needed for Type 42 fonts.)
  16.  
  17. % Note that if you want to use this file without including the ttfont.dev
  18. % option when you built Ghostscript, you will need to load the following
  19. % files before this one:
  20. %    lib/gs_mgl_e.ps
  21. %    lib/gs_mro_e.ps
  22. %    lib/gs_wan_e.ps
  23.  
  24. % Thanks to B. Jackowski and GUST (the Polish TeX Users' Group) for
  25. % the glyf-splitting code.
  26.  
  27. % ---------------- Font loading machinery ---------------- %
  28.  
  29. % Augment the FONTPATH machinery so it recognizes TrueType fonts.
  30.  
  31. /.scanfontheaders where {
  32.   pop /.scanfontheaders [
  33.    .scanfontheaders aload pop (\000\001\000\000*) (true*)
  34.   ] def
  35. } if
  36.  
  37. % <file> <key> .findfontvalue <value> true
  38. % <file> <key> .findfontvalue false
  39. % Closes the file in either case.
  40. /.findnonttfontvalue /.findfontvalue load def
  41. /.findfontvalue {
  42.   1 index read {
  43.     2 index 1 index unread
  44.     dup 0 eq exch (t) 0 get eq or {
  45.         % If this is a font at all, it's a TrueType font.
  46.       dup /FontType eq {
  47.         pop closefile 42 true
  48.       } {
  49.         dup /FontName eq { pop .findttfontname } { pop closefile false } ifelse
  50.       } ifelse
  51.     } {
  52.         % Not a TrueType font.
  53.       .findnonttfontvalue
  54.     } ifelse
  55.   } { pop closefile false } ifelse
  56. } bind def
  57.  
  58. % <file> .findttfontname <fname> true
  59. % <file> .findttfontname false
  60. % Closes the file in either case.
  61. /.findttfontname {
  62.   //true 0 .loadttfonttables
  63.   tabdict /name .knownget {
  64.     dup 8 getu32 f exch setfileposition
  65.     12 getu32 string f exch readstring pop
  66.     6 findname
  67.   } {
  68.     false
  69.   } ifelse
  70.   f closefile end end
  71. } bind def
  72.  
  73. % Load a font file that might be a TrueType font.
  74.  
  75. % <file> .loadfontfile -
  76. /.loadnonttfontfile /.loadfontfile load def
  77. /.loadfontfile {
  78.   dup read pop 2 copy unread 0 eq {
  79.         % If this is a font at all, it's a TrueType font.
  80.     .loadttfont pop
  81.   } {
  82.         % Not a TrueType font.
  83.     .loadnonttfontfile
  84.   } ifelse
  85. } bind def
  86.  
  87. % ---------------- Automatic Type 42 generation ---------------- %
  88.  
  89. % Load a TrueType font from a file as a Type 42 PostScript font.
  90. % The thing that makes this really messy is the handling of encodings.
  91. % There are 2 interacting tables that affect the encoding:
  92. %       'cmap' provides multiple maps from character codes to glyph indices
  93. %       'post' maps glyph indices to glyph names (if present)
  94. % What we need to get out of this is:
  95. %       Encoding mapping character codes to glyph names
  96. %         (the composition of cmap and post)
  97. %       CharStrings mapping glyph names to glyph indices
  98. %         (the inverse of post)
  99. % If the post table is missing, we have to take a guess based on the cmap
  100. % table.
  101.  
  102. /.loadttfontdict 50 dict dup begin
  103.  
  104. /orgXUID AladdinEnterprisesXUID def
  105. /maxstring 32764 def    % half the maximum length of a PostScript string,
  106.             % must be a multiple of 4 (for hmtx / loca / vmtx)
  107.  
  108. /.invert_encoding   % <array> invert_encoding <dict>
  109. { dup 256 dict exch
  110.   0 exch 1 exch length 1 sub {     % [] <> i
  111.     dup 3 index exch get           % [] <> i v
  112.     dup /.notdef ne {
  113.       exch 2 index 2 index .knownget {
  114.         dup type /arraytype eq {
  115.       [ exch aload pop counttomark 2 add -1 roll ]
  116.         } {
  117.       exch 2 array astore
  118.         } ifelse
  119.       } if 2 index 3 1 roll put
  120.     } {
  121.       pop pop
  122.     } ifelse
  123.   } for
  124.   exch pop
  125. } bind def
  126.  
  127. % Define the Macintosh standard mapping from characters to glyph indices.
  128. /MacRomanEncoding dup .findencoding def
  129. /MacGlyphEncoding dup .findencoding def
  130.  
  131. % Invert the MacRomanEncoding.
  132. /.romanmacdict MacRomanEncoding .invert_encoding def
  133.  
  134. % Define remapping for misnamed glyphs in TrueType 'post' tables.
  135. % There are probably a lot more than this!
  136. /postremap mark
  137.   /Cdot /Cdotaccent
  138.   /Edot /Edotaccent
  139.   /Eoverdot /Edotaccent
  140.   /Gdot /Gdotaccent
  141.   /Ldot /Ldotaccent
  142.   /Zdot /Zdotaccent
  143.   /cdot /cdotaccent 
  144.   /edot /edotaccent 
  145.   /eoverdot /edotaccent
  146.   /gdot /gdotaccent 
  147.   /ldot /ldotaccent
  148.   /zdot /zdotaccent 
  149. .dicttomark readonly def
  150.  
  151. % Array used for fast pre-filling of cmap array
  152. /.array1024z [ 1024 { 0 } repeat ] def
  153.  
  154. % ---- Utilities ---- %
  155.  
  156. % Define a serial number for creating unique XUIDs for TrueType fonts.
  157. % We used to use the checkSumAdjustment value from the font, but this is
  158. % not reliable, since some fonts don't set it correctly.
  159. % Note that we must do this in a string to make it immune to save/restore.
  160. /xuidstring <80000000> def
  161. /curxuid {        % - curxuid <int>
  162.   0 xuidstring { exch 8 bitshift exch add } forall
  163. } bind def
  164. /nextxuid {        % - nextxuid -
  165.   3 -1 0 {
  166.     xuidstring 1 index 2 copy get dup 255 ne {
  167.       1 add put pop exit
  168.     } if pop 0 put pop
  169.   } for
  170. } bind def
  171.  
  172. % <string> <index> getu16 <integer>
  173. /getu16 {
  174.   2 copy get 8 bitshift 3 1 roll 1 add get add
  175. } bind def
  176.  
  177. % <string> <index> gets16 <integer>
  178. /gets16 {
  179.   getu16 16#8000 xor 16#8000 sub
  180. } bind def
  181.  
  182. % <string> <index> getu32 <integer>
  183. /getu32 {
  184.   2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add
  185. } bind def
  186.  
  187. % <string> <index> gets32 <integer>
  188. /gets32 {
  189.   2 copy gets16 16 bitshift 3 1 roll 2 add getu16 add
  190. } bind def
  191.  
  192. 16#ffffffff 0 gt {  % 64-bit sign extension
  193.   { /curxuid /gets32 } {
  194.     mark 1 index load aload pop { 16#80000000 xor 16#80000000 sub } aload pop
  195.     .packtomark cvx def
  196.   } bind forall
  197. } if
  198.  
  199. % <string> <index> <integer> putu16 -
  200. /putu16 {
  201.   3 copy -8 bitshift put
  202.   exch 1 add exch 16#ff and put
  203. } bind def
  204.  
  205. % <string> <index> <integer> putu32 -
  206. /putu32 {
  207.   3 copy -16 bitshift putu16
  208.   exch 2 add exch 16#ffff and putu16
  209. } bind def
  210.  
  211. % <nametable> <nameid> findname <string> true
  212. % <nametable> <nameid> findname false
  213. /findname {
  214.   TTFDEBUG { (findname: ) print dup =only  } if
  215.   false 3 1 roll 0 1 3 index 2 getu16 1 sub {
  216.         % Stack: false table id index
  217.     12 mul 6 add 2 index exch 12 getinterval
  218.     dup 6 getu16 2 index eq {
  219.         % We found the name we want.
  220.       exch pop
  221.         % Stack: false table record
  222.       dup 10 getu16 2 index 4 getu16 add
  223.       1 index 8 getu16 4 -1 roll 3 1 roll
  224.       3 copy add 1 index length
  225.       le {
  226.         pop
  227.         getinterval exch
  228.         % Stack: false string record
  229.         % Check for 8- vs. 16-bit characters.
  230.         is2byte { string2to1 } if true null 4 -1 roll exit
  231.       } {
  232.         pop pop pop pop
  233.         false
  234.         exit
  235.       } ifelse
  236.     } if pop
  237.   } for pop pop
  238.   TTFDEBUG {
  239.     dup { ( = ) print 1 index == } { ( not found) = } ifelse
  240.   } if
  241. } bind def
  242.  
  243. % <namerecord> is2byte <bool>
  244. /is2byte {
  245.   dup 0 getu16 {
  246.     { pop true }        % Apple Unicode
  247.     { pop false }        % Macintosh Script manager
  248.     { 1 getu16 1 eq }        % ISO
  249.     { 1 getu16 1 eq }        % Microsoft
  250.   } exch get exec
  251. } bind def
  252.  
  253. % <string2> string2to1 <string>
  254. /string2to1 {
  255.   dup length 2 idiv string dup
  256.   0 1 3 index length 1 sub {
  257.     3 index 1 index 2 mul 1 add get put dup
  258.   } for pop exch pop
  259. } bind def
  260.  
  261. % Each procedure in this dictionary is called as follows:
  262. %       <encodingtable> proc <glypharray>
  263. /cmapformats mark
  264.   0 {        % Apple standard 1-to-1 mapping.
  265.     6 256 getinterval { } forall 256 packedarray
  266.   } bind
  267.   2 {        % Apple 16bit CJK (ShiftJIS etc)
  268.  
  269.     % /sHK_sz        subHeaderKey_size    % 1 * uint16
  270.     % /sH_sz        subHeader_size        % 4 * uint16
  271.     % /sH_len        subHeader_length
  272.     % /cmapf2_tblen    total table length
  273.     % /cmapf2_lang    language code (not used)
  274.     % /sHKs        subHeaderKeys
  275.  
  276.     /sHK_sz 2 def
  277.     /sH_sz 8 def
  278.     dup 2 getu16 /cmapf2_tblen exch def
  279.  
  280.     dup 4 getu16 /cmapf2_lang exch def
  281.  
  282.     dup 6 256 sHK_sz mul getinterval /sHKs exch def
  283.  
  284.     0        % initialization value for /sH_len
  285.     0 1 255 {
  286.        sHKs exch
  287.        2 mul getu16
  288.        1 index    % get current max
  289.        1 index    % get current subHeaderKey
  290.        lt {exch} if pop
  291.     } for
  292.     /sH_len exch def
  293.  
  294.     dup 6 256 sHK_sz mul add
  295.     cmapf2_tblen 1 index sub getinterval
  296.     /sH_gIA exch def
  297.  
  298.     /cmapf2_glyph_array 65535 array def
  299.  
  300.     /.cmapf2_putGID {
  301.         /cmapf2_ch cmapf2_ch_hi 8 bitshift cmapf2_ch_lo add def
  302.         firstCode cmapf2_ch_lo le
  303.         cmapf2_ch_lo firstCode entryCount add lt
  304.         and { % true: j is inside
  305.             sH_offset idRangeOffset add        % offset to gI
  306.             cmapf2_ch_lo firstCode sub 2 mul    % rel. pos. in range
  307.             add 6 add                % offset in sH_gIA
  308.             sH_gIA exch getu16
  309.             dup 0 gt { %
  310.                 idDelta add
  311.                 cmapf2_glyph_array exch cmapf2_ch exch put
  312.             } {
  313.                 pop
  314.                 % cmapf2_glyph_array cmapf2_ch 0 put
  315.             } ifelse
  316.         } {   % false: j is outside
  317.             % cmapf2_glyph_array cmapf2_ch 0 put
  318.         } ifelse
  319.     } def
  320.  
  321.     16#00 1 16#ff { % hi_byte scan
  322.         /cmapf2_ch_hi exch def
  323.         sHKs cmapf2_ch_hi sHK_sz mul getu16
  324.         /sH_offset exch def
  325.         sH_gIA sH_offset sH_sz getinterval
  326.             dup 0 getu16 /firstCode exch def
  327.             dup 2 getu16 /entryCount exch def
  328.             dup 4 gets16 /idDelta exch def
  329.             dup 6 getu16 /idRangeOffset exch def
  330.         pop
  331.         sH_offset 0 eq {
  332.            /cmapf2_ch_lo cmapf2_ch_hi def
  333.            /cmapf2_ch_hi 0 def
  334.            .cmapf2_putGID
  335.         } {
  336.            16#00 1 16#ff { % lo_byte scan
  337.                /cmapf2_ch_lo exch def
  338.                .cmapf2_putGID
  339.            } for
  340.         } ifelse
  341.      } for
  342.      pop
  343.      0 1 cmapf2_glyph_array length 1 sub { % rewrite null -> 0.
  344.         dup cmapf2_glyph_array exch get
  345.         null eq { cmapf2_glyph_array exch 0 put } {pop} ifelse
  346.      } for
  347.      cmapf2_glyph_array
  348.   } bind
  349.   4 {        % Microsoft/Adobe segmented mapping.
  350.     /etab exch def
  351.     /nseg2 etab 6 getu16 def
  352.     14 /endc etab 2 index nseg2 getinterval def
  353.         % The Apple TrueType documentation omits the 2-byte
  354.         % 'reserved pad' that follows the endCount vector!
  355.     2 add
  356.     nseg2 add /startc etab 2 index nseg2 getinterval def
  357.     nseg2 add /iddelta etab 2 index nseg2 getinterval def
  358.     nseg2 add /idroff etab 2 index nseg2 getinterval def
  359.         % The following hack allows us to properly handle
  360.         % idiosyncratic fonts that start at 0xf000:
  361.     pop
  362.     /firstcode startc 0 getu16 16#ff00 and dup 16#f000 ne { pop 0 } if def
  363.     /putglyph {
  364.       glyphs code 3 -1 roll put /code code 1 add def
  365.     } bind def
  366.         % Do a first pass to compute the size of the glyphs array.
  367.     /numcodes 0 def /glyphs 0 0 2 nseg2 3 sub {
  368.         % Stack: /glyphs numglyphs i2
  369.       /i2 exch def
  370.       /scode startc i2 getu16 def
  371.       /ecode endc i2 getu16 def
  372.       numcodes scode firstcode sub
  373.         % Hack for fonts that have only 0x0000 and 0xf000 ranges
  374.       %dup 16#e000 ge { 255 and } if
  375.       % the previous line is obstructive to CJK fonts, so it was removed
  376.       exch sub 0 .max ecode scode sub 1 add add
  377.       exch 1 index add exch
  378.       numcodes add /numcodes exch def
  379.     } for array def
  380.     % prefill the array with 0's faster than a { 0 putglyph } repeat
  381.     glyphs length 1024 ge {
  382.       .array1024z 0 1024 glyphs length 1023 sub { glyphs exch 2 index putinterval } for
  383.       glyphs dup length 1024 sub 3 -1 roll
  384.       putinterval
  385.     } {
  386.       0 1 glyphs length 1 sub { glyphs exch 0 put } for
  387.     } ifelse
  388.         % Now fill in the array.
  389.     /numcodes 0 def /code 0 def
  390.     0 2 nseg2 3 sub {
  391.       /i2 exch def
  392.       /scode startc i2 getu16 def
  393.       /ecode endc i2 getu16 def
  394.       numcodes scode firstcode sub
  395.         % Hack for fonts that have only 0x0000 and 0xf000 ranges
  396.       %dup 16#e000 ge { 255 and } if
  397.       % the previous line is obstructive to CJK fonts, so it was removed
  398.       exch sub 0 .max dup /code exch code exch add def
  399.       ecode scode sub 1 add add numcodes add /numcodes exch def
  400.       /delta iddelta i2 gets16 def
  401.       TTFDEBUG {
  402.     (scode=) print scode =only
  403.     ( ecode=) print ecode =only
  404.     ( delta=) print delta =only
  405.     ( droff=) print idroff i2 getu16 =
  406.       } if
  407.       idroff i2 getu16 dup 0 eq {
  408.     pop scode delta add 65535 and 1 ecode delta add 65535 and
  409.     { putglyph } for
  410.       } {    % The +2 is for the 'reserved pad'.
  411.         /gloff exch 14 nseg2 3 mul add 2 add i2 add add def
  412.         0 1 ecode scode sub {
  413.       2 mul gloff add etab exch getu16
  414.       dup 0 ne { delta add 65535 and } if putglyph
  415.     } for
  416.       } ifelse
  417.     } for glyphs /glyphs null def    % for GC
  418.   } bind
  419.   6 {        % Single interval lookup.
  420.     dup 6 getu16 /firstcode exch def dup 8 getu16 /ng exch def
  421.     firstcode ng add array
  422.         % Stack: tab array
  423.         % Fill elements 0 .. firstcode-1 with 0
  424.     0 1 firstcode 1 sub { 2 copy 0 put pop } for
  425.     dup firstcode ng getinterval
  426.         % Stack: tab array subarray
  427.         % Fill elements firstcode .. firstcode+nvalue-1 with glyph values
  428.     0 1 ng 1 sub {
  429.       dup 2 mul 10 add 4 index exch getu16 3 copy put pop pop
  430.     } for pop exch pop
  431.   } bind
  432. .dicttomark readonly def                % cmapformats
  433.  
  434. % <cmaptab> cmaparray <glypharray>
  435. /cmaparray {
  436.   dup 0 getu16 cmapformats exch .knownget {
  437.     TTFDEBUG {
  438.       (cmap: format ) print 1 index 0 getu16 = flush
  439.     } if exec
  440.   } {
  441.     (Can't handle format ) print 0 getu16 = flush
  442.     0 1 255 { } for 256 packedarray
  443.   } ifelse
  444.   TTFDEBUG {
  445.     (cmap: length=) print dup length = dup ==
  446.   } if
  447. } bind def
  448.  
  449. % Each procedure in this dictionary is called as follows:
  450. %       posttable <<proc>> glyphencoding
  451. /postformats mark
  452.   16#00010000  {    % 258 standard Macintosh glyphs.
  453.     pop MacGlyphEncoding
  454.   }
  455.   16#00020000  {    % Detailed map, required by Microsoft fonts.
  456.     dup length 36 lt {
  457.       TTFDEBUG { (post format 2.0 invalid.) = flush } if
  458.       pop [ ]
  459.     } {
  460.     /postglyphs exch def
  461.       postglyphs 32 getu16 /numglyphs exch def
  462.       /glyphnames numglyphs 2 mul 34 add def
  463.       % Build names array in the order they occur in the 'post' table
  464.       /postpos glyphnames def
  465.       [ numglyphs 1 sub {
  466.     postpos postglyphs length ge { exit } if
  467.     % No name available, /postnames will be defined as an empty
  468.     % array and the glyph won't get a name attached.
  469.     postglyphs postpos get 
  470.         postglyphs postpos 1 add 2 index getinterval cvn
  471.     exch postpos add 1 add /postpos exch def
  472.       } repeat
  473.       ] /postnames exch def
  474.       [ 0 1 numglyphs 1 sub {
  475.     2 mul 34 add postglyphs exch getu16
  476.     dup 258 lt {
  477.       MacGlyphEncoding exch get
  478.     } {
  479.       dup 32768 ge {
  480.         % According to the published TrueType spec, such values are
  481.         % "reserved for future use", but at least some PDF files
  482.         % produced by the Adobe PDF library contain entries with a
  483.         % value of 16#ffff.
  484.         pop /.notdef
  485.       } {
  486.         % Get the name for this glyph
  487.         258 sub dup postnames length ge {
  488.           TTFDEBUG { (   *** warning: glyph index past end of 'post' table) = flush } if
  489.           exit
  490.         } if
  491.         postnames exch get
  492.         % At least some of Microsoft's TrueType fonts use incorrect
  493.         % (Adobe-incompatible) names for some glyphs.
  494.         % Correct for this here.
  495.         postremap 1 index .knownget { exch pop } if
  496.       } ifelse
  497.     } ifelse
  498.       } for ]
  499.     }
  500.     ifelse
  501.   } bind
  502.   16#00030000  {    % No map.
  503.     pop [ ]
  504.   } bind
  505. .dicttomark readonly def                % postformats
  506.  
  507. % Each procedure in this dictionary is called as follows:
  508. %    <file> <length> -proc- <string|array_of_strings>
  509. % Note that each table must have an even length, because of a strange
  510. % Adobe requirement that each sfnts entry have even length.
  511. /readtables mark
  512.     % Ordinary tables
  513.   (cmap) { .readtable }
  514.   (head) 1 index
  515.   (hhea) 1 index
  516.   (maxp) 1 index
  517.   (name) 1 index
  518.   (OS/2) 1 index
  519.   (post) 1 index
  520.   (vhea) 1 index
  521.     % Big tables
  522.   (glyf) { .readbigtable }
  523.   (loca) 1 index
  524.   (hmtx) 1 index
  525.   (vmtx) 1 index
  526.     % Tables only needed for embedding in PDF files
  527.   (cvt ) { .readtable }
  528.   (fpgm) 1 index
  529.   (prep) 1 index
  530. .dicttomark
  531. % Normally there would be a 'readonly' here, but the ttf2pf utility wants
  532. % to include the 'kern' table as well, so we leave the readtables dictionary
  533. % writable.
  534. def                % readtables
  535.  
  536. /readtables_stripped readtables dup length dict copy
  537. dup (loca) { .skiptable } put
  538. dup (glyf) { .skiptable } put
  539. def
  540.  
  541. % Read a table as a single string.
  542. % <file> <length> .skiptable <string>
  543. /.skiptable {
  544.   pop pop ()
  545. } bind def
  546.  
  547. % Read a table as a single string.
  548. % <file> <length> .readtable <string>
  549. /.readtable {
  550.   dup dup 1 and add string
  551.         % Stack: f len str
  552.   dup 0 4 -1 roll getinterval
  553.         % Stack: f str str1
  554.     % Because of the absurd PostScript specification that gives an
  555.     % error for reading into an empty string, we have to check for
  556.     % this explicitly here.
  557.   3 -1 roll exch
  558.   dup () ne { readstring } if pop pop
  559. } bind def
  560.  
  561. % Read a big table (one that may exceed 64K).
  562. % <file> <length> .readbigtable <string[s]>
  563. /.readbigtable {
  564.   dup 65400 lt {
  565.     .readtable
  566.   } {
  567.     currentuserparams /VMReclaim get -2 vmreclaim
  568.     [ 4 2 roll {
  569.         % Stack: mark ... f left
  570.       dup maxstring le { exit } if
  571.       1 index maxstring string readstring pop 3 1 roll maxstring sub
  572.     } loop .readtable ]
  573.     exch vmreclaim
  574.   } ifelse
  575. } bind def
  576.  
  577. end readonly def                % .loadttfontdict
  578.  
  579. % <tab> .printtab -
  580. /.printtab {
  581.   dup 0 4 getinterval print ( ) print
  582.   dup 8 getu32 =only ( ) print
  583.   12 getu32 =
  584. } bind def
  585.  
  586. % <file> <bool> <SubfontID> .loadttfonttables -
  587. % Pushes .loadttfontdict & scratch dict on d-stack.
  588. % Defines f, offsets, tables, tabdict, tabs.
  589. % Skips loca nd glyf if <bool> is true.
  590. /.loadttfonttables {
  591.   .loadttfontdict begin
  592.   40 dict begin
  593.   /SubfontID exch def
  594.   /load_stripped exch def
  595.   /f exch def
  596.   /offsets f 12 string readstring pop def
  597.   load_stripped { readtables_stripped } { readtables } ifelse /readtables_ exch def
  598.   offsets 0 4 getinterval (ttcf) eq {
  599.     % We need to handle TT collections with disk fonts only.
  600.     % Therefore the file is a disk file and it can be positioned.
  601.     offsets 8 getu32 /num_fonts exch def
  602.     SubfontID num_fonts ge {
  603.       QUIET not { (True Type collection contains insufficient fonts.) = } if
  604.       /.loadttfonttables cvx /invalidfont signalerror
  605.     } if
  606.     SubfontID 4 mul 12 add f exch setfileposition
  607.     f 4 string readstring pop 0
  608.     getu32 /ttc_offset exch def
  609.     f ttc_offset setfileposition
  610.     /offsets f 12 string readstring pop def
  611.   } {
  612.     SubfontID 0 gt {
  613.       QUIET not { (SubfontID > 0 with a True Type file which is not a collection.) = } if
  614.       /.loadttfonttables cvx /invalidfont signalerror
  615.     } if
  616.     /ttc_offset 0 def
  617.   } ifelse
  618.   /tables f offsets 4 getu16 16 mul string readstring pop def
  619.   /tabdict tables length 16 idiv dict def
  620.     % tabs = tables we want to keep, sorted by file position.
  621.   /tabs [ 0 16 tables length 1 sub {
  622.     tables exch 16 getinterval
  623.     TTFDEBUG { dup .printtab } if
  624.     dup 0 4 getinterval readtables_ 1 index known {
  625.       1 index 12 4 getinterval (\0\0\0\0) eq {
  626.         pop pop    % Ignore zero-length table
  627.       } {
  628.         tabdict exch 2 index put
  629.       } ifelse
  630.     } {
  631.       pop pop
  632.     } ifelse
  633.   } for ] {
  634.     exch 8 getu32 exch 8 getu32 lt
  635.   } .sort def
  636.     % In certain malformed TrueType fonts, tables overlap.
  637.     % Truncate tables if necessary.
  638.   0 1 tabs length 2 sub {
  639.     dup tabs exch get exch 1 add tabs exch get
  640.     1 index 8 getu32 2 index 12 getu32 add
  641.     1 index 8 getu32 gt {
  642.       (**** Warning: ) print 1 index 0 4 getinterval print
  643.       ( overlaps ) print dup 0 4 getinterval print
  644.       (, truncating.) = flush
  645.       dup 8 getu32 2 index 8 getu32 sub
  646.       2 index 12 3 -1 roll putu32
  647.     } if pop pop
  648.   } for
  649. } bind def
  650.  
  651. /.file_table_pos_names
  652. mark
  653. /glyf 0
  654. /loca 0
  655. .dicttomark readonly def
  656.  
  657. % - .readttdata -
  658. % Read data.  Updates offsets, tabs; stores data in tabdict.
  659. /.readttdata {
  660.   /file_table_pos 10 dict def
  661.   /fpos offsets length tables length add ttc_offset add def
  662.   /sfpos offsets length tabs length 16 mul add def
  663.   offsets 4 tabs length putu16
  664.   tabs {
  665.     dup 0 4 getinterval /tname exch def
  666.     dup 8 getu32 /tpos exch def
  667.     dup 12 getu32 /tlen exch def
  668.     load_stripped //.file_table_pos_names tname known and {
  669.         pop
  670.         file_table_pos tname [tpos tlen] put
  671.         tabdict tname () put
  672.     } {
  673.       8 sfpos putu32
  674.       % Skip data between the end of the previous table and
  675.     % the beginning of this one, if any.
  676.       tpos fpos gt {
  677.         load_stripped {
  678.           % 'setfileposition' is faster for skipping a big data.
  679.           f tpos setfileposition
  680.         } {
  681.           f tpos fpos sub () /SubFileDecode filter dup flushfile closefile
  682.           /fpos tpos def
  683.         } ifelse
  684.       } if
  685.       f tlen readtables_ tname get exec
  686.       tabdict tname 3 -1 roll put
  687.     % Round up the table length to an even value.
  688.       /sfpos sfpos tlen dup 1 and add add def
  689.     } ifelse
  690.     /fpos fpos tlen add def
  691.   } forall
  692. } bind def
  693.  
  694. % Find the string in a list of strings that includes a given index.
  695. % <strings> <index> .findseg <string> <index'>
  696. /.findseg {
  697.   exch {
  698.     dup length 2 index gt { exch exit } if
  699.     length sub
  700.   } forall
  701. } bind def
  702.  
  703. % - .makesfnts -
  704. % Defines checksum, getloca, head, locatable, numloca, post, sfnts, upem
  705. /.makesfnts {
  706.   .readttdata
  707.   /head tabdict /head get def
  708.   /post tabdict /post .knownget not { null } if def
  709.   load_stripped not {
  710.     /locatable tabdict /loca get def
  711.     /numloca
  712.       locatable dup type /stringtype eq
  713.        { length }
  714.        { 0 exch { length add } forall }
  715.       ifelse    % no def yet
  716.     locatable type /stringtype eq {
  717.       /.indexloca {} def
  718.     } {
  719.       /.indexloca /.findseg load def
  720.     } ifelse
  721.     head 50 getu16 0 ne {
  722.       /getloca {
  723.         2 bitshift locatable exch .indexloca getu32
  724.       } def
  725.       4 idiv 1 sub
  726.     } {
  727.       /getloca {
  728.         dup add locatable exch .indexloca getu16 dup add
  729.       } def
  730.       2 idiv 1 sub
  731.     } ifelse def        % numloca
  732.     % If necessary, re-partition the glyfs.
  733.     tabdict /glyf get dup type /stringtype ne {
  734.       .dividesfnts tabdict /glyf 3 -1 roll put
  735.     } {
  736.       pop
  737.     } ifelse
  738.   } {
  739.     % We did not load loca, take the number of glyphs from maxp.
  740.     /numloca tabdict /maxp get 4 getu16 def
  741.   } ifelse
  742.   /sfnts [
  743.     offsets tabs { concatstrings } forall
  744.     tabs {
  745.       0 4 getinterval tabdict exch get
  746.       dup type /stringtype ne { aload pop } if
  747.     } forall
  748.   ] def
  749. } bind def
  750.  
  751. % <glyfs> .dividesfnts <glyfs'>
  752. /.dividesfnts {
  753.   /glyfs exch def
  754.   /len1 0 glyfs { length add } forall def
  755.         % Determine where to split the glyfs by scanning loca.
  756.         % The very last entry in loca may be bogus.
  757.         % Note that some loca entries may be odd, but we can only
  758.         % split at even positions.
  759.         %
  760.         % Construct splitarray, the array of final lengths of
  761.         % the sfnts entries covering the glyfs (i.e., all but
  762.         % the first and last sfnts entries).
  763.     /prevsplit 0 def
  764.     /prevboundary 0 def
  765.     /splitarray [
  766.       0 1 numloca 1 sub {
  767.     getloca dup prevsplit maxstring add gt {
  768.       prevboundary prevsplit sub exch
  769.       /prevsplit prevboundary def
  770.     } if
  771.     dup 1 and 0 eq { /prevboundary exch def } { pop } ifelse
  772.       } for
  773.       len1 prevsplit sub
  774.     ] def
  775.     currentuserparams /VMReclaim get -2 vmreclaim
  776.     [
  777.         % Re-split the sfnts glyfs strings according to splitarray.
  778.         % We do this by iterating over the final segments defined
  779.         % by splitarray, and constructing them from pieces of the
  780.         % current glyfs strings.  We recycle the current strings
  781.         % when possible, to avoid stressing the allocator.
  782.       /sfnt_idx 0 def
  783.       /strpos 0 def
  784.       /avail () def
  785.       splitarray {
  786.     /seglen exch def
  787.     /segpos 0 def
  788.     avail length seglen ge
  789.       { avail 0 seglen getinterval /avail () def } { seglen string }
  790.     ifelse
  791.     {
  792.       /str glyfs sfnt_idx get def
  793.       /strlen str length def
  794.       /strleft strlen strpos sub def
  795.       seglen segpos sub strleft lt { exit } if
  796.         % Copy the (rest of the) string into the new segment.
  797.         % We know strleft <= segleft.
  798.       dup segpos str strpos strleft getinterval putinterval
  799.       /segpos segpos strleft add def
  800.       /avail str def
  801.       /sfnt_idx sfnt_idx 1 add def
  802.       /strpos 0 def
  803.       segpos seglen eq { exit } if
  804.     } loop
  805.         % Fill up the segment with an initial piece of the next
  806.         % existing glyfs string.  We know strleft > segleft.
  807.     /segleft seglen segpos sub def
  808.     dup segpos str strpos segleft getinterval putinterval
  809.     /strpos strpos segleft add def
  810.       } forall
  811.     ]
  812.     exch vmreclaim
  813. } bind def
  814.  
  815. % - .getpost -
  816. % Uses post, defines glyphencoding
  817. /.getpost {
  818.   /glyphencoding post null eq {
  819.     TTFDEBUG { (post missing) = flush } if [ ]
  820.   } {
  821.     postformats post 0 getu32 .knownget {
  822.       TTFDEBUG {
  823.     (post: format ) print
  824.     post 0 getu16 =only (,) print post 2 getu16 = flush
  825.       } if
  826.       post exch exec
  827.     } {
  828.       TTFDEBUG { (post: unknown format ) print post 0 getu32 = flush } if [ ]
  829.     } ifelse
  830.   } ifelse def
  831. } bind def
  832.  
  833. % - .ttkeys <key> <value> ...
  834. /.ttkeys {
  835.   count /ttkeycount exch def
  836.   /upem head 18 getu16 def
  837.   /FontMatrix matrix
  838.   /FontBBox [ 36 2 42 { head exch gets16 upem div } for ]
  839.   nextxuid
  840.   tabdict /name .knownget {
  841.         % Find the names from the 'name' table.
  842.     /names exch def
  843.     /FontName names 6 findname not { curxuid 16 8 string cvrs } if
  844.       /fontname 1 index def
  845.     /FontInfo mark
  846.       names 0 findname { /Notice exch } if
  847.       names 1 findname { /FamilyName exch } if
  848.       names 4 findname { /FullName exch } if
  849.       names 5 findname { /Version exch } if
  850.   } {
  851.         % No name table, fabricate a FontName.
  852.     /FontName curxuid 16 8 string cvrs
  853.       /fontname 1 index def
  854.     /FontInfo mark
  855.   } ifelse
  856.         % Stack: ... /FontInfo mark key1 value1 ...
  857.   post null ne {
  858.     /ItalicAngle post 4 gets32 65536.0 div
  859.     /isFixedPitch post 12 getu32 0 ne
  860.     /UnderlinePosition post 8 gets16 upem div
  861.     /UnderlineThickness post 10 gets16 upem div
  862.   } if
  863.   counttomark 0 ne { .dicttomark } { pop pop } ifelse
  864.   /XUID [orgXUID 42 curxuid]
  865.   TTFDEBUG {
  866.     tabs { .printtab } forall
  867.     [ sfnts { length } forall ] ==
  868.     count ttkeycount sub array astore dup { == } forall aload pop
  869.   } if
  870.   /sfnts sfnts
  871. } bind def
  872.  
  873. % ---------------- Standard TrueType font loading ---------------- %
  874.  
  875. % - .pickcmap_with_no_xlatmap -
  876. % Defines cmapsub, cmaptab
  877. /.pickcmap_with_no_xlatmap {
  878.   tabdict /cmap get
  879.         % The Apple cmap format is no help in determining the encoding.
  880.         % Look for a Microsoft table.  If we can't find one,
  881.         % just use the first table, whatever it is.
  882.   dup 4 8 getinterval exch             % the default
  883.   0 1 2 index 2 getu16 1 sub {
  884.     8 mul 4 add 1 index exch 8 getinterval
  885.     TTFDEBUG {
  886.       (cmap: platform ) print dup 0 getu16 =only
  887.       ( encoding ) print dup 2 getu16 = flush
  888.     } if
  889.     dup 0 getu16 3 eq { exch 3 -1 roll pop exit } if pop
  890.   } for
  891.         % Stack: subentry table
  892.   /cmapsub 2 index def
  893.   exch 4 getu32 1 index length 1 index sub getinterval
  894.   /cmaptab exch def
  895. } bind def
  896.  
  897. % - .pickcmap_with_xlatmap -
  898. % Defines cmapsub, cmaptab
  899. /.pickcmap_with_xlatmap {
  900.   .xlatmap_dict /TrueType known not {
  901.     (Emulating a CID font with a True Type file, ) print
  902.     (the file gs/lib/xlatmap must contain /TrueType key.) =
  903.     /.pickcmap_with_xlatmap cvx /configurationerror signalerror
  904.   } if
  905.   false
  906.   .xlatmap_dict /TrueType get 
  907.   dup length 2 sub 0 exch 2 exch {                       % bool [] i
  908.     2 copy get                                           % bool [] i ()
  909.     (.) search {                                         % bool [] i post match pre
  910.       cvi exch pop exch cvi                              % bool [] i PlatID SpecID
  911.     } {
  912.       (gs/lib/xlatmap containg a record with an invalid (PlatformID.SpecificID)) =
  913.       /.pickcmap_with_xlatmap cvx /configurationerror signalerror
  914.     } ifelse
  915.     TTFDEBUG {
  916.       (Seeking a cmap for platform=) print 1 index =only ( encoding=) print dup =
  917.     } if
  918.     tabdict /cmap get                                   % bool [] i PlatID SpecID (cmap)
  919.     dup /cmaptab exch def % temporary
  920.     0 1 2 index 2 getu16 1 sub {                         % bool [] i PlatID SpecID (cmap) j
  921.       8 mul 4 add 1 index exch 8 getinterval             % bool [] i PlatID SpecID (cmap) (cmapsub)
  922.       TTFDEBUG {
  923.         (cmap: platform ) print dup 0 getu16 =only
  924.         ( encoding ) print dup 2 getu16 = flush
  925.       } if
  926.       dup 0 getu16 4 index eq {
  927.         dup 2 getu16 3 index eq {                        % bool [] i PlatID SpecID (cmap) (cmapsub)
  928.           TTFDEBUG {
  929.             (Choosen a cmap for platform=) print 3 index =only
  930.             ( encoding=) print 2 index =
  931.           } if
  932.           /cmapsub 1 index def
  933.           dup 4 getu32                                   % bool [] i PlatID SpecID (cmap) (cmapsub) p
  934.           cmaptab length 1 index sub                     % bool [] i PlatID SpecID (cmap) (cmapsub) p l
  935.           cmaptab 3 1 roll getinterval
  936.           /cmaptab exch def                              % bool [] i PlatID SpecID (cmap) (cmapsub)
  937.           5 index 5 index 1 add get                      % bool [] i PlatID SpecID (cmap) (cmapsub) /Decoding
  938.           /Decoding exch def                             % bool [] i PlatID SpecID (cmap) (cmapsub)
  939.           7 -1 roll pop true 7 1 roll                    % true [] i PlatID SpecID (cmap) (cmapsub)
  940.         } if
  941.       } if
  942.       pop                                                % true [] i PlatID SpecID (cmap)
  943.       5 index { exit } if
  944.     } for                                                % bool [] i PlatID SpecID (cmap)
  945.     pop pop pop pop                                      % bool []
  946.     1 index { exit } if
  947.   } for                                                  % bool []
  948.   pop                                                    % bool
  949.   not { 
  950.     QUIET not { (True Type font doesn't contain a charset listed in gs/lib/xlatmap.) = } if
  951.     /.pickcmap_with_xlatmap cvx /invalidfont signalerror
  952.   } if                                                   %
  953. } bind def
  954.  
  955. % - .pickcmap -
  956. % Defines cmapsub, cmaptab
  957. /.pickcmap {
  958.   % Currently we use xlatmap only for emulation CIDFontType 2 with
  959.   % a disk True Type font files, and use load_stripped
  960.   % to check this regime. We would like to do so
  961.   % while emulating a Type 42, but first the old code
  962.   % about handling them to be changed 
  963.   % with adding a handling of a Decoding.
  964.   % fixme : A correct way to fix this is to implenent 
  965.   % the Type 42 emulation with gs_fntem.ps .
  966.   % Also note that PDF embedded fonts probably don't need a xlatmap -
  967.   % see PDF spec, "Encodings for True Type fonts".
  968.   load_stripped {
  969.     //.pickcmap_with_xlatmap exec
  970.   } {
  971.     //.pickcmap_with_no_xlatmap exec
  972.   } ifelse
  973. } bind def
  974.  
  975. % <glyph> .nname <_name>
  976. /.nname {
  977.   =string cvs (_) exch concatstrings cvn
  978. } bind def
  979.  
  980. % - .charkeys /CharStrings <charstrings> /Encoding <encoding>
  981. % Resets glyphencoding
  982. /.charkeys {
  983.   TTFDEBUG {
  984.     (glyphencoding: length=) print glyphencoding dup length = === flush
  985.   } if
  986.         % Hack: if there is no usable post table but the cmap uses
  987.         % the Microsoft Unicode encoding, use ISOLatin1Encoding.
  988.   glyphencoding length 0 eq cmapsub 0 4 getinterval <00030001> eq and {
  989.     /glyphencoding ISOLatin1Encoding dup length array copy def
  990.   } if
  991.         % If necessary, fabricate additional glyphencoding entries
  992.         % to cover all of loca, or truncate glyphencoding.
  993.   glyphencoding length numloca lt {
  994.     /glyphencoding numloca array
  995.       glyphencoding length dup 1 sub 0 1 3 2 roll {
  996.         dup glyphencoding exch get
  997.         3 index 3 1 roll put
  998.       } for
  999.       % /glyphencoding <newarray> <glyphencoding length>
  1000.       1 numloca 1 sub {
  1001.         1 index exch dup .nname put
  1002.       } for
  1003.     def
  1004.   } {
  1005.     /glyphencoding glyphencoding 0 numloca getinterval def
  1006.   } ifelse
  1007.         % Some badly designed Chinese fonts have a post table
  1008.         % in which all glyphs other than 0 are named .null.
  1009.         % Use CharStrings to keep track of the reverse map from
  1010.         % names to glyphs, and don't let any name be used for
  1011.         % more than one glyph.
  1012.   /CharStrings glyphencoding dup length 1 add dict    % +1 for .notdef
  1013.     0 1 3 index length 1 sub {
  1014.         % Stack: glyphencoding dict index
  1015.       2 index 1 index get 2 index 1 index known {
  1016.         % The same name maps to more than one glyph.
  1017.         % Change the name.
  1018.     pop dup .nname 3 index 2 index 2 index put
  1019.       } if
  1020.       2 index exch 3 -1 roll put
  1021.     } for exch pop
  1022.         % If there is no .notdef entry, map it to glyph 0.
  1023.   dup /.notdef known not { dup /.notdef 0 put } if
  1024.   readonly
  1025.   /Encoding
  1026.     [ cmaptab cmaparray dup length 256 gt { 0 256 getinterval } if
  1027.     { glyphencoding exch get } forall
  1028.     counttomark 256 exch sub { /.notdef } repeat ]
  1029.   TTFDEBUG { (Encoding: ) print dup === flush } if
  1030. } bind def
  1031.  
  1032. % -mark- <key> <value> ... .definettfont <font>
  1033. /.definettfont {
  1034.   /FontType 42
  1035.   /PaintType 0
  1036.   TTFDEBUG {
  1037.     (numloca=) print numloca =
  1038.   } if
  1039.   .dicttomark
  1040.   end end dup /FontName get exch definefont
  1041. } bind def
  1042.  
  1043. % <file> .loadttfont <type42font>
  1044. /.loadttfont {
  1045.   //false 0 .loadttfonttables
  1046.   .makesfnts
  1047.   .getpost
  1048.   .pickcmap
  1049.   mark
  1050.   .charkeys
  1051.   .ttkeys
  1052.   .definettfont
  1053. } bind def
  1054.  
  1055. % ---------------- CIDFontType 2 font loading ---------------- %
  1056.  
  1057. % Fill a string with sequential CIDs starting from the initial value.
  1058. % <string> <value> .fill_identity_cmap <string>
  1059. /.fill_identity_cmap {             % () v
  1060.   1 index length 2 sub          % () v n-2
  1061.   0 2 3 2 roll {                % () v 0 2 n-1
  1062.       3 copy exch               % () v i () i v 
  1063.       -8 bitshift               % () v i () i v>>8
  1064.       put                       % () v i
  1065.       3 copy 1 add              % () v i () v i+1
  1066.       exch 255 and              % () v i () i+1 v&255
  1067.       put                       % () v i 
  1068.       pop 1 add                 % () v+1
  1069.   } for
  1070.   pop
  1071. } bind def
  1072.  
  1073. % -mark- <key> <value> ... .definettcidfont <font>
  1074. /.definettcidfont {
  1075.   /CIDFontName fontname
  1076.   /CIDFontType 2
  1077.   /CIDSystemInfo mark
  1078.     /Registry (Adobe)
  1079.     /Ordering (Japan1)        % adhoc
  1080.     /Supplement 0
  1081.   .dicttomark
  1082.   /CharStrings mark /.notdef 0 .dicttomark
  1083.         % The cmap isn't of any use even if it is present.
  1084.         % Just construct an identity CIDMap covering all the glyphs.
  1085.  
  1086.   /CIDCount numloca % Wrong if a CIDFontType2 embedded into PDF with a non-Identity CIDToGIDMap.
  1087.                     % processCIDToGIDMap may replace.
  1088.   /CIDMap numloca maxstring le {
  1089.                 % Use a single string.
  1090.       numloca 2 mul string 0 .fill_identity_cmap
  1091.   } {
  1092.                 % We must use 2 strings.
  1093.       maxstring 2 mul string 0 .fill_identity_cmap
  1094.       numloca maxstring sub 2 mul string maxstring .fill_identity_cmap
  1095.       2 array astore
  1096.   } ifelse
  1097.  
  1098.   /GDBytes 2
  1099.   .dicttomark
  1100.   end end dup /CIDFontName get exch /CIDFont defineresource
  1101. } bind def
  1102.  
  1103. % <file> .loadttcidfont <cidtype2font>
  1104. /.loadttcidfont {
  1105.   //false 0 .loadttfonttables
  1106.   .makesfnts
  1107.     % CIDFontType2 fonts don't have a cmap: they are indexed by CID.
  1108.   mark
  1109.   .ttkeys
  1110.   .definettcidfont
  1111. } bind def
  1112.  
  1113. % <file> <SubfontID> .load_tt_font_stripped <font_data>
  1114. % The font_data includes sfnts, NumGlyphs, TT_cmap, file_table_pos, Decoding.
  1115. % CIDMap to be created later from TT_cmap.
  1116. /.load_tt_font_stripped {
  1117.   //true exch .loadttfonttables
  1118.   .makesfnts
  1119.   .pickcmap
  1120.   mark
  1121.   .ttkeys
  1122.   /NumGlyphs numloca
  1123.   /TT_cmap cmaptab cmaparray
  1124.   /file_table_pos file_table_pos
  1125.   /Decoding Decoding
  1126.   .dicttomark
  1127.   end end 
  1128. } bind def
  1129.  
  1130. % ---------------- PDF TrueType font loading ---------------- %
  1131.  
  1132. % Strictly speaking, this code should be loaded only if we have a PDF
  1133. % interpreter, but it's so closely tied to the rest of the code in this
  1134. % file that we always include it.
  1135.  
  1136. % <plat+enc> .findcmap <subtable> true
  1137. % <plat+enc> .findcmap false
  1138. /.findcmap {
  1139.   false exch tabdict /cmap get
  1140.         % Some fonts have multiple cmaps with the same platform and
  1141.         % encoding.  Use the first one we find.
  1142.   0 1 2 index 2 getu16 1 sub {
  1143.         % Stack: false plat+enc cmap index
  1144.     8 mul 4 add 1 index exch 8 getinterval 
  1145.     dup 0 4 getinterval 3 index eq {
  1146.       4 getu32 1 index exch 1 index length 1 index sub getinterval
  1147.       4 -1 roll not 4 2 roll exit
  1148.     } if pop
  1149.   } for
  1150.         % Stack: false plat+enc cmap || subtable true plat+enc cmap
  1151.   pop pop
  1152. } bind def
  1153.  
  1154. % Build .symbol_list for .pdfcharkeys .
  1155. % It is a dictionary containing all SymbolEncoding glyph names
  1156. % and random names for filling gaps in the character code range.
  1157. /.symbol_list 256 dict def
  1158. {
  1159.   =string 0 (x) 0 get put
  1160.   /SymbolEncoding .findencoding
  1161.   0 1 255 {
  1162.     dup 2 index exch get
  1163.     dup /.notdef eq {
  1164.       pop dup
  1165.       =string 1 3 getinterval cvs length 1 add
  1166.       =string exch 0 exch getinterval cvn
  1167.     } if
  1168.     exch //.symbol_list 3 1 roll put
  1169.   } for
  1170.   pop
  1171. } bind exec
  1172.  
  1173. % Create .GS_extended_SymbolEncoding as inverse of .symbol_list .
  1174. {
  1175.   /.GS_extended_SymbolEncoding 256 array
  1176.   //.symbol_list {
  1177.     exch 2 index 3 1 roll put  
  1178.   } forall
  1179.   .defineencoding
  1180. } bind exec
  1181.  
  1182. /.addglyph    % <name> <glyph#> .addglyph <name> <glyph#> 
  1183.               % <name> <glyph#> .addglyph -
  1184. {
  1185.   dup cmapencoding length lt {
  1186.     cmapencoding exch get dup 0 eq {
  1187.       pop pop
  1188.     } if
  1189.   } {
  1190.     pop pop
  1191.   } ifelse
  1192. } bind def
  1193.  
  1194. % <subcmap> <chartoglyphmap> .pdfmapchars
  1195. %   /CharStrings <charstrings>
  1196. /.pdfmapchars {
  1197.   exch cmaparray /cmapencoding exch def
  1198.   /CharStrings mark 
  1199.  
  1200.   % Add glyphs of <chartoglyphmap>*<subcmap> :
  1201.   3 2 roll {
  1202.     dup type /arraytype eq {
  1203.       exch /.name exch def
  1204.       { .name exch //.addglyph exec
  1205.       } forall
  1206.       currentdict /.name undef
  1207.     } {
  1208.       //.addglyph exec
  1209.     } ifelse
  1210.   } forall
  1211.  
  1212.         % stack: /CharStrings mark /name1 glyph#1 /name2 glyph#2 ... /namen glyph#n
  1213.         % Stack depth is restricted with AdobeGlyphList size.
  1214.  
  1215.   % Add glyphs of 'post' (with lower priority, see .dicttomark) :
  1216.   0 1 glyphencoding length 1 sub {
  1217.     dup glyphencoding exch get exch
  1218.     dup 0 eq {
  1219.       pop pop
  1220.     } if
  1221.   } for
  1222.  
  1223.   /.notdef 0
  1224.   .dicttomark
  1225. } bind def
  1226.  
  1227. % - .pdfcharkeys /CharStrings <charstrings> /Encoding <encoding>
  1228. /.pdfcharkeys {
  1229.     % The following algorithms are per the PDF Reference, Second Edition
  1230.     % (PDF 1.3 reference manual).
  1231.   
  1232.   is_symbolic {
  1233.     <00030001> .findcmap {
  1234.       %
  1235.       % Adobe PDF spec says that symbolic fonts should contain exactly one 
  1236.       % cmap subtable for Platform=1, Encoding=0.
  1237.       % Perhaps "Adobe Acrobat PDFWriter 4.0 for Windows" sometimes embeds
  1238.       % fonts with both subtables 3.1 and 1.0 (see comparefiles/159.pdf,
  1239.       % the font "Arial,Bold" with the character "registered"),
  1240.       % and both Acrobat Reader 4.0 and 5.0 choose 3.1.
  1241.       % Therefore we try 3.1 first.
  1242.       %
  1243.       (   **** Warning: Embedded symbolic TT fonts should not contain a cmap for Platform=3 Encoding=1.\n)
  1244.         pdfformaterror
  1245.       AdobeGlyphList .pdfmapchars 
  1246.       /Encoding /WinAnsiEncoding .findencoding
  1247.     } {
  1248.       %
  1249.       % Adobe PDF spec says that in this case PDF interpreter should
  1250.       % map character codes directly to glyphs using
  1251.       % the cmap <00010000>. But we use PS interpreter to emulate
  1252.       % a PDF interpreter. Therefore we need to construct
  1253.       % a type 42 font, which requires an Encoding and a Charstrings.
  1254.       % We construct them with symbol_list, which
  1255.       % includes all glyphs from SymbolEncoding and additional
  1256.       % random names for 1-to-1 mapping.
  1257.       %
  1258.       % A real TT font may use a different characters than
  1259.       % the Symbol charaster set. Perhaps our code
  1260.       % will give a correct printing, because glyph names are not
  1261.       % important for symbolic fonts in PDF.
  1262.       %
  1263.       <00010000> .findcmap {
  1264.         prebuilt_encoding null ne {
  1265.           prebuilt_encoding .invert_encoding .pdfmapchars
  1266.           /Encoding prebuilt_encoding
  1267.         } {
  1268.           .symbol_list .pdfmapchars
  1269.           /Encoding /.GS_extended_SymbolEncoding .findencoding
  1270.         } ifelse
  1271.       } {
  1272.         % This is illegal with PDF spec.
  1273.         (   **** Warning: Embedded symbolic TT fonts must contain a cmap for Platform=1 Encoding=0.\n)
  1274.         pdfformaterror
  1275.         % Try to map Unicode to SymbolEncoding
  1276.         <00030001> .findcmap {
  1277.           AdobeGlyphList .pdfmapchars
  1278.           /Encoding /SymbolEncoding .findencoding
  1279.         } {
  1280.           % Apply the default algorithm. Hopely it has 'post'.
  1281.           .charkeys
  1282.           % check if the CharStrings dict contains glyphs needed by the
  1283.       % prebuilt_encoding otherwise try the 3,0 cmap.
  1284.       prebuilt_encoding null ne {
  1285.         false prebuilt_encoding {    % false means no missing glyphs
  1286.           4 index exch known not { pop true exit } if
  1287.             } forall
  1288.             {
  1289.           (   **** Warning: Encoding derived from 'post' is incomplete.\n)
  1290.           pdfformaterror
  1291.           % Try another cmap format 3,0 -- Adobe doesn't mention it, but does
  1292.           % use it apparently (empirically determined).
  1293.           <00030000> .findcmap {
  1294.            5 1 roll pop pop pop pop             
  1295.         prebuilt_encoding null ne {
  1296.           prebuilt_encoding .invert_encoding .pdfmapchars
  1297.           /Encoding prebuilt_encoding
  1298.         } {
  1299.           AdobeGlyphList .pdfmapchars
  1300.           /Encoding /SymbolEncoding .findencoding
  1301.         } ifelse
  1302.           } if
  1303.             }if
  1304.           } if
  1305.         } ifelse
  1306.       } ifelse
  1307.     } ifelse
  1308.   } {
  1309.     <00030001> .findcmap {
  1310.       AdobeGlyphList .pdfmapchars 
  1311.       /Encoding /WinAnsiEncoding .findencoding
  1312.         % WinAnsiEncoding is just a stub here. 
  1313.         % It will be replaced with one from font resource,
  1314.         % because PDF spec requires it.
  1315.     } {
  1316.       <00010000> .findcmap {
  1317.     .romanmacdict .pdfmapchars 
  1318.         /Encoding /MacRomanEncoding .findencoding
  1319.       } {
  1320.         % Apply the default algorithm for using the 'post'.
  1321.     .charkeys
  1322.       } ifelse
  1323.     } ifelse
  1324.   } ifelse
  1325. } bind def
  1326.  
  1327. % <file> <is_symbolic> <Encoding|null> .loadpdfttfont <type42font>
  1328. /.loadpdfttfont {
  1329.   /prebuilt_encoding exch def     % for .pdfcharkeys
  1330.   /is_symbolic exch def
  1331.   //false 0 .loadttfonttables
  1332.   .makesfnts
  1333.   .getpost
  1334.   .pickcmap
  1335.   mark
  1336.   .pdfcharkeys
  1337.   .ttkeys
  1338.   .definettfont
  1339. } bind def
  1340.