summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlgs/lib/gs_ttf.ps
diff options
context:
space:
mode:
authorReinhard Kotucha <reinhard.kotucha@web.de>2008-02-21 22:07:42 +0000
committerReinhard Kotucha <reinhard.kotucha@web.de>2008-02-21 22:07:42 +0000
commitf90099230db6de68f2285dca3d08174bda872f7a (patch)
tree48fbfd44b5c240a4430dd4a54b286de5f1102583 /Master/tlpkg/tlgs/lib/gs_ttf.ps
parent2deea5f17b0505ffeb480154ace47e0a72863c97 (diff)
tlpkg/tlgs: Subset of Ghostscript added.
git-svn-id: svn://tug.org/texlive/trunk@6709 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/tlpkg/tlgs/lib/gs_ttf.ps')
-rw-r--r--Master/tlpkg/tlgs/lib/gs_ttf.ps1802
1 files changed, 1802 insertions, 0 deletions
diff --git a/Master/tlpkg/tlgs/lib/gs_ttf.ps b/Master/tlpkg/tlgs/lib/gs_ttf.ps
new file mode 100644
index 00000000000..e657112b199
--- /dev/null
+++ b/Master/tlpkg/tlgs/lib/gs_ttf.ps
@@ -0,0 +1,1802 @@
+% Copyright (C) 1996-2003 Artifex Software, Inc. 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 8022 2007-06-05 22:23:38Z giles $
+% 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
+ dup
+ 6 findname not {
+ 4 findname % Try FullName
+ } {
+ exch pop true
+ }
+ ifelse
+ } {
+ false
+ } ifelse
+ f closefile end end
+} bind def
+
+% Load a font file that might be a TrueType font.
+
+/tt_tag_dict << <00010000> 0 (true) 0 (typ1) 0 (ttcf) 0 >> readonly def
+
+% <file> .loadfontfile -
+/.loadnonttfontfile /.loadfontfile load def
+/.loadfontfile {
+ dup (1234) .peekstring { //tt_tag_dict exch known } { //false } ifelse {
+ % If this is a font at all, it's a TrueType font.
+ .loadttfont pop
+ } {
+ % Not a TrueType font.
+ .loadnonttfontfile
+ } ifelse
+} bind def
+
+currentdict /tt_tag_dict .undef
+
+% ---------------- 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!
+% Also see /postalias table below.
+/postremap mark
+ /Eoverdot /Edotaccent
+ /eoverdot /edotaccent
+.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
+
+% <string|array> <index> getu16 <integer>
+/getu16a {
+ 2 getinterval_from_stringarray 0 getu16
+} bind def
+
+% <string|array> <index> gets16 <integer>
+/gets16a {
+ 2 getinterval_from_stringarray 0 gets16
+} bind def
+
+% <string|array> <index> getu32a <integer>
+/getu32a {
+ 4 getinterval_from_stringarray 0 getu32
+} bind def
+
+% <string|array> <index> gets32a <integer>
+/gets32a {
+ 4 getinterval_from_stringarray 0 gets32
+} bind def
+
+16#ffffffff 0 gt { % 64-bit sign extension
+ { /curxuid /gets32 /gets32a} {
+ 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 { true } { dup is2byte2 } ifelse { 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
+
+% <string> is2byte2 <bool>
+/is2byte2 {
+ dup length
+ dup 2 mod 0 ne {
+ pop pop false
+ } { % s l
+ true exch % s b l
+ 1 sub 0 exch 2 exch {
+ 2 index exch get 0 ne {
+ pop false exit
+ } if
+ } for
+ exch pop
+ } ifelse
+} 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_from_stringarray { } 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 getu16a /cmapf2_tblen exch def
+
+ dup 4 getu16a /cmapf2_lang exch def
+
+ dup 6 256 sHK_sz mul getinterval_from_stringarray /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_from_stringarray
+ /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_from_stringarray 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_from_stringarray def
+ nseg2 add /iddelta etab 2 index nseg2 getinterval_from_stringarray def
+ nseg2 add /idroff etab 2 index nseg2 getinterval_from_stringarray 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 getu16a
+ 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 getu16a /firstcode exch def
+ dup 8 getu16a /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 getu16a 3 copy put pop pop
+ } for pop exch pop
+ } bind
+.dicttomark readonly def % cmapformats
+
+% <cmaptab> cmaparray <glypharray>
+/cmaparray {
+ dup 0 getu16a cmapformats exch .knownget {
+ TTFDEBUG {
+ (cmap: format ) print 1 index 0 getu16a = flush
+ } if exec
+ } {
+ (Can't handle format ) print 0 getu16a = 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 ge {
+ 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 array 0 1 numglyphs 1 sub {
+ postpos total_length ge { pop 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
+ 2 index 3 1 roll put
+ } for
+ /postnames exch def
+ numglyphs array 0 1 numglyphs 1 sub {
+ dup 2 mul 34 add postglyphs exch 2 //getinterval_from_stringarray exec
+ dup 0 get 8 bitshift exch 1 get add 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
+ pop
+ 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
+ 2 index 3 1 roll put
+ } 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
+ (head) //call.readtable
+ (hhea) 1 index
+ (maxp) 1 index
+ (name) 1 index
+ (OS/2) 1 index
+ (post) //call.readbigtable
+ (vhea) //call.readtable
+ % Big tables
+ (cmap) //call.readbigtable
+ (glyf) 1 index
+ (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 { names 4 findname not { curxuid 16#ffffffff and 16 32 string cvrs } if } 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#ffffffff and 16 32 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_from_stringarray exch % () [] % the default
+ 0 1 2 index 2 getu16a 1 sub { % () [] i
+ 8 mul 4 add 1 index exch 8 getinterval_from_stringarray % () [] ()
+ 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 string_array_size 1 index sub getinterval_from_stringarray
+ /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 getu16a 1 sub { % bool [] i PlatID SpecID (cmap) j
+ 8 mul 4 add 1 index exch 8
+ getinterval_from_stringarray % 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
+
+% Provide alternative backward-compatible names for new TTF glyphs.
+% This list was extracted from Adobe's Glyph List 2.0 and consists of
+% glyph names that map to the same Unicode value.
+% See: http://partners.adobe.com/asn/developer/typeforum/unicodegn.html
+/postalias mark
+ /pi1 /pi /plusinus /plusminus
+ /Acyrillic /afii10017 /Becyrillic /afii10018
+ /Cdot /Cdotaccent /Checyrillic /afii10041
+ /Dcroat /Dslash /Decyrillic /afii10021
+ /Delta /increment /Djecyrillic /afii10051
+ /Dzecyrillic /afii10054 /Dzhecyrillic /afii10145
+ /Ecyrillic /afii10053 /Edot /Edotaccent
+ /Efcyrillic /afii10038 /Elcyrillic /afii10029
+ /Emcyrillic /afii10030 /Encyrillic /afii10031
+ /Ercyrillic /afii10034 /Ereversedcyrillic /afii10047
+ /Escyrillic /afii10035 /Euro /euro
+ /Fitacyrillic /afii10147 /Gcedilla /Gcommaaccent
+ /Gdot /Gdotaccent /Gecyrillic /afii10020
+ /Gheupturncyrillic /afii10050 /Gjecyrillic /afii10052
+ /H18533 /blackcircle /H18543 /blacksmallsquare
+ /H18551 /whitesmallsquare /H22073 /whitesquare
+ /Hardsigncyrillic /afii10044 /IAcyrillic /afii10049
+ /IUcyrillic /afii10048 /Icyrillic /afii10055
+ /Idot /Idotaccent /Iecyrillic /afii10022
+ /Iicyrillic /afii10026 /Iishortcyrillic /afii10027
+ /Iocyrillic /afii10023 /Izhitsacyrillic /afii10148
+ /Jecyrillic /afii10057 /Kacyrillic /afii10028
+ /Kcedilla /Kcommaaccent /Khacyrillic /afii10039
+ /Kjecyrillic /afii10061 /Lcedilla /Lcommaaccent
+ /Ldot /Ldotaccent /Ljecyrillic /afii10058
+ /Ncedilla /Ncommaaccent /Njecyrillic /afii10059
+ /Ocyrillic /afii10032 /Odblacute /Ohungarumlaut
+ /Ohm /Omega /Oslashacute /Ostrokeacute
+ /Pecyrillic /afii10033 /Rcedilla /Rcommaaccent
+ /Shacyrillic /afii10042 /Shchacyrillic /afii10043
+ /Softsigncyrillic /afii10046 /Tcedilla /Tcommaaccent
+ /Tecyrillic /afii10036 /Tsecyrillic /afii10040
+ /Tshecyrillic /afii10060 /Ucyrillic /afii10037
+ /Udblacute /Uhungarumlaut /Upsilon1 /Upsilonhooksymbol
+ /Ushortcyrillic /afii10062 /Vecyrillic /afii10019
+ /Yatcyrillic /afii10146 /Yericyrillic /afii10045
+ /Yicyrillic /afii10056 /Zdot /Zdotaccent
+ /Zecyrillic /afii10025 /Zhecyrillic /afii10024
+ /acutecmb /acutecomb /acyrillic /afii10065
+ /afii00208 /horizontalbar /afii08941 /lira
+ /afii10066 /becyrillic /afii10067 /vecyrillic
+ /afii10068 /gecyrillic /afii10069 /decyrillic
+ /afii10070 /iecyrillic /afii10071 /iocyrillic
+ /afii10072 /zhecyrillic /afii10073 /zecyrillic
+ /afii10074 /iicyrillic /afii10075 /iishortcyrillic
+ /afii10076 /kacyrillic /afii10077 /elcyrillic
+ /afii10078 /emcyrillic /afii10079 /encyrillic
+ /afii10080 /ocyrillic /afii10081 /pecyrillic
+ /afii10082 /ercyrillic /afii10083 /escyrillic
+ /afii10084 /tecyrillic /afii10085 /ucyrillic
+ /afii10086 /efcyrillic /afii10087 /khacyrillic
+ /afii10088 /tsecyrillic /afii10089 /checyrillic
+ /afii10090 /shacyrillic /afii10091 /shchacyrillic
+ /afii10092 /hardsigncyrillic /afii10093 /yericyrillic
+ /afii10094 /softsigncyrillic /afii10095 /ereversedcyrillic
+ /afii10096 /iucyrillic /afii10097 /iacyrillic
+ /afii10098 /gheupturncyrillic /afii10099 /djecyrillic
+ /afii10100 /gjecyrillic /afii10101 /ecyrillic
+ /afii10102 /dzecyrillic /afii10103 /icyrillic
+ /afii10104 /yicyrillic /afii10105 /jecyrillic
+ /afii10106 /ljecyrillic /afii10107 /njecyrillic
+ /afii10108 /tshecyrillic /afii10109 /kjecyrillic
+ /afii10110 /ushortcyrillic /afii10193 /dzhecyrillic
+ /afii10194 /yatcyrillic /afii10195 /fitacyrillic
+ /afii10196 /izhitsacyrillic /afii10846 /schwacyrillic
+ /afii57381 /percentarabic /afii57388 /commaarabic
+ /afii57392 /zeroarabic /afii57393 /onearabic
+ /afii57394 /twoarabic /afii57395 /threearabic
+ /afii57396 /fourarabic /afii57397 /fivearabic
+ /afii57398 /sixarabic /afii57399 /sevenarabic
+ /afii57400 /eightarabic /afii57401 /ninearabic
+ /afii57403 /semicolonarabic /afii57407 /questionarabic
+ /afii57409 /hamzaarabic /afii57410 /alefmaddaabovearabic
+ /afii57411 /alefhamzaabovearabic /afii57412 /wawhamzaabovearabic
+ /afii57413 /alefhamzabelowarabic /afii57414 /yehhamzaabovearabic
+ /afii57415 /alefarabic /afii57416 /beharabic
+ /afii57417 /tehmarbutaarabic /afii57418 /teharabic
+ /afii57419 /theharabic /afii57420 /jeemarabic
+ /afii57421 /haharabic /afii57422 /khaharabic
+ /afii57423 /dalarabic /afii57424 /thalarabic
+ /afii57425 /reharabic /afii57426 /zainarabic
+ /afii57427 /seenarabic /afii57428 /sheenarabic
+ /afii57429 /sadarabic /afii57430 /dadarabic
+ /afii57431 /taharabic /afii57432 /zaharabic
+ /afii57433 /ainarabic /afii57434 /ghainarabic
+ /afii57440 /tatweelarabic /afii57441 /feharabic
+ /afii57442 /qafarabic /afii57443 /kafarabic
+ /afii57444 /lamarabic /afii57445 /meemarabic
+ /afii57446 /noonarabic /afii57448 /wawarabic
+ /afii57449 /alefmaksuraarabic /afii57450 /yeharabic
+ /afii57451 /fathatanarabic /afii57452 /dammatanarabic
+ /afii57453 /kasratanarabic /afii57454 /fathaarabic
+ /afii57455 /dammaarabic /afii57456 /kasraarabic
+ /afii57457 /shaddaarabic /afii57458 /sukunarabic
+ /afii57470 /heharabic /afii57505 /veharabic
+ /afii57506 /peharabic /afii57507 /tcheharabic
+ /afii57508 /jeharabic /afii57509 /gafarabic
+ /afii57511 /tteharabic /afii57512 /ddalarabic
+ /afii57513 /rreharabic /afii57514 /noonghunnaarabic
+ /afii57519 /yehbarreearabic /afii57636 /newsheqelsign
+ /afii57645 /maqafhebrew /afii57658 /sofpasuqhebrew
+ /afii57664 /alef /afii57665 /bet
+ /afii57666 /gimel /afii57667 /dalet
+ /afii57668 /he /afii57669 /vav
+ /afii57670 /zayin /afii57671 /het
+ /afii57672 /tet /afii57673 /yod
+ /afii57674 /finalkaf /afii57675 /kaf
+ /afii57676 /lamed /afii57677 /finalmem
+ /afii57678 /mem /afii57679 /finalnun
+ /afii57680 /nun /afii57681 /samekh
+ /afii57682 /ayin /afii57683 /finalpe
+ /afii57684 /pe /afii57685 /finaltsadi
+ /afii57686 /tsadi /afii57687 /qof
+ /afii57688 /resh /afii57689 /shin
+ /afii57690 /tav /afii57694 /shinshindot
+ /afii57695 /shinsindot /afii57700 /vavholam
+ /afii57705 /doubleyodpatah /afii57716 /vavvavhebrew
+ /afii57717 /vavyodhebrew /afii57718 /yodyodhebrew
+ /afii57723 /vavdagesh /afii57793 /hiriq
+ /afii57794 /tsere /afii57795 /segol
+ /afii57796 /qubuts /afii57797 /qamats
+ /afii57798 /patah /afii57799 /sheva
+ /afii57800 /hatafpatah /afii57801 /hatafsegol
+ /afii57802 /hatafqamats /afii57803 /sindothebrew
+ /afii57804 /shindothebrew /afii57806 /holam
+ /afii57807 /dagesh /afii57839 /siluqhebrew
+ /afii57841 /rafe /afii57842 /paseqhebrew
+ /afii57929 /apostrophemod /afii61248 /careof
+ /afii61289 /lsquare /afii61352 /numero
+ /afii61664 /zerowidthnonjoiner /afii63167 /asteriskarabic
+ /afii64937 /commareversedmod /alefmaksurainitialarabic /yehinitialarabic
+ /alefmaksuramedialarabic /yehmedialarabic /approximatelyequal /congruent
+ /arrowdblboth /dblarrowleft /arrowdblleft /arrowleftdbl
+ /arrowdblright /dblarrowright /arrowupdnbse /arrowupdownbase
+ /bar /verticalbar /betdagesh /betdageshhebrew
+ /blackdownpointingtriangle /triagdn /blackleftpointingpointer /triaglf
+ /blackrectangle /filledrect /blackrightpointingpointer /triagrt
+ /blacksmilingface /invsmileface /blacksquare /filledbox
+ /blackuppointingtriangle /triagup /bulletinverse /invbullet
+ /cdot /cdotaccent /circle /whitecircle
+ /circlemultiply /timescircle /circleplus /pluscircle
+ /club /clubsuitblack /colonmonetary /colonsign
+ /compass /sun /daletdagesh /daletdageshhebrew
+ /dargahebrew /dargalefthebrew /dbllowline /underscoredbl
+ /dcroat /dmacron /decimalseparatorarabic /decimalseparatorpersian
+ /dialytikatonos /dieresistonos /dkshade /shadedark
+ /dotbelowcmb /dotbelowcomb /edot /edotaccent
+ /eighthnotebeamed /musicalnotedbl /etnahtafoukhhebrew /etnahtahebrew
+ /existential /thereexists /female /venus
+ /finalkafdagesh /finalkafdageshhebrew /forall /universal
+ /gcedilla /gcommaaccent /gdot /gdotaccent
+ /gimeldagesh /gimeldageshhebrew /gradient /nabla
+ /gravecmb /gravecomb /haaltonearabic /hehaltonearabic
+ /heart /heartsuitblack /hedagesh /hedageshhebrew
+ /hehfinalalttwoarabic /hehfinalarabic /hookabovecomb /hookcmb
+ /ilde /tilde /integralbottom /integralbt
+ /integraltop /integraltp /invcircle /whitecircleinverse
+ /kafdagesh /kafdageshhebrew /kcedilla /kcommaaccent
+ /lameddagesh /lameddageshhebrew /lcedilla /lcommaaccent
+ /ldot /ldotaccent /logicalnotreversed /revlogicalnot
+ /longs /slong /ltshade /shadelight
+ /macron /overscore /mahapakhhebrew /mahapakhlefthebrew
+ /male /mars /memdagesh /memdageshhebrew
+ /merkhahebrew /merkhalefthebrew /merkhakefulahebrew /merkhakefulalefthebrew
+ /middot /periodcentered /mu /mu1
+ /munahhebrew /munahlefthebrew /napostrophe /quoterightn
+ /nbspace /nonbreakingspace /ncedilla /ncommaaccent
+ /notelement /notelementof /nundagesh /nundageshhebrew
+ /odblacute /ohungarumlaut /omega1 /pisymbolgreek
+ /openbullet /whitebullet /orthogonal /rightangle
+ /oslashacute /ostrokeacute /pedagesh /pedageshhebrew
+ /phi1 /phisymbolgreek /propersubset /subset
+ /propersuperset /superset /qofdagesh /qofdageshhebrew
+ /quoteleftreversed /quotereversed /rcedilla /rcommaaccent
+ /reflexsubset /subsetorequal /reflexsuperset /supersetorequal
+ /reviahebrew /reviamugrashhebrew /samekhdagesh /samekhdageshhebrew
+ /sfthyphen /softhyphen /shade /shademedium
+ /sheqel /sheqelhebrew /shindagesh /shindageshhebrew
+ /shindageshshindot /shindageshshindothebrew /shindageshsindot /shindageshsindothebrew
+ /sigma1 /sigmafinal /similar /tildeoperator
+ /smileface /whitesmilingface /space /spacehackarabic
+ /spade /spadesuitblack /tavdages /tavdagesh
+ /tcedilla /tcommaaccent /tetdagesh /tetdageshhebrew
+ /tevirhebrew /tevirlefthebrew /theta1 /thetasymbolgreek
+ /thousandsseparatorarabic /thousandsseparatorpersian /tildecmb /tildecomb
+ /tipehahebrew /tipehalefthebrew /tsadidagesh /tsadidageshhebrew
+ /twodotenleader /twodotleader /udblacute /uhungarumlaut
+ /yerahbenyomohebrew /yerahbenyomolefthebrew /yoddagesh /yoddageshhebrew
+ /zayindagesh /zayindageshhebrew /zdot /zdotaccent
+.dicttomark readonly 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.
+ % if 'post' presents, .charkeys computes (with dropping minor details) :
+ % CharStrings = glyphencoding^-1
+ % Encoding = cmap*glyphencoding
+ % because 'post' maps glyph indices to glyph names.
+ % Otherwise .charkeys must compute (with dropping same details) :
+ % CharStrings = glyphencoding^-1 * cmap
+ % Encoding = glyphencoding
+ % because glyphencoding is stubbed with an encoding,
+ % which maps char codes to glyph names.
+ glyphencoding length 0 eq {
+ /have_post false def
+ 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
+ } {
+ /have_post true def
+ } ifelse
+ % If necessary, fabricate additional glyphencoding entries
+ % to cover all of loca
+ 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
+ } if
+ /cmapa cmaptab cmaparray def
+ % 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
+ have_post not {
+ exch dup cmapa length lt {
+ cmapa exch get
+ } {
+ pop 0 % a stub for a while. Must skip the entry.
+ } ifelse
+ exch
+ } if
+ 2 index 1 index known
+ { dup /.notdef eq {
+ pop pop % discard duplicate .notdef glyphs
+ } {
+ % The same name maps to more than one glyph. Change the name.
+ pop dup .nname 3 index 2 index 2 index put
+ 2 index exch 3 -1 roll put
+ }
+ ifelse
+ } {
+ 2 index exch 3 -1 roll put % unique name
+ } ifelse
+ } for exch pop
+ % If there is no .notdef entry, map it to glyph 0.
+ dup /.notdef known not { dup /.notdef 0 put } if
+ TTFDEBUG {
+ (CharStrings:)= dup { exch =string cvs print ( ) print == } forall
+ } if
+ //postalias {
+ % process pairs of names. If both names are known, do nothing. Otherwise
+ % make the name that is not defined an alias for the one that does exist.
+ % Stack: CharStrings(dict) /name1 /name2
+ 2 index 2 index known 3 index 2 index known 1 index xor not {
+ pop pop pop % both names known or neither known
+ } {
+ % Stack: CharStrings(dict) /name1 /name2 name1_known(bool)
+ { exch } if % /name1 known -- we need it on top
+ % Stack: CharStrings(dict) /alias_name /known_name
+ TTFDEBUG { (setting alias: ) print 1 index ==only ( to be the same as glyph: ) print dup == } if
+ 2 index exch get 2 index 3 1 roll put
+ } ifelse
+ } forall
+ readonly
+ /Encoding [
+ have_post {
+ cmapa dup length 256 gt { 0 256 getinterval } if
+ { glyphencoding exch get } forall
+ } {
+ glyphencoding dup length 256 gt { 0 256 getinterval } if
+ aload pop
+ } ifelse
+ counttomark 256 exch sub { /.notdef } repeat
+ ]
+ TTFDEBUG { (Encoding: ) print dup === flush } if
+} bind def
+
+currentdict /postalias undef
+
+% -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 {
+ TTFDEBUG { (.loadttfont) = } if
+ //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 getu16a 1 sub {
+ % Stack: false plat+enc cmap index
+ 8 mul 4 add 1 index exch 8 getinterval_from_stringarray
+ dup 0 4 getinterval 3 index eq {
+ 4 getu32 1 index exch 1 index string_array_size 1 index sub getinterval_from_stringarray
+ 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
+
+/.hexdigits (0123456789ABCDEF) def
+
+/.is_hex_digit { % <int> .is_hex_digit <bool>
+ dup 48 ge exch
+ dup 57 le exch
+ dup 65 ge exch
+ 70 le and
+ 3 1 roll
+ and or
+} bind def
+
+/.popfex { pop //false exit } bind def
+/.pop3ex { pop pop pop exit } bind def
+
+/.addglyph { % <dict> <name> <glyph#> .addglyph -
+ 1 index .namestring % d n g s
+ dup length 7 eq {
+ % Bug688467.ps doesn't work if the uniXXXX mapping is allowed with any cmap.
+ % Allow it with cmap 3.1 only.
+ currentdict /.allow_uniXXXX_glyph_names .knownget not { //false } if
+ } { //false
+ } ifelse % d n g s b
+ {
+ % An undocumented Adobe feature (not sure) :
+ % if the name is uniXXXX, obtain Unicode code from it.
+ % See bug 688946.
+ TTFDEBUG { (Try uniXXXX:) print dup print } if
+ { dup 0 get 117 ne //.popfex if % u
+ dup 1 get 110 ne //.popfex if % n
+ dup 2 get 105 ne //.popfex if % i
+ dup 3 get //.is_hex_digit exec not //.popfex if
+ dup 4 get //.is_hex_digit exec not //.popfex if
+ dup 5 get //.is_hex_digit exec not //.popfex if
+ dup 6 get //.is_hex_digit exec not //.popfex if
+ dup 3 1 getinterval .hexdigits exch search pop length exch pop exch pop 12 bitshift exch
+ dup 4 1 getinterval .hexdigits exch search pop length exch pop exch pop 8 bitshift exch
+ dup 5 1 getinterval .hexdigits exch search pop length exch pop exch pop 4 bitshift exch
+ dup 6 1 getinterval .hexdigits exch search pop length exch pop exch pop exch pop
+ add add add
+ dup cmapencoding length ge //.popfex if
+ cmapencoding exch get
+ dup 0 eq //.popfex if
+ TTFDEBUG { ( index=) print dup =string cvs print } if
+ exch pop
+ put //true exit
+ } loop
+ TTFDEBUG { ()= } if
+ } {
+ pop //false
+ } ifelse
+ not { % d n g
+ { dup cmapencoding length ge //.pop3ex if
+ cmapencoding exch get dup 0 eq //.pop3ex if
+ 3 copy pop known //.pop3ex if
+ put exit
+ } loop
+ } if
+} bind def
+
+% <subcmap> <chartoglyphmap> .pdfmapchars /CharStrings <charstrings>
+/.pdfmapchars {
+ exch cmaparray /cmapencoding exch def % c2g
+ /CharStrings 0 dict % c2g /CS <<>>
+
+ % Add glyphs of <chartoglyphmap>*<subcmap> :
+ 3 2 roll { % /CS <<>> v
+ dup type /arraytype eq { % /CS <<>> /name []
+ { 3 copy //.addglyph exec
+ pop
+ } forall
+ } {
+ 3 copy //.addglyph exec pop
+ } ifelse
+ pop
+ } forall
+
+ % Add glyphs of 'post' with lower priority :
+ 0 1 glyphencoding length 1 sub {
+ dup glyphencoding exch get exch
+ dup 0 ne {
+ 3 copy pop known not {
+ 3 copy put
+ } if
+ } if
+ pop pop
+ } for
+
+ dup /.notdef 0 put
+
+} bind def
+
+% - .pdfcharkeys /CharStrings <charstrings> /Encoding <encoding>
+/.pdfcharkeys {
+ % The following algorithms are per the PDF Reference, Second Edition
+ % (PDF 1.3 reference manual).
+ TTFDEBUG { (.pdfcharkeys beg) = } if
+ 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
+ prebuilt_encoding null ne {
+ % Bug 689083.
+ TTFDEBUG { (Using cmap 3.0 with prebuilt_encoding.) = } if
+ prebuilt_encoding .invert_encoding .pdfmapchars
+ /Encoding prebuilt_encoding
+ } {
+ TTFDEBUG { (Using cmap 3.1 with WinAnsiEncoding) = } if
+ AdobeGlyphList .pdfmapchars
+ /Encoding /WinAnsiEncoding .findencoding
+ } ifelse
+ } {
+ %
+ % 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
+ % 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
+ } {
+ <00030001> .findcmap {
+ prebuilt_encoding null ne {
+ TTFDEBUG { (Using cmap 3.1 with prebuilt_encoding for non-symbolic.) = } if
+ /.allow_uniXXXX_glyph_names //true def
+ prebuilt_encoding .invert_encoding .pdfmapchars
+ /Encoding prebuilt_encoding
+ } {
+ % Likely this branch is now obsolete.
+ 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.
+ } ifelse
+ } {
+ <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
+ TTFDEBUG { (.pdfcharkeys end) = } if
+} bind def
+
+% <file> <is_symbolic> <Encoding|null> .loadpdfttfont <type42font>
+/.loadpdfttfont {
+ TTFDEBUG { (.loadpdfttfont Encoding=) print dup == } if
+ /prebuilt_encoding gput % for .pdfcharkeys
+ /is_symbolic gput
+ //false 0 .loadttfonttables
+ .makesfnts
+ .getpost
+ .pickcmap
+ mark
+ .pdfcharkeys
+ .ttkeys
+ .definettfont
+} bind def