Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_fixcpp/sys/lib/ghostscript/gs_ttf.ps – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
 
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
 
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
 
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
 
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
 
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
 
293
 
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
 
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
 
395
    } ifelse
396
		% Now fill in the array.
397
    /numcodes 0 def /code 0 def
398
 
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
 
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
 
433
    dup firstcode ng getinterval
434
		% Stack: tab array subarray
435
		% Fill elements firstcode .. firstcode+nvalue-1 with glyph values
436
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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