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

  1. %    Copyright (C) 1996, 2000 Aladdin Enterprises.  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_ttf.ps,v 1.8 2000/09/23 18:47:06 lpd Exp $
  16. % Support code for direct use of TrueType fonts.
  17. % (Not needed for Type 42 fonts.)
  18.  
  19. % Note that if you want to use this file without including the ttfont.dev
  20. % option when you built Ghostscript, you will need to load the following
  21. % files before this one:
  22. %    lib/gs_mgl_e.ps
  23. %    lib/gs_mro_e.ps
  24. %    lib/gs_wan_e.ps
  25.  
  26. % Thanks to B. Jackowski and GUST (the Polish TeX Users' Group) for
  27. % the glyf-splitting code.
  28.  
  29. % ---------------- Font loading machinery ---------------- %
  30.  
  31. % Augment the FONTPATH machinery so it recognizes TrueType fonts.
  32.  
  33. /.scanfontheaders where {
  34.   pop /.scanfontheaders [
  35.    .scanfontheaders aload pop (\000\001\000\000*) (true*)
  36.   ] def
  37. } if
  38.  
  39. % <file> <key> .findfontvalue <value> true
  40. % <file> <key> .findfontvalue false
  41. % Closes the file in either case.
  42. /.findnonttfontvalue /.findfontvalue load def
  43. /.findfontvalue {
  44.   1 index read pop 2 index 1 index unread
  45.   dup 0 eq exch (t) 0 get eq or {
  46.         % If this is a font at all, it's a TrueType font.
  47.     dup /FontType eq {
  48.       pop closefile 42 true
  49.     } {
  50.       dup /FontName eq { pop .findttfontname } { pop closefile false } ifelse
  51.     } ifelse
  52.   } {
  53.         % Not a TrueType font.
  54.     .findnonttfontvalue
  55.   } ifelse
  56. } bind def
  57.  
  58. % <file> .findttfontname <fname> true
  59. % <file> .findttfontname false
  60. % Closes the file in either case.
  61. /.findttfontname {
  62.   .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 32000 def    % half the maximum length of a PostScript string,
  106.             % must be a multiple of 4 (for hmtx / loca / vmtx)
  107.  
  108. % Define the Macintosh standard mapping from characters to glyph indices.
  109. /MacRomanEncoding dup .findencoding def
  110. /MacGlyphEncoding dup .findencoding def
  111.  
  112. % Invert the MacRomanEncoding.
  113. /.romanmacdict 300 dict
  114. 0 1 MacRomanEncoding length 1 sub {
  115.   MacRomanEncoding 1 index get
  116.         % Stack: dict index charname
  117.   dup /.notdef ne {
  118.     exch 2 index 2 index .knownget {
  119.       dup type /arraytype eq {
  120.     [ exch aload pop counttomark 2 add -1 roll ]
  121.       } {
  122.     exch 2 array astore
  123.       } ifelse
  124.     } if 2 index 3 1 roll put
  125.   } {
  126.     pop pop
  127.   } ifelse
  128. } for def
  129.  
  130. % Define remapping for misnamed glyphs in TrueType 'post' tables.
  131. % There are probably a lot more than this!
  132. /postremap mark
  133.   /Cdot /Cdotaccent
  134.   /Edot /Edotaccent
  135.   /Eoverdot /Edotaccent
  136.   /Gdot /Gdotaccent
  137.   /Ldot /Ldotaccent
  138.   /Zdot /Zdotaccent
  139.   /cdot /cdotaccent 
  140.   /edot /edotaccent 
  141.   /eoverdot /edotaccent
  142.   /gdot /gdotaccent 
  143.   /ldot /ldotaccent
  144.   /zdot /zdotaccent 
  145. .dicttomark readonly def
  146.  
  147. % ---- Utilities ---- %
  148.  
  149. % Define a serial number for creating unique XUIDs for TrueType fonts.
  150. % We used to use the checkSumAdjustment value from the font, but this is
  151. % not reliable, since some fonts don't set it correctly.
  152. % Note that we must do this in a string to make it immune to save/restore.
  153. /xuidstring <80000000> def
  154. /curxuid {        % - curxuid <int>
  155.   0 xuidstring { exch 8 bitshift exch add } forall
  156. } bind def
  157. /nextxuid {        % - nextxuid -
  158.   3 -1 0 {
  159.     xuidstring 1 index 2 copy get dup 255 ne {
  160.       1 add put pop exit
  161.     } if pop 0 put pop
  162.   } for
  163. } bind def
  164.  
  165. % <string> <index> getu16 <integer>
  166. /getu16 {
  167.   2 copy get 8 bitshift 3 1 roll 1 add get add
  168. } bind def
  169.  
  170. % <string> <index> gets16 <integer>
  171. /gets16 {
  172.   getu16 16#8000 xor 16#8000 sub
  173. } bind def
  174.  
  175. % <string> <index> getu32 <integer>
  176. /getu32 {
  177.   2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add
  178. } bind def
  179.  
  180. % <string> <index> gets32 <integer>
  181. /gets32 {
  182.   2 copy gets16 16 bitshift 3 1 roll 2 add getu16 add
  183. } bind def
  184.  
  185. % <string> <index> <integer> putu16 -
  186. /putu16 {
  187.   3 copy -8 bitshift put
  188.   exch 1 add exch 16#ff and put
  189. } bind def
  190.  
  191. % <string> <index> <integer> putu32 -
  192. /putu32 {
  193.   3 copy -16 bitshift putu16
  194.   exch 2 add exch 16#ffff and putu16
  195. } bind def
  196.  
  197. % <nametable> <nameid> findname <string> true
  198. % <nametable> <nameid> findname false
  199. /findname {
  200.   DEBUG { (findname: ) print dup =only  } if
  201.   false 3 1 roll 0 1 3 index 2 getu16 1 sub {
  202.         % Stack: false table id index
  203.     12 mul 6 add 2 index exch 12 getinterval
  204.     dup 6 getu16 2 index eq {
  205.         % We found the name we want.
  206.       exch pop
  207.         % Stack: false table record
  208.       dup 10 getu16 2 index 4 getu16 add
  209.       1 index 8 getu16 4 -1 roll 3 1 roll getinterval exch
  210.         % Stack: false string record
  211.         % Check for 8- vs. 16-bit characters.
  212.       is2byte { string2to1 } if true null 4 -1 roll exit
  213.     } if pop
  214.   } for pop pop
  215.   DEBUG {
  216.     dup { ( = ) print 1 index == } { ( not found) = } ifelse
  217.   } if
  218. } bind def
  219.  
  220. % <namerecord> is2byte <bool>
  221. /is2byte {
  222.   dup 0 getu16 {
  223.     { pop true }        % Apple Unicode
  224.     { pop false }        % Macintosh Script manager
  225.     { 1 getu16 1 eq }        % ISO
  226.     { 1 getu16 1 eq }        % Microsoft
  227.   } exch get exec
  228. } bind def
  229.  
  230. % <string2> string2to1 <string>
  231. /string2to1 {
  232.   dup length 2 idiv string dup
  233.   0 1 3 index length 1 sub {
  234.     3 index 1 index 2 mul 1 add get put dup
  235.   } for pop exch pop
  236. } bind def
  237.  
  238. % <array> <lt-proc> sort <array>
  239. /sort {
  240.   1 index length 1 sub -1 1 {
  241.     2 index exch 2 copy get 3 copy    % arr proc arr i arr[i] arr i arr[i]
  242.     0 1 3 index 1 sub {
  243.       3 index 1 index get    % arr proc arr i arr[i] arr imax amax j arr[j]
  244.       2 index 1 index 10 index exec {    % ... amax < arr[j]
  245.     4 2 roll
  246.       } if pop pop
  247.     } for            % arr proc arr i arr[i] arr imax amax
  248.     4 -1 roll exch 4 1 roll put put
  249.   } for pop
  250. } def
  251.  
  252. % Each procedure in this dictionary is called as follows:
  253. %       <encodingtable> proc <glypharray>
  254. /cmapformats mark
  255.   0 {        % Apple standard 1-to-1 mapping.
  256.     6 256 getinterval { } forall 256 packedarray
  257.   } bind
  258.   4 {        % Microsoft/Adobe segmented mapping.
  259.     /etab exch def
  260.     /nseg2 etab 6 getu16 def
  261.     14 /endc etab 2 index nseg2 getinterval def
  262.         % The Apple TrueType documentation omits the 2-byte
  263.         % 'reserved pad' that follows the endCount vector!
  264.     2 add
  265.     nseg2 add /startc etab 2 index nseg2 getinterval def
  266.     nseg2 add /iddelta etab 2 index nseg2 getinterval def
  267.     nseg2 add /idroff etab 2 index nseg2 getinterval def
  268.         % The following hack allows us to properly handle
  269.         % idiosyncratic fonts that start at 0xf000:
  270.     pop
  271.     /firstcode startc 0 getu16 16#ff00 and dup 16#f000 ne { pop 0 } if def
  272.     /putglyph {
  273.       glyphs code 3 -1 roll put /code code 1 add def
  274.     } bind def
  275.         % Do a first pass to compute the size of the glyphs array.
  276.     /numcodes 0 def /glyphs 0 0 2 nseg2 3 sub {
  277.         % Stack: /glyphs numglyphs i2
  278.       /i2 exch def
  279.       /scode startc i2 getu16 def
  280.       /ecode endc i2 getu16 def
  281.       numcodes scode firstcode sub
  282.         % Hack for fonts that have only 0x0000 and 0xf000 ranges
  283.       dup 16#e000 ge { 255 and } if
  284.       exch sub 0 max ecode scode sub 1 add add
  285.       exch 1 index add exch
  286.       numcodes add /numcodes exch def
  287.     } for array def
  288.         % Now fill in the array.
  289.     /numcodes 0 def /code 0 def
  290.     0 2 nseg2 3 sub {
  291.       /i2 exch def
  292.       /scode startc i2 getu16 def
  293.       /ecode endc i2 getu16 def
  294.       numcodes scode firstcode sub
  295.         % Hack for fonts that have only 0x0000 and 0xf000 ranges
  296.       dup 16#e000 ge { 255 and } if
  297.       exch sub 0 max dup { 0 putglyph } repeat
  298.       ecode scode sub 1 add add numcodes add /numcodes exch def
  299.       /delta iddelta i2 gets16 def
  300.       DEBUG {
  301.     (scode=) print scode =only
  302.     ( ecode=) print ecode =only
  303.     ( delta=) print delta =only
  304.     ( droff=) print idroff i2 getu16 =
  305.       } if
  306.       idroff i2 getu16 dup 0 eq {
  307.     pop scode delta add 65535 and 1 ecode delta add 65535 and
  308.     { putglyph } for
  309.       } {    % The +2 is for the 'reserved pad'.
  310.         /gloff exch 14 nseg2 3 mul add 2 add i2 add add def
  311.         0 1 ecode scode sub {
  312.       2 mul gloff add etab exch getu16
  313.       dup 0 ne { delta add 65535 and } if putglyph
  314.     } for
  315.       } ifelse
  316.     } for glyphs /glyphs null def    % for GC
  317.   } bind
  318.   6 {        % Single interval lookup.
  319.     dup 6 getu16 /firstcode exch def dup 8 getu16 /ng exch def
  320.     firstcode ng add array
  321.         % Stack: tab array
  322.         % Fill elements 0 .. firstcode-1 with 0
  323.     0 1 firstcode 1 sub { 2 copy 0 put pop } for
  324.     dup firstcode ng getinterval
  325.         % Stack: tab array subarray
  326.         % Fill elements firstcode .. firstcode+nvalue-1 with glyph values
  327.     0 1 ng 1 sub {
  328.       dup 2 mul 10 add 4 index exch getu16 3 copy put pop pop
  329.     } for pop exch pop
  330.   } bind
  331. .dicttomark readonly def                % cmapformats
  332.  
  333. % <cmaptab> cmaparray <glypharray>
  334. /cmaparray {
  335.   dup 0 getu16 cmapformats exch .knownget {
  336.     DEBUG {
  337.       (cmap: format ) print 1 index 0 getu16 = flush
  338.     } if exec
  339.   } {
  340.     (Can't handle format ) print 0 getu16 = flush
  341.     0 1 255 { } for 256 packedarray
  342.   } ifelse
  343.   DEBUG {
  344.     (cmap: length=) print dup length = dup ==
  345.   } if
  346. } bind def
  347.  
  348. % Each procedure in this dictionary is called as follows:
  349. %       posttable <<proc>> glyphencoding
  350. /postformats mark
  351.   16#00010000  {    % 258 standard Macintosh glyphs.
  352.     pop MacGlyphEncoding
  353.   }
  354.   16#00020000  {    % Detailed map, required by Microsoft fonts.
  355.     /postglyphs exch def
  356.       postglyphs 32 getu16 /numglyphs exch def
  357.       /glyphnames numglyphs 2 mul 34 add def
  358.       [ 0 1 numglyphs 1 sub {
  359.     2 mul 34 add postglyphs exch getu16
  360.     dup 258 lt {
  361.       MacGlyphEncoding exch get
  362.     } {
  363.       dup 32768 ge {
  364.         % According to the published TrueType spec, such values are
  365.         % "reserved for future use", but at least some PDF files
  366.         % produced by the Adobe PDF library contain entries with a
  367.         % value of 16#ffff.
  368.         pop /.notdef
  369.       } {
  370.         258 sub glyphnames exch {
  371.           postglyphs 1 index get 1 add add
  372.         } repeat
  373.         1 add postglyphs exch 2 copy 1 sub get getinterval cvn
  374.         % At least some of Microsoft's TrueType fonts use incorrect
  375.         % (Adobe-incompatible) names for some glyphs.
  376.         % Correct for this here.
  377.         postremap 1 index .knownget { exch pop } if
  378.       } ifelse
  379.     } ifelse
  380.       } for ]
  381.   } bind
  382.   16#00030000  {    % No map.
  383.     pop [ ]
  384.   } bind
  385. .dicttomark readonly def                % postformats
  386.  
  387. % Each procedure in this dictionary is called as follows:
  388. %    <file> <length> -proc- <string|array_of_strings>
  389. % Note that each table must have an even length, because of a strange
  390. % Adobe requirement that each sfnts entry have even length.
  391. /readtables mark
  392.     % Ordinary tables
  393.   (cmap) { .readtable }
  394.   (head) 1 index
  395.   (hhea) 1 index
  396.   (maxp) 1 index
  397.   (name) 1 index
  398.   (OS/2) 1 index
  399.   (post) 1 index
  400.   (vhea) 1 index
  401.     % Big tables
  402.   (glyf) { .readbigtable }
  403.   (loca) 1 index
  404.   (hmtx) 1 index
  405.   (vmtx) 1 index
  406.     % Tables only needed for embedding in PDF files
  407.   (cvt ) { .readtable }
  408.   (fpgm) 1 index
  409.   (prep) 1 index
  410. .dicttomark
  411. % Normally there would be a 'readonly' here, but the ttf2pf utility wants
  412. % to include the 'kern' table as well, so we leave the readtables dictionary
  413. % writable.
  414. def                % readtables
  415.  
  416. % Read a table as a single string.
  417. % <file> <length> .readtable <string>
  418. /.readtable {
  419.   dup dup 1 and add string
  420.         % Stack: f len str
  421.   dup 0 4 -1 roll getinterval
  422.         % Stack: f str str1
  423.   3 -1 roll exch readstring pop pop
  424. } bind def
  425.  
  426. % Read a big table (one that may exceed 64K).
  427. % <file> <length> .readbigtable <string[s]>
  428. /.readbigtable {
  429.   dup 65400 lt {
  430.     .readtable
  431.   } {
  432.     currentuserparams /VMReclaim get -2 vmreclaim
  433.     [ 4 2 roll {
  434.         % Stack: mark ... f left
  435.       dup maxstring le { exit } if
  436.       1 index maxstring string readstring pop 3 1 roll maxstring sub
  437.     } loop .readtable ]
  438.     exch vmreclaim
  439.   } ifelse
  440. } bind def
  441.  
  442. end readonly def                % .loadttfontdict
  443.  
  444. % <tab> .printtab -
  445. /.printtab {
  446.   dup 0 4 getinterval print ( ) print
  447.   dup 8 getu32 =only ( ) print
  448.   12 getu32 =
  449. } bind def
  450.  
  451. % <file> .loadttfonttables -
  452. % Pushes .loadttfontdict & scratch dict on d-stack.
  453. % Defines f, offsets, tables, tabdict, tabs.
  454. /.loadttfonttables {
  455.   .loadttfontdict begin
  456.   40 dict begin
  457.   /f exch def
  458.   /offsets f 12 string readstring pop def
  459.   /tables f offsets 4 getu16 16 mul string readstring pop def
  460.   /tabdict tables length 16 idiv dict def
  461.     % tabs = tables we want to keep, sorted by file position.
  462.   /tabs [ 0 16 tables length 1 sub {
  463.     tables exch 16 getinterval
  464.     DEBUG { dup .printtab } if
  465.     dup 0 4 getinterval readtables 1 index known {
  466.       tabdict exch 2 index put
  467.     } {
  468.       pop pop
  469.     } ifelse
  470.   } for ] {
  471.     exch 8 getu32 exch 8 getu32 lt
  472.   } sort def
  473.     % In certain malformed TrueType fonts, tables overlap.
  474.     % Truncate tables if necessary.
  475.   0 1 tabs length 2 sub {
  476.     dup tabs exch get exch 1 add tabs exch get
  477.     1 index 8 getu32 2 index 12 getu32 add
  478.     1 index 8 getu32 gt {
  479.       (**** Warning: ) print 1 index 0 4 getinterval print
  480.       ( overlaps ) print dup 0 4 getinterval print
  481.       (, truncating.) = flush
  482.       dup 8 getu32 2 index 8 getu32 sub
  483.       2 index 12 3 -1 roll putu32
  484.     } if pop pop
  485.   } for
  486. } bind def
  487.  
  488. % - .readttdata -
  489. % Read data.  Updates offsets, tabs; stores data in tabdict.
  490. /.readttdata {
  491.   /fpos offsets length tables length add def
  492.   /sfpos offsets length tabs length 16 mul add def
  493.   offsets 4 tabs length putu16
  494.   tabs {
  495.     dup 0 4 getinterval /tname exch def
  496.     dup 8 getu32 /tpos exch def
  497.     dup 12 getu32 /tlen exch def
  498.     8 sfpos putu32
  499.     % Skip data between the end of the previous table and
  500.     % the beginning of this one, if any.
  501.     tpos fpos gt {
  502.       f tpos fpos sub () /SubFileDecode filter dup flushfile closefile
  503.       /fpos tpos def
  504.     } if
  505.     f tlen readtables tname get exec
  506.     tabdict tname 3 -1 roll put
  507.     /fpos fpos tlen add def
  508.     % Round up the table length to an even value.
  509.     /sfpos sfpos tlen dup 1 and add add def
  510.   } forall
  511. } bind def
  512.  
  513. % Find the string in a list of strings that includes a given index.
  514. % <strings> <index> .findseg <string> <index'>
  515. /.findseg {
  516.   exch {
  517.     dup length 2 index gt { exch exit } if
  518.     length sub
  519.   } forall
  520. } bind def
  521.  
  522. % - .makesfnts -
  523. % Defines checksum, getloca, head, locatable, numloca, post, sfnts, upem
  524. /.makesfnts {
  525.   .readttdata
  526.   /head tabdict /head get def
  527.   /locatable tabdict /loca get def
  528.   /post tabdict /post .knownget not { null } if def
  529.   /numloca
  530.     locatable dup type /stringtype eq
  531.      { length }
  532.      { 0 exch { length add } forall }
  533.     ifelse    % no def yet
  534.   locatable type /stringtype eq {
  535.     /.indexloca {} def
  536.   } {
  537.     /.indexloca /.findseg load def
  538.   } ifelse
  539.   head 50 getu16 0 ne {
  540.     /getloca {
  541.       2 bitshift locatable exch .indexloca getu32
  542.     } def
  543.     4 idiv 1 sub
  544.   } {
  545.     /getloca {
  546.       dup add locatable exch .indexloca getu16 dup add
  547.     } def
  548.     2 idiv 1 sub
  549.   } ifelse def        % numloca
  550.     % If necessary, re-partition the glyfs.
  551.   tabdict /glyf get dup type /stringtype ne {
  552.     .dividesfnts tabdict /glyf 3 -1 roll put
  553.   } {
  554.     pop
  555.   } ifelse
  556.   /sfnts [
  557.     offsets tabs { concatstrings } forall
  558.     tabs {
  559.       0 4 getinterval tabdict exch get
  560.       dup type /stringtype ne { aload pop } if
  561.     } forall
  562.   ] def
  563. } bind def
  564.  
  565. % <glyfs> .dividesfnts <glyfs'>
  566. /.dividesfnts {
  567.   /glyfs exch def
  568.   /len1 0 glyfs { length add } forall def
  569.         % Determine where to split the glyfs by scanning loca.
  570.         % The very last entry in loca may be bogus.
  571.         % Note that some loca entries may be odd, but we can only
  572.         % split at even positions.
  573.         %
  574.         % Construct splitarray, the array of final lengths of
  575.         % the sfnts entries covering the glyfs (i.e., all but
  576.         % the first and last sfnts entries).
  577.     /prevsplit 0 def
  578.     /prevboundary 0 def
  579.     /splitarray [
  580.       0 1 numloca 1 sub {
  581.     getloca dup prevsplit maxstring add gt {
  582.       prevboundary prevsplit sub exch
  583.       /prevsplit prevboundary def
  584.     } if
  585.     dup 1 and 0 eq { /prevboundary exch def } { pop } ifelse
  586.       } for
  587.       len1 prevsplit sub
  588.     ] def
  589.     currentuserparams /VMReclaim get -2 vmreclaim
  590.     [
  591.         % Re-split the sfnts glyfs strings according to splitarray.
  592.         % We do this by iterating over the final segments defined
  593.         % by splitarray, and constructing them from pieces of the
  594.         % current glyfs strings.  We recycle the current strings
  595.         % when possible, to avoid stressing the allocator.
  596.       /sfnt_idx 0 def
  597.       /strpos 0 def
  598.       /avail () def
  599.       splitarray {
  600.     /seglen exch def
  601.     /segpos 0 def
  602.     avail length seglen ge
  603.       { avail 0 seglen getinterval /avail () def } { seglen string }
  604.     ifelse
  605.     {
  606.       /str glyfs sfnt_idx get def
  607.       /strlen str length def
  608.       /strleft strlen strpos sub def
  609.       seglen segpos sub strleft lt { exit } if
  610.         % Copy the (rest of the) string into the new segment.
  611.         % We know strleft <= segleft.
  612.       dup segpos str strpos strleft getinterval putinterval
  613.       /segpos segpos strleft add def
  614.       /avail str def
  615.       /sfnt_idx sfnt_idx 1 add def
  616.       /strpos 0 def
  617.       segpos seglen eq { exit } if
  618.     } loop
  619.         % Fill up the segment with an initial piece of the next
  620.         % existing glyfs string.  We know strleft > segleft.
  621.     /segleft seglen segpos sub def
  622.     dup segpos str strpos segleft getinterval putinterval
  623.     /strpos strpos segleft add def
  624.       } forall
  625.     ]
  626.     exch vmreclaim
  627. } bind def
  628.  
  629. % - .getpost -
  630. % Uses post, defines glyphencoding
  631. /.getpost {
  632.   /glyphencoding post null eq {
  633.     DEBUG { (post missing) = flush } if [ ]
  634.   } {
  635.     postformats post 0 getu32 .knownget {
  636.       DEBUG {
  637.     (post: format ) print
  638.     post 0 getu16 =only (,) print post 2 getu16 = flush
  639.       } if
  640.       post exch exec
  641.     } {
  642.       DEBUG { (post: unknown format ) print post 0 getu32 = flush } if [ ]
  643.     } ifelse
  644.   } ifelse def
  645. } bind def
  646.  
  647. % - .ttkeys <key> <value> ...
  648. /.ttkeys {
  649.   count /ttkeycount exch def
  650.   /upem head 18 getu16 def
  651.   /FontMatrix matrix
  652.   /FontBBox [ 36 2 42 { head exch gets16 upem div } for ]
  653.   nextxuid
  654.   tabdict /name .knownget {
  655.         % Find the names from the 'name' table.
  656.     /names exch def
  657.     /FontName names 6 findname not { curxuid 16 8 string cvrs } if
  658.       /fontname 1 index def
  659.     /FontInfo mark
  660.       names 0 findname { /Notice exch } if
  661.       names 1 findname { /FamilyName exch } if
  662.       names 4 findname { /FullName exch } if
  663.       names 5 findname { /Version exch } if
  664.   } {
  665.         % No name table, fabricate a FontName.
  666.     /FontName curxuid 16 8 string cvrs
  667.       /fontname 1 index def
  668.     /FontInfo mark
  669.   } ifelse
  670.         % Stack: ... /FontInfo mark key1 value1 ...
  671.   post null ne {
  672.     /ItalicAngle post 4 gets32 65536.0 div
  673.     /isFixedPitch post 12 getu32 0 ne
  674.     /UnderlinePosition post 8 gets16 upem div
  675.     /UnderlineThickness post 10 gets16 upem div
  676.   } if
  677.   counttomark 0 ne { .dicttomark } { pop pop } ifelse
  678.   /XUID [orgXUID 42 curxuid]
  679.   DEBUG {
  680.     tabs { .printtab } forall
  681.     [ sfnts { length } forall ] ==
  682.     count ttkeycount sub array astore dup { == } forall aload pop
  683.   } if
  684.   /sfnts sfnts
  685. } bind def
  686.  
  687. % ---------------- Standard TrueType font loading ---------------- %
  688.  
  689. % - .pickcmap -
  690. % Defines cmapsub, cmaptab
  691. /.pickcmap {
  692.   tabdict /cmap get
  693.         % The Apple cmap format is no help in determining the encoding.
  694.         % Look for a Microsoft table.  If we can't find one,
  695.         % just use the first table, whatever it is.
  696.   dup 4 8 getinterval exch             % the default
  697.   0 1 2 index 2 getu16 1 sub {
  698.     8 mul 4 add 1 index exch 8 getinterval
  699.     DEBUG {
  700.       (cmap: platform ) print dup 0 getu16 =only
  701.       ( encoding ) print dup 2 getu16 = flush
  702.     } if
  703.     dup 0 getu16 3 eq { exch 3 -1 roll pop exit } if pop
  704.   } for
  705.         % Stack: subentry table
  706.   /cmapsub 2 index def
  707.   exch 4 getu32 1 index length 1 index sub getinterval
  708.   /cmaptab exch def
  709. } bind def
  710.  
  711. % <glyph> .nname <_name>
  712. /.nname {
  713.   =string cvs (_) exch concatstrings cvn
  714. } bind def
  715.  
  716. % - .charkeys /CharStrings <charstrings> /Encoding <encoding>
  717. % Resets glyphencoding
  718. /.charkeys {
  719.   DEBUG {
  720.     (glyphencoding: length=) print glyphencoding dup length = === flush
  721.   } if
  722.         % Hack: if there is no usable post table but the cmap uses
  723.         % the Microsoft Unicode encoding, use ISOLatin1Encoding.
  724.   glyphencoding length 0 eq cmapsub 0 4 getinterval <00030001> eq and {
  725.     /glyphencoding ISOLatin1Encoding dup length array copy def
  726.   } if
  727.         % If necessary, fabricate additional glyphencoding entries
  728.         % to cover all of loca, or truncate glyphencoding.
  729.   glyphencoding length numloca lt {
  730.     /glyphencoding [ glyphencoding aload pop
  731.     counttomark 1 numloca 1 sub { .nname } for ] def
  732.   } {
  733.     /glyphencoding glyphencoding 0 numloca getinterval def
  734.   } ifelse
  735.         % Some badly designed Chinese fonts have a post table
  736.         % in which all glyphs other than 0 are named .null.
  737.         % Use CharStrings to keep track of the reverse map from
  738.         % names to glyphs, and don't let any name be used for
  739.         % more than one glyph.
  740.   /CharStrings glyphencoding dup length 1 add dict    % +1 for .notdef
  741.     0 1 3 index length 1 sub {
  742.         % Stack: glyphencoding dict index
  743.       2 index 1 index get 2 index 1 index known {
  744.         % The same name maps to more than one glyph.
  745.         % Change the name.
  746.     pop dup .nname 3 index 2 index 2 index put
  747.       } if
  748.       2 index exch 3 -1 roll put
  749.     } for exch pop
  750.         % If there is no .notdef entry, map it to glyph 0.
  751.   dup /.notdef known not { dup /.notdef 0 put } if
  752.   readonly
  753.   /Encoding
  754.     [ cmaptab cmaparray dup length 256 gt { 0 256 getinterval } if
  755.     { glyphencoding exch get } forall
  756.     counttomark 256 exch sub { /.notdef } repeat ]
  757.   DEBUG { (Encoding: ) print dup === flush } if
  758. } bind def
  759.  
  760. % -mark- <key> <value> ... .definettfont <font>
  761. /.definettfont {
  762.   /FontType 42
  763.   /PaintType 0
  764.   DEBUG {
  765.     (numloca=) print numloca =
  766.   } if
  767.   .dicttomark
  768.   end end dup /FontName get exch definefont
  769. } bind def
  770.  
  771. % <file> .loadttfont <type42font>
  772. /.loadttfont {
  773.   .loadttfonttables
  774.   .makesfnts
  775.   .getpost
  776.   .pickcmap
  777.   mark
  778.   .charkeys
  779.   .ttkeys
  780.   .definettfont
  781. } bind def
  782.  
  783. % ---------------- CIDFontType 2 font loading ---------------- %
  784.  
  785. % Create a string with N CIDs from the top of the stack.
  786. % <cid1> ... <cidN> <N> .makecidmap <string>
  787. /.makecidmap {
  788.   dup 2 mul string dup 3 -1 roll 1 sub 2 mul -2 0 {
  789.         % Stack: cids str str i2
  790.     2 copy 5 index -8 bitshift put
  791.     1 add 4 -1 roll 16#ff and put dup
  792.   } for pop
  793. } bind def
  794.  
  795. % -mark- <key> <value> ... .definettcidfont <font>
  796. /.definettcidfont {
  797.   /CIDFontName fontname
  798.   /CIDFontType 2
  799.   /CIDSystemInfo mark
  800.     /Registry (Adobe)
  801.     /Ordering (Japan1)        % adhoc
  802.     /Supplement 0
  803.   .dicttomark
  804.   /CharStrings mark /.notdef 0 .dicttomark
  805.         % The cmap isn't of any use even if it is present.
  806.         % Just construct an identity CIDMap covering all the glyphs.
  807.   mark 0 1 numloca 1 sub { } for
  808.   counttomark /cidcount exch def
  809.   cidcount maxstring le {
  810.         % Use a single string.
  811.     cidcount .makecidmap exch pop
  812.   } {
  813.         % We must use 2 strings.
  814.     maxstring .makecidmap counttomark 1 add 1 roll
  815.     counttomark .makecidmap exch pop exch 2 array astore
  816.   } ifelse
  817.   /CIDMap exch
  818.   /CIDCount cidcount
  819.   /GDBytes 2
  820.   .dicttomark
  821.   end end dup /CIDFontName get exch /CIDFont defineresource
  822. } bind def
  823.  
  824. % <file> .loadttcidfont <cidtype2font>
  825. /.loadttcidfont {
  826.   .loadttfonttables
  827.   .makesfnts
  828.     % CIDFontType2 fonts don't have a cmap: they are indexed by CID.
  829.   mark
  830.   .ttkeys
  831.   .definettcidfont
  832. } bind def
  833.  
  834. % ---------------- PDF TrueType font loading ---------------- %
  835.  
  836. % Strictly speaking, this code should be loaded only if we have a PDF
  837. % interpreter, but it's so closely tied to the rest of the code in this
  838. % file that we always include it.
  839.  
  840. % <plat+enc> .findcmap <subtable> true
  841. % <plat+enc> .findcmap false
  842. /.findcmap {
  843.   false exch tabdict /cmap get
  844.         % Some fonts have multiple cmaps with the same platform and
  845.         % encoding.  Use the first one we find.
  846.   0 1 2 index 2 getu16 1 sub {
  847.         % Stack: false plat+enc cmap index
  848.     8 mul 4 add 1 index exch 8 getinterval 
  849.     dup 0 4 getinterval 3 index eq {
  850.       4 getu32 1 index exch 1 index length 1 index sub getinterval
  851.       4 -1 roll not 4 2 roll exit
  852.     } if pop
  853.   } for
  854.         % Stack: false plat+enc cmap || subtable true plat+enc cmap
  855.   pop pop
  856. } bind def
  857.  
  858. % <subcmap> <chartoglyphmap> .pdfmapchars
  859. %   /CharStrings <charstrings> /Encoding <encoding>
  860. % Uses encoding
  861. /.pdfmapchars {
  862.   exch cmaparray /cmapencoding exch def
  863.     % Invert glyphencoding (post).
  864.   /inversepost glyphencoding length dict def
  865.   0 1 glyphencoding length 1 sub {
  866.     glyphencoding 1 index get exch inversepost 3 1 roll put
  867.   } for
  868.   /CharStrings mark 3 -1 roll {
  869.     dup type /arraytype eq {
  870.       exch /ch exch def { ch exch .pdfaddchar } forall
  871.     } {
  872.       .pdfaddchar
  873.     } ifelse
  874.   } forall
  875.     % Add a .notdef => 0 entry if needed.  Per Adobe's spec,
  876.     % .dicttomark (>>) adds pairs in top-to-bottom order.
  877.   /.notdef 0
  878.   .dicttomark
  879.   /Encoding encoding
  880. } bind def
  881. % <charname> <charcode> .pdfaddchar <charname> <glyph#>
  882. % <charname> <charcode> .pdfaddchar -
  883. /.pdfaddchar {
  884.   dup cmapencoding length lt {
  885.     cmapencoding exch get dup 0 eq {
  886.       pop .pdfaddpost
  887.     } if
  888.   } {
  889.     pop .pdfaddpost
  890.   } ifelse
  891. } bind def
  892. % <charname> .pdfaddpost <charname> <glyph#>
  893. % <charname> .pdfaddpost -
  894. /.pdfaddpost {
  895.   inversepost 1 index .knownget not { pop } if
  896. } bind def
  897.  
  898. % - .pdfcharkeys /CharStrings <charstrings> /Encoding <encoding>
  899. /.pdfcharkeys {
  900.     % The following algorithms are per the PDF Reference, Second Edition
  901.     % (PDF 1.3 reference manual).
  902.   encoding null eq {
  903.     .charkeys        % use default algorithm
  904.   } {
  905.     <00030001> .findcmap {
  906.       AdobeGlyphList .pdfmapchars
  907.     } {
  908.       <00010000> .findcmap {
  909.     .romanmacdict .pdfmapchars
  910.       } {
  911.     .charkeys    % use default algorithm
  912.       } ifelse
  913.     } ifelse
  914.   } ifelse
  915. } bind def
  916.  
  917. % <file> <encoding|null> .loadpdfttfont <type42font>
  918. /.loadpdfttfont {
  919.   exch .loadttfonttables
  920.   /encoding exch def
  921.   .makesfnts
  922.   .getpost
  923.   .pickcmap
  924.   mark
  925.   .pdfcharkeys
  926.   .ttkeys
  927.   .definettfont
  928. } bind def
  929.