]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/ghostscript/gs_ttf.ps
merge
[plan9front.git] / sys / lib / ghostscript / gs_ttf.ps
1 %    Copyright (C) 1996-2003 artofcode LLC.  All rights reserved.
2
3 % This software is provided AS-IS with no warranty, either express or
4 % implied.
5
6 % This software is distributed under license and may not be copied,
7 % modified or distributed except as expressly authorized under the terms
8 % of the license contained in the file LICENSE in this distribution.
9
10 % For more information about licensing, please refer to
11 % http://www.ghostscript.com/licensing/. For information on
12 % commercial licensing, go to http://www.artifex.com/licensing/ or
13 % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 % San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
16 % $Id: gs_ttf.ps,v 1.48 2005/09/22 16:11:37 ray Exp $
17 % Support code for direct use of TrueType fonts.
18 % (Not needed for Type 42 fonts.)
19
20 % Note that if you want to use this file without including the ttfont.dev
21 % option when you built Ghostscript, you will need to load the following
22 % files before this one:
23 %       lib/gs_mgl_e.ps
24 %       lib/gs_mro_e.ps
25 %       lib/gs_wan_e.ps
26
27 % Thanks to B. Jackowski and GUST (the Polish TeX Users' Group) for
28 % the glyf-splitting code.
29
30 % ---------------- Font loading machinery ---------------- %
31
32 % Augment the FONTPATH machinery so it recognizes TrueType fonts.
33
34 /.scanfontheaders where {
35   pop /.scanfontheaders [
36    .scanfontheaders aload pop (\000\001\000\000*) (true*)
37   ] def
38 } if
39
40 % <file> <key> .findfontvalue <value> true
41 % <file> <key> .findfontvalue false
42 % Closes the file in either case.
43 /.findnonttfontvalue /.findfontvalue load def
44 /.findfontvalue {
45   1 index read {
46     2 index 1 index unread
47     % beginning with binary 0 or 't' (TrueType), or 'O' (OpenType)
48     dup 0 eq 1 index (O) 0 get eq or exch (t) 0 get eq or {
49                 % If this is a font at all, it's a TrueType font.
50       dup /FontType eq {
51         pop closefile 42 true
52       } {
53         dup /FontName eq { pop .findttfontname } { pop closefile false } ifelse
54       } ifelse
55     } {
56                 % Not a TrueType font.
57       .findnonttfontvalue
58     } ifelse
59   } { pop closefile false } ifelse
60 } bind def
61
62 % <file> .findttfontname <fname> true
63 % <file> .findttfontname false
64 % Closes the file in either case.
65 /.findttfontname {
66   //true 0 .loadttfonttables
67   tabdict /name .knownget {
68     dup 8 getu32 f exch setfileposition
69     12 getu32 string f exch readstring pop
70     6 findname
71   } {
72     false
73   } ifelse
74   f closefile end end
75 } bind def
76
77 % Load a font file that might be a TrueType font.
78
79 % <file> .loadfontfile -
80 /.loadnonttfontfile /.loadfontfile load def
81 /.loadfontfile {
82   dup read pop 2 copy unread 0 eq {
83                 % If this is a font at all, it's a TrueType font.
84     .loadttfont pop
85   } {
86                 % Not a TrueType font.
87     .loadnonttfontfile
88   } ifelse
89 } bind def
90
91 % ---------------- Automatic Type 42 generation ---------------- %
92
93 % Load a TrueType font from a file as a Type 42 PostScript font.
94 % The thing that makes this really messy is the handling of encodings.
95 % There are 2 interacting tables that affect the encoding:
96 %       'cmap' provides multiple maps from character codes to glyph indices
97 %       'post' maps glyph indices to glyph names (if present)
98 % What we need to get out of this is:
99 %       Encoding mapping character codes to glyph names
100 %         (the composition of cmap and post)
101 %       CharStrings mapping glyph names to glyph indices
102 %         (the inverse of post)
103 % If the post table is missing, we have to take a guess based on the cmap
104 % table.
105
106 /.loadttfontdict 50 dict dup begin
107
108 /orgXUID AladdinEnterprisesXUID def
109 /maxstring 32764 def    % half the maximum length of a PostScript string,
110                         % must be a multiple of 4 (for hmtx / loca / vmtx)
111
112 /.invert_encoding   % <array> invert_encoding <dict>
113 { dup 256 dict exch
114   0 exch 1 exch length 1 sub {     % [] <> i
115     dup 3 index exch get           % [] <> i v
116     dup /.notdef ne {
117       exch 2 index 2 index .knownget {
118         dup type /arraytype eq {
119         [ exch aload pop counttomark 2 add -1 roll ]
120         } {
121         exch 2 array astore
122         } ifelse
123       } if 2 index 3 1 roll put
124     } {
125       pop pop
126     } ifelse
127   } for
128   exch pop
129 } bind def
130
131 % Define the Macintosh standard mapping from characters to glyph indices.
132 /MacRomanEncoding dup .findencoding def
133 /MacGlyphEncoding dup .findencoding def
134
135 % Invert the MacRomanEncoding.
136 /.romanmacdict MacRomanEncoding .invert_encoding def
137
138 % Define remapping for misnamed glyphs in TrueType 'post' tables.
139 % There are probably a lot more than this!
140 /postremap mark
141   /Cdot /Cdotaccent
142   /Edot /Edotaccent
143   /Eoverdot /Edotaccent
144   /Gdot /Gdotaccent
145   /Ldot /Ldotaccent
146   /Zdot /Zdotaccent
147   /cdot /cdotaccent 
148   /edot /edotaccent 
149   /eoverdot /edotaccent
150   /gdot /gdotaccent 
151   /ldot /ldotaccent
152   /zdot /zdotaccent 
153 .dicttomark readonly def
154
155 % Array used for fast pre-filling of cmap array
156 /.array1024z [ 1024 { 0 } repeat ] def
157
158 % ---- Utilities ---- %
159
160 % Define a serial number for creating unique XUIDs for TrueType fonts.
161 % We used to use the checkSumAdjustment value from the font, but this is
162 % not reliable, since some fonts don't set it correctly.
163 % Note that we must do this in a string to make it immune to save/restore.
164 /xuidstring <80000000> def
165 /curxuid {              % - curxuid <int>
166   0 xuidstring { exch 8 bitshift exch add } forall
167 } bind def
168 /nextxuid {             % - nextxuid -
169   3 -1 0 {
170     xuidstring 1 index 2 copy get dup 255 ne {
171       1 add put pop exit
172     } if pop 0 put pop
173   } for
174 } bind def
175
176 % <string> <index> getu16 <integer>
177 /getu16 {
178   2 copy get 8 bitshift 3 1 roll 1 add get add
179 } bind def
180
181 % <string> <index> gets16 <integer>
182 /gets16 {
183   getu16 16#8000 xor 16#8000 sub
184 } bind def
185
186 % <string> <index> getu32 <integer>
187 /getu32 {
188   2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add
189 } bind def
190
191 % <string> <index> gets32 <integer>
192 /gets32 {
193   2 copy gets16 16 bitshift 3 1 roll 2 add getu16 add
194 } bind def
195
196 16#ffffffff 0 gt {  % 64-bit sign extension
197   { /curxuid /gets32 } {
198     mark 1 index load aload pop { 16#80000000 xor 16#80000000 sub } aload pop
199     .packtomark cvx def
200   } bind forall
201 } if
202
203 % <string> <index> <integer> putu16 -
204 /putu16 {
205   3 copy -8 bitshift put
206   exch 1 add exch 16#ff and put
207 } bind def
208
209 % <string> <index> <integer> putu32 -
210 /putu32 {
211   3 copy -16 bitshift putu16
212   exch 2 add exch 16#ffff and putu16
213 } bind def
214
215 % <nametable> <nameid> findname <string> true
216 % <nametable> <nameid> findname false
217 /findname {
218   TTFDEBUG { (findname: ) print dup =only  } if
219   false 3 1 roll
220   1 index length 0 gt { % check for zero length name table 
221     0 1 3 index 2 getu16 1 sub {
222                 % Stack: false table id index
223       12 mul 6 add 2 index exch 12 getinterval
224       dup 6 getu16 2 index eq {
225                   % We found the name we want.
226         exch pop
227                   % Stack: false table record
228         dup 10 getu16 2 index 4 getu16 add
229         1 index 8 getu16 4 -1 roll 3 1 roll
230             3 copy add 1 index length
231             le {
232               pop
233               getinterval exch
234                   % Stack: false string record
235                   % Check for 8- vs. 16-bit characters.
236           is2byte { string2to1 } if true null 4 -1 roll exit
237             } {
238               pop pop pop pop
239               false
240                   exit
241             } ifelse
242       } if pop
243     } for
244   } if
245   pop pop
246   TTFDEBUG {
247     dup { ( = ) print 1 index == } { ( not found) = } ifelse
248   } if
249 } bind def
250
251 % <namerecord> is2byte <bool>
252 /is2byte {
253   dup 0 getu16 {
254     { pop true }                % Apple Unicode
255     { pop false }               % Macintosh Script manager
256     { 1 getu16 1 eq }           % ISO
257     { 1 getu16 1 eq }           % Microsoft
258   } exch get exec
259 } bind def
260
261 % <string2> string2to1 <string>
262 /string2to1 {
263   dup length 2 idiv string dup
264   0 1 3 index length 1 sub {
265     3 index 1 index 2 mul 1 add get put dup
266   } for pop exch pop
267 } bind def
268
269 % Each procedure in this dictionary is called as follows:
270 %       <encodingtable> proc <glypharray>
271 /cmapformats mark
272   0 {           % Apple standard 1-to-1 mapping.
273     6 256 getinterval { } forall 256 packedarray
274   } bind
275   2 {           % Apple 16bit CJK (ShiftJIS etc)
276
277     % /sHK_sz           subHeaderKey_size       % 1 * uint16
278     % /sH_sz            subHeader_size          % 4 * uint16
279     % /sH_len           subHeader_length
280     % /cmapf2_tblen     total table length
281     % /cmapf2_lang      language code (not used)
282     % /sHKs             subHeaderKeys
283
284     /sHK_sz 2 def
285     /sH_sz 8 def
286     dup 2 getu16 /cmapf2_tblen exch def
287
288     dup 4 getu16 /cmapf2_lang exch def
289
290     dup 6 256 sHK_sz mul getinterval /sHKs exch def
291
292     0           % initialization value for /sH_len
293     0 1 255 {
294        sHKs exch
295        2 mul getu16
296        1 index  % get current max
297        1 index  % get current subHeaderKey
298        lt {exch} if pop
299     } for
300     /sH_len exch def
301
302     dup 6 256 sHK_sz mul add
303     cmapf2_tblen 1 index sub getinterval
304     /sH_gIA exch def
305
306     /cmapf2_glyph_array 65535 array def
307
308     /.cmapf2_putGID {
309         /cmapf2_ch cmapf2_ch_hi 8 bitshift cmapf2_ch_lo add def
310         firstCode cmapf2_ch_lo le
311         cmapf2_ch_lo firstCode entryCount add lt
312         and { % true: j is inside
313             sH_offset idRangeOffset add         % offset to gI
314             cmapf2_ch_lo firstCode sub 2 mul    % rel. pos. in range
315             add 6 add                           % offset in sH_gIA
316             sH_gIA exch getu16
317             dup 0 gt { %
318                 idDelta add
319                 cmapf2_glyph_array exch cmapf2_ch exch put
320             } {
321                 pop
322                 % cmapf2_glyph_array cmapf2_ch 0 put
323             } ifelse
324         } {   % false: j is outside
325             % cmapf2_glyph_array cmapf2_ch 0 put
326         } ifelse
327     } def
328
329     16#00 1 16#ff { % hi_byte scan
330         /cmapf2_ch_hi exch def
331         sHKs cmapf2_ch_hi sHK_sz mul getu16
332         /sH_offset exch def
333         sH_gIA sH_offset sH_sz getinterval
334             dup 0 getu16 /firstCode exch def
335             dup 2 getu16 /entryCount exch def
336             dup 4 gets16 /idDelta exch def
337             dup 6 getu16 /idRangeOffset exch def
338         pop
339         sH_offset 0 eq {
340            /cmapf2_ch_lo cmapf2_ch_hi def
341            /cmapf2_ch_hi 0 def
342            .cmapf2_putGID
343         } {
344            16#00 1 16#ff { % lo_byte scan
345                /cmapf2_ch_lo exch def
346                .cmapf2_putGID
347            } for
348         } ifelse
349      } for
350      pop
351      0 1 cmapf2_glyph_array length 1 sub { % rewrite null -> 0.
352         dup cmapf2_glyph_array exch get
353         null eq { cmapf2_glyph_array exch 0 put } {pop} ifelse
354      } for
355      cmapf2_glyph_array
356   } bind
357   4 {           % Microsoft/Adobe segmented mapping.
358     /etab exch def
359     /nseg2 etab 6 getu16 def
360     14 /endc etab 2 index nseg2 getinterval def
361                 % The Apple TrueType documentation omits the 2-byte
362                 % 'reserved pad' that follows the endCount vector!
363     2 add
364     nseg2 add /startc etab 2 index nseg2 getinterval def
365     nseg2 add /iddelta etab 2 index nseg2 getinterval def
366     nseg2 add /idroff etab 2 index nseg2 getinterval def
367                 % The following hack allows us to properly handle
368                 % idiosyncratic fonts that start at 0xf000:
369     pop
370     /firstcode startc 0 getu16 16#ff00 and dup 16#f000 ne { pop 0 } if def
371     /putglyph {
372       glyphs code 3 -1 roll put /code code 1 add def
373     } bind def
374                 % Do a first pass to compute the size of the glyphs array.
375     /numcodes 0 def /glyphs 0 0 2 nseg2 3 sub {
376                 % Stack: /glyphs numglyphs i2
377       /i2 exch def
378       /scode startc i2 getu16 def
379       /ecode endc i2 getu16 def
380       numcodes scode firstcode sub
381                 % Hack for fonts that have only 0x0000 and 0xf000 ranges
382       %dup 16#e000 ge { 255 and } if
383       % the previous line is obstructive to CJK fonts, so it was removed
384       exch sub 0 .max ecode scode sub 1 add add
385       exch 1 index add exch
386       numcodes add /numcodes exch def
387     } for array def
388     % prefill the array with 0's faster than a { 0 putglyph } repeat
389     glyphs length 1024 ge {
390       .array1024z 0 1024 glyphs length 1023 sub { glyphs exch 2 index putinterval } for
391       glyphs dup length 1024 sub 3 -1 roll
392       putinterval
393     } {
394       0 1 glyphs length 1 sub { glyphs exch 0 put } for
395     } ifelse
396                 % Now fill in the array.
397     /numcodes 0 def /code 0 def
398     0 2 nseg2 3 sub {
399       /i2 exch def
400       /scode startc i2 getu16 def
401       /ecode endc i2 getu16 def
402       numcodes scode firstcode sub
403                 % Hack for fonts that have only 0x0000 and 0xf000 ranges
404       %dup 16#e000 ge { 255 and } if
405       % the previous line is obstructive to CJK fonts, so it was removed
406       exch sub 0 .max dup /code exch code exch add def
407       ecode scode sub 1 add add numcodes add /numcodes exch def
408       /delta iddelta i2 gets16 def
409       TTFDEBUG {
410         (scode=) print scode =only
411         ( ecode=) print ecode =only
412         ( delta=) print delta =only
413         ( droff=) print idroff i2 getu16 =
414       } if
415       idroff i2 getu16 dup 0 eq {
416         pop scode delta add 65535 and 1 ecode delta add 65535 and
417         { putglyph } for
418       } {       % The +2 is for the 'reserved pad'.
419         /gloff exch 14 nseg2 3 mul add 2 add i2 add add def
420         0 1 ecode scode sub {
421           2 mul gloff add etab exch getu16
422           dup 0 ne { delta add 65535 and } if putglyph
423         } for
424       } ifelse
425     } for glyphs /glyphs null def       % for GC
426   } bind
427   6 {           % Single interval lookup.
428     dup 6 getu16 /firstcode exch def dup 8 getu16 /ng exch def
429     firstcode ng add array
430                 % Stack: tab array
431                 % Fill elements 0 .. firstcode-1 with 0
432     0 1 firstcode 1 sub { 2 copy 0 put pop } for
433     dup firstcode ng getinterval
434                 % Stack: tab array subarray
435                 % Fill elements firstcode .. firstcode+nvalue-1 with glyph values
436     0 1 ng 1 sub {
437       dup 2 mul 10 add 4 index exch getu16 3 copy put pop pop
438     } for pop exch pop
439   } bind
440 .dicttomark readonly def                % cmapformats
441
442 % <cmaptab> cmaparray <glypharray>
443 /cmaparray {
444   dup 0 getu16 cmapformats exch .knownget {
445     TTFDEBUG {
446       (cmap: format ) print 1 index 0 getu16 = flush
447     } if exec
448   } {
449     (Can't handle format ) print 0 getu16 = flush
450     0 1 255 { } for 256 packedarray
451   } ifelse
452   TTFDEBUG {
453     (cmap: length=) print dup length = dup ==
454   } if
455 } bind def
456
457 /get_from_stringarray % <array|string> <offset> get_from_stringarray <int>
458 { 1 index type /stringtype eq {
459     get
460   } {
461     exch {                % o ()
462       2 copy length gt {
463         length sub
464       } {
465         exch get exit
466       } ifelse
467     } forall
468   } ifelse
469 } bind def
470
471 /getinterval_from_stringarray % <array|string> <offset> <length> getinterval_from_stringarray <string>
472 { % May allocate a string in VM.
473   2 index type /stringtype eq {
474     getinterval
475   } {
476     string exch 0                                 % [] s o p
477     4 3 roll {                                    % s o p Si
478       dup length                                  % s o p Si lSi
479       dup 4 index lt {
480         3 index exch sub                          % s o p Si o'
481         exch pop 3 1 roll exch pop                % s o' p
482       } {                                         % s o p Si lSi
483         dup 3 1 roll                              % s o p lSi Si lSi
484         4 index sub                               % s o p lSi Si lSi-o
485         5 index length 4 index sub                % s o p lSi Si lSi-o ls-p
486         2 copy gt { exch } if pop                 % s o p lSi Si minl
487         dup 3 1 roll                              % s o p lSi minl Si minl
488         5 index exch getinterval                  % s o p lSi minl from
489         5 index 4 index 3 index                   % s o p lSi minl from s p minl
490         getinterval                               % s o p lSi minl from to
491         copy pop                                  % s o p lSi minl
492         3 1 roll                                  % s o minl p lSi
493         sub                                       % s o minl p'
494         3 1 roll add                              % s p' o'
495         dup 3 index length ge {
496           exch exit                               % s o p'
497         } if
498         exch                                      % s o' p'
499       } ifelse
500     } forall
501     pop pop                                       % s
502   } ifelse
503 } bind def
504
505 /string_array_size  % <array|string> string_array_size <int>
506 { dup type /stringtype eq {
507     length
508   } { 
509     0 exch { length add } forall
510   } ifelse
511 } bind def
512
513 % Each procedure in this dictionary is called as follows:
514 %       posttable <<proc>> glyphencoding
515 /postformats mark
516   16#00010000  {        % 258 standard Macintosh glyphs.
517     pop MacGlyphEncoding
518   }
519   16#00020000  {        % Detailed map, required by Microsoft fonts.
520     dup dup type /arraytype  eq { 0 get } if length 36 lt {
521       TTFDEBUG { (post format 2.0 invalid.) = flush } if
522       pop [ ]
523     } {
524       /postglyphs exch def
525       /post_first postglyphs dup type /arraytype eq { 0 get } if def
526       post_first 32 getu16 /numglyphs exch def
527       /glyphnames numglyphs 2 mul 34 add def
528       % Build names array in the order they occur in the 'post' table
529       /postpos glyphnames def
530       /total_length postglyphs //string_array_size exec def
531       [ numglyphs 1 sub {
532         postpos total_length ge { exit } if
533         % No name available, /postnames will be defined as an empty
534         % array and the glyph won't get a name attached.
535         postglyphs postpos //get_from_stringarray exec
536         postglyphs postpos 1 add 2 index //getinterval_from_stringarray exec cvn
537         exch postpos add 1 add /postpos exch def
538       } repeat
539       ] /postnames exch def
540       [ 0 1 numglyphs 1 sub {
541         2 mul 34 add post_first exch getu16
542         dup 258 lt {
543           MacGlyphEncoding exch get
544         } {
545           dup 32768 ge {
546                 % According to the published TrueType spec, such values are
547                 % "reserved for future use", but at least some PDF files
548                 % produced by the Adobe PDF library contain entries with a
549                 % value of 16#ffff.
550             pop /.notdef
551           } {
552             % Get the name for this glyph
553             258 sub dup postnames length ge {
554               TTFDEBUG { (   *** warning: glyph index past end of 'post' table) = flush } if
555               exit
556             } if
557             postnames exch get
558             % At least some of Microsoft's TrueType fonts use incorrect
559             % (Adobe-incompatible) names for some glyphs.
560             % Correct for this here.
561             postremap 1 index .knownget { exch pop } if
562           } ifelse
563         } ifelse
564       } for ] 
565     }
566     ifelse
567   } bind
568   16#00030000  {        % No map.
569     pop [ ]
570   } bind
571 .dicttomark readonly def                % postformats
572
573 /call.readtable
574 { .readtable
575 } bind def
576 /call.readbigtable
577 { .readbigtable
578 } bind def
579
580 % Each procedure in this dictionary is called as follows:
581 %       <file> <length> -proc- <string|array_of_strings>
582 % Note that each table must have an even length, because of a strange
583 % Adobe requirement that each sfnts entry have even length.
584 /readtables mark
585         % Ordinary tables
586   (cmap) //call.readtable
587   (head) 1 index
588   (hhea) 1 index
589   (maxp) 1 index
590   (name) 1 index
591   (OS/2) 1 index
592   (post) //call.readbigtable
593   (vhea) //call.readtable
594         % Big tables
595   (glyf) //call.readbigtable
596   (loca) 1 index
597   (hmtx) 1 index
598   (vmtx) 1 index
599         % Tables only needed for embedding in PDF files
600   (cvt ) //call.readtable
601   (fpgm) 1 index
602   (prep) 1 index
603 .dicttomark
604 % Normally there would be a 'readonly' here, but the ttf2pf utility wants
605 % to include the 'kern' table as well, so we leave the readtables dictionary
606 % writable.
607 def                % readtables
608
609 /readtables_stripped readtables dup length dict copy
610 dup (loca) { .skiptable } put
611 dup (glyf) { .skiptable } put
612 def
613
614 % Read a table as a single string.
615 % <file> <length> .skiptable <string>
616 /.skiptable {
617   pop pop ()
618 } bind def
619
620 % Read a table as a single string.
621 % <file> <length> .readtable <string>
622 /.readtable {
623   dup dup 1 and add string
624                 % Stack: f len str
625   dup 0 4 -1 roll getinterval
626                 % Stack: f str str1
627         % Because of the absurd PostScript specification that gives an
628         % error for reading into an empty string, we have to check for
629         % this explicitly here.
630   3 -1 roll exch
631   dup () ne { readstring } if pop pop
632 } bind def
633
634 % Read a big table (one that may exceed 64K).
635 % <file> <length> .readbigtable <string[s]>
636 /.readbigtable {
637   dup 65400 lt {
638     .readtable
639   } {
640     currentuserparams /VMReclaim get -2 vmreclaim
641     [ 4 2 roll {
642                 % Stack: mark ... f left
643       dup maxstring le { exit } if
644       1 index maxstring string readstring pop 3 1 roll maxstring sub
645     } loop .readtable ]
646     exch vmreclaim
647   } ifelse
648 } bind def
649
650 end readonly def                % .loadttfontdict
651
652 % <tab> .printtab -
653 /.printtab {
654   dup 0 4 getinterval print ( ) print
655   dup 8 getu32 =only ( ) print
656   12 getu32 =
657 } bind def
658
659 % <file> <bool> <SubfontID> .loadttfonttables -
660 % Pushes .loadttfontdict & scratch dict on d-stack.
661 % Defines f, offsets, tables, tabdict, tabs.
662 % Skips loca and glyf if <bool> is true.
663 /.loadttfonttables {
664   .loadttfontdict begin
665   40 dict begin
666   /SubfontID exch def
667   /load_stripped exch def
668   /f exch def
669   /offsets f 12 string readstring pop def
670   load_stripped { readtables_stripped } { readtables } ifelse /readtables_ exch def
671   offsets 0 4 getinterval (ttcf) eq {
672     % We need to handle TT collections with disk fonts only.
673     % Therefore the file is a disk file and it can be positioned.
674     offsets 8 getu32 /num_fonts exch def
675     SubfontID num_fonts ge {
676       QUIET not { (True Type collection contains insufficient fonts.) = } if
677       /.loadttfonttables cvx /invalidfont signalerror
678     } if
679     SubfontID 4 mul 12 add f exch setfileposition
680     f 4 string readstring pop 0
681     getu32 /ttc_offset exch def
682     f ttc_offset setfileposition
683     /offsets f 12 string readstring pop def
684   } {
685     SubfontID 0 gt {
686       QUIET not { (SubfontID > 0 with a True Type file which is not a collection.) = } if
687       /.loadttfonttables cvx /invalidfont signalerror
688     } if
689     /ttc_offset 0 def
690   } ifelse
691   /tables f offsets 4 getu16 16 mul string readstring pop def
692   /tabdict tables length 16 idiv dict def
693         % tabs = tables we want to keep, sorted by file position.
694   /tabs [ 0 16 tables length 1 sub {
695     tables exch 16 getinterval
696     TTFDEBUG { dup .printtab } if
697     dup 0 4 getinterval readtables_ 1 index known {
698       % put all 0 length tables at 0 to avoid overlap
699       1 index 12 getu32 0 eq { 1 index 8 0 putu32 } if
700       tabdict exch 2 index put
701     } {
702       pop pop
703     } ifelse
704   } for ] {
705     exch 8 getu32 exch 8 getu32 lt
706   } .sort def
707         % In certain malformed TrueType fonts, tables overlap.
708         % Truncate tables if necessary.
709   0 1 tabs length 2 sub {
710     dup tabs exch get exch 1 add tabs exch get
711     1 index 8 getu32 2 index 12 getu32 add
712     1 index 8 getu32 gt {
713       (**** Warning: ) print 1 index 0 4 getinterval print
714       ( overlaps ) print dup 0 4 getinterval print
715       (, truncating.) = flush
716       dup 8 getu32 2 index 8 getu32 sub
717       2 index 12 3 -1 roll putu32
718     } if pop pop
719   } for
720 } bind def
721
722 /.file_table_pos_names
723 mark
724 /glyf 0
725 /loca 0
726 .dicttomark readonly def
727
728 % - .readttdata -
729 % Read data.  Updates offsets, tabs; stores data in tabdict.
730 /.readttdata {
731   /file_table_pos 10 dict def
732   /fpos offsets length tables length add ttc_offset add def
733   /sfpos offsets length tabs length 16 mul add def
734   offsets 4 tabs length putu16
735   tabs {
736     dup 0 4 getinterval /tname exch def
737     dup 8 getu32 /tpos exch def
738     dup 12 getu32 /tlen exch def
739     load_stripped //.file_table_pos_names tname known and {
740         pop
741         file_table_pos tname [tpos tlen] put
742         tabdict tname () put
743     } {
744       8 sfpos putu32
745         % Skip data between the end of the previous table and
746         % the beginning of this one, if any.
747       tpos fpos gt {
748         load_stripped {
749           % 'setfileposition' is faster for skipping a big data.
750           f tpos setfileposition
751         } {
752           f tpos fpos sub () /SubFileDecode filter dup flushfile closefile
753           /fpos tpos def
754         } ifelse
755       } if
756       f tlen readtables_ tname get exec
757       tabdict tname 3 -1 roll put
758         % Round up the table length to an even value.
759       /sfpos sfpos tlen dup 1 and add add def
760     } ifelse
761     /fpos fpos tlen add def
762   } forall
763 } bind def
764
765 % Find the string in a list of strings that includes a given index.
766 % <strings> <index> .findseg <string> <index'>
767 /.findseg {
768   exch {
769     dup length 2 index gt { exch exit } if
770     length sub
771   } forall
772 } bind def
773
774 % - .makesfnts -
775 % Defines checksum, getloca, head, locatable, numloca, post, sfnts, upem
776 % Note that the 'loca' table may be out of order. This is handled when
777 % needed in .dividesfnts
778 /.makesfnts {
779   .readttdata
780   /head tabdict /head get def
781   /post tabdict /post .knownget { 
782     dup 0 get /post_first_part exch def 
783   } { 
784     null 
785   } ifelse def
786   load_stripped not {
787     /locatable tabdict /loca get def
788     /numloca
789       locatable dup type /stringtype eq
790        { length }
791        { 0 exch { length add } forall }
792       ifelse    % no def yet
793     locatable type /stringtype eq {
794       /.indexloca {} def
795     } {
796       /.indexloca /.findseg load def
797     } ifelse
798     head 50 getu16 0 ne {
799       /getloca {
800         2 bitshift locatable exch .indexloca getu32
801       } def
802       4 idiv 1 sub
803     } {
804       /getloca {
805         dup add locatable exch .indexloca getu16 dup add
806       } def
807       2 idiv 1 sub
808     } ifelse def                % numloca
809         % If necessary, re-partition the glyfs.
810     tabdict /glyf get dup type /stringtype ne {
811       .dividesfnts tabdict /glyf 3 -1 roll put
812     } {
813       pop
814     } ifelse
815   } {
816     % We did not load loca, take the number of glyphs from maxp.
817     /numloca tabdict /maxp get 4 getu16 def
818   } ifelse
819   /sfnts [
820     offsets tabs { concatstrings } forall
821     tabs {
822       0 4 getinterval tabdict exch get
823       dup type /stringtype ne { aload pop } if
824     } forall
825   ] def
826 } bind def
827
828 % <glyfs> .dividesfnts <glyfs'>
829 /.dividesfnts {
830   /glyfs exch def
831   /len1 0 glyfs { length add } forall def
832         % Determine where to split the glyfs by scanning the sorted locatable
833         % The very last entry in loca may be bogus.
834         % Note that some loca entries may be odd, but we can only
835         % split at even positions.
836         %
837         % Construct splitarray, the array of final lengths of
838         % the sfnts entries covering the glyfs (i.e., all but
839         % the first and last sfnts entries).
840     /prevsplit 0 def
841     /prevboundary 0 def
842     % sort the locatable in case it is out of order
843     % Note the 'loca' table remains unchanged
844     /needsort false def
845     numloca array       % the array of 'loca' entries (may be out of order)
846     -1  % initial values for in order check
847     0 1 numloca 1 sub {
848       dup getloca dup
849       4 -1 roll lt { /needsort true def } if 
850       3 copy put exch pop
851     } for pop           % discard inorder check value
852     needsort {
853       { lt } bind .sort  % stack: locatable_array
854     } if
855     /splitarray [
856       3 -1 roll 0 1 numloca 1 sub {
857         % stack: /splitarray -mark- { splitlen splitlen ... } locatable_array index
858         1 index exch get dup prevsplit maxstring add gt {
859           prevboundary prevsplit sub exch
860           /prevsplit prevboundary def
861         } if
862         dup 1 and 0 eq { /prevboundary exch def } { pop } ifelse
863         dup type /arraytype ne { exch } if      % keep locatable_array on top
864       } for
865       len1 prevsplit sub
866       exch pop          % discard locatable_array
867     ] def
868     currentuserparams /VMReclaim get -2 vmreclaim
869     [
870         % Re-split the sfnts glyfs strings according to splitarray.
871         % We do this by iterating over the final segments defined
872         % by splitarray, and constructing them from pieces of the
873         % current glyfs strings.  We recycle the current strings
874         % when possible, to avoid stressing the allocator.
875       /sfnt_idx 0 def
876       /strpos 0 def
877       /avail () def
878       splitarray {
879         /seglen exch def
880         /segpos 0 def
881         avail length seglen ge
882           { avail 0 seglen getinterval /avail () def } { seglen string }
883         ifelse
884         {
885           /str glyfs sfnt_idx get def
886           /strlen str length def
887           /strleft strlen strpos sub def
888           seglen segpos sub strleft lt { exit } if
889                 % Copy the (rest of the) string into the new segment.
890                 % We know strleft <= segleft.
891           dup segpos str strpos strleft getinterval putinterval
892           /segpos segpos strleft add def
893           /avail str def
894           /sfnt_idx sfnt_idx 1 add def
895           /strpos 0 def
896           segpos seglen eq { exit } if
897         } loop
898                 % Fill up the segment with an initial piece of the next
899                 % existing glyfs string.  We know strleft > segleft.
900         /segleft seglen segpos sub def
901         dup segpos str strpos segleft getinterval putinterval
902         /strpos strpos segleft add def
903       } forall
904     ]
905     exch vmreclaim
906 } bind def
907
908 /first_post_string % - first_post_string <string>
909 {
910   post dup type /arraytype eq { 0 get } if
911 } bind def
912
913 % - .getpost -
914 % Uses post, defines glyphencoding
915 /.getpost {
916   /glyphencoding post null eq {
917     TTFDEBUG { (post missing) = flush } if [ ]
918   } {
919     postformats first_post_string 0 getu32 .knownget {
920       TTFDEBUG {
921         (post: format ) print
922         first_post_string
923         dup 0 getu16 =only (,) print 2 getu16 = flush
924       } if
925       post exch exec
926     } {
927       TTFDEBUG { (post: unknown format ) print post 0 getu32 = flush } if [ ]
928     } ifelse
929   } ifelse
930   TTFDEBUG { (post=) print dup == } if
931   def
932 } bind def
933
934 % - .ttkeys <key> <value> ...
935 /.ttkeys {
936   count /ttkeycount exch def
937   /upem head 18 getu16 def
938   /FontMatrix matrix
939   /FontBBox [ 36 2 42 { head exch gets16 upem div } for ]
940   nextxuid
941   tabdict /name .knownget {
942                 % Find the names from the 'name' table.
943     /names exch def
944     /FontName names 6 findname not { curxuid 16 8 string cvrs } if
945       /fontname 1 index def
946     /FontInfo mark
947       names 0 findname { /Notice exch } if
948       names 1 findname { /FamilyName exch } if
949       names 4 findname { /FullName exch } if
950       names 5 findname { /Version exch } if
951   } {
952                 % No name table, fabricate a FontName.
953     /FontName curxuid 16 8 string cvrs
954       /fontname 1 index def
955     /FontInfo mark
956   } ifelse
957                 % Stack: ... /FontInfo mark key1 value1 ...
958   post null ne {
959     /ItalicAngle first_post_string 4 gets32 65536.0 div
960     /isFixedPitch first_post_string 12 getu32 0 ne
961     /UnderlinePosition first_post_string 8 gets16 upem div
962     /UnderlineThickness first_post_string 10 gets16 upem div
963   } if
964   counttomark 0 ne { .dicttomark } { pop pop } ifelse
965   /XUID [orgXUID 42 curxuid]
966   TTFDEBUG {
967     tabs { .printtab } forall
968     [ sfnts { length } forall ] ==
969     count ttkeycount sub array astore dup { == } forall aload pop
970   } if
971   /sfnts sfnts
972 } bind def
973
974 % ---------------- Standard TrueType font loading ---------------- %
975
976 % - .pickcmap_with_no_xlatmap -
977 % Defines cmapsub, cmaptab
978 /.pickcmap_with_no_xlatmap {
979   tabdict /cmap get
980                 % The Apple cmap format is no help in determining the encoding.
981                 % Look for a Microsoft table.  If we can't find one,
982                 % just use the first table, whatever it is.
983   dup 4 8 getinterval exch             % the default
984   0 1 2 index 2 getu16 1 sub {
985     8 mul 4 add 1 index exch 8 getinterval
986     TTFDEBUG {
987       (cmap: platform ) print dup 0 getu16 =only
988       ( encoding ) print dup 2 getu16 = flush
989     } if
990     dup 0 getu16 3 eq { exch 3 -1 roll pop exit } if pop
991   } for
992                 % Stack: subentry table
993   /cmapsub 2 index def
994   exch 4 getu32 1 index length 1 index sub getinterval
995   /cmaptab exch def
996 } bind def
997
998 % - .pickcmap_with_xlatmap -
999 % Defines cmapsub, cmaptab
1000 /.pickcmap_with_xlatmap {
1001   .xlatmap_dict /TrueType known not {
1002     (Emulating a CID font with a True Type file, ) print
1003     (the file gs/lib/xlatmap must contain /TrueType key.) =
1004     /.pickcmap_with_xlatmap cvx /configurationerror signalerror
1005   } if
1006   false
1007   .xlatmap_dict /TrueType get 
1008   dup length 2 sub 0 exch 2 exch {                       % bool [] i
1009     2 copy get                                           % bool [] i ()
1010     (.) search {                                         % bool [] i post match pre
1011       cvi exch pop exch cvi                              % bool [] i PlatID SpecID
1012     } {
1013       (gs/lib/xlatmap containg a record with an invalid (PlatformID.SpecificID)) =
1014       /.pickcmap_with_xlatmap cvx /configurationerror signalerror
1015     } ifelse
1016     TTFDEBUG {
1017       (Seeking a cmap for platform=) print 1 index =only ( encoding=) print dup =
1018     } if
1019     tabdict /cmap get                                   % bool [] i PlatID SpecID (cmap)
1020     dup /cmaptab exch def % temporary
1021     0 1 2 index 2 getu16 1 sub {                         % bool [] i PlatID SpecID (cmap) j
1022       8 mul 4 add 1 index exch 8 getinterval             % bool [] i PlatID SpecID (cmap) (cmapsub)
1023       TTFDEBUG {
1024         (cmap: platform ) print dup 0 getu16 =only
1025         ( encoding ) print dup 2 getu16 = flush
1026       } if
1027       dup 0 getu16 4 index eq {
1028         dup 2 getu16 3 index eq {                        % bool [] i PlatID SpecID (cmap) (cmapsub)
1029           TTFDEBUG {
1030             (Choosen a cmap for platform=) print 3 index =only
1031             ( encoding=) print 2 index =
1032           } if
1033           /cmapsub 1 index def
1034           dup 4 getu32                                   % bool [] i PlatID SpecID (cmap) (cmapsub) p
1035           cmaptab length 1 index sub                     % bool [] i PlatID SpecID (cmap) (cmapsub) p l
1036           cmaptab 3 1 roll getinterval
1037           /cmaptab exch def                              % bool [] i PlatID SpecID (cmap) (cmapsub)
1038           5 index 5 index 1 add get                      % bool [] i PlatID SpecID (cmap) (cmapsub) /Decoding
1039           /Decoding exch def                             % bool [] i PlatID SpecID (cmap) (cmapsub)
1040           7 -1 roll pop true 7 1 roll                    % true [] i PlatID SpecID (cmap) (cmapsub)
1041         } if
1042       } if
1043       pop                                                % true [] i PlatID SpecID (cmap)
1044       5 index { exit } if
1045     } for                                                % bool [] i PlatID SpecID (cmap)
1046     pop pop pop pop                                      % bool []
1047     1 index { exit } if
1048   } for                                                  % bool []
1049   pop                                                    % bool
1050   not { 
1051     QUIET not { (True Type font doesn't contain a charset listed in gs/lib/xlatmap.) = } if
1052     /.pickcmap_with_xlatmap cvx /invalidfont signalerror
1053   } if                                                   %
1054 } bind def
1055
1056 % - .pickcmap -
1057 % Defines cmapsub, cmaptab
1058 /.pickcmap {
1059   % Currently we use xlatmap only for emulation CIDFontType 2 with
1060   % a disk True Type font files, and use load_stripped
1061   % to check this regime. We would like to do so
1062   % while emulating a Type 42, but first the old code
1063   % about handling them to be changed 
1064   % with adding a handling of a Decoding.
1065   % fixme : A correct way to fix this is to implenent 
1066   % the Type 42 emulation with gs_fntem.ps .
1067   % Also note that PDF embedded fonts probably don't need a xlatmap -
1068   % see PDF spec, "Encodings for True Type fonts".
1069   load_stripped {
1070     //.pickcmap_with_xlatmap exec
1071   } {
1072     //.pickcmap_with_no_xlatmap exec
1073   } ifelse
1074 } bind def
1075
1076 % <glyph> .nname <_name>
1077 /.nname {
1078   =string cvs (_) exch concatstrings cvn
1079 } bind def
1080
1081 % - .charkeys /CharStrings <charstrings> /Encoding <encoding>
1082 % Resets glyphencoding
1083 /.charkeys {
1084   TTFDEBUG {
1085     (glyphencoding: length=) print glyphencoding dup length = === flush
1086   } if
1087                 % Hack: if there is no usable post table but the cmap uses
1088                 % the Microsoft Unicode encoding, use ISOLatin1Encoding.
1089   glyphencoding length 0 eq {
1090     cmapsub 0 4 getinterval <00030001> eq {
1091     PDFDEBUG { (No post but have cmap 3.1, so use ISOLatin1Encoding) } if
1092       /glyphencoding ISOLatin1Encoding dup length array copy def
1093     } {
1094       PDFDEBUG { (No encoding info, use .GS_extended_SymbolEncoding) } if
1095       /glyphencoding /.GS_extended_SymbolEncoding findencoding dup length array copy def
1096     } ifelse
1097   } if
1098                 % If necessary, fabricate additional glyphencoding entries
1099                 % to cover all of loca, or truncate glyphencoding.
1100   glyphencoding length numloca lt {
1101     /glyphencoding numloca array
1102       glyphencoding length dup 1 sub 0 1 3 2 roll {
1103         dup glyphencoding exch get
1104         3 index 3 1 roll put
1105       } for
1106       % /glyphencoding <newarray> <glyphencoding length>
1107       1 numloca 1 sub {
1108         1 index exch dup .nname put
1109       } for
1110     def
1111   } {
1112     /glyphencoding glyphencoding 0 numloca getinterval def
1113   } ifelse
1114                 % Some badly designed Chinese fonts have a post table
1115                 % in which all glyphs other than 0 are named .null.
1116                 % Use CharStrings to keep track of the reverse map from
1117                 % names to glyphs, and don't let any name be used for
1118                 % more than one glyph.
1119   /CharStrings glyphencoding dup length 1 add dict      % +1 for .notdef
1120     0 1 3 index length 1 sub {
1121                 % Stack: glyphencoding dict index
1122       2 index 1 index get 2 index 1 index known {
1123                 % The same name maps to more than one glyph.
1124                 % Change the name.
1125         pop dup .nname 3 index 2 index 2 index put
1126       } if
1127       2 index exch 3 -1 roll put
1128     } for exch pop
1129                 % If there is no .notdef entry, map it to glyph 0.
1130   dup /.notdef known not { dup /.notdef 0 put } if
1131   readonly
1132   /Encoding
1133     [ cmaptab cmaparray dup length 256 gt { 0 256 getinterval } if
1134     { glyphencoding exch get } forall
1135     counttomark 256 exch sub { /.notdef } repeat ]
1136   TTFDEBUG { (Encoding: ) print dup === flush } if
1137 } bind def
1138
1139 % -mark- <key> <value> ... .definettfont <font>
1140 /.definettfont {
1141   /FontType 42
1142   /PaintType 0
1143   TTFDEBUG {
1144     (numloca=) print numloca =
1145   } if
1146   .dicttomark
1147   end end dup /FontName get exch definefont
1148 } bind def
1149
1150 % <file> .loadttfont <type42font>
1151 /.loadttfont {
1152   //false 0 .loadttfonttables
1153   .makesfnts
1154   .getpost
1155   .pickcmap
1156   mark
1157   .charkeys
1158   .ttkeys
1159   .definettfont
1160 } bind def
1161
1162 % ---------------- CIDFontType 2 font loading ---------------- %
1163
1164 % Fill a string with sequential CIDs starting from the initial value.
1165 % <string> <value> .fill_identity_cmap <string>
1166 /.fill_identity_cmap {             % () v
1167   1 index length 2 sub          % () v n-2
1168   0 2 3 2 roll {                % () v 0 2 n-1
1169       3 copy exch               % () v i () i v 
1170       -8 bitshift               % () v i () i v>>8
1171       put                       % () v i
1172       3 copy 1 add              % () v i () v i+1
1173       exch 255 and              % () v i () i+1 v&255
1174       put                       % () v i 
1175       pop 1 add                 % () v+1
1176   } for
1177   pop
1178 } bind def
1179
1180 % -mark- <key> <value> ... .definettcidfont <font>
1181 /.definettcidfont {
1182   /CIDFontName fontname
1183   /CIDFontType 2
1184   /CIDSystemInfo mark
1185     /Registry (Adobe)
1186     /Ordering (Japan1)          % adhoc
1187     /Supplement 0
1188   .dicttomark
1189   /CharStrings mark /.notdef 0 .dicttomark
1190                 % The cmap isn't of any use even if it is present.
1191                 % Just construct an identity CIDMap covering all the glyphs.
1192
1193   /CIDCount numloca % Wrong if a CIDFontType2 embedded into PDF with a non-Identity CIDToGIDMap.
1194                     % processCIDToGIDMap may replace.
1195   /CIDMap numloca maxstring le {
1196                 % Use a single string.
1197       numloca 2 mul string 0 .fill_identity_cmap
1198   } {
1199                 % We must use 2 strings.
1200       maxstring 2 mul string 0 .fill_identity_cmap
1201       numloca maxstring sub 2 mul string maxstring .fill_identity_cmap
1202       2 array astore
1203   } ifelse
1204
1205   /GDBytes 2
1206   .dicttomark
1207   end end dup /CIDFontName get exch /CIDFont defineresource
1208 } bind def
1209
1210 % <file> .loadttcidfont <cidtype2font>
1211 /.loadttcidfont {
1212   //false 0 .loadttfonttables
1213   .makesfnts
1214         % CIDFontType2 fonts don't have a cmap: they are indexed by CID.
1215   mark
1216   .ttkeys
1217   .definettcidfont
1218 } bind def
1219
1220 % <file> <SubfontID> .load_tt_font_stripped <font_data>
1221 % The font_data includes sfnts, NumGlyphs, TT_cmap, file_table_pos, Decoding.
1222 % CIDMap to be created later from TT_cmap.
1223 /.load_tt_font_stripped {
1224   //true exch .loadttfonttables
1225   .makesfnts
1226   .pickcmap
1227   mark
1228   .ttkeys
1229   /NumGlyphs numloca
1230   /TT_cmap cmaptab cmaparray
1231   /file_table_pos file_table_pos
1232   /Decoding Decoding
1233   .dicttomark
1234   end end 
1235 } bind def
1236
1237 % ---------------- PDF TrueType font loading ---------------- %
1238
1239 % Strictly speaking, this code should be loaded only if we have a PDF
1240 % interpreter, but it's so closely tied to the rest of the code in this
1241 % file that we always include it.
1242
1243 % <plat+enc> .findcmap <subtable> true
1244 % <plat+enc> .findcmap false
1245 /.findcmap {
1246   false exch tabdict /cmap get
1247                 % Some fonts have multiple cmaps with the same platform and
1248                 % encoding.  Use the first one we find.
1249   0 1 2 index 2 getu16 1 sub {
1250                 % Stack: false plat+enc cmap index
1251     8 mul 4 add 1 index exch 8 getinterval 
1252     dup 0 4 getinterval 3 index eq {
1253       4 getu32 1 index exch 1 index length 1 index sub getinterval
1254       4 -1 roll not 4 2 roll exit
1255     } if pop
1256   } for
1257                 % Stack: false plat+enc cmap || subtable true plat+enc cmap
1258   pop pop
1259 } bind def
1260
1261 % Build .symbol_list for .pdfcharkeys .
1262 % It is a dictionary containing all SymbolEncoding glyph names
1263 % and random names for filling gaps in the character code range.
1264 /.symbol_list 256 dict def
1265 {
1266   =string 0 (x) 0 get put
1267   /SymbolEncoding .findencoding
1268   0 1 255 {
1269     dup 2 index exch get
1270     dup /.notdef eq {
1271       pop dup
1272       =string 1 3 getinterval cvs length 1 add
1273       =string exch 0 exch getinterval cvn
1274     } if
1275     exch //.symbol_list 3 1 roll put
1276   } for
1277   pop
1278 } bind exec
1279
1280 % Create .GS_extended_SymbolEncoding as inverse of .symbol_list .
1281 {
1282   /.GS_extended_SymbolEncoding 256 array
1283   //.symbol_list {
1284     exch 2 index 3 1 roll put  
1285   } forall
1286   .defineencoding
1287 } bind exec
1288
1289 /.addglyph    % <name> <glyph#> .addglyph <name> <glyph#> 
1290               % <name> <glyph#> .addglyph -
1291 {
1292   dup cmapencoding length lt {
1293     cmapencoding exch get dup 0 eq {
1294       pop pop
1295     } if
1296   } {
1297     pop pop
1298   } ifelse
1299 } bind def
1300
1301 % <subcmap> <chartoglyphmap> .pdfmapchars
1302 %   /CharStrings <charstrings>
1303 /.pdfmapchars {
1304   exch cmaparray /cmapencoding exch def
1305   /CharStrings mark 
1306
1307   % Add glyphs of <chartoglyphmap>*<subcmap> :
1308   3 2 roll {
1309     dup type /arraytype eq {
1310       exch /.name exch def
1311       { .name exch //.addglyph exec
1312       } forall
1313       currentdict /.name undef
1314     } {
1315       //.addglyph exec
1316     } ifelse
1317   } forall
1318
1319         % stack: /CharStrings mark /name1 glyph#1 /name2 glyph#2 ... /namen glyph#n
1320         % Stack depth is restricted with AdobeGlyphList size.
1321
1322   % Add glyphs of 'post' (with lower priority, see .dicttomark) :
1323   0 1 glyphencoding length 1 sub {
1324     dup glyphencoding exch get exch
1325     dup 0 eq {
1326       pop pop
1327     } if
1328   } for
1329
1330   /.notdef 0
1331   .dicttomark
1332 } bind def
1333
1334 % - .pdfcharkeys /CharStrings <charstrings> /Encoding <encoding>
1335 /.pdfcharkeys {
1336         % The following algorithms are per the PDF Reference, Second Edition
1337         % (PDF 1.3 reference manual).
1338   
1339   is_symbolic {
1340     <00030001> .findcmap {
1341       %
1342       % Adobe PDF spec says that symbolic fonts should contain exactly one 
1343       % cmap subtable for Platform=1, Encoding=0.
1344       % Perhaps "Adobe Acrobat PDFWriter 4.0 for Windows" sometimes embeds
1345       % fonts with both subtables 3.1 and 1.0 (see comparefiles/159.pdf,
1346       % the font "Arial,Bold" with the character "registered"),
1347       % and both Acrobat Reader 4.0 and 5.0 choose 3.1.
1348       % Therefore we try 3.1 first.
1349       %
1350       (   **** Warning: Embedded symbolic TT fonts should not contain a cmap for Platform=3 Encoding=1.\n)
1351         pdfformaterror
1352       TTFDEBUG { (Using cmap 3.1) = } if
1353       AdobeGlyphList .pdfmapchars 
1354       /Encoding /WinAnsiEncoding .findencoding
1355     } {
1356       %
1357       % Adobe PDF spec says that in this case PDF interpreter should
1358       % map character codes directly to glyphs using
1359       % the cmap <00010000>. But we use PS interpreter to emulate
1360       % a PDF interpreter. Therefore we need to construct
1361       % a type 42 font, which requires an Encoding and a Charstrings.
1362       % We construct them with symbol_list, which
1363       % includes all glyphs from SymbolEncoding and additional
1364       % random names for 1-to-1 mapping.
1365       %
1366       % A real TT font may use a different characters than
1367       % the Symbol charaster set. Perhaps our code
1368       % will give a correct printing, because glyph names are not
1369       % important for symbolic fonts in PDF.
1370       %
1371       <00010000> .findcmap {
1372         prebuilt_encoding null ne {
1373           TTFDEBUG { (Using cmap 1.0 with prebuilt_encoding.) = } if
1374           prebuilt_encoding .invert_encoding .pdfmapchars
1375           /Encoding prebuilt_encoding
1376         } {
1377           % This is a case, in which an obsolete software could stupidly specify Macintosh Roman
1378           % for a random encoding. Particulatrly GPL Ghostscript 7.06 does so.
1379           % Trying to recover with 'post'.
1380           pop  % The table itself doesn't contain useful data.
1381           TTFDEBUG { (Using cmap 1.0 with post or .GS_extended_SymbolEncoding) = } if
1382           .charkeys
1383         } ifelse
1384       } {
1385         % This is illegal with PDF spec.
1386         (   **** Warning: Embedded symbolic TT fonts must contain a cmap for Platform=1 Encoding=0.\n)
1387         pdfformaterror
1388         % Try to map Unicode to SymbolEncoding
1389         <00030001> .findcmap {
1390           TTFDEBUG { (Using cmap 3.1) = } if
1391           AdobeGlyphList .pdfmapchars
1392           /Encoding /SymbolEncoding .findencoding
1393         } {
1394           % Apply the default algorithm. Hopely it has 'post'.
1395           .charkeys
1396           % check if the CharStrings dict contains glyphs needed by the
1397           % prebuilt_encoding otherwise try the 3,0 cmap.
1398           prebuilt_encoding null ne {
1399             false prebuilt_encoding {   % false means no missing glyphs
1400               4 index exch known not { pop true exit } if
1401             } forall
1402             {
1403               (   **** Warning: Encoding derived from 'post' is incomplete.\n)
1404               pdfformaterror
1405               % Try another cmap format 3,0 -- Adobe doesn't mention it, but does
1406               % use it apparently (empirically determined).
1407               <00030000> .findcmap {
1408                 TTFDEBUG { (Adding cmap 3.0) = } if
1409                 5 1 roll pop pop pop pop             
1410                 prebuilt_encoding null ne {
1411                   prebuilt_encoding .invert_encoding .pdfmapchars
1412                   /Encoding prebuilt_encoding
1413                 } {
1414                   AdobeGlyphList .pdfmapchars
1415                   /Encoding /SymbolEncoding .findencoding
1416                 } ifelse
1417               } if
1418             }if
1419           } if
1420         } ifelse
1421       } ifelse
1422     } ifelse
1423   } {
1424     <00030001> .findcmap {
1425       TTFDEBUG { (Using cmap 3.1 for non-symbolic.) = } if
1426       AdobeGlyphList .pdfmapchars 
1427       /Encoding /WinAnsiEncoding .findencoding
1428         % WinAnsiEncoding is just a stub here. 
1429         % It will be replaced with one from font resource,
1430         % because PDF spec requires it.
1431     } {
1432       <00010000> .findcmap {
1433         TTFDEBUG { (Using cmap 1.0 for non-symbolic.) = } if
1434         .romanmacdict .pdfmapchars 
1435         /Encoding /MacRomanEncoding .findencoding
1436       } {
1437         % Apply the default algorithm for using the 'post'.
1438         .charkeys
1439       } ifelse
1440     } ifelse
1441   } ifelse
1442 } bind def
1443
1444 % <file> <is_symbolic> <Encoding|null> .loadpdfttfont <type42font>
1445 /.loadpdfttfont {
1446   /prebuilt_encoding exch def     % for .pdfcharkeys
1447   /is_symbolic exch def
1448   //false 0 .loadttfonttables
1449   .makesfnts
1450   .getpost
1451   .pickcmap
1452   mark
1453   .pdfcharkeys
1454   .ttkeys
1455   .definettfont
1456 } bind def