summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlgs/Resource/Init/gs_ttf.ps
diff options
context:
space:
mode:
Diffstat (limited to 'Master/tlpkg/tlgs/Resource/Init/gs_ttf.ps')
-rw-r--r--Master/tlpkg/tlgs/Resource/Init/gs_ttf.ps1987
1 files changed, 1987 insertions, 0 deletions
diff --git a/Master/tlpkg/tlgs/Resource/Init/gs_ttf.ps b/Master/tlpkg/tlgs/Resource/Init/gs_ttf.ps
new file mode 100644
index 00000000000..ebacc6bbd0d
--- /dev/null
+++ b/Master/tlpkg/tlgs/Resource/Init/gs_ttf.ps
@@ -0,0 +1,1987 @@
+% Copyright (C) 2001-2012 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.
+%
+% Refer to licensing information at http://www.artifex.com or contact
+% Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
+% CA 94903, U.S.A., +1(415)492-9861, for further information.
+%
+
+% 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*) (wOFF*)
+ ] def
+} if
+
+% <file> <key> .findfontvalue <value> true
+% <file> <key> .findfontvalue false
+% Closes the file in either case.
+/.findnonttfontvalue /.findfontvalue load def
+/.findfontvalue {
+ 1 index .is_woff {
+ dup /FontType eq {
+ pop closefile 42 //true
+ } {
+ dup /FontName eq { pop .findwoffname } { pop closefile //false } ifelse
+ } ifelse
+ }
+ {
+ 1 index .is_ttf_or_otf {
+ % 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
+ } 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
+ dup 65535 gt { pop 65535 } if % protect against extremely large name
+ 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
+
+/.findwoffname {
+ //true 0 .loadwofftables
+ tabdict /name .knownget {
+ dup /clen exch 8 getu32 def
+ dup /olen exch 12 getu32 def
+ 4 getu32 f exch setfileposition
+ olen dup 65535 gt { pop 65535 } if % protect against extremely large name
+ /fs
+ clen olen ne
+ {f clen () /SubFileDecode filter /FlateDecode filter}
+ {f clen () /SubFileDecode filter}
+ ifelse def
+ string fs exch readstring pop
+ fs closefile
+ 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
+/ttf_otf_tag_dict << <00010000> 0 (true) 0 (typ1) 0 (ttcf) 0 (OTTO) 0>> readonly def
+% The wOFF tag is immediately followed by the sfnt "flavour" so for simplicity
+% combine them
+/woff_tag_dict <<
+ (wOFF) 0
+ <774F464600010000> 0 % (wOFF)<00010000> .concatstrings
+ (wOFFtrue) 0
+ (wOFFtyp1) 0
+>> readonly def
+
+% <file> .loadfontfile -
+/.loadnonttfontfile /.loadfontfile load def
+/.loadfontfile {
+ dup (12345678) .peekstring { //woff_tag_dict exch known } { //false } ifelse
+ {
+ .loadwofffont pop
+ }
+ {
+ 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
+ } ifelse
+} bind def
+
+% <file> .is_ttf_or_otf <bool>
+/.is_ttf_or_otf {
+ dup 0 setfileposition (1234) .peekstring { //ttf_otf_tag_dict exch known } { //false } ifelse
+} bind def
+
+/.is_woff {
+ dup 0 setfileposition (1234) .peekstring { //woff_tag_dict exch known } { //false } ifelse
+} bind def
+
+currentdict /tt_tag_dict .undef
+currentdict /ttf_otf_tag_dict .undef
+currentdict /woff_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
+
+% Make /MacRomanEncodingForTrueType including additional
+% characters in Mac OS Roman encoding, which is missing
+% in /MacRomanEncoding. See PDF spec 1.7, p. 431 or
+% "Inside Macintosh: Text" 1-55, Figure 1-36.
+% This is useful to exploit the glyphs via Apple Roman
+% TrueType cmap subtable, but not appropriate for information
+% interchange.
+
+/MacRomanEncodingForTrueType
+ /MacRomanEncoding .findencoding
+ dup length array copy
+ <<
+ /notequal 173
+ /infinity 176
+ /lessequal 178
+ /greaterequal 179
+ /partialdiff 182
+ /summation 183
+ /product 184
+ /pi 185
+ /integral 186
+ /Omega 189
+ /radical 195
+ /approxequal 197
+ /Delta 198
+ /lozenge 215
+ /Euro 219
+ /apple 240
+ >> {
+ TTFDEBUG { (Extend MacRomanEncodingForTrueType for TrueType: ) =only } if
+
+ % check /.notdef to avoid overwriting
+ 2 index 1 index get dup /.notdef eq {
+ TTFDEBUG { (insert /) =only 2 index =only ( @ ) =only 1 index //== exec } if
+ pop
+ exch 2 index 3 1 roll put
+ } {
+ TTFDEBUG { (cannot insert /) =only 2 index =only ( @ ) =only 1 index =only ( used for ) =only dup //== exec } if
+ pop
+ pop pop
+ } ifelse
+ } forall
+ aload pop
+ 256 packedarray
+ 5 1 index .registerencoding
+.defineencoding
+
+% Define the Macintosh standard mapping from characters to glyph indices.
+/MacRomanEncoding dup .findencoding def
+/MacGlyphEncoding dup .findencoding def
+/MacRomanEncodingForTrueType dup .findencoding def
+
+% Invert the MacRomanEncoding.
+/.romanmacdict MacRomanEncodingForTrueType .invert_encoding def
+/.latin1isodict ISOLatin1Encoding .invert_encoding def
+
+% Define remapping for misnamed glyphs in TrueType 'post' tables.
+% There are probably a lot more than this!
+/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.
+
+% handle 64 bit integer objects
+/xuidstring 16#ffffffff 0 gt
+{
+ <8000000000000000>
+}
+{
+ <80000000>
+} ifelse def
+/curxuid { % - curxuid <int>
+ .getCPSImode
+ //false .setCPSImode
+ 0 xuidstring { exch 8 bitshift exch add } forall
+ % for tbe benefit of pdfwrite/ps2write we want the resulting XUID contents
+ % to fit into a 32 bit value
+ 16#ffffffff 0 gt
+ {
+ 16#ffffffff idiv
+ } if
+ exch .setCPSImode
+} 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
+ { /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 1 index 8 getu16 0 ne and {
+ % 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 //== exec } { ( 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
+ { pop //false } % default - *MUST* be last
+ }
+ % check for a valid Platform ID, if we don't get one, assume single byte encoding
+ dup length 1 sub
+ 2 index lt {exch pop dup length 1 sub}{exch} ifelse
+ 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
+ mark 0 3 -1 roll
+ { 1 index 1 add } forall pop
+ .dicttomark
+ } 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 getu16a
+ 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 0 dict 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 getu16a
+ 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 getu16a
+ /sH_offset exch def
+ sH_gIA sH_offset sH_sz getinterval
+ dup 0 getu16a /firstCode exch def
+ dup 2 getu16a /entryCount exch def
+ dup 4 gets16a /idDelta exch def
+ dup 6 getu16a /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
+ cmapf2_glyph_array
+ } bind
+ 4 { % Microsoft/Adobe segmented mapping.
+ /etab exch def
+ /nseg2 etab 6 getu16a 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 getu16a 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 dict def
+ 0 0 2 nseg2 3 sub {
+ % Stack: /glyphs numglyphs i2
+ /i2 exch def
+ /scode startc i2 getu16a def
+ /ecode endc i2 getu16a def
+
+ % Bug 693538: More undocumented nonsense: in cases where scode == ecode,
+ % see Bug 691326 below *except*, it seems when both are zero
+ scode 0 eq ecode 0 eq and not {
+ scode ecode 1 add gt { % Bug 691326.
+ /ecode scode 1 add def % Acrobat does this contrary to TTF spec that
+ } if % requires such intervals to be ignored.
+
+ 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
+ } if
+ } for pop
+
+ % Now fill in the array.
+ /numcodes 0 def /code 0 def
+ 0 2 nseg2 3 sub {
+ /i2 exch def
+ /scode startc i2 getu16a def
+ /ecode endc i2 getu16a def
+ % Bug 693538: see above
+ scode 0 eq ecode 0 eq and not {
+ scode ecode 1 add gt { /ecode scode 1 add def } if % Bug 691326. See above.
+
+ 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 gets16a def
+ TTFDEBUG {
+ (scode=) print scode =only
+ ( ecode=) print ecode =only
+ ( delta=) print delta =only
+ ( droff=) print idroff i2 getu16 =
+ } if
+ idroff i2 getu16a 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
+ } if
+ } for glyphs /glyphs //null def % for GC
+ } bind
+ 6 { % Single interval lookup.
+ dup 6 getu16a /firstcode exch def
+ dup 8 getu16a /ng exch def
+ ng dict
+ dup
+ % Stack: tab dict dict
+ % Fill elements firstcode .. firstcode+nvalue-1 with glyph values
+ 0 1 ng 1 sub {
+ dup firstcode add exch
+ 2 mul 10 add 4 index exch getu16a 3 copy put pop pop
+ } for pop exch pop
+ } bind
+ 12 { % Microsoft/Adobe segmented mapping.
+ /etab exch def
+ /glyphs 0 dict def
+
+ 0 1
+ etab 12 getu32a % nGroups
+ 1 sub {
+ /ind exch def
+ /gid etab 12 ind mul 8 add 16 add getu32a def % startGlyphID
+ etab 12 ind mul 16 add getu32a % startCharCode
+ 1
+ etab 12 ind mul 4 add 16 add getu32a % endCharCode
+ {
+ gid glyphs 3 1 roll put
+ /gid gid 1 add def
+ } for
+ } for
+ glyphs /glyphs //null def % for GC
+ } 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
+ mark 0 1 255 { dup } for .dicttomark
+ } 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
+ } {
+ dup 65535 le {
+ 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
+ exch pop add exch pop 0 exch % s 0 p'
+ dup 3 index length ge { exit } if
+ } ifelse
+ } forall
+ pop pop % s
+ } {
+ [ 4 1 roll
+ {
+ dup 0 eq {
+ pop pop pop exit
+ } if
+ 3 copy
+ dup 65535 ge {
+ pop 65535
+ } if
+ getinterval_from_stringarray 4 1 roll
+ 3 index length sub
+ exch
+ 3 index length add
+ exch
+ } loop
+ ]
+ } ifelse
+ } 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
+ % Build names array in the order they occur in the 'post' table
+ /postpos numglyphs 2 mul 34 add def
+ /total_length postglyphs //string_array_size exec def
+
+ % the number of names in a post table is not declared up front
+ % and there are fonts with more names than glyph indices <sigh>
+ % so we have to pre-process and find the highest index used.
+ % We start with a base value of numglyphs as it's most common,
+ % and we can safely have a array that's too large.
+ % Rather than parse out the indices twice, we store them in an
+ % array on the stack, which we then reuse, overwriting entries
+ % as we go later on.
+ numglyphs array numglyphs postglyphs
+ 0 1 numglyphs 1 sub {
+ dup 2 mul 34 add 2 index exch 2 //getinterval_from_stringarray exec
+ dup 0 get 8 bitshift exch 1 get add
+ dup 5 index exch
+ 4 -1 roll exch put
+ 258 sub dup 3 index gt
+ % if we find a reference to an index higher than the value
+ % already on the stack, replace the value on the stack
+ { 3 -1 roll pop 2 1 roll} {pop} ifelse
+ } for
+ pop
+ 1 add array 0 1 2 index length 1 sub {
+ postpos total_length ge {
+ % Fill the rest with .notdef
+ 1 2 index length 1 sub { 1 index exch /.notdef put } for
+ 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
+ 2 copy add total_length gt {
+ TTFDEBUG { (post table ends in the middle of the entry.) print flush } if
+ pop pop pop pop
+ % Fill the rest with .notdef
+ 1 2 index length 1 sub { 1 index exch /.notdef put } for
+ exit
+ } if
+ //getinterval_from_stringarray exec cvn
+ exch postpos add 1 add /postpos exch def
+ 2 index 3 1 roll
+ put
+ } for
+ /postnames exch def
+ % Some TrueType fonts converted by "Windows Type 1 Installer" have
+ % problematic post table including MacGlyphEncoding entries which
+ % should be omitted. Such extra entries in the beginning of glyphName
+ % array make /Encoding broken. If we find populary predefined
+ % ISOLatin1Encoding glyph name in the post table, empty encoding is
+ % returned. Some TrueType fonts for Microsoft Windows redefines
+ % MacGlyphEncoding glyph name out of predefined range). To permit
+ % such fonts, ISOLatin1Encoding is used to find broken post. Bug 689495.
+ /.broken_post //false def
+ tabdict /name .knownget {
+ (Windows Type 1 Installer V1.0) search {
+ pop pop pop
+ .latin1isodict postnames {
+ dup /.notdef ne {
+ 2 copy known {
+ TTFDEBUG { (ignore post table that redefines ISOLatin1Encoding glyph name ) print dup //== exec flush } if
+ /.broken_post //true def
+ pop exit
+ } if
+ } if
+ pop
+ } forall
+ pop
+ } {
+ pop
+ } ifelse
+ } if
+ % Loop through the array of name indices we created above.
+ % This loop replaces name index in the array with the name
+ % it references.
+ 0 1 2 index length 1 sub {
+ dup 2 index exch get dup 258 lt {
+ MacGlyphEncoding exch get
+ } {
+ 258 sub 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
+ 2 index 3 1 roll
+ put
+ } for
+
+ .broken_post {
+ pop
+ [ postnames aload length 1 roll ]
+ } if
+ }
+ 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
+ (GSUB) //call.readbigtable
+ (glyf) //call.readbigtable
+ (loca) 1 index
+ (hmtx) 1 index
+ (vmtx) 1 index
+ (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, tthdrlen.
+% 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
+ /tthdrlen offsets length def
+ load_stripped { readtables_stripped } { readtables } ifelse /readtables_ exch def
+ offsets 0 4 getinterval (ttcf) eq {
+ 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
+ f SubfontID 4 mul dup 0 ne {
+ () /SubFileDecode filter flushfile
+ } {
+ pop pop
+ } ifelse
+
+ f 4 string readstring pop
+ 0 getu32 /ttc_offset exch def
+
+ f ttc_offset SubfontID 4 mul sub 16 sub
+ dup 0 ne {
+ () /SubFileDecode filter flushfile
+ } {
+ pop pop
+ } ifelse
+ /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
+ % Peek because table counter may be incorrect.
+ /tables f offsets 4 getu16 16 mul string .peekstring 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> <bool> <SubfontID> .loadwofftables -
+% Pushes .loadttfontdict & scratch dict on d-stack.
+% Defines f, offsets, tables, tabdict, tabs, tthdrlen.
+% Skips loca and glyf if <bool> is true.
+/.loadwofftables {
+ .loadttfontdict begin
+ 40 dict begin
+ /SubfontID exch def
+ /load_stripped exch def
+ /f exch def
+ % loading WOFFs "stripped" only works for .findfontvalue - we cannot
+ % (currently) use a stripped wOFF font
+ load_stripped { readtables_stripped } { readtables } ifelse /readtables_ exch def
+ /offsets 12 string def
+ /woffhdr f 44 string readstring pop def
+ /tthdrlen woffhdr length def
+ /ttc_offset 0 def
+ woffhdr 0 4 getinterval (wOFF) eq not
+ % allow loading wOFFOTTO fonts "stripped" for .findfontvalue
+ woffhdr 4 4 getinterval (OTTO) eq load_stripped not and or
+ {/.loadwofftables cvx /invalidfont signalerror}
+ {
+ offsets 0 woffhdr 4 4 getinterval putinterval
+ /tables f woffhdr 12 getu16 20 mul string .peekstring pop def
+ offsets 4 tables length 20 idiv putu16
+ /tabdict tables length 20 idiv dict def
+ /tabs [ 0 20 tables length 1 sub
+ {
+ tables exch 20 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 4 getu32 exch 4 getu32 lt } .sort
+ def
+ } ifelse
+} 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 tthdrlen ttc_offset add def
+ /sfpos offsets length tabs length 16 mul add def
+ offsets 4 tabs length putu16
+ 0 1 tabs length 1 sub {
+ dup tabs exch get
+ dup 0 4 getinterval /tname exch def
+ dup length 20 eq
+ {
+ dup 4 getu32 /tpos exch def
+ dup 8 getu32 /tclen exch def
+ dup 12 getu32 /tlen exch def
+ }
+ {
+ dup 8 getu32 /tpos exch def
+ dup 12 getu32 /tlen exch def
+ /tclen tlen def
+ } ifelse
+ load_stripped //.file_table_pos_names tname known and {
+ pop
+ file_table_pos tname [tpos tlen tclen] put
+ tabdict tname () put
+ pop
+ } {
+ dup length 20 eq
+ {
+ 0 16 getinterval dup 8 sfpos putu32
+ tabs 3 -2 roll put
+ }
+ {8 sfpos putu32 pop}
+ ifelse
+ % 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
+ /ff
+ tlen tclen eq not
+ {f tclen () /SubFileDecode filter /FlateDecode filter}
+ {f tlen () /SubFileDecode filter}
+ ifelse
+ def
+ ff tlen readtables_ tname get exec
+ ff closefile
+ 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 tclen add def
+ } for
+} 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.
+/.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
+ } {
+ % 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
+
+/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 //== exec } 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 ] //== exec
+ count ttkeycount sub array astore dup { //== exec } 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 1 index getu16a % get cmap format
+ 8 lt { % length for traditional 16bit format 0, 2, 4, 6
+ cmaptab 1 index 2 add getu16a
+ } { % length for advanced 32bit format 8, 10, 12
+ cmaptab 1 index 4 add getu32a
+ } ifelse % bool [] i PlatID SpecID (cmap) (cmapsub) p l
+ cmaptab 3 1 roll getinterval_from_stringarray
+ /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.
+ % 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
+ dup 3 index 1 index get
+ have_post not {
+ exch
+ cmapa exch .knownget not {
+ 0 % a stub for a while. Must skip the entry.
+ } if
+ exch
+ } if
+ 3 index 1 index known
+ { % The same name maps to more than one glyph. Change the name.
+ % No special treatment for /.notdef glyph. Bug 689408.
+ pop .nname 3 index 2 index 2 index put
+ 2 index exch 3 -1 roll put
+ } {
+ 3 index exch 3 -1 roll put % unique name
+ pop
+ } 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 //== exec } forall
+ } if
+
+ % Provide all known aliases for each glyph
+ cmapsub 0 4 getinterval <00030001> eq % is the cmap table a unicode one?
+ cmapa //ReverseAdobeGlyphList //AdobeGlyphList
+ { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) gname(name) codep(integer)
+ exch
+ dup 6 index exch .knownget
+ { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) codep(integer) gname(name) gindex(integer)
+ 3 index 3 index .knownget
+ { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) codep(integer) gname(name) gindex(integer) gnames(array)
+ { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) codep(integer) gname(name) gindex(integer) gname(name)
+ TTFDEBUG { (\n1 setting alias: ) print dup ==only
+ ( to be the same as ) print 2 index //== exec } if
+
+ 7 index 2 index 3 -1 roll exch //.growput superexec
+ } forall
+ pop pop pop
+ }
+ {
+ pop pop
+ } ifelse
+ }
+ { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) gname(name) codep(integer)
+ exch
+ % Only do this for Unicode cmap table
+ 4 index
+ {
+ dup 4 index exch .knownget
+ { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) gname(name) codep(integer) gindex(integer)
+ exch pop
+ TTFDEBUG { (\n2 setting alias: ) print 1 index ==only
+ ( to use glyph index: ) print dup //== exec } if
+ 5 index 3 1 roll //.growput superexec
+ //false
+ }
+ {
+ //true
+ }ifelse
+ }
+ {
+ //true
+ } ifelse
+
+ { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) gname(name) codep(integer)
+ 16 4 string cvrs dup length neg 7 add (uni0000) dup
+ 4 -2 roll exch putinterval cvn 3 index 1 index .knownget
+ { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) gname(name) codep(integer) gindex(integer)
+ TTFDEBUG { (\3 nsetting alias: ) print 1 index ==only
+ ( to be index: ) print dup //== exec } if
+ exch pop 5 index 3 1 roll //.growput superexec
+ }
+ {
+ pop pop
+ } ifelse
+ } if
+ } ifelse
+ } forall
+ pop pop pop
+
+ readonly
+
+ /Encoding [
+ have_post {
+ 0 1 255 {
+ cmapa exch .knownget not { 0 } if
+ glyphencoding dup length
+ 2 index le {
+ pop pop /.notdef
+ } {
+ exch get
+ } ifelse
+ } for
+ } {
+ glyphencoding dup length 256 gt { 0 256 getinterval } if
+ aload pop
+ counttomark 256 exch sub { /.notdef } repeat
+ } ifelse
+ ]
+ TTFDEBUG { (Encoding: ) print dup === flush } if
+} bind def
+
+% to be removed 9.09......
+currentdict /postalias undef
+% .....to be removed 9.09
+
+% <file> .loadttfont <type42font>
+/.loadttfont {
+ TTFDEBUG { (.loadttfont) = } if
+ //false 0 .loadttfonttables
+ .makesfnts
+ .getpost
+ .pickcmap
+ mark
+ % if we're loading to substitute for TTF in a PDF,
+ % load the font the "PDF way"
+ /prebuilt_encoding where
+ {pop .pdfcharkeys}
+ {.charkeys} ifelse
+ .ttkeys
+ /FontType 42
+ /PaintType 0
+ TTFDEBUG {
+ (numloca=) print numloca =
+ } if
+ .dicttomark
+ end end dup /FontName get exch definefont
+} bind def
+
+% <file> .loadwofffont <type42font>
+/.loadwofffont
+{
+ TTFDEBUG { (.loadwofffont) = } if
+ //false 0 .loadwofftables
+ .makesfnts
+ .getpost
+ .pickcmap
+ mark
+ .charkeys
+ .ttkeys
+ /FontType 42
+ /PaintType 0
+ TTFDEBUG {
+ (numloca=) print numloca =
+ } if
+ .dicttomark
+ end end dup /FontName get exch
+ definefont
+} 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
+
+% <CIDSystemInfo dict> <dict> .definettcidfont <font>
+/.definettcidfont {
+ dup begin
+ /CIDFontName fontname def
+ /CIDFontType 2 def
+ /CIDSystemInfo 4 -1 roll def
+ /CharStrings mark /.notdef 0 .dicttomark def
+ % 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.
+ def % 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
+ def
+
+ /GDBytes 2 def
+ end
+
+ end end dup /CIDFontName get exch /CIDFont defineresource
+} bind def
+
+% <CIDSystemInfo dict> <file> <Substite name> .loadttcidfont <cidtype2font>
+/.loadttcidfont {
+ exch
+ //false 0 .loadttfonttables
+ .makesfnts
+ % CIDFontType2 fonts don't have a cmap: they are indexed by CID.
+ mark
+ .ttkeys
+ .dicttomark dup % convert keys to dict and copy dict
+ 3 -1 roll % Bring PDF substitute name to top of stack
+
+ dup
+ /fontname exch def
+ /FontName exch put % replace any definition of /FontName
+ .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
+
+/.load_woff_for_cid {
+ //false exch .loadwofftables
+ .makesfnts
+ % we have to set load_stripped here so
+ % .pickcmap will follow the right logic
+ % for emulating a CIDFont
+ /load_stripped //true def
+ .pickcmap
+ /load_stripped //false def
+ 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
+
+ cmapencoding exch .knownget not { 0 } if
+ 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
+ {
+ cmapencoding exch .knownget not { 0 } if
+ dup 0 eq //.pop3ex if
+ 3 copy pop known //.pop3ex if
+ put exit
+ } loop
+ } if
+} bind def
+
+% <chartoglyphmap> <subcmap> <AGL> .pdfmapchars /CharStrings <charstrings>
+/.pdfmapchars {
+ exch cmaparray /cmapencoding exch def % c2g
+ /CharStrings 0 dict % c2g /CS <<>>
+
+ % Add glyphs of <AGL>*<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
+
+ % Finally, add glyphs from the prebuilt_encoding with lowest priority
+ % this is a catch-all for poorly matched font/PDF combos
+ 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
+
+ dup /.notdef 0 put
+
+} bind def
+
+% <subtable> .pdfmapsymbolic /Encoding [] /CharStrings <<>>
+/.pdfmapsymbolic {
+ //true /.render_notdef gput
+ cmaparray
+ dup length 1 add dict begin
+ [ 64 { /.notdef /.notdef /.notdef /.notdef } repeat ]
+ exch { % [] char glyph
+ exch
+ dup 255 gt {
+ 255 and
+ 2 index 1 index get /.notdef ne {
+ pop pop
+ //false
+ } {
+ //true
+ } ifelse
+ } {
+ //true
+ } ifelse {
+ dup (01234567) cvs cvn % glyph char /char
+ 3 1 roll % /char glyph char
+ 3 index exch % /char glyph [] char
+ 3 index put % /char glyph
+ def % -
+ } if
+ } forall
+ /.notdef 0 def
+ /Encoding exch
+ /CharStrings currentdict end
+} bind def
+
+% - .pdfcharkeys /CharStrings <charstrings> /Encoding <encoding>
+/.pdfcharkeys {
+ % The following algorithms are per the PDF 1.7 Reference.
+ TTFDEBUG { (.pdfcharkeys beg) = } if
+
+ % if the flags say symbolic, *and* the font contains a symbol
+ % cmap table, ignore Encoding if there is one, treat as symbolic.
+ % If the flags say symbolic, and the font doesn't have a symbol cmap
+ % and we have an Encoding, treat it as non-symbolic
+ % if we don't have an Encoding, try the MacRoman cmap table.
+ % Finally, if none of that works, remove the Encoding, and treat it
+ % as non-symbolic.
+ is_symbolic {
+ <00030000> .findcmap { //true } { prebuilt_encoding //null eq { <00010000> .findcmap}{//false}ifelse } ifelse {
+ .pdfmapsymbolic
+ /prebuilt_encoding //null def
+ //false
+ } {
+ /prebuilt_encoding //null def
+ //true
+ } ifelse
+ } {
+ //true
+ }
+ ifelse
+ {
+ <00030001> .findcmap {
+ prebuilt_encoding //null ne {
+ TTFDEBUG { (Using cmap 3.1 with prebuilt_encoding for non-symbolic.) = } if
+ //true /.render_notdef gput
+ % The character code in /prebuilt_encoding[] is not guaranteed to be
+ % compatible with the Microsoft UCS2 TrueType cmap subtable.
+ % If the glyphname is known by AdobeGlyphList, the charcode for the glyph
+ % is replaced by UCS2 charcode from AdobeGlyphList. Otherwise it is left
+ % as in /prebuilt_encoding[]. /.pdfmapchars should dredge them.
+
+ /.allow_uniXXXX_glyph_names //true def
+ AdobeGlyphList prebuilt_encoding .invert_encoding dup { % <<AGL>> <<pbe>> <glyphname> <pbecode>
+ pop % <<AGL>> <<pbe>> <glyphname>
+ TTFDEBUG { (check glypname /) print dup =only flush } if
+ 2 index 1 index .knownget { % <<AGL>> <<pbe>> <glyphname> <AGLcode>
+ 2 index 3 1 roll % <<AGL>> <<pbe>> <<pbe>> <glyphname> <AGLcode>
+ TTFDEBUG { ( redefine codepoint by AdobeGlyphList, ) print dup //== exec flush } if
+ put % <<AGL>> <<pbe>>
+ } { % <<AGL>> <<pbe>> <glyphname>
+ TTFDEBUG { ( unknown glyphname, leave as it is ) = flush } if
+ pop % <<AGL>> <<pbe>>
+ } ifelse
+ } forall
+ exch pop % <<pbe>>
+ TTFDEBUG { dup (<<\n) print { exch ( ) print =only (\t) print //== exec } forall (>>\n) print flush } if
+ exch AdobeGlyphList
+ .pdfmapchars
+ /Encoding prebuilt_encoding
+ } {
+ % Likely this branch is now obsolete.
+ TTFDEBUG { (Using cmap 3.1 for non-symbolic.) = } if
+ 0 dict exch
+ 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
+ 0 dict exch
+ .romanmacdict .pdfmapchars
+ /Encoding
+ prebuilt_encoding //null ne {
+ prebuilt_encoding
+ } {
+ /MacRomanEncodingForTrueType .findencoding
+ } ifelse
+ } {
+ % Apply the default algorithm for using the 'post'.
+ .charkeys
+ % But use PDF encoding when available.
+ prebuilt_encoding //null ne {
+ pop prebuilt_encoding
+ } if
+ } ifelse
+ } ifelse
+ } if
+ TTFDEBUG { (.pdfcharkeys end) = } if
+} bind def
+
+% <file> <is_symbolic> <Encoding|null> <FontName> .loadpdfttfont <type42font>
+/.loadpdfttfont {
+ TTFDEBUG { (.loadpdfttfont FontName=) print dup == } if
+ /font_name gput
+ TTFDEBUG { (.loadpdfttfont Encoding=) print dup //== exec } if
+ /prebuilt_encoding gput % for .pdfcharkeys
+ /is_symbolic gput
+ % init key for whether to display the TTF notdef
+ //false /.render_notdef gput
+ //false 0 .loadttfonttables
+ .makesfnts
+ tabdict /cmap known not {
+ ( **** Warning: Embedded TT font lacks required cmap table. Using identity cmap.\n)
+ pdfformaterror
+ % Unknown (i.e. not 0 ) language ID brings in post table.
+ % Fields: cmap_version, number_of_subtables,
+ % plarform_id, encoding_id, offset,
+ % format, subtable_length, language,
+ % 256 bytes of identity mapping.
+ tabdict /cmap
+ < 0000 0001
+ 0001 D00D 0000000c
+ 0000 0106 0000
+ 00 01 02 03 04 05 06 07 08 09 0a 0d 0c 0d 0e 0f
+ 10 11 12 13 14 15 16 17 18 19 1a 1d 1c 1d 1e 1f
+ 20 21 22 23 24 25 26 27 28 29 2a 2d 2c 2d 2e 2f
+ 30 31 32 33 34 35 36 37 38 39 3a 3d 3c 3d 3e 3f
+ 40 41 42 43 44 45 46 47 48 49 4a 4d 4c 4d 4e 4f
+ 50 51 52 53 54 55 56 57 58 59 5a 5d 5c 5d 5e 5f
+ 60 61 62 63 64 65 66 67 68 69 6a 6d 6c 6d 6e 6f
+ 70 71 72 73 74 75 76 77 78 79 7a 7d 7c 7d 7e 7f
+ 80 81 82 83 84 85 86 87 88 89 8a 8d 8c 8d 8e 8f
+ 90 91 92 93 94 95 96 97 98 99 9a 9d 9c 9d 9e 9f
+ a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ad ac ad ae af
+ b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bd bc bd be bf
+ c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cd cc cd ce cf
+ d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da dd dc dd de df
+ e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea ed ec ed ee ef
+ f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fd fc fd fe ff
+ > readonly put
+ } if
+ .getpost
+ .pickcmap
+ mark
+ .pdfcharkeys
+ .ttkeys
+ /FontType 42
+ /PaintType 0
+ /.render_notdef .render_notdef
+ TTFDEBUG {
+ (numloca=) print numloca =
+ } if
+ .dicttomark
+ dup /FontName font_name put % replace any definition of /FontName
+ end end
+ .completefont
+} bind def