shithub: riscv

ref: dde3628d54073e0569bf565e6ec861e42cfa35f6
dir: /sys/src/cmd/gs/lib/gs_ttf.ps/

View raw version
%    Copyright (C) 1996-2003 artofcode LLC.  All rights reserved.
% 
% This software is provided AS-IS with no warranty, either express or
% implied.
% 
% This software is distributed under license and may not be copied,
% modified or distributed except as expressly authorized under the terms
% of the license contained in the file LICENSE in this distribution.
% 
% For more information about licensing, please refer to
% http://www.ghostscript.com/licensing/. For information on
% commercial licensing, go to http://www.artifex.com/licensing/ or
% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
% San Rafael, CA  94903, U.S.A., +1(415)492-9861.

% $Id: gs_ttf.ps,v 1.48 2005/09/22 16:11:37 ray Exp $
% Support code for direct use of TrueType fonts.
% (Not needed for Type 42 fonts.)

% Note that if you want to use this file without including the ttfont.dev
% option when you built Ghostscript, you will need to load the following
% files before this one:
%	lib/gs_mgl_e.ps
%	lib/gs_mro_e.ps
%	lib/gs_wan_e.ps

% Thanks to B. Jackowski and GUST (the Polish TeX Users' Group) for
% the glyf-splitting code.

% ---------------- Font loading machinery ---------------- %

% Augment the FONTPATH machinery so it recognizes TrueType fonts.

/.scanfontheaders where {
  pop /.scanfontheaders [
   .scanfontheaders aload pop (\000\001\000\000*) (true*)
  ] def
} if

% <file> <key> .findfontvalue <value> true
% <file> <key> .findfontvalue false
% Closes the file in either case.
/.findnonttfontvalue /.findfontvalue load def
/.findfontvalue {
  1 index read {
    2 index 1 index unread
    % beginning with binary 0 or 't' (TrueType), or 'O' (OpenType)
    dup 0 eq 1 index (O) 0 get eq or exch (t) 0 get eq or {
		% If this is a font at all, it's a TrueType font.
      dup /FontType eq {
        pop closefile 42 true
      } {
        dup /FontName eq { pop .findttfontname } { pop closefile false } ifelse
      } ifelse
    } {
		% Not a TrueType font.
      .findnonttfontvalue
    } ifelse
  } { pop closefile false } ifelse
} bind def

% <file> .findttfontname <fname> true
% <file> .findttfontname false
% Closes the file in either case.
/.findttfontname {
  //true 0 .loadttfonttables
  tabdict /name .knownget {
    dup 8 getu32 f exch setfileposition
    12 getu32 string f exch readstring pop
    6 findname
  } {
    false
  } ifelse
  f closefile end end
} bind def

% Load a font file that might be a TrueType font.

% <file> .loadfontfile -
/.loadnonttfontfile /.loadfontfile load def
/.loadfontfile {
  dup read pop 2 copy unread 0 eq {
		% If this is a font at all, it's a TrueType font.
    .loadttfont pop
  } {
		% Not a TrueType font.
    .loadnonttfontfile
  } ifelse
} bind def

% ---------------- Automatic Type 42 generation ---------------- %

% Load a TrueType font from a file as a Type 42 PostScript font.
% The thing that makes this really messy is the handling of encodings.
% There are 2 interacting tables that affect the encoding:
%       'cmap' provides multiple maps from character codes to glyph indices
%       'post' maps glyph indices to glyph names (if present)
% What we need to get out of this is:
%       Encoding mapping character codes to glyph names
%         (the composition of cmap and post)
%       CharStrings mapping glyph names to glyph indices
%         (the inverse of post)
% If the post table is missing, we have to take a guess based on the cmap
% table.

/.loadttfontdict 50 dict dup begin

/orgXUID AladdinEnterprisesXUID def
/maxstring 32764 def    % half the maximum length of a PostScript string,
			% must be a multiple of 4 (for hmtx / loca / vmtx)

/.invert_encoding   % <array> invert_encoding <dict>
{ dup 256 dict exch
  0 exch 1 exch length 1 sub {     % [] <> i
    dup 3 index exch get           % [] <> i v
    dup /.notdef ne {
      exch 2 index 2 index .knownget {
        dup type /arraytype eq {
  	[ exch aload pop counttomark 2 add -1 roll ]
        } {
  	exch 2 array astore
        } ifelse
      } if 2 index 3 1 roll put
    } {
      pop pop
    } ifelse
  } for
  exch pop
} bind def

% Define the Macintosh standard mapping from characters to glyph indices.
/MacRomanEncoding dup .findencoding def
/MacGlyphEncoding dup .findencoding def

% Invert the MacRomanEncoding.
/.romanmacdict MacRomanEncoding .invert_encoding def

% Define remapping for misnamed glyphs in TrueType 'post' tables.
% There are probably a lot more than this!
/postremap mark
  /Cdot /Cdotaccent
  /Edot /Edotaccent
  /Eoverdot /Edotaccent
  /Gdot /Gdotaccent
  /Ldot /Ldotaccent
  /Zdot /Zdotaccent
  /cdot /cdotaccent 
  /edot /edotaccent 
  /eoverdot /edotaccent
  /gdot /gdotaccent 
  /ldot /ldotaccent
  /zdot /zdotaccent 
.dicttomark readonly def

% Array used for fast pre-filling of cmap array
/.array1024z [ 1024 { 0 } repeat ] def

% ---- Utilities ---- %

% Define a serial number for creating unique XUIDs for TrueType fonts.
% We used to use the checkSumAdjustment value from the font, but this is
% not reliable, since some fonts don't set it correctly.
% Note that we must do this in a string to make it immune to save/restore.
/xuidstring <80000000> def
/curxuid {		% - curxuid <int>
  0 xuidstring { exch 8 bitshift exch add } forall
} bind def
/nextxuid {		% - nextxuid -
  3 -1 0 {
    xuidstring 1 index 2 copy get dup 255 ne {
      1 add put pop exit
    } if pop 0 put pop
  } for
} bind def

% <string> <index> getu16 <integer>
/getu16 {
  2 copy get 8 bitshift 3 1 roll 1 add get add
} bind def

% <string> <index> gets16 <integer>
/gets16 {
  getu16 16#8000 xor 16#8000 sub
} bind def

% <string> <index> getu32 <integer>
/getu32 {
  2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add
} bind def

% <string> <index> gets32 <integer>
/gets32 {
  2 copy gets16 16 bitshift 3 1 roll 2 add getu16 add
} bind def

16#ffffffff 0 gt {  % 64-bit sign extension
  { /curxuid /gets32 } {
    mark 1 index load aload pop { 16#80000000 xor 16#80000000 sub } aload pop
    .packtomark cvx def
  } bind forall
} if

% <string> <index> <integer> putu16 -
/putu16 {
  3 copy -8 bitshift put
  exch 1 add exch 16#ff and put
} bind def

% <string> <index> <integer> putu32 -
/putu32 {
  3 copy -16 bitshift putu16
  exch 2 add exch 16#ffff and putu16
} bind def

% <nametable> <nameid> findname <string> true
% <nametable> <nameid> findname false
/findname {
  TTFDEBUG { (findname: ) print dup =only  } if
  false 3 1 roll
  1 index length 0 gt {	% check for zero length name table 
    0 1 3 index 2 getu16 1 sub {
		% Stack: false table id index
      12 mul 6 add 2 index exch 12 getinterval
      dup 6 getu16 2 index eq {
		  % We found the name we want.
	exch pop
		  % Stack: false table record
	dup 10 getu16 2 index 4 getu16 add
	1 index 8 getu16 4 -1 roll 3 1 roll
	    3 copy add 1 index length
	    le {
	      pop
	      getinterval exch
		  % Stack: false string record
		  % Check for 8- vs. 16-bit characters.
	  is2byte { string2to1 } if true null 4 -1 roll exit
	    } {
	      pop pop pop pop
	      false
		  exit
	    } ifelse
      } if pop
    } for
  } if
  pop pop
  TTFDEBUG {
    dup { ( = ) print 1 index == } { ( not found) = } ifelse
  } if
} bind def

% <namerecord> is2byte <bool>
/is2byte {
  dup 0 getu16 {
    { pop true }		% Apple Unicode
    { pop false }		% Macintosh Script manager
    { 1 getu16 1 eq }		% ISO
    { 1 getu16 1 eq }		% Microsoft
  } exch get exec
} bind def

% <string2> string2to1 <string>
/string2to1 {
  dup length 2 idiv string dup
  0 1 3 index length 1 sub {
    3 index 1 index 2 mul 1 add get put dup
  } for pop exch pop
} bind def

% Each procedure in this dictionary is called as follows:
%       <encodingtable> proc <glypharray>
/cmapformats mark
  0 {		% Apple standard 1-to-1 mapping.
    6 256 getinterval { } forall 256 packedarray
  } bind
  2 {		% Apple 16bit CJK (ShiftJIS etc)

    % /sHK_sz		subHeaderKey_size	% 1 * uint16
    % /sH_sz		subHeader_size		% 4 * uint16
    % /sH_len		subHeader_length
    % /cmapf2_tblen	total table length
    % /cmapf2_lang	language code (not used)
    % /sHKs		subHeaderKeys

    /sHK_sz 2 def
    /sH_sz 8 def
    dup 2 getu16 /cmapf2_tblen exch def

    dup 4 getu16 /cmapf2_lang exch def

    dup 6 256 sHK_sz mul getinterval /sHKs exch def

    0		% initialization value for /sH_len
    0 1 255 {
       sHKs exch
       2 mul getu16
       1 index	% get current max
       1 index	% get current subHeaderKey
       lt {exch} if pop
    } for
    /sH_len exch def

    dup 6 256 sHK_sz mul add
    cmapf2_tblen 1 index sub getinterval
    /sH_gIA exch def

    /cmapf2_glyph_array 65535 array def

    /.cmapf2_putGID {
        /cmapf2_ch cmapf2_ch_hi 8 bitshift cmapf2_ch_lo add def
        firstCode cmapf2_ch_lo le
        cmapf2_ch_lo firstCode entryCount add lt
        and { % true: j is inside
            sH_offset idRangeOffset add		% offset to gI
            cmapf2_ch_lo firstCode sub 2 mul	% rel. pos. in range
            add 6 add				% offset in sH_gIA
            sH_gIA exch getu16
            dup 0 gt { %
                idDelta add
                cmapf2_glyph_array exch cmapf2_ch exch put
            } {
                pop
                % cmapf2_glyph_array cmapf2_ch 0 put
            } ifelse
        } {   % false: j is outside
            % cmapf2_glyph_array cmapf2_ch 0 put
        } ifelse
    } def

    16#00 1 16#ff { % hi_byte scan
        /cmapf2_ch_hi exch def
        sHKs cmapf2_ch_hi sHK_sz mul getu16
        /sH_offset exch def
        sH_gIA sH_offset sH_sz getinterval
            dup 0 getu16 /firstCode exch def
            dup 2 getu16 /entryCount exch def
            dup 4 gets16 /idDelta exch def
            dup 6 getu16 /idRangeOffset exch def
        pop
        sH_offset 0 eq {
           /cmapf2_ch_lo cmapf2_ch_hi def
           /cmapf2_ch_hi 0 def
           .cmapf2_putGID
        } {
           16#00 1 16#ff { % lo_byte scan
               /cmapf2_ch_lo exch def
               .cmapf2_putGID
           } for
        } ifelse
     } for
     pop
     0 1 cmapf2_glyph_array length 1 sub { % rewrite null -> 0.
        dup cmapf2_glyph_array exch get
        null eq { cmapf2_glyph_array exch 0 put } {pop} ifelse
     } for
     cmapf2_glyph_array
  } bind
  4 {		% Microsoft/Adobe segmented mapping.
    /etab exch def
    /nseg2 etab 6 getu16 def
    14 /endc etab 2 index nseg2 getinterval def
		% The Apple TrueType documentation omits the 2-byte
		% 'reserved pad' that follows the endCount vector!
    2 add
    nseg2 add /startc etab 2 index nseg2 getinterval def
    nseg2 add /iddelta etab 2 index nseg2 getinterval def
    nseg2 add /idroff etab 2 index nseg2 getinterval def
		% The following hack allows us to properly handle
		% idiosyncratic fonts that start at 0xf000:
    pop
    /firstcode startc 0 getu16 16#ff00 and dup 16#f000 ne { pop 0 } if def
    /putglyph {
      glyphs code 3 -1 roll put /code code 1 add def
    } bind def
		% Do a first pass to compute the size of the glyphs array.
    /numcodes 0 def /glyphs 0 0 2 nseg2 3 sub {
		% Stack: /glyphs numglyphs i2
      /i2 exch def
      /scode startc i2 getu16 def
      /ecode endc i2 getu16 def
      numcodes scode firstcode sub
		% Hack for fonts that have only 0x0000 and 0xf000 ranges
      %dup 16#e000 ge { 255 and } if
      % the previous line is obstructive to CJK fonts, so it was removed
      exch sub 0 .max ecode scode sub 1 add add
      exch 1 index add exch
      numcodes add /numcodes exch def
    } for array def
    % prefill the array with 0's faster than a { 0 putglyph } repeat
    glyphs length 1024 ge {
      .array1024z 0 1024 glyphs length 1023 sub { glyphs exch 2 index putinterval } for
      glyphs dup length 1024 sub 3 -1 roll
      putinterval
    } {
      0 1 glyphs length 1 sub { glyphs exch 0 put } for
    } ifelse
		% Now fill in the array.
    /numcodes 0 def /code 0 def
    0 2 nseg2 3 sub {
      /i2 exch def
      /scode startc i2 getu16 def
      /ecode endc i2 getu16 def
      numcodes scode firstcode sub
		% Hack for fonts that have only 0x0000 and 0xf000 ranges
      %dup 16#e000 ge { 255 and } if
      % the previous line is obstructive to CJK fonts, so it was removed
      exch sub 0 .max dup /code exch code exch add def
      ecode scode sub 1 add add numcodes add /numcodes exch def
      /delta iddelta i2 gets16 def
      TTFDEBUG {
	(scode=) print scode =only
	( ecode=) print ecode =only
	( delta=) print delta =only
	( droff=) print idroff i2 getu16 =
      } if
      idroff i2 getu16 dup 0 eq {
	pop scode delta add 65535 and 1 ecode delta add 65535 and
	{ putglyph } for
      } {	% The +2 is for the 'reserved pad'.
        /gloff exch 14 nseg2 3 mul add 2 add i2 add add def
        0 1 ecode scode sub {
	  2 mul gloff add etab exch getu16
	  dup 0 ne { delta add 65535 and } if putglyph
	} for
      } ifelse
    } for glyphs /glyphs null def	% for GC
  } bind
  6 {		% Single interval lookup.
    dup 6 getu16 /firstcode exch def dup 8 getu16 /ng exch def
    firstcode ng add array
		% Stack: tab array
		% Fill elements 0 .. firstcode-1 with 0
    0 1 firstcode 1 sub { 2 copy 0 put pop } for
    dup firstcode ng getinterval
		% Stack: tab array subarray
		% Fill elements firstcode .. firstcode+nvalue-1 with glyph values
    0 1 ng 1 sub {
      dup 2 mul 10 add 4 index exch getu16 3 copy put pop pop
    } for pop exch pop
  } bind
.dicttomark readonly def                % cmapformats

% <cmaptab> cmaparray <glypharray>
/cmaparray {
  dup 0 getu16 cmapformats exch .knownget {
    TTFDEBUG {
      (cmap: format ) print 1 index 0 getu16 = flush
    } if exec
  } {
    (Can't handle format ) print 0 getu16 = flush
    0 1 255 { } for 256 packedarray
  } ifelse
  TTFDEBUG {
    (cmap: length=) print dup length = dup ==
  } if
} bind def

/get_from_stringarray % <array|string> <offset> get_from_stringarray <int>
{ 1 index type /stringtype eq {
    get
  } {
    exch {                % o ()
      2 copy length gt {
        length sub
      } {
        exch get exit
      } ifelse
    } forall
  } ifelse
} bind def

/getinterval_from_stringarray % <array|string> <offset> <length> getinterval_from_stringarray <string>
{ % May allocate a string in VM.
  2 index type /stringtype eq {
    getinterval
  } {
    string exch 0                                 % [] s o p
    4 3 roll {                                    % s o p Si
      dup length                                  % s o p Si lSi
      dup 4 index lt {
        3 index exch sub                          % s o p Si o'
        exch pop 3 1 roll exch pop                % s o' p
      } {                                         % s o p Si lSi
        dup 3 1 roll                              % s o p lSi Si lSi
        4 index sub                               % s o p lSi Si lSi-o
        5 index length 4 index sub                % s o p lSi Si lSi-o ls-p
        2 copy gt { exch } if pop                 % s o p lSi Si minl
        dup 3 1 roll                              % s o p lSi minl Si minl
        5 index exch getinterval                  % s o p lSi minl from
        5 index 4 index 3 index                   % s o p lSi minl from s p minl
        getinterval                               % s o p lSi minl from to
        copy pop                                  % s o p lSi minl
        3 1 roll                                  % s o minl p lSi
        sub                                       % s o minl p'
        3 1 roll add                              % s p' o'
        dup 3 index length ge {
          exch exit                               % s o p'
        } if
        exch                                      % s o' p'
      } ifelse
    } forall
    pop pop                                       % s
  } ifelse
} bind def

/string_array_size  % <array|string> string_array_size <int>
{ dup type /stringtype eq {
    length
  } { 
    0 exch { length add } forall
  } ifelse
} bind def

% Each procedure in this dictionary is called as follows:
%       posttable <<proc>> glyphencoding
/postformats mark
  16#00010000  {	% 258 standard Macintosh glyphs.
    pop MacGlyphEncoding
  }
  16#00020000  {	% Detailed map, required by Microsoft fonts.
    dup dup type /arraytype  eq { 0 get } if length 36 lt {
      TTFDEBUG { (post format 2.0 invalid.) = flush } if
      pop [ ]
    } {
      /postglyphs exch def
      /post_first postglyphs dup type /arraytype eq { 0 get } if def
      post_first 32 getu16 /numglyphs exch def
      /glyphnames numglyphs 2 mul 34 add def
      % Build names array in the order they occur in the 'post' table
      /postpos glyphnames def
      /total_length postglyphs //string_array_size exec def
      [ numglyphs 1 sub {
	postpos total_length ge { exit } if
	% No name available, /postnames will be defined as an empty
	% array and the glyph won't get a name attached.
	postglyphs postpos //get_from_stringarray exec
        postglyphs postpos 1 add 2 index //getinterval_from_stringarray exec cvn
	exch postpos add 1 add /postpos exch def
      } repeat
      ] /postnames exch def
      [ 0 1 numglyphs 1 sub {
	2 mul 34 add post_first exch getu16
	dup 258 lt {
	  MacGlyphEncoding exch get
	} {
	  dup 32768 ge {
		% According to the published TrueType spec, such values are
		% "reserved for future use", but at least some PDF files
		% produced by the Adobe PDF library contain entries with a
		% value of 16#ffff.
	    pop /.notdef
	  } {
	    % Get the name for this glyph
	    258 sub dup postnames length ge {
	      TTFDEBUG { (   *** warning: glyph index past end of 'post' table) = flush } if
	      exit
	    } if
	    postnames exch get
	    % At least some of Microsoft's TrueType fonts use incorrect
	    % (Adobe-incompatible) names for some glyphs.
	    % Correct for this here.
	    postremap 1 index .knownget { exch pop } if
	  } ifelse
	} ifelse
      } for ] 
    }
    ifelse
  } bind
  16#00030000  {	% No map.
    pop [ ]
  } bind
.dicttomark readonly def                % postformats

/call.readtable
{ .readtable
} bind def
/call.readbigtable
{ .readbigtable
} bind def

% Each procedure in this dictionary is called as follows:
%	<file> <length> -proc- <string|array_of_strings>
% Note that each table must have an even length, because of a strange
% Adobe requirement that each sfnts entry have even length.
/readtables mark
	% Ordinary tables
  (cmap) //call.readtable
  (head) 1 index
  (hhea) 1 index
  (maxp) 1 index
  (name) 1 index
  (OS/2) 1 index
  (post) //call.readbigtable
  (vhea) //call.readtable
	% Big tables
  (glyf) //call.readbigtable
  (loca) 1 index
  (hmtx) 1 index
  (vmtx) 1 index
	% Tables only needed for embedding in PDF files
  (cvt ) //call.readtable
  (fpgm) 1 index
  (prep) 1 index
.dicttomark
% Normally there would be a 'readonly' here, but the ttf2pf utility wants
% to include the 'kern' table as well, so we leave the readtables dictionary
% writable.
def                % readtables

/readtables_stripped readtables dup length dict copy
dup (loca) { .skiptable } put
dup (glyf) { .skiptable } put
def

% Read a table as a single string.
% <file> <length> .skiptable <string>
/.skiptable {
  pop pop ()
} bind def

% Read a table as a single string.
% <file> <length> .readtable <string>
/.readtable {
  dup dup 1 and add string
		% Stack: f len str
  dup 0 4 -1 roll getinterval
		% Stack: f str str1
	% Because of the absurd PostScript specification that gives an
	% error for reading into an empty string, we have to check for
	% this explicitly here.
  3 -1 roll exch
  dup () ne { readstring } if pop pop
} bind def

% Read a big table (one that may exceed 64K).
% <file> <length> .readbigtable <string[s]>
/.readbigtable {
  dup 65400 lt {
    .readtable
  } {
    currentuserparams /VMReclaim get -2 vmreclaim
    [ 4 2 roll {
		% Stack: mark ... f left
      dup maxstring le { exit } if
      1 index maxstring string readstring pop 3 1 roll maxstring sub
    } loop .readtable ]
    exch vmreclaim
  } ifelse
} bind def

end readonly def                % .loadttfontdict

% <tab> .printtab -
/.printtab {
  dup 0 4 getinterval print ( ) print
  dup 8 getu32 =only ( ) print
  12 getu32 =
} bind def

% <file> <bool> <SubfontID> .loadttfonttables -
% Pushes .loadttfontdict & scratch dict on d-stack.
% Defines f, offsets, tables, tabdict, tabs.
% Skips loca and glyf if <bool> is true.
/.loadttfonttables {
  .loadttfontdict begin
  40 dict begin
  /SubfontID exch def
  /load_stripped exch def
  /f exch def
  /offsets f 12 string readstring pop def
  load_stripped { readtables_stripped } { readtables } ifelse /readtables_ exch def
  offsets 0 4 getinterval (ttcf) eq {
    % We need to handle TT collections with disk fonts only.
    % Therefore the file is a disk file and it can be positioned.
    offsets 8 getu32 /num_fonts exch def
    SubfontID num_fonts ge {
      QUIET not { (True Type collection contains insufficient fonts.) = } if
      /.loadttfonttables cvx /invalidfont signalerror
    } if
    SubfontID 4 mul 12 add f exch setfileposition
    f 4 string readstring pop 0
    getu32 /ttc_offset exch def
    f ttc_offset setfileposition
    /offsets f 12 string readstring pop def
  } {
    SubfontID 0 gt {
      QUIET not { (SubfontID > 0 with a True Type file which is not a collection.) = } if
      /.loadttfonttables cvx /invalidfont signalerror
    } if
    /ttc_offset 0 def
  } ifelse
  /tables f offsets 4 getu16 16 mul string readstring pop def
  /tabdict tables length 16 idiv dict def
	% tabs = tables we want to keep, sorted by file position.
  /tabs [ 0 16 tables length 1 sub {
    tables exch 16 getinterval
    TTFDEBUG { dup .printtab } if
    dup 0 4 getinterval readtables_ 1 index known {
      % put all 0 length tables at 0 to avoid overlap
      1 index 12 getu32 0 eq { 1 index 8 0 putu32 } if
      tabdict exch 2 index put
    } {
      pop pop
    } ifelse
  } for ] {
    exch 8 getu32 exch 8 getu32 lt
  } .sort def
	% In certain malformed TrueType fonts, tables overlap.
	% Truncate tables if necessary.
  0 1 tabs length 2 sub {
    dup tabs exch get exch 1 add tabs exch get
    1 index 8 getu32 2 index 12 getu32 add
    1 index 8 getu32 gt {
      (**** Warning: ) print 1 index 0 4 getinterval print
      ( overlaps ) print dup 0 4 getinterval print
      (, truncating.) = flush
      dup 8 getu32 2 index 8 getu32 sub
      2 index 12 3 -1 roll putu32
    } if pop pop
  } for
} bind def

/.file_table_pos_names
mark
/glyf 0
/loca 0
.dicttomark readonly def

% - .readttdata -
% Read data.  Updates offsets, tabs; stores data in tabdict.
/.readttdata {
  /file_table_pos 10 dict def
  /fpos offsets length tables length add ttc_offset add def
  /sfpos offsets length tabs length 16 mul add def
  offsets 4 tabs length putu16
  tabs {
    dup 0 4 getinterval /tname exch def
    dup 8 getu32 /tpos exch def
    dup 12 getu32 /tlen exch def
    load_stripped //.file_table_pos_names tname known and {
        pop
        file_table_pos tname [tpos tlen] put
        tabdict tname () put
    } {
      8 sfpos putu32
  	% Skip data between the end of the previous table and
	% the beginning of this one, if any.
      tpos fpos gt {
        load_stripped {
          % 'setfileposition' is faster for skipping a big data.
          f tpos setfileposition
        } {
          f tpos fpos sub () /SubFileDecode filter dup flushfile closefile
          /fpos tpos def
        } ifelse
      } if
      f tlen readtables_ tname get exec
      tabdict tname 3 -1 roll put
	% Round up the table length to an even value.
      /sfpos sfpos tlen dup 1 and add add def
    } ifelse
    /fpos fpos tlen add def
  } forall
} bind def

% Find the string in a list of strings that includes a given index.
% <strings> <index> .findseg <string> <index'>
/.findseg {
  exch {
    dup length 2 index gt { exch exit } if
    length sub
  } forall
} bind def

% - .makesfnts -
% Defines checksum, getloca, head, locatable, numloca, post, sfnts, upem
% Note that the 'loca' table may be out of order. This is handled when
% needed in .dividesfnts
/.makesfnts {
  .readttdata
  /head tabdict /head get def
  /post tabdict /post .knownget { 
    dup 0 get /post_first_part exch def 
  } { 
    null 
  } ifelse def
  load_stripped not {
    /locatable tabdict /loca get def
    /numloca
      locatable dup type /stringtype eq
       { length }
       { 0 exch { length add } forall }
      ifelse	% no def yet
    locatable type /stringtype eq {
      /.indexloca {} def
    } {
      /.indexloca /.findseg load def
    } ifelse
    head 50 getu16 0 ne {
      /getloca {
        2 bitshift locatable exch .indexloca getu32
      } def
      4 idiv 1 sub
    } {
      /getloca {
        dup add locatable exch .indexloca getu16 dup add
      } def
      2 idiv 1 sub
    } ifelse def		% numloca
	% If necessary, re-partition the glyfs.
    tabdict /glyf get dup type /stringtype ne {
      .dividesfnts tabdict /glyf 3 -1 roll put
    } {
      pop
    } ifelse
  } {
    % We did not load loca, take the number of glyphs from maxp.
    /numloca tabdict /maxp get 4 getu16 def
  } ifelse
  /sfnts [
    offsets tabs { concatstrings } forall
    tabs {
      0 4 getinterval tabdict exch get
      dup type /stringtype ne { aload pop } if
    } forall
  ] def
} bind def

% <glyfs> .dividesfnts <glyfs'>
/.dividesfnts {
  /glyfs exch def
  /len1 0 glyfs { length add } forall def
	% Determine where to split the glyfs by scanning the sorted locatable
	% The very last entry in loca may be bogus.
	% Note that some loca entries may be odd, but we can only
	% split at even positions.
	%
	% Construct splitarray, the array of final lengths of
	% the sfnts entries covering the glyfs (i.e., all but
	% the first and last sfnts entries).
    /prevsplit 0 def
    /prevboundary 0 def
    % sort the locatable in case it is out of order
    % Note the 'loca' table remains unchanged
    /needsort false def
    numloca array	% the array of 'loca' entries (may be out of order)
    -1	% initial values for in order check
    0 1 numloca 1 sub {
      dup getloca dup
      4 -1 roll lt { /needsort true def } if 
      3 copy put exch pop
    } for pop		% discard inorder check value
    needsort {
      { lt } bind .sort	 % stack: locatable_array
    } if
    /splitarray [
      3 -1 roll 0 1 numloca 1 sub {
	% stack: /splitarray -mark- { splitlen splitlen ... } locatable_array index
	1 index exch get dup prevsplit maxstring add gt {
	  prevboundary prevsplit sub exch
	  /prevsplit prevboundary def
	} if
	dup 1 and 0 eq { /prevboundary exch def } { pop } ifelse
	dup type /arraytype ne { exch } if	% keep locatable_array on top
      } for
      len1 prevsplit sub
      exch pop		% discard locatable_array
    ] def
    currentuserparams /VMReclaim get -2 vmreclaim
    [
	% Re-split the sfnts glyfs strings according to splitarray.
	% We do this by iterating over the final segments defined
	% by splitarray, and constructing them from pieces of the
	% current glyfs strings.  We recycle the current strings
	% when possible, to avoid stressing the allocator.
      /sfnt_idx 0 def
      /strpos 0 def
      /avail () def
      splitarray {
	/seglen exch def
	/segpos 0 def
	avail length seglen ge
	  { avail 0 seglen getinterval /avail () def } { seglen string }
	ifelse
	{
	  /str glyfs sfnt_idx get def
	  /strlen str length def
	  /strleft strlen strpos sub def
	  seglen segpos sub strleft lt { exit } if
		% Copy the (rest of the) string into the new segment.
		% We know strleft <= segleft.
	  dup segpos str strpos strleft getinterval putinterval
	  /segpos segpos strleft add def
	  /avail str def
	  /sfnt_idx sfnt_idx 1 add def
	  /strpos 0 def
	  segpos seglen eq { exit } if
	} loop
		% Fill up the segment with an initial piece of the next
		% existing glyfs string.  We know strleft > segleft.
	/segleft seglen segpos sub def
	dup segpos str strpos segleft getinterval putinterval
	/strpos strpos segleft add def
      } forall
    ]
    exch vmreclaim
} bind def

/first_post_string % - first_post_string <string>
{
  post dup type /arraytype eq { 0 get } if
} bind def

% - .getpost -
% Uses post, defines glyphencoding
/.getpost {
  /glyphencoding post null eq {
    TTFDEBUG { (post missing) = flush } if [ ]
  } {
    postformats first_post_string 0 getu32 .knownget {
      TTFDEBUG {
	(post: format ) print
	first_post_string
	dup 0 getu16 =only (,) print 2 getu16 = flush
      } if
      post exch exec
    } {
      TTFDEBUG { (post: unknown format ) print post 0 getu32 = flush } if [ ]
    } ifelse
  } ifelse
  TTFDEBUG { (post=) print dup == } if
  def
} bind def

% - .ttkeys <key> <value> ...
/.ttkeys {
  count /ttkeycount exch def
  /upem head 18 getu16 def
  /FontMatrix matrix
  /FontBBox [ 36 2 42 { head exch gets16 upem div } for ]
  nextxuid
  tabdict /name .knownget {
		% Find the names from the 'name' table.
    /names exch def
    /FontName names 6 findname not { curxuid 16 8 string cvrs } if
      /fontname 1 index def
    /FontInfo mark
      names 0 findname { /Notice exch } if
      names 1 findname { /FamilyName exch } if
      names 4 findname { /FullName exch } if
      names 5 findname { /Version exch } if
  } {
		% No name table, fabricate a FontName.
    /FontName curxuid 16 8 string cvrs
      /fontname 1 index def
    /FontInfo mark
  } ifelse
		% Stack: ... /FontInfo mark key1 value1 ...
  post null ne {
    /ItalicAngle first_post_string 4 gets32 65536.0 div
    /isFixedPitch first_post_string 12 getu32 0 ne
    /UnderlinePosition first_post_string 8 gets16 upem div
    /UnderlineThickness first_post_string 10 gets16 upem div
  } if
  counttomark 0 ne { .dicttomark } { pop pop } ifelse
  /XUID [orgXUID 42 curxuid]
  TTFDEBUG {
    tabs { .printtab } forall
    [ sfnts { length } forall ] ==
    count ttkeycount sub array astore dup { == } forall aload pop
  } if
  /sfnts sfnts
} bind def

% ---------------- Standard TrueType font loading ---------------- %

% - .pickcmap_with_no_xlatmap -
% Defines cmapsub, cmaptab
/.pickcmap_with_no_xlatmap {
  tabdict /cmap get
		% The Apple cmap format is no help in determining the encoding.
		% Look for a Microsoft table.  If we can't find one,
		% just use the first table, whatever it is.
  dup 4 8 getinterval exch             % the default
  0 1 2 index 2 getu16 1 sub {
    8 mul 4 add 1 index exch 8 getinterval
    TTFDEBUG {
      (cmap: platform ) print dup 0 getu16 =only
      ( encoding ) print dup 2 getu16 = flush
    } if
    dup 0 getu16 3 eq { exch 3 -1 roll pop exit } if pop
  } for
		% Stack: subentry table
  /cmapsub 2 index def
  exch 4 getu32 1 index length 1 index sub getinterval
  /cmaptab exch def
} bind def

% - .pickcmap_with_xlatmap -
% Defines cmapsub, cmaptab
/.pickcmap_with_xlatmap {
  .xlatmap_dict /TrueType known not {
    (Emulating a CID font with a True Type file, ) print
    (the file gs/lib/xlatmap must contain /TrueType key.) =
    /.pickcmap_with_xlatmap cvx /configurationerror signalerror
  } if
  false
  .xlatmap_dict /TrueType get 
  dup length 2 sub 0 exch 2 exch {                       % bool [] i
    2 copy get                                           % bool [] i ()
    (.) search {                                         % bool [] i post match pre
      cvi exch pop exch cvi                              % bool [] i PlatID SpecID
    } {
      (gs/lib/xlatmap containg a record with an invalid (PlatformID.SpecificID)) =
      /.pickcmap_with_xlatmap cvx /configurationerror signalerror
    } ifelse
    TTFDEBUG {
      (Seeking a cmap for platform=) print 1 index =only ( encoding=) print dup =
    } if
    tabdict /cmap get                                   % bool [] i PlatID SpecID (cmap)
    dup /cmaptab exch def % temporary
    0 1 2 index 2 getu16 1 sub {                         % bool [] i PlatID SpecID (cmap) j
      8 mul 4 add 1 index exch 8 getinterval             % bool [] i PlatID SpecID (cmap) (cmapsub)
      TTFDEBUG {
        (cmap: platform ) print dup 0 getu16 =only
        ( encoding ) print dup 2 getu16 = flush
      } if
      dup 0 getu16 4 index eq {
        dup 2 getu16 3 index eq {                        % bool [] i PlatID SpecID (cmap) (cmapsub)
          TTFDEBUG {
            (Choosen a cmap for platform=) print 3 index =only
            ( encoding=) print 2 index =
          } if
          /cmapsub 1 index def
          dup 4 getu32                                   % bool [] i PlatID SpecID (cmap) (cmapsub) p
          cmaptab length 1 index sub                     % bool [] i PlatID SpecID (cmap) (cmapsub) p l
          cmaptab 3 1 roll getinterval
          /cmaptab exch def                              % bool [] i PlatID SpecID (cmap) (cmapsub)
          5 index 5 index 1 add get                      % bool [] i PlatID SpecID (cmap) (cmapsub) /Decoding
          /Decoding exch def                             % bool [] i PlatID SpecID (cmap) (cmapsub)
          7 -1 roll pop true 7 1 roll                    % true [] i PlatID SpecID (cmap) (cmapsub)
        } if
      } if
      pop                                                % true [] i PlatID SpecID (cmap)
      5 index { exit } if
    } for                                                % bool [] i PlatID SpecID (cmap)
    pop pop pop pop                                      % bool []
    1 index { exit } if
  } for                                                  % bool []
  pop                                                    % bool
  not { 
    QUIET not { (True Type font doesn't contain a charset listed in gs/lib/xlatmap.) = } if
    /.pickcmap_with_xlatmap cvx /invalidfont signalerror
  } if                                                   %
} bind def

% - .pickcmap -
% Defines cmapsub, cmaptab
/.pickcmap {
  % Currently we use xlatmap only for emulation CIDFontType 2 with
  % a disk True Type font files, and use load_stripped
  % to check this regime. We would like to do so
  % while emulating a Type 42, but first the old code
  % about handling them to be changed 
  % with adding a handling of a Decoding.
  % fixme : A correct way to fix this is to implenent 
  % the Type 42 emulation with gs_fntem.ps .
  % Also note that PDF embedded fonts probably don't need a xlatmap -
  % see PDF spec, "Encodings for True Type fonts".
  load_stripped {
    //.pickcmap_with_xlatmap exec
  } {
    //.pickcmap_with_no_xlatmap exec
  } ifelse
} bind def

% <glyph> .nname <_name>
/.nname {
  =string cvs (_) exch concatstrings cvn
} bind def

% - .charkeys /CharStrings <charstrings> /Encoding <encoding>
% Resets glyphencoding
/.charkeys {
  TTFDEBUG {
    (glyphencoding: length=) print glyphencoding dup length = === flush
  } if
		% Hack: if there is no usable post table but the cmap uses
		% the Microsoft Unicode encoding, use ISOLatin1Encoding.
  glyphencoding length 0 eq {
    cmapsub 0 4 getinterval <00030001> eq {
    PDFDEBUG { (No post but have cmap 3.1, so use ISOLatin1Encoding) } if
      /glyphencoding ISOLatin1Encoding dup length array copy def
    } {
      PDFDEBUG { (No encoding info, use .GS_extended_SymbolEncoding) } if
      /glyphencoding /.GS_extended_SymbolEncoding findencoding dup length array copy def
    } ifelse
  } if
		% If necessary, fabricate additional glyphencoding entries
		% to cover all of loca, or truncate glyphencoding.
  glyphencoding length numloca lt {
    /glyphencoding numloca array
      glyphencoding length dup 1 sub 0 1 3 2 roll {
        dup glyphencoding exch get
        3 index 3 1 roll put
      } for
      % /glyphencoding <newarray> <glyphencoding length>
      1 numloca 1 sub {
        1 index exch dup .nname put
      } for
    def
  } {
    /glyphencoding glyphencoding 0 numloca getinterval def
  } ifelse
		% Some badly designed Chinese fonts have a post table
		% in which all glyphs other than 0 are named .null.
		% Use CharStrings to keep track of the reverse map from
		% names to glyphs, and don't let any name be used for
		% more than one glyph.
  /CharStrings glyphencoding dup length 1 add dict	% +1 for .notdef
    0 1 3 index length 1 sub {
		% Stack: glyphencoding dict index
      2 index 1 index get 2 index 1 index known {
		% The same name maps to more than one glyph.
		% Change the name.
	pop dup .nname 3 index 2 index 2 index put
      } if
      2 index exch 3 -1 roll put
    } for exch pop
		% If there is no .notdef entry, map it to glyph 0.
  dup /.notdef known not { dup /.notdef 0 put } if
  readonly
  /Encoding
    [ cmaptab cmaparray dup length 256 gt { 0 256 getinterval } if
    { glyphencoding exch get } forall
    counttomark 256 exch sub { /.notdef } repeat ]
  TTFDEBUG { (Encoding: ) print dup === flush } if
} bind def

% -mark- <key> <value> ... .definettfont <font>
/.definettfont {
  /FontType 42
  /PaintType 0
  TTFDEBUG {
    (numloca=) print numloca =
  } if
  .dicttomark
  end end dup /FontName get exch definefont
} bind def

% <file> .loadttfont <type42font>
/.loadttfont {
  //false 0 .loadttfonttables
  .makesfnts
  .getpost
  .pickcmap
  mark
  .charkeys
  .ttkeys
  .definettfont
} bind def

% ---------------- CIDFontType 2 font loading ---------------- %

% Fill a string with sequential CIDs starting from the initial value.
% <string> <value> .fill_identity_cmap <string>
/.fill_identity_cmap {             % () v
  1 index length 2 sub          % () v n-2
  0 2 3 2 roll {                % () v 0 2 n-1
      3 copy exch               % () v i () i v 
      -8 bitshift               % () v i () i v>>8
      put                       % () v i
      3 copy 1 add              % () v i () v i+1
      exch 255 and              % () v i () i+1 v&255
      put                       % () v i 
      pop 1 add                 % () v+1
  } for
  pop
} bind def

% -mark- <key> <value> ... .definettcidfont <font>
/.definettcidfont {
  /CIDFontName fontname
  /CIDFontType 2
  /CIDSystemInfo mark
    /Registry (Adobe)
    /Ordering (Japan1)		% adhoc
    /Supplement 0
  .dicttomark
  /CharStrings mark /.notdef 0 .dicttomark
		% The cmap isn't of any use even if it is present.
		% Just construct an identity CIDMap covering all the glyphs.

  /CIDCount numloca % Wrong if a CIDFontType2 embedded into PDF with a non-Identity CIDToGIDMap.
                    % processCIDToGIDMap may replace.
  /CIDMap numloca maxstring le {
                % Use a single string.
      numloca 2 mul string 0 .fill_identity_cmap
  } {
                % We must use 2 strings.
      maxstring 2 mul string 0 .fill_identity_cmap
      numloca maxstring sub 2 mul string maxstring .fill_identity_cmap
      2 array astore
  } ifelse

  /GDBytes 2
  .dicttomark
  end end dup /CIDFontName get exch /CIDFont defineresource
} bind def

% <file> .loadttcidfont <cidtype2font>
/.loadttcidfont {
  //false 0 .loadttfonttables
  .makesfnts
	% CIDFontType2 fonts don't have a cmap: they are indexed by CID.
  mark
  .ttkeys
  .definettcidfont
} bind def

% <file> <SubfontID> .load_tt_font_stripped <font_data>
% The font_data includes sfnts, NumGlyphs, TT_cmap, file_table_pos, Decoding.
% CIDMap to be created later from TT_cmap.
/.load_tt_font_stripped {
  //true exch .loadttfonttables
  .makesfnts
  .pickcmap
  mark
  .ttkeys
  /NumGlyphs numloca
  /TT_cmap cmaptab cmaparray
  /file_table_pos file_table_pos
  /Decoding Decoding
  .dicttomark
  end end 
} bind def

% ---------------- PDF TrueType font loading ---------------- %

% Strictly speaking, this code should be loaded only if we have a PDF
% interpreter, but it's so closely tied to the rest of the code in this
% file that we always include it.

% <plat+enc> .findcmap <subtable> true
% <plat+enc> .findcmap false
/.findcmap {
  false exch tabdict /cmap get
		% Some fonts have multiple cmaps with the same platform and
		% encoding.  Use the first one we find.
  0 1 2 index 2 getu16 1 sub {
		% Stack: false plat+enc cmap index
    8 mul 4 add 1 index exch 8 getinterval 
    dup 0 4 getinterval 3 index eq {
      4 getu32 1 index exch 1 index length 1 index sub getinterval
      4 -1 roll not 4 2 roll exit
    } if pop
  } for
		% Stack: false plat+enc cmap || subtable true plat+enc cmap
  pop pop
} bind def

% Build .symbol_list for .pdfcharkeys .
% It is a dictionary containing all SymbolEncoding glyph names
% and random names for filling gaps in the character code range.
/.symbol_list 256 dict def
{
  =string 0 (x) 0 get put
  /SymbolEncoding .findencoding
  0 1 255 {
    dup 2 index exch get
    dup /.notdef eq {
      pop dup
      =string 1 3 getinterval cvs length 1 add
      =string exch 0 exch getinterval cvn
    } if
    exch //.symbol_list 3 1 roll put
  } for
  pop
} bind exec

% Create .GS_extended_SymbolEncoding as inverse of .symbol_list .
{
  /.GS_extended_SymbolEncoding 256 array
  //.symbol_list {
    exch 2 index 3 1 roll put  
  } forall
  .defineencoding
} bind exec

/.addglyph    % <name> <glyph#> .addglyph <name> <glyph#> 
              % <name> <glyph#> .addglyph -
{
  dup cmapencoding length lt {
    cmapencoding exch get dup 0 eq {
      pop pop
    } if
  } {
    pop pop
  } ifelse
} bind def

% <subcmap> <chartoglyphmap> .pdfmapchars
%   /CharStrings <charstrings>
/.pdfmapchars {
  exch cmaparray /cmapencoding exch def
  /CharStrings mark 

  % Add glyphs of <chartoglyphmap>*<subcmap> :
  3 2 roll {
    dup type /arraytype eq {
      exch /.name exch def
      { .name exch //.addglyph exec
      } forall
      currentdict /.name undef
    } {
      //.addglyph exec
    } ifelse
  } forall

        % stack: /CharStrings mark /name1 glyph#1 /name2 glyph#2 ... /namen glyph#n
        % Stack depth is restricted with AdobeGlyphList size.

  % Add glyphs of 'post' (with lower priority, see .dicttomark) :
  0 1 glyphencoding length 1 sub {
    dup glyphencoding exch get exch
    dup 0 eq {
      pop pop
    } if
  } for

  /.notdef 0
  .dicttomark
} bind def

% - .pdfcharkeys /CharStrings <charstrings> /Encoding <encoding>
/.pdfcharkeys {
	% The following algorithms are per the PDF Reference, Second Edition
	% (PDF 1.3 reference manual).
  
  is_symbolic {
    <00030001> .findcmap {
      %
      % Adobe PDF spec says that symbolic fonts should contain exactly one 
      % cmap subtable for Platform=1, Encoding=0.
      % Perhaps "Adobe Acrobat PDFWriter 4.0 for Windows" sometimes embeds
      % fonts with both subtables 3.1 and 1.0 (see comparefiles/159.pdf,
      % the font "Arial,Bold" with the character "registered"),
      % and both Acrobat Reader 4.0 and 5.0 choose 3.1.
      % Therefore we try 3.1 first.
      %
      (   **** Warning: Embedded symbolic TT fonts should not contain a cmap for Platform=3 Encoding=1.\n)
        pdfformaterror
      TTFDEBUG { (Using cmap 3.1) = } if
      AdobeGlyphList .pdfmapchars 
      /Encoding /WinAnsiEncoding .findencoding
    } {
      %
      % Adobe PDF spec says that in this case PDF interpreter should
      % map character codes directly to glyphs using
      % the cmap <00010000>. But we use PS interpreter to emulate
      % a PDF interpreter. Therefore we need to construct
      % a type 42 font, which requires an Encoding and a Charstrings.
      % We construct them with symbol_list, which
      % includes all glyphs from SymbolEncoding and additional
      % random names for 1-to-1 mapping.
      %
      % A real TT font may use a different characters than
      % the Symbol charaster set. Perhaps our code
      % will give a correct printing, because glyph names are not
      % important for symbolic fonts in PDF.
      %
      <00010000> .findcmap {
        prebuilt_encoding null ne {
          TTFDEBUG { (Using cmap 1.0 with prebuilt_encoding.) = } if
          prebuilt_encoding .invert_encoding .pdfmapchars
          /Encoding prebuilt_encoding
        } {
          % This is a case, in which an obsolete software could stupidly specify Macintosh Roman
          % for a random encoding. Particulatrly GPL Ghostscript 7.06 does so.
          % Trying to recover with 'post'.
          pop  % The table itself doesn't contain useful data.
          TTFDEBUG { (Using cmap 1.0 with post or .GS_extended_SymbolEncoding) = } if
          .charkeys
        } ifelse
      } {
        % This is illegal with PDF spec.
        (   **** Warning: Embedded symbolic TT fonts must contain a cmap for Platform=1 Encoding=0.\n)
        pdfformaterror
        % Try to map Unicode to SymbolEncoding
        <00030001> .findcmap {
          TTFDEBUG { (Using cmap 3.1) = } if
          AdobeGlyphList .pdfmapchars
          /Encoding /SymbolEncoding .findencoding
        } {
          % Apply the default algorithm. Hopely it has 'post'.
          .charkeys
          % check if the CharStrings dict contains glyphs needed by the
	  % prebuilt_encoding otherwise try the 3,0 cmap.
	  prebuilt_encoding null ne {
	    false prebuilt_encoding {	% false means no missing glyphs
	      4 index exch known not { pop true exit } if
            } forall
            {
	      (   **** Warning: Encoding derived from 'post' is incomplete.\n)
	      pdfformaterror
	      % Try another cmap format 3,0 -- Adobe doesn't mention it, but does
	      % use it apparently (empirically determined).
	      <00030000> .findcmap {
	        TTFDEBUG { (Adding cmap 3.0) = } if
   		5 1 roll pop pop pop pop             
		prebuilt_encoding null ne {
		  prebuilt_encoding .invert_encoding .pdfmapchars
		  /Encoding prebuilt_encoding
		} {
		  AdobeGlyphList .pdfmapchars
		  /Encoding /SymbolEncoding .findencoding
		} ifelse
	      } if
            }if
          } if
        } ifelse
      } ifelse
    } ifelse
  } {
    <00030001> .findcmap {
      TTFDEBUG { (Using cmap 3.1 for non-symbolic.) = } if
      AdobeGlyphList .pdfmapchars 
      /Encoding /WinAnsiEncoding .findencoding
        % WinAnsiEncoding is just a stub here. 
        % It will be replaced with one from font resource,
        % because PDF spec requires it.
    } {
      <00010000> .findcmap {
        TTFDEBUG { (Using cmap 1.0 for non-symbolic.) = } if
	.romanmacdict .pdfmapchars 
        /Encoding /MacRomanEncoding .findencoding
      } {
        % Apply the default algorithm for using the 'post'.
	.charkeys
      } ifelse
    } ifelse
  } ifelse
} bind def

% <file> <is_symbolic> <Encoding|null> .loadpdfttfont <type42font>
/.loadpdfttfont {
  /prebuilt_encoding exch def     % for .pdfcharkeys
  /is_symbolic exch def
  //false 0 .loadttfonttables
  .makesfnts
  .getpost
  .pickcmap
  mark
  .pdfcharkeys
  .ttkeys
  .definettfont
} bind def