% Copyright (C) 1996-2003 artofcode LLC. All rights reserved.% % This software is provided AS-IS with no warranty, either express or% implied.% % This software is distributed under license and may not be copied,% modified or distributed except as expressly authorized under the terms% of the license contained in the file LICENSE in this distribution.% % For more information about licensing, please refer to% http://www.ghostscript.com/licensing/. For information on% commercial licensing, go to http://www.artifex.com/licensing/ or% contact Artifex Software, Inc., 101 Lucas Valley Road #110,% San Rafael, CA 94903, U.S.A., +1(415)492-9861. % $Id: gs_ttf.ps,v 1.48 2005/09/22 16:11:37 ray Exp $% Support code for direct use of TrueType fonts.% (Not needed for Type 42 fonts.) % Note that if you want to use this file without including the ttfont.dev% option when you built Ghostscript, you will need to load the following% files before this one:% lib/gs_mgl_e.ps% lib/gs_mro_e.ps% lib/gs_wan_e.ps % Thanks to B. Jackowski and GUST (the Polish TeX Users' Group) for% the glyf-splitting code. % ---------------- Font loading machinery ---------------- % % Augment the FONTPATH machinery so it recognizes TrueType fonts. /.scanfontheaders where { pop /.scanfontheaders [ .scanfontheaders aload pop (\000\001\000\000*) (true*) ] def} if % <file> <key> .findfontvalue <value> true% <file> <key> .findfontvalue false% Closes the file in either case./.findnonttfontvalue /.findfontvalue load def/.findfontvalue { 1 index read { 2 index 1 index unread % beginning with binary 0 or 't' (TrueType), or 'O' (OpenType) dup 0 eq 1 index (O) 0 get eq or exch (t) 0 get eq or { % If this is a font at all, it's a TrueType font. dup /FontType eq { pop closefile 42 true } { dup /FontName eq { pop .findttfontname } { pop closefile false } ifelse } ifelse } { % Not a TrueType font. .findnonttfontvalue } ifelse } { pop closefile false } ifelse} bind def % <file> .findttfontname <fname> true% <file> .findttfontname false% Closes the file in either case./.findttfontname { //true 0 .loadttfonttables tabdict /name .knownget { dup 8 getu32 f exch setfileposition 12 getu32 string f exch readstring pop 6 findname } { false } ifelse f closefile end end} bind def % Load a font file that might be a TrueType font. % <file> .loadfontfile -/.loadnonttfontfile /.loadfontfile load def/.loadfontfile { dup read pop 2 copy unread 0 eq { % If this is a font at all, it's a TrueType font. .loadttfont pop } { % Not a TrueType font. .loadnonttfontfile } ifelse} bind def % ---------------- Automatic Type 42 generation ---------------- % % Load a TrueType font from a file as a Type 42 PostScript font.% The thing that makes this really messy is the handling of encodings.% There are 2 interacting tables that affect the encoding:% 'cmap' provides multiple maps from character codes to glyph indices% 'post' maps glyph indices to glyph names (if present)% What we need to get out of this is:% Encoding mapping character codes to glyph names% (the composition of cmap and post)% CharStrings mapping glyph names to glyph indices% (the inverse of post)% If the post table is missing, we have to take a guess based on the cmap% table. /.loadttfontdict 50 dict dup begin /orgXUID AladdinEnterprisesXUID def/maxstring 32764 def % half the maximum length of a PostScript string, % must be a multiple of 4 (for hmtx / loca / vmtx) /.invert_encoding % <array> invert_encoding <dict>{ dup 256 dict exch 0 exch 1 exch length 1 sub { % [] <> i dup 3 index exch get % [] <> i v dup /.notdef ne { exch 2 index 2 index .knownget { dup type /arraytype eq { [ exch aload pop counttomark 2 add -1 roll ] } { exch 2 array astore } ifelse } if 2 index 3 1 roll put } { pop pop } ifelse } for exch pop} bind def % Define the Macintosh standard mapping from characters to glyph indices./MacRomanEncoding dup .findencoding def/MacGlyphEncoding dup .findencoding def % Invert the MacRomanEncoding./.romanmacdict MacRomanEncoding .invert_encoding def % Define remapping for misnamed glyphs in TrueType 'post' tables.% There are probably a lot more than this!/postremap mark /Cdot /Cdotaccent /Edot /Edotaccent /Eoverdot /Edotaccent /Gdot /Gdotaccent /Ldot /Ldotaccent /Zdot /Zdotaccent /cdot /cdotaccent /edot /edotaccent /eoverdot /edotaccent /gdot /gdotaccent /ldot /ldotaccent /zdot /zdotaccent .dicttomark readonly def % Array used for fast pre-filling of cmap array/.array1024z [ 1024 { 0 } repeat ] def % ---- Utilities ---- % % Define a serial number for creating unique XUIDs for TrueType fonts.% We used to use the checkSumAdjustment value from the font, but this is% not reliable, since some fonts don't set it correctly.% Note that we must do this in a string to make it immune to save/restore./xuidstring <80000000> def/curxuid { % - curxuid <int> 0 xuidstring { exch 8 bitshift exch add } forall} bind def/nextxuid { % - nextxuid - 3 -1 0 { xuidstring 1 index 2 copy get dup 255 ne { 1 add put pop exit } if pop 0 put pop } for} bind def % <string> <index> getu16 <integer>/getu16 { 2 copy get 8 bitshift 3 1 roll 1 add get add} bind def % <string> <index> gets16 <integer>/gets16 { getu16 16#8000 xor 16#8000 sub} bind def % <string> <index> getu32 <integer>/getu32 { 2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add} bind def % <string> <index> gets32 <integer>/gets32 { 2 copy gets16 16 bitshift 3 1 roll 2 add getu16 add} bind def 16#ffffffff 0 gt { % 64-bit sign extension { /curxuid /gets32 } { mark 1 index load aload pop { 16#80000000 xor 16#80000000 sub } aload pop .packtomark cvx def } bind forall} if % <string> <index> <integer> putu16 -/putu16 { 3 copy -8 bitshift put exch 1 add exch 16#ff and put} bind def % <string> <index> <integer> putu32 -/putu32 { 3 copy -16 bitshift putu16 exch 2 add exch 16#ffff and putu16} bind def % <nametable> <nameid> findname <string> true% <nametable> <nameid> findname false/findname { TTFDEBUG { (findname: ) print dup =only } if false 3 1 roll 1 index length 0 gt { % check for zero length name table 0 1 3 index 2 getu16 1 sub { % Stack: false table id index 12 mul 6 add 2 index exch 12 getinterval dup 6 getu16 2 index eq { % We found the name we want. exch pop % Stack: false table record dup 10 getu16 2 index 4 getu16 add 1 index 8 getu16 4 -1 roll 3 1 roll 3 copy add 1 index length le { pop getinterval exch % Stack: false string record % Check for 8- vs. 16-bit characters. is2byte { string2to1 } if true null 4 -1 roll exit } { pop pop pop pop false exit } ifelse } if pop } for } if pop pop TTFDEBUG { dup { ( = ) print 1 index == } { ( not found) = } ifelse } if} bind def % <namerecord> is2byte <bool>/is2byte { dup 0 getu16 { { pop true } % Apple Unicode { pop false } % Macintosh Script manager { 1 getu16 1 eq } % ISO { 1 getu16 1 eq } % Microsoft } exch get exec} bind def % <string2> string2to1 <string>/string2to1 { dup length 2 idiv string dup 0 1 3 index length 1 sub { 3 index 1 index 2 mul 1 add get put dup } for pop exch pop} bind def % Each procedure in this dictionary is called as follows:% <encodingtable> proc <glypharray>/cmapformats mark 0 { % Apple standard 1-to-1 mapping. 6 256 getinterval { } forall 256 packedarray } bind 2 { % Apple 16bit CJK (ShiftJIS etc) % /sHK_sz subHeaderKey_size % 1 * uint16 % /sH_sz subHeader_size % 4 * uint16 % /sH_len subHeader_length % /cmapf2_tblen total table length % /cmapf2_lang language code (not used) % /sHKs subHeaderKeys /sHK_sz 2 def /sH_sz 8 def dup 2 getu16 /cmapf2_tblen exch def dup 4 getu16 /cmapf2_lang exch def dup 6 256 sHK_sz mul getinterval /sHKs exch def 0 % initialization value for /sH_len 0 1 255 { sHKs exch 2 mul getu16 1 index % get current max 1 index % get current subHeaderKey lt {exch} if pop } for /sH_len exch def dup 6 256 sHK_sz mul add cmapf2_tblen 1 index sub getinterval /sH_gIA exch def /cmapf2_glyph_array 65535 array def /.cmapf2_putGID { /cmapf2_ch cmapf2_ch_hi 8 bitshift cmapf2_ch_lo add def firstCode cmapf2_ch_lo le cmapf2_ch_lo firstCode entryCount add lt and { % true: j is inside sH_offset idRangeOffset add % offset to gI cmapf2_ch_lo firstCode sub 2 mul % rel. pos. in range add 6 add % offset in sH_gIA sH_gIA exch getu16 dup 0 gt { % idDelta add cmapf2_glyph_array exch cmapf2_ch exch put } { pop % cmapf2_glyph_array cmapf2_ch 0 put } ifelse } { % false: j is outside % cmapf2_glyph_array cmapf2_ch 0 put } ifelse } def 16#00 1 16#ff { % hi_byte scan /cmapf2_ch_hi exch def sHKs cmapf2_ch_hi sHK_sz mul getu16 /sH_offset exch def sH_gIA sH_offset sH_sz getinterval dup 0 getu16 /firstCode exch def dup 2 getu16 /entryCount exch def dup 4 gets16 /idDelta exch def dup 6 getu16 /idRangeOffset exch def pop sH_offset 0 eq { /cmapf2_ch_lo cmapf2_ch_hi def /cmapf2_ch_hi 0 def .cmapf2_putGID } { 16#00 1 16#ff { % lo_byte scan /cmapf2_ch_lo exch def .cmapf2_putGID } for } ifelse } for pop 0 1 cmapf2_glyph_array length 1 sub { % rewrite null -> 0. dup cmapf2_glyph_array exch get null eq { cmapf2_glyph_array exch 0 put } {pop} ifelse } for cmapf2_glyph_array } bind 4 { % Microsoft/Adobe segmented mapping. /etab exch def /nseg2 etab 6 getu16 def 14 /endc etab 2 index nseg2 getinterval def % The Apple TrueType documentation omits the 2-byte % 'reserved pad' that follows the endCount vector! 2 add nseg2 add /startc etab 2 index nseg2 getinterval def nseg2 add /iddelta etab 2 index nseg2 getinterval def nseg2 add /idroff etab 2 index nseg2 getinterval def % The following hack allows us to properly handle % idiosyncratic fonts that start at 0xf000: pop /firstcode startc 0 getu16 16#ff00 and dup 16#f000 ne { pop 0 } if def /putglyph { glyphs code 3 -1 roll put /code code 1 add def } bind def % Do a first pass to compute the size of the glyphs array. /numcodes 0 def /glyphs 0 0 2 nseg2 3 sub { % Stack: /glyphs numglyphs i2 /i2 exch def /scode startc i2 getu16 def /ecode endc i2 getu16 def numcodes scode firstcode sub % Hack for fonts that have only 0x0000 and 0xf000 ranges %dup 16#e000 ge { 255 and } if % the previous line is obstructive to CJK fonts, so it was removed exch sub 0 .max ecode scode sub 1 add add exch 1 index add exch numcodes add /numcodes exch def } for array def % prefill the array with 0's faster than a { 0 putglyph } repeat glyphs length 1024 ge { .array1024z 0 1024 glyphs length 1023 sub { glyphs exch 2 index putinterval } for glyphs dup length 1024 sub 3 -1 roll putinterval } { 0 1 glyphs length 1 sub { glyphs exch 0 put } for } ifelse % Now fill in the array. /numcodes 0 def /code 0 def 0 2 nseg2 3 sub { /i2 exch def /scode startc i2 getu16 def /ecode endc i2 getu16 def numcodes scode firstcode sub % Hack for fonts that have only 0x0000 and 0xf000 ranges %dup 16#e000 ge { 255 and } if % the previous line is obstructive to CJK fonts, so it was removed exch sub 0 .max dup /code exch code exch add def ecode scode sub 1 add add numcodes add /numcodes exch def /delta iddelta i2 gets16 def TTFDEBUG { (scode=) print scode =only ( ecode=) print ecode =only ( delta=) print delta =only ( droff=) print idroff i2 getu16 = } if idroff i2 getu16 dup 0 eq { pop scode delta add 65535 and 1 ecode delta add 65535 and { putglyph } for } { % The +2 is for the 'reserved pad'. /gloff exch 14 nseg2 3 mul add 2 add i2 add add def 0 1 ecode scode sub { 2 mul gloff add etab exch getu16 dup 0 ne { delta add 65535 and } if putglyph } for } ifelse } for glyphs /glyphs null def % for GC } bind 6 { % Single interval lookup. dup 6 getu16 /firstcode exch def dup 8 getu16 /ng exch def firstcode ng add array % Stack: tab array % Fill elements 0 .. firstcode-1 with 0 0 1 firstcode 1 sub { 2 copy 0 put pop } for dup firstcode ng getinterval % Stack: tab array subarray % Fill elements firstcode .. firstcode+nvalue-1 with glyph values 0 1 ng 1 sub { dup 2 mul 10 add 4 index exch getu16 3 copy put pop pop } for pop exch pop } bind.dicttomark readonly def % cmapformats % <cmaptab> cmaparray <glypharray>/cmaparray { dup 0 getu16 cmapformats exch .knownget { TTFDEBUG { (cmap: format ) print 1 index 0 getu16 = flush } if exec } { (Can't handle format ) print 0 getu16 = flush 0 1 255 { } for 256 packedarray } ifelse TTFDEBUG { (cmap: length=) print dup length = dup == } if} bind def /get_from_stringarray % <array|string> <offset> get_from_stringarray <int>{ 1 index type /stringtype eq { get } { exch { % o () 2 copy length gt { length sub } { exch get exit } ifelse } forall } ifelse} bind def /getinterval_from_stringarray % <array|string> <offset> <length> getinterval_from_stringarray <string>{ % May allocate a string in VM. 2 index type /stringtype eq { getinterval } { string exch 0 % [] s o p 4 3 roll { % s o p Si dup length % s o p Si lSi dup 4 index lt { 3 index exch sub % s o p Si o' exch pop 3 1 roll exch pop % s o' p } { % s o p Si lSi dup 3 1 roll % s o p lSi Si lSi 4 index sub % s o p lSi Si lSi-o 5 index length 4 index sub % s o p lSi Si lSi-o ls-p 2 copy gt { exch } if pop % s o p lSi Si minl dup 3 1 roll % s o p lSi minl Si minl 5 index exch getinterval % s o p lSi minl from 5 index 4 index 3 index % s o p lSi minl from s p minl getinterval % s o p lSi minl from to copy pop % s o p lSi minl 3 1 roll % s o minl p lSi sub % s o minl p' 3 1 roll add % s p' o' dup 3 index length ge { exch exit % s o p' } if exch % s o' p' } ifelse } forallLines 1–500 of 1456. Load more
% Copyright (C) 1996-2003 artofcode LLC. All rights reserved. % % This software is provided AS-IS with no warranty, either express or % implied. % % This software is distributed under license and may not be copied, % modified or distributed except as expressly authorized under the terms % of the license contained in the file LICENSE in this distribution. % % For more information about licensing, please refer to % http://www.ghostscript.com/licensing/. For information on % commercial licensing, go to http://www.artifex.com/licensing/ or % contact Artifex Software, Inc., 101 Lucas Valley Road #110, % San Rafael, CA 94903, U.S.A., +1(415)492-9861. % $Id: gs_ttf.ps,v 1.48 2005/09/22 16:11:37 ray Exp $ % Support code for direct use of TrueType fonts. % (Not needed for Type 42 fonts.) % Note that if you want to use this file without including the ttfont.dev % option when you built Ghostscript, you will need to load the following % files before this one: % lib/gs_mgl_e.ps % lib/gs_mro_e.ps % lib/gs_wan_e.ps % Thanks to B. Jackowski and GUST (the Polish TeX Users' Group) for % the glyf-splitting code. % ---------------- Font loading machinery ---------------- % % Augment the FONTPATH machinery so it recognizes TrueType fonts. /.scanfontheaders where { pop /.scanfontheaders [ .scanfontheaders aload pop (\000\001\000\000*) (true*) ] def } if % <file> <key> .findfontvalue <value> true % <file> <key> .findfontvalue false % Closes the file in either case. /.findnonttfontvalue /.findfontvalue load def /.findfontvalue { 1 index read { 2 index 1 index unread % beginning with binary 0 or 't' (TrueType), or 'O' (OpenType) dup 0 eq 1 index (O) 0 get eq or exch (t) 0 get eq or { % If this is a font at all, it's a TrueType font. dup /FontType eq { pop closefile 42 true } { dup /FontName eq { pop .findttfontname } { pop closefile false } ifelse } ifelse } { % Not a TrueType font. .findnonttfontvalue } ifelse } { pop closefile false } ifelse } bind def % <file> .findttfontname <fname> true % <file> .findttfontname false % Closes the file in either case. /.findttfontname { //true 0 .loadttfonttables tabdict /name .knownget { dup 8 getu32 f exch setfileposition 12 getu32 string f exch readstring pop 6 findname } { false } ifelse f closefile end end } bind def % Load a font file that might be a TrueType font. % <file> .loadfontfile - /.loadnonttfontfile /.loadfontfile load def /.loadfontfile { dup read pop 2 copy unread 0 eq { % If this is a font at all, it's a TrueType font. .loadttfont pop } { % Not a TrueType font. .loadnonttfontfile } ifelse } bind def % ---------------- Automatic Type 42 generation ---------------- % % Load a TrueType font from a file as a Type 42 PostScript font. % The thing that makes this really messy is the handling of encodings. % There are 2 interacting tables that affect the encoding: % 'cmap' provides multiple maps from character codes to glyph indices % 'post' maps glyph indices to glyph names (if present) % What we need to get out of this is: % Encoding mapping character codes to glyph names % (the composition of cmap and post) % CharStrings mapping glyph names to glyph indices % (the inverse of post) % If the post table is missing, we have to take a guess based on the cmap % table. /.loadttfontdict 50 dict dup begin /orgXUID AladdinEnterprisesXUID def /maxstring 32764 def % half the maximum length of a PostScript string, % must be a multiple of 4 (for hmtx / loca / vmtx) /.invert_encoding % <array> invert_encoding <dict> { dup 256 dict exch 0 exch 1 exch length 1 sub { % [] <> i dup 3 index exch get % [] <> i v dup /.notdef ne { exch 2 index 2 index .knownget { dup type /arraytype eq { [ exch aload pop counttomark 2 add -1 roll ] } { exch 2 array astore } ifelse } if 2 index 3 1 roll put } { pop pop } ifelse } for exch pop } bind def % Define the Macintosh standard mapping from characters to glyph indices. /MacRomanEncoding dup .findencoding def /MacGlyphEncoding dup .findencoding def % Invert the MacRomanEncoding. /.romanmacdict MacRomanEncoding .invert_encoding def % Define remapping for misnamed glyphs in TrueType 'post' tables. % There are probably a lot more than this! /postremap mark /Cdot /Cdotaccent /Edot /Edotaccent /Eoverdot /Edotaccent /Gdot /Gdotaccent /Ldot /Ldotaccent /Zdot /Zdotaccent /cdot /cdotaccent /edot /edotaccent /eoverdot /edotaccent /gdot /gdotaccent /ldot /ldotaccent /zdot /zdotaccent .dicttomark readonly def % Array used for fast pre-filling of cmap array /.array1024z [ 1024 { 0 } repeat ] def % ---- Utilities ---- % % Define a serial number for creating unique XUIDs for TrueType fonts. % We used to use the checkSumAdjustment value from the font, but this is % not reliable, since some fonts don't set it correctly. % Note that we must do this in a string to make it immune to save/restore. /xuidstring <80000000> def /curxuid { % - curxuid <int> 0 xuidstring { exch 8 bitshift exch add } forall } bind def /nextxuid { % - nextxuid - 3 -1 0 { xuidstring 1 index 2 copy get dup 255 ne { 1 add put pop exit } if pop 0 put pop } for } bind def % <string> <index> getu16 <integer> /getu16 { 2 copy get 8 bitshift 3 1 roll 1 add get add } bind def % <string> <index> gets16 <integer> /gets16 { getu16 16#8000 xor 16#8000 sub } bind def % <string> <index> getu32 <integer> /getu32 { 2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add } bind def % <string> <index> gets32 <integer> /gets32 { 2 copy gets16 16 bitshift 3 1 roll 2 add getu16 add } bind def 16#ffffffff 0 gt { % 64-bit sign extension { /curxuid /gets32 } { mark 1 index load aload pop { 16#80000000 xor 16#80000000 sub } aload pop .packtomark cvx def } bind forall } if % <string> <index> <integer> putu16 - /putu16 { 3 copy -8 bitshift put exch 1 add exch 16#ff and put } bind def % <string> <index> <integer> putu32 - /putu32 { 3 copy -16 bitshift putu16 exch 2 add exch 16#ffff and putu16 } bind def % <nametable> <nameid> findname <string> true % <nametable> <nameid> findname false /findname { TTFDEBUG { (findname: ) print dup =only } if false 3 1 roll 1 index length 0 gt { % check for zero length name table 0 1 3 index 2 getu16 1 sub { % Stack: false table id index 12 mul 6 add 2 index exch 12 getinterval dup 6 getu16 2 index eq { % We found the name we want. exch pop % Stack: false table record dup 10 getu16 2 index 4 getu16 add 1 index 8 getu16 4 -1 roll 3 1 roll 3 copy add 1 index length le { pop getinterval exch % Stack: false string record % Check for 8- vs. 16-bit characters. is2byte { string2to1 } if true null 4 -1 roll exit } { pop pop pop pop false exit } ifelse } if pop } for } if pop pop TTFDEBUG { dup { ( = ) print 1 index == } { ( not found) = } ifelse } if } bind def % <namerecord> is2byte <bool> /is2byte { dup 0 getu16 { { pop true } % Apple Unicode { pop false } % Macintosh Script manager { 1 getu16 1 eq } % ISO { 1 getu16 1 eq } % Microsoft } exch get exec } bind def % <string2> string2to1 <string> /string2to1 { dup length 2 idiv string dup 0 1 3 index length 1 sub { 3 index 1 index 2 mul 1 add get put dup } for pop exch pop } bind def % Each procedure in this dictionary is called as follows: % <encodingtable> proc <glypharray> /cmapformats mark 0 { % Apple standard 1-to-1 mapping. 6 256 getinterval { } forall 256 packedarray } bind 2 { % Apple 16bit CJK (ShiftJIS etc) % /sHK_sz subHeaderKey_size % 1 * uint16 % /sH_sz subHeader_size % 4 * uint16 % /sH_len subHeader_length % /cmapf2_tblen total table length % /cmapf2_lang language code (not used) % /sHKs subHeaderKeys /sHK_sz 2 def /sH_sz 8 def dup 2 getu16 /cmapf2_tblen exch def dup 4 getu16 /cmapf2_lang exch def dup 6 256 sHK_sz mul getinterval /sHKs exch def 0 % initialization value for /sH_len 0 1 255 { sHKs exch 2 mul getu16 1 index % get current max 1 index % get current subHeaderKey lt {exch} if pop } for /sH_len exch def dup 6 256 sHK_sz mul add cmapf2_tblen 1 index sub getinterval /sH_gIA exch def /cmapf2_glyph_array 65535 array def /.cmapf2_putGID { /cmapf2_ch cmapf2_ch_hi 8 bitshift cmapf2_ch_lo add def firstCode cmapf2_ch_lo le cmapf2_ch_lo firstCode entryCount add lt and { % true: j is inside sH_offset idRangeOffset add % offset to gI cmapf2_ch_lo firstCode sub 2 mul % rel. pos. in range add 6 add % offset in sH_gIA sH_gIA exch getu16 dup 0 gt { % idDelta add cmapf2_glyph_array exch cmapf2_ch exch put } { pop % cmapf2_glyph_array cmapf2_ch 0 put } ifelse } { % false: j is outside % cmapf2_glyph_array cmapf2_ch 0 put } ifelse } def 16#00 1 16#ff { % hi_byte scan /cmapf2_ch_hi exch def sHKs cmapf2_ch_hi sHK_sz mul getu16 /sH_offset exch def sH_gIA sH_offset sH_sz getinterval dup 0 getu16 /firstCode exch def dup 2 getu16 /entryCount exch def dup 4 gets16 /idDelta exch def dup 6 getu16 /idRangeOffset exch def pop sH_offset 0 eq { /cmapf2_ch_lo cmapf2_ch_hi def /cmapf2_ch_hi 0 def .cmapf2_putGID } { 16#00 1 16#ff { % lo_byte scan /cmapf2_ch_lo exch def .cmapf2_putGID } for } ifelse } for pop 0 1 cmapf2_glyph_array length 1 sub { % rewrite null -> 0. dup cmapf2_glyph_array exch get null eq { cmapf2_glyph_array exch 0 put } {pop} ifelse } for cmapf2_glyph_array } bind 4 { % Microsoft/Adobe segmented mapping. /etab exch def /nseg2 etab 6 getu16 def 14 /endc etab 2 index nseg2 getinterval def % The Apple TrueType documentation omits the 2-byte % 'reserved pad' that follows the endCount vector! 2 add nseg2 add /startc etab 2 index nseg2 getinterval def nseg2 add /iddelta etab 2 index nseg2 getinterval def nseg2 add /idroff etab 2 index nseg2 getinterval def % The following hack allows us to properly handle % idiosyncratic fonts that start at 0xf000: pop /firstcode startc 0 getu16 16#ff00 and dup 16#f000 ne { pop 0 } if def /putglyph { glyphs code 3 -1 roll put /code code 1 add def } bind def % Do a first pass to compute the size of the glyphs array. /numcodes 0 def /glyphs 0 0 2 nseg2 3 sub { % Stack: /glyphs numglyphs i2 /i2 exch def /scode startc i2 getu16 def /ecode endc i2 getu16 def numcodes scode firstcode sub % Hack for fonts that have only 0x0000 and 0xf000 ranges %dup 16#e000 ge { 255 and } if % the previous line is obstructive to CJK fonts, so it was removed exch sub 0 .max ecode scode sub 1 add add exch 1 index add exch numcodes add /numcodes exch def } for array def % prefill the array with 0's faster than a { 0 putglyph } repeat glyphs length 1024 ge { .array1024z 0 1024 glyphs length 1023 sub { glyphs exch 2 index putinterval } for glyphs dup length 1024 sub 3 -1 roll putinterval } { 0 1 glyphs length 1 sub { glyphs exch 0 put } for } ifelse % Now fill in the array. /numcodes 0 def /code 0 def 0 2 nseg2 3 sub { /i2 exch def /scode startc i2 getu16 def /ecode endc i2 getu16 def numcodes scode firstcode sub % Hack for fonts that have only 0x0000 and 0xf000 ranges %dup 16#e000 ge { 255 and } if % the previous line is obstructive to CJK fonts, so it was removed exch sub 0 .max dup /code exch code exch add def ecode scode sub 1 add add numcodes add /numcodes exch def /delta iddelta i2 gets16 def TTFDEBUG { (scode=) print scode =only ( ecode=) print ecode =only ( delta=) print delta =only ( droff=) print idroff i2 getu16 = } if idroff i2 getu16 dup 0 eq { pop scode delta add 65535 and 1 ecode delta add 65535 and { putglyph } for } { % The +2 is for the 'reserved pad'. /gloff exch 14 nseg2 3 mul add 2 add i2 add add def 0 1 ecode scode sub { 2 mul gloff add etab exch getu16 dup 0 ne { delta add 65535 and } if putglyph } for } ifelse } for glyphs /glyphs null def % for GC } bind 6 { % Single interval lookup. dup 6 getu16 /firstcode exch def dup 8 getu16 /ng exch def firstcode ng add array % Stack: tab array % Fill elements 0 .. firstcode-1 with 0 0 1 firstcode 1 sub { 2 copy 0 put pop } for dup firstcode ng getinterval % Stack: tab array subarray % Fill elements firstcode .. firstcode+nvalue-1 with glyph values 0 1 ng 1 sub { dup 2 mul 10 add 4 index exch getu16 3 copy put pop pop } for pop exch pop } bind .dicttomark readonly def % cmapformats % <cmaptab> cmaparray <glypharray> /cmaparray { dup 0 getu16 cmapformats exch .knownget { TTFDEBUG { (cmap: format ) print 1 index 0 getu16 = flush } if exec } { (Can't handle format ) print 0 getu16 = flush 0 1 255 { } for 256 packedarray } ifelse TTFDEBUG { (cmap: length=) print dup length = dup == } if } bind def /get_from_stringarray % <array|string> <offset> get_from_stringarray <int> { 1 index type /stringtype eq { get } { exch { % o () 2 copy length gt { length sub } { exch get exit } ifelse } forall } ifelse } bind def /getinterval_from_stringarray % <array|string> <offset> <length> getinterval_from_stringarray <string> { % May allocate a string in VM. 2 index type /stringtype eq { getinterval } { string exch 0 % [] s o p 4 3 roll { % s o p Si dup length % s o p Si lSi dup 4 index lt { 3 index exch sub % s o p Si o' exch pop 3 1 roll exch pop % s o' p } { % s o p Si lSi dup 3 1 roll % s o p lSi Si lSi 4 index sub % s o p lSi Si lSi-o 5 index length 4 index sub % s o p lSi Si lSi-o ls-p 2 copy gt { exch } if pop % s o p lSi Si minl dup 3 1 roll % s o p lSi minl Si minl 5 index exch getinterval % s o p lSi minl from 5 index 4 index 3 index % s o p lSi minl from s p minl getinterval % s o p lSi minl from to copy pop % s o p lSi minl 3 1 roll % s o minl p lSi sub % s o minl p' 3 1 roll add % s p' o' dup 3 index length ge { exch exit % s o p' } if exch % s o' p' } ifelse } forall