% 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 % .findfontvalue true % .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 % .findttfontname true % .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 % .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 % invert_encoding { 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 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 % getu16 /getu16 { 2 copy get 8 bitshift 3 1 roll 1 add get add } bind def % gets16 /gets16 { getu16 16#8000 xor 16#8000 sub } bind def % getu32 /getu32 { 2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add } bind def % gets32 /gets32 { 2 copy gets16 16 bitshift 3 1 roll 2 add getu16 add } bind def % getu16 /getu16a { 2 getinterval_from_stringarray 0 getu16 } bind def % gets16 /gets16a { 2 getinterval_from_stringarray 0 gets16 } bind def % getu32a /getu32a { 4 getinterval_from_stringarray 0 getu32 } bind def % gets32a /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 % putu16 - /putu16 { 3 copy -8 bitshift put exch 1 add exch 16#ff and put } bind def % putu32 - /putu32 { 3 copy -16 bitshift putu16 exch 2 add exch 16#ffff and putu16 } bind def % findname true % 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 % is2byte /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 % is2byte2 /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 % string2to1 /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: % proc /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 % cmaparray /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 % get_from_stringarray { 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 % getinterval_from_stringarray { % 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 % string_array_size { dup type /stringtype eq { length } { 0 exch { length add } forall } ifelse } bind def % Each procedure in this dictionary is called as follows: % posttable <> 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: % -proc- % 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. % .skiptable /.skiptable { pop pop () } bind def % Read a table as a single string. % .readtable /.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). % .readbigtable /.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 % .printtab - /.printtab { dup 0 4 getinterval print ( ) print dup 8 getu32 =only ( ) print 12 getu32 = } bind def % .loadttfonttables - % Pushes .loadttfontdict & scratch dict on d-stack. % Defines f, offsets, tables, tabdict, tabs. % Skips loca and glyf if 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. % .findseg /.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 % .dividesfnts /.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 { 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 ... /.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 % .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 /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 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- ... .definettfont /.definettfont { /FontType 42 /PaintType 0 TTFDEBUG { (numloca=) print numloca = } if .dicttomark end end dup /FontName get exch definefont } bind def % .loadttfont /.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. % .fill_identity_cmap /.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- ... .definettcidfont /.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 % .loadttcidfont /.loadttcidfont { //false 0 .loadttfonttables .makesfnts % CIDFontType2 fonts don't have a cmap: they are indexed by CID. mark .ttkeys .definettcidfont } bind def % .load_tt_font_stripped % 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. % .findcmap true % .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 { % .is_hex_digit 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 { % .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 % .pdfmapchars /CharStrings /.pdfmapchars { exch cmaparray /cmapencoding exch def % c2g /CharStrings 0 dict % c2g /CS <<>> % Add glyphs of * : 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 /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 % .loadpdfttfont /.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