1 % Copyright (C) 1996-2003 artofcode LLC. All rights reserved.
3 % This software is provided AS-IS with no warranty, either express or
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.
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.
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.)
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:
27 % Thanks to B. Jackowski and GUST (the Polish TeX Users' Group) for
28 % the glyf-splitting code.
30 % ---------------- Font loading machinery ---------------- %
32 % Augment the FONTPATH machinery so it recognizes TrueType fonts.
34 /.scanfontheaders where {
35 pop /.scanfontheaders [
36 .scanfontheaders aload pop (\000\001\000\000*) (true*)
40 % <file> <key> .findfontvalue <value> true
41 % <file> <key> .findfontvalue false
42 % Closes the file in either case.
43 /.findnonttfontvalue /.findfontvalue load def
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.
53 dup /FontName eq { pop .findttfontname } { pop closefile false } ifelse
56 % Not a TrueType font.
59 } { pop closefile false } ifelse
62 % <file> .findttfontname <fname> true
63 % <file> .findttfontname false
64 % Closes the file in either case.
66 //true 0 .loadttfonttables
67 tabdict /name .knownget {
68 dup 8 getu32 f exch setfileposition
69 12 getu32 string f exch readstring pop
77 % Load a font file that might be a TrueType font.
79 % <file> .loadfontfile -
80 /.loadnonttfontfile /.loadfontfile load def
82 dup read pop 2 copy unread 0 eq {
83 % If this is a font at all, it's a TrueType font.
86 % Not a TrueType font.
91 % ---------------- Automatic Type 42 generation ---------------- %
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
106 /.loadttfontdict 50 dict dup begin
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)
112 /.invert_encoding % <array> invert_encoding <dict>
114 0 exch 1 exch length 1 sub { % [] <> i
115 dup 3 index exch get % [] <> i v
117 exch 2 index 2 index .knownget {
118 dup type /arraytype eq {
119 [ exch aload pop counttomark 2 add -1 roll ]
123 } if 2 index 3 1 roll put
131 % Define the Macintosh standard mapping from characters to glyph indices.
132 /MacRomanEncoding dup .findencoding def
133 /MacGlyphEncoding dup .findencoding def
135 % Invert the MacRomanEncoding.
136 /.romanmacdict MacRomanEncoding .invert_encoding def
138 % Define remapping for misnamed glyphs in TrueType 'post' tables.
139 % There are probably a lot more than this!
143 /Eoverdot /Edotaccent
149 /eoverdot /edotaccent
153 .dicttomark readonly def
155 % Array used for fast pre-filling of cmap array
156 /.array1024z [ 1024 { 0 } repeat ] def
158 % ---- Utilities ---- %
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
168 /nextxuid { % - nextxuid -
170 xuidstring 1 index 2 copy get dup 255 ne {
176 % <string> <index> getu16 <integer>
178 2 copy get 8 bitshift 3 1 roll 1 add get add
181 % <string> <index> gets16 <integer>
183 getu16 16#8000 xor 16#8000 sub
186 % <string> <index> getu32 <integer>
188 2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add
191 % <string> <index> gets32 <integer>
193 2 copy gets16 16 bitshift 3 1 roll 2 add getu16 add
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
203 % <string> <index> <integer> putu16 -
205 3 copy -8 bitshift put
206 exch 1 add exch 16#ff and put
209 % <string> <index> <integer> putu32 -
211 3 copy -16 bitshift putu16
212 exch 2 add exch 16#ffff and putu16
215 % <nametable> <nameid> findname <string> true
216 % <nametable> <nameid> findname false
218 TTFDEBUG { (findname: ) print dup =only } if
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.
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
234 % Stack: false string record
235 % Check for 8- vs. 16-bit characters.
236 is2byte { string2to1 } if true null 4 -1 roll exit
247 dup { ( = ) print 1 index == } { ( not found) = } ifelse
251 % <namerecord> is2byte <bool>
254 { pop true } % Apple Unicode
255 { pop false } % Macintosh Script manager
256 { 1 getu16 1 eq } % ISO
257 { 1 getu16 1 eq } % Microsoft
261 % <string2> string2to1 <string>
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
269 % Each procedure in this dictionary is called as follows:
270 % <encodingtable> proc <glypharray>
272 0 { % Apple standard 1-to-1 mapping.
273 6 256 getinterval { } forall 256 packedarray
275 2 { % Apple 16bit CJK (ShiftJIS etc)
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
286 dup 2 getu16 /cmapf2_tblen exch def
288 dup 4 getu16 /cmapf2_lang exch def
290 dup 6 256 sHK_sz mul getinterval /sHKs exch def
292 0 % initialization value for /sH_len
296 1 index % get current max
297 1 index % get current subHeaderKey
302 dup 6 256 sHK_sz mul add
303 cmapf2_tblen 1 index sub getinterval
306 /cmapf2_glyph_array 65535 array def
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
319 cmapf2_glyph_array exch cmapf2_ch exch put
322 % cmapf2_glyph_array cmapf2_ch 0 put
324 } { % false: j is outside
325 % cmapf2_glyph_array cmapf2_ch 0 put
329 16#00 1 16#ff { % hi_byte scan
330 /cmapf2_ch_hi exch def
331 sHKs cmapf2_ch_hi sHK_sz mul getu16
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
340 /cmapf2_ch_lo cmapf2_ch_hi def
344 16#00 1 16#ff { % lo_byte scan
345 /cmapf2_ch_lo exch def
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
357 4 { % Microsoft/Adobe segmented mapping.
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!
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:
370 /firstcode startc 0 getu16 16#ff00 and dup 16#f000 ne { pop 0 } if def
372 glyphs code 3 -1 roll put /code code 1 add 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
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
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
394 0 1 glyphs length 1 sub { glyphs exch 0 put } for
396 % Now fill in the array.
397 /numcodes 0 def /code 0 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
410 (scode=) print scode =only
411 ( ecode=) print ecode =only
412 ( delta=) print delta =only
413 ( droff=) print idroff i2 getu16 =
415 idroff i2 getu16 dup 0 eq {
416 pop scode delta add 65535 and 1 ecode delta add 65535 and
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
425 } for glyphs /glyphs null def % for GC
427 6 { % Single interval lookup.
428 dup 6 getu16 /firstcode exch def dup 8 getu16 /ng exch def
429 firstcode ng add 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
437 dup 2 mul 10 add 4 index exch getu16 3 copy put pop pop
440 .dicttomark readonly def % cmapformats
442 % <cmaptab> cmaparray <glypharray>
444 dup 0 getu16 cmapformats exch .knownget {
446 (cmap: format ) print 1 index 0 getu16 = flush
449 (Can't handle format ) print 0 getu16 = flush
450 0 1 255 { } for 256 packedarray
453 (cmap: length=) print dup length = dup ==
457 /get_from_stringarray % <array|string> <offset> get_from_stringarray <int>
458 { 1 index type /stringtype eq {
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 {
476 string exch 0 % [] s o p
477 4 3 roll { % s o p Si
478 dup length % s o p Si lSi
480 3 index exch sub % s o p Si o'
481 exch pop 3 1 roll exch pop % s o' p
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
494 3 1 roll add % s p' o'
495 dup 3 index length ge {
505 /string_array_size % <array|string> string_array_size <int>
506 { dup type /stringtype eq {
509 0 exch { length add } forall
513 % Each procedure in this dictionary is called as follows:
514 % posttable <<proc>> glyphencoding
516 16#00010000 { % 258 standard Macintosh glyphs.
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
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
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
539 ] /postnames exch def
540 [ 0 1 numglyphs 1 sub {
541 2 mul 34 add post_first exch getu16
543 MacGlyphEncoding exch get
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
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
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
568 16#00030000 { % No map.
571 .dicttomark readonly def % postformats
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.
586 (cmap) //call.readtable
592 (post) //call.readbigtable
593 (vhea) //call.readtable
595 (glyf) //call.readbigtable
599 % Tables only needed for embedding in PDF files
600 (cvt ) //call.readtable
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
609 /readtables_stripped readtables dup length dict copy
610 dup (loca) { .skiptable } put
611 dup (glyf) { .skiptable } put
614 % Read a table as a single string.
615 % <file> <length> .skiptable <string>
620 % Read a table as a single string.
621 % <file> <length> .readtable <string>
623 dup dup 1 and add string
625 dup 0 4 -1 roll getinterval
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.
631 dup () ne { readstring } if pop pop
634 % Read a big table (one that may exceed 64K).
635 % <file> <length> .readbigtable <string[s]>
640 currentuserparams /VMReclaim get -2 vmreclaim
642 % Stack: mark ... f left
643 dup maxstring le { exit } if
644 1 index maxstring string readstring pop 3 1 roll maxstring sub
650 end readonly def % .loadttfontdict
654 dup 0 4 getinterval print ( ) print
655 dup 8 getu32 =only ( ) print
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.
664 .loadttfontdict begin
667 /load_stripped 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
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
686 QUIET not { (SubfontID > 0 with a True Type file which is not a collection.) = } if
687 /.loadttfonttables cvx /invalidfont signalerror
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
705 exch 8 getu32 exch 8 getu32 lt
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
722 /.file_table_pos_names
726 .dicttomark readonly def
729 % Read data. Updates offsets, tabs; stores data in tabdict.
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
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 {
741 file_table_pos tname [tpos tlen] put
745 % Skip data between the end of the previous table and
746 % the beginning of this one, if any.
749 % 'setfileposition' is faster for skipping a big data.
750 f tpos setfileposition
752 f tpos fpos sub () /SubFileDecode filter dup flushfile closefile
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
761 /fpos fpos tlen add def
765 % Find the string in a list of strings that includes a given index.
766 % <strings> <index> .findseg <string> <index'>
769 dup length 2 index gt { exch exit } if
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
780 /head tabdict /head get def
781 /post tabdict /post .knownget {
782 dup 0 get /post_first_part exch def
787 /locatable tabdict /loca get def
789 locatable dup type /stringtype eq
791 { 0 exch { length add } forall }
793 locatable type /stringtype eq {
796 /.indexloca /.findseg load def
798 head 50 getu16 0 ne {
800 2 bitshift locatable exch .indexloca getu32
805 dup add locatable exch .indexloca getu16 dup add
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
816 % We did not load loca, take the number of glyphs from maxp.
817 /numloca tabdict /maxp get 4 getu16 def
820 offsets tabs { concatstrings } forall
822 0 4 getinterval tabdict exch get
823 dup type /stringtype ne { aload pop } if
828 % <glyfs> .dividesfnts <glyfs'>
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.
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).
842 % sort the locatable in case it is out of order
843 % Note the 'loca' table remains unchanged
845 numloca array % the array of 'loca' entries (may be out of order)
846 -1 % initial values for in order check
849 4 -1 roll lt { /needsort true def } if
851 } for pop % discard inorder check value
853 { lt } bind .sort % stack: locatable_array
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
862 dup 1 and 0 eq { /prevboundary exch def } { pop } ifelse
863 dup type /arraytype ne { exch } if % keep locatable_array on top
866 exch pop % discard locatable_array
868 currentuserparams /VMReclaim get -2 vmreclaim
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.
881 avail length seglen ge
882 { avail 0 seglen getinterval /avail () def } { seglen string }
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
894 /sfnt_idx sfnt_idx 1 add def
896 segpos seglen eq { exit } if
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
908 /first_post_string % - first_post_string <string>
910 post dup type /arraytype eq { 0 get } if
914 % Uses post, defines glyphencoding
916 /glyphencoding post null eq {
917 TTFDEBUG { (post missing) = flush } if [ ]
919 postformats first_post_string 0 getu32 .knownget {
921 (post: format ) print
923 dup 0 getu16 =only (,) print 2 getu16 = flush
927 TTFDEBUG { (post: unknown format ) print post 0 getu32 = flush } if [ ]
930 TTFDEBUG { (post=) print dup == } if
934 % - .ttkeys <key> <value> ...
936 count /ttkeycount exch def
937 /upem head 18 getu16 def
939 /FontBBox [ 36 2 42 { head exch gets16 upem div } for ]
941 tabdict /name .knownget {
942 % Find the names from the 'name' table.
944 /FontName names 6 findname not { curxuid 16 8 string cvrs } if
945 /fontname 1 index def
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
952 % No name table, fabricate a FontName.
953 /FontName curxuid 16 8 string cvrs
954 /fontname 1 index def
957 % Stack: ... /FontInfo mark key1 value1 ...
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
964 counttomark 0 ne { .dicttomark } { pop pop } ifelse
965 /XUID [orgXUID 42 curxuid]
967 tabs { .printtab } forall
968 [ sfnts { length } forall ] ==
969 count ttkeycount sub array astore dup { == } forall aload pop
974 % ---------------- Standard TrueType font loading ---------------- %
976 % - .pickcmap_with_no_xlatmap -
977 % Defines cmapsub, cmaptab
978 /.pickcmap_with_no_xlatmap {
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
987 (cmap: platform ) print dup 0 getu16 =only
988 ( encoding ) print dup 2 getu16 = flush
990 dup 0 getu16 3 eq { exch 3 -1 roll pop exit } if pop
992 % Stack: subentry table
994 exch 4 getu32 1 index length 1 index sub getinterval
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
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
1013 (gs/lib/xlatmap containg a record with an invalid (PlatformID.SpecificID)) =
1014 /.pickcmap_with_xlatmap cvx /configurationerror signalerror
1017 (Seeking a cmap for platform=) print 1 index =only ( encoding=) print dup =
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)
1024 (cmap: platform ) print dup 0 getu16 =only
1025 ( encoding ) print dup 2 getu16 = flush
1027 dup 0 getu16 4 index eq {
1028 dup 2 getu16 3 index eq { % bool [] i PlatID SpecID (cmap) (cmapsub)
1030 (Choosen a cmap for platform=) print 3 index =only
1031 ( encoding=) print 2 index =
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)
1043 pop % true [] i PlatID SpecID (cmap)
1045 } for % bool [] i PlatID SpecID (cmap)
1046 pop pop pop pop % bool []
1051 QUIET not { (True Type font doesn't contain a charset listed in gs/lib/xlatmap.) = } if
1052 /.pickcmap_with_xlatmap cvx /invalidfont signalerror
1057 % Defines cmapsub, cmaptab
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".
1070 //.pickcmap_with_xlatmap exec
1072 //.pickcmap_with_no_xlatmap exec
1076 % <glyph> .nname <_name>
1078 =string cvs (_) exch concatstrings cvn
1081 % - .charkeys /CharStrings <charstrings> /Encoding <encoding>
1082 % Resets glyphencoding
1085 (glyphencoding: length=) print glyphencoding dup length = === flush
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
1094 PDFDEBUG { (No encoding info, use .GS_extended_SymbolEncoding) } if
1095 /glyphencoding /.GS_extended_SymbolEncoding findencoding dup length array copy def
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
1106 % /glyphencoding <newarray> <glyphencoding length>
1108 1 index exch dup .nname put
1112 /glyphencoding glyphencoding 0 numloca getinterval def
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.
1125 pop dup .nname 3 index 2 index 2 index put
1127 2 index exch 3 -1 roll put
1129 % If there is no .notdef entry, map it to glyph 0.
1130 dup /.notdef known not { dup /.notdef 0 put } if
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
1139 % -mark- <key> <value> ... .definettfont <font>
1144 (numloca=) print numloca =
1147 end end dup /FontName get exch definefont
1150 % <file> .loadttfont <type42font>
1152 //false 0 .loadttfonttables
1162 % ---------------- CIDFontType 2 font loading ---------------- %
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
1172 3 copy 1 add % () v i () v i+1
1173 exch 255 and % () v i () i+1 v&255
1180 % -mark- <key> <value> ... .definettcidfont <font>
1182 /CIDFontName fontname
1186 /Ordering (Japan1) % adhoc
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.
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
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
1207 end end dup /CIDFontName get exch /CIDFont defineresource
1210 % <file> .loadttcidfont <cidtype2font>
1212 //false 0 .loadttfonttables
1214 % CIDFontType2 fonts don't have a cmap: they are indexed by CID.
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
1230 /TT_cmap cmaptab cmaparray
1231 /file_table_pos file_table_pos
1237 % ---------------- PDF TrueType font loading ---------------- %
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.
1243 % <plat+enc> .findcmap <subtable> true
1244 % <plat+enc> .findcmap false
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
1257 % Stack: false plat+enc cmap || subtable true plat+enc cmap
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
1266 =string 0 (x) 0 get put
1267 /SymbolEncoding .findencoding
1269 dup 2 index exch get
1272 =string 1 3 getinterval cvs length 1 add
1273 =string exch 0 exch getinterval cvn
1275 exch //.symbol_list 3 1 roll put
1280 % Create .GS_extended_SymbolEncoding as inverse of .symbol_list .
1282 /.GS_extended_SymbolEncoding 256 array
1284 exch 2 index 3 1 roll put
1289 /.addglyph % <name> <glyph#> .addglyph <name> <glyph#>
1290 % <name> <glyph#> .addglyph -
1292 dup cmapencoding length lt {
1293 cmapencoding exch get dup 0 eq {
1301 % <subcmap> <chartoglyphmap> .pdfmapchars
1302 % /CharStrings <charstrings>
1304 exch cmaparray /cmapencoding exch def
1307 % Add glyphs of <chartoglyphmap>*<subcmap> :
1309 dup type /arraytype eq {
1310 exch /.name exch def
1311 { .name exch //.addglyph exec
1313 currentdict /.name undef
1319 % stack: /CharStrings mark /name1 glyph#1 /name2 glyph#2 ... /namen glyph#n
1320 % Stack depth is restricted with AdobeGlyphList size.
1322 % Add glyphs of 'post' (with lower priority, see .dicttomark) :
1323 0 1 glyphencoding length 1 sub {
1324 dup glyphencoding exch get exch
1334 % - .pdfcharkeys /CharStrings <charstrings> /Encoding <encoding>
1336 % The following algorithms are per the PDF Reference, Second Edition
1337 % (PDF 1.3 reference manual).
1340 <00030001> .findcmap {
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.
1350 ( **** Warning: Embedded symbolic TT fonts should not contain a cmap for Platform=3 Encoding=1.\n)
1352 TTFDEBUG { (Using cmap 3.1) = } if
1353 AdobeGlyphList .pdfmapchars
1354 /Encoding /WinAnsiEncoding .findencoding
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.
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.
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
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
1385 % This is illegal with PDF spec.
1386 ( **** Warning: Embedded symbolic TT fonts must contain a cmap for Platform=1 Encoding=0.\n)
1388 % Try to map Unicode to SymbolEncoding
1389 <00030001> .findcmap {
1390 TTFDEBUG { (Using cmap 3.1) = } if
1391 AdobeGlyphList .pdfmapchars
1392 /Encoding /SymbolEncoding .findencoding
1394 % Apply the default algorithm. Hopely it has 'post'.
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
1403 ( **** Warning: Encoding derived from 'post' is incomplete.\n)
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
1414 AdobeGlyphList .pdfmapchars
1415 /Encoding /SymbolEncoding .findencoding
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.
1432 <00010000> .findcmap {
1433 TTFDEBUG { (Using cmap 1.0 for non-symbolic.) = } if
1434 .romanmacdict .pdfmapchars
1435 /Encoding /MacRomanEncoding .findencoding
1437 % Apply the default algorithm for using the 'post'.
1444 % <file> <is_symbolic> <Encoding|null> .loadpdfttfont <type42font>
1446 /prebuilt_encoding exch def % for .pdfcharkeys
1447 /is_symbolic exch def
1448 //false 0 .loadttfonttables