summaryrefslogtreecommitdiff
path: root/gs/lib/pdf_font.ps
blob: 01739080d387a5fdbf86e60bb54e4e5fdbefbdd1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
%    Copyright (C) 1994, 1996, 1997, 1998 Aladdin Enterprises.  All rights reserved.
% 
% This file is part of Aladdin Ghostscript.
% 
% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
% or distributor accepts any responsibility for the consequences of using it,
% or for whether it serves any particular purpose or works at all, unless he
% or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
% License (the "License") for full details.
% 
% Every copy of Aladdin Ghostscript must include a copy of the License,
% normally in a plain ASCII text file named PUBLIC.  The License grants you
% the right to copy, modify and redistribute Aladdin Ghostscript, but only
% under certain conditions described in the License.  Among other things, the
% License requires that the copyright notice and this notice be preserved on
% all copies.

% pdf_font.ps
% PDF font operations.

/.setlanguagelevel where { pop 2 .setlanguagelevel } if
.currentglobal true .setglobal
/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
GS_PDF_ProcSet begin
pdfdict begin

% We cache the PostScript font in an additional element of the
% font resource dictionary, called PSFont.

% ---------------- Encodings ---------------- %

% Apply a list of differences to an Encoding.
/updateencoding		% <encoding> <differences> updateencoding <enc'>
 { exch dup length array copy
   exch 0 exch {
		% Stack: enc' code element
     dup type /nametype ne
      { exch pop }
      { 3 copy put pop 1 add }
     ifelse
   } forall pop
 } bdef

% Get the Encoding for a font.
/getencoding		% <base-encoding> <font-resource> getencoding <enc>
 { /Encoding knownoget
    { dup type /nametype eq
       { exch pop findencoding
       }
       { dup /BaseEncoding knownoget
	  { findencoding 3 -1 roll pop exch
	  }
	 if
	 /Differences knownoget { updateencoding } if
       }
      ifelse
    }
   if
 } bdef

% Adjust a font according to the Encoding and Widths in the font resource.
/adjustfont		% <font-resource> <font> adjustfont
			%   <font'> <changed>
 { getfontencoding getfontmetrics 4 -1 roll pop .updatefont
    { dup /FontName 2 copy get genfontname dup 5 1 roll put definefont }
   if
 } bind def

% Get the (possibly modified) encoding of a font.
/getfontencoding	% <font-resource> <font> getfontencoding
			%   <font-resource> <font> <encoding>
 { dup /Encoding get 2 index getencoding
 } bdef

% Get the metrics of a font, if specified.
/getfontmetrics		% <font-resource> <font> <encoding> getfontmetrics
			%   <font-resource> <font> <encoding> <Metrics|null>
 { 2 index /Widths known
    { 2 dict begin
      /Encoding exch def
      /Metrics Encoding length dict def
      exch
		% Stack: font font-res
		% Note that widths are always based on a 1000-unit
		% character space, but the FontMatrix may specify
		% some other scale factor.  Compensate for this here,
		% by scaling the Widths if necessary.
      0.001 2 index /FontMatrix get 0 get div
		% Stack: font font-res mscale
      1 index /FirstChar oget dup 1 4 index /LastChar oget
       {	% Stack: font font-res mscale first-char index
	 Encoding 1 index get
	 4 index /Widths oget 2 index 4 index sub get
	 	% Stack: font font-res mscale first-char index charname width
	 4 index mul
		% There is a hack here to deal with encodings where the
		% same character appears more than once, because the Metrics
		% dictionary works by character name, not by character code.
		% Because of this, we can't deal with Width vectors that
		% specify different widths for the same character name
		% appearing multiple times in the Encoding.
	 Metrics 2 index .knownget not { 0 } if 0 ne
	  { pop pop }
	  { Metrics 3 1 roll put }
	 ifelse pop
       }
      for pop
		% Now fill in the MissingWidth for any encoded characters
		% that aren't in Metrics already.
		% Stack: font font-res mscale
      Metrics 2 index /FontDescriptor oget
      /MissingWidth knownoget { 2 index mul } { 0 } ifelse exch
      Encoding
       {	% Stack: font font-res mscale missing-width metrics charname
	 2 copy known not { 2 copy 4 index put } if pop
       }
      forall pop pop pop
      exch Encoding Metrics end
    }
    { null
    }
   ifelse
 } bdef

% ---------------- Descriptors ---------------- %

% Partial descriptors for the 14 built-in fonts.
/standardfontdescriptors mark
  /Courier mark /Flags 16#23 .dicttomark
  /Courier-Oblique 1 index
  /Courier-Bold 1 index
  /Courier-BoldOblique 1 index
  /Helvetica mark /Flags 16#20 .dicttomark
  /Helvetica-Oblique 1 index
  /Helvetica-Bold 1 index
  /Helvetica-BoldOblique 1 index
  /Times-Roman mark /Flags 16#22 .dicttomark
  /Times-Bold 1 index
  /Times-Italic mark /Flags 16#62 .dicttomark
  /Times-BoldItalic 1 index
  /Symbol mark /Flags 16#4 .dicttomark
  /ZapfDingbats 1 index
.dicttomark readonly def

% ---------------- Utilities ---------------- %

% Fabricate a font name by adding %'s on the end.
/genfontname		% <name> genfontname <name>
 { dup length string cvs
    { (%) concatstrings
      dup cvn FontDirectory exch known not { cvn exit } if
    }
   loop
 } bdef

% Find a font, and adjust its encoding if necessary.
/pdffindfont		% <font-resource> <fontname> pdffindfont <font>
 { findfont adjustfont
 } bdef

% ---------------- Type 1 fonts ---------------- %

/buildType1		% <Type1-font-resource> buildType1 <font>
 { dup /BaseFont get pdffindfont
 } bdef

% The state dictionary for the embedded Type 1 font reading procedure
% has the following keys and values:
%	data - stream (filter)
%	buffer, buffer2 - string
%	leftstr - string containing (non-negative) integer
%	sectionstr - string containing a character 0 .. 2
%	stream - (stream) dictionary
%	proc - procedure of the form {-dict- type1read}
% When the procedure is executing, this dictionary is current.
% leftstr and sectionstr are strings so that we can change their values
% reliably in case the font executes a restore!

% Read an embedded Type 1 font.
/readfontfilter		% <proc> readfontfilter <filter>
 {	% We make this a separate procedure so that we can
	% redefine it when we're writing PostScript.
   0 () /SubFileDecode filter
 } bdef
/readtype1dict 5 dict dup begin
  /definefont {
    dup wcheck not { dup length dict copy } if
    exch pop savedFontName exch
    //systemdict /definefont get exec
  } bdef
  /eexec {
    55665 /eexecDecode filter
    //systemdict begin readtype1dictcopy begin cvx stopped
    currentdict readtype1dictcopy eq { end } if
    currentdict //systemdict eq { end } if
     { stop } if
  } bdef
end readonly def
/readtype1		% <font-resource> <stream-dict> readtype1 <font>
 {		% Read the definition, using a procedure-based filter
		% that turns binary/hex conversion on and off
		% at the right times.
   PDFfile fileposition 3 1 roll
   7 dict begin
     /leftstr (          ) 10 string copy def
       dup /Length1 oget leftstr cvs pop
     /sectionstr <00> 1 string copy def
     /stream 1 index def
     true resolvestream /data exch def
     /buffer 1000 string def		% arbitrary
     /buffer2 buffer length 2.1 div cvi 1 sub string def
   currentdict end
   /type1read cvx 2 array astore cvx dup 0 get /proc 2 index put
   readfontfilter
		% Some buggy embedded fonts leave extra junk on the stack,
		% so we have to make a closure that records the stack depth
		% in a fail-safe way.
   //systemdict begin
		% Rebind definefont so we can substitute the FontName
		% from the descriptor.
   //readtype1dict dup length 2 add dict copy begin
   1 index /FontDescriptor oget /FontName oget /savedFontName exch def
   /readtype1dictcopy currentdict def
    { run } aload pop count 1 sub 2 packedarray cvx exec
   end end
   count exch sub { pop } repeat
   PDFfile 3 -1 roll setfileposition
   /FontDescriptor oget /FontName oget findfont
 } bdef

% Execute the appropriate reading procedure.
/type1read		% <dict> type1read <string>
 { begin leftstr cvi
    { type1read1 type1read2 type1read3 } sectionstr 0 get get exec
   (          ) leftstr copy cvs pop end
 } bdef

% Read the next block of data into the buffer.
/type1readdata		% <left> <buffer> type1readdata <substring> <left'>
 { 0 2 index 2 index length min getinterval
		% Adobe requires readstring to signal an error if given
		% an empty string.  Work around this nonsense here.
   dup length 0 ne { data exch readstring pop } if
   dup length 3 -1 roll exch sub
   DEBUG
    { dup =only ( read ) print
      1 index length =only (: ) print
      1 index == flush
    } if
 } bdef

% Read the next block of the initial text portion.
/type1read1		% <left> type1read1 <string> <left'>
 { DEBUG { (read1 ) print } if
   dup 0 eq
    { pop sectionstr 0 1 put
      stream /Length2 oget type1read2
    }
    { buffer type1readdata
    }
   ifelse
 } bdef

% Read the next block of the encrypted portion.
/type1trailer
(0000000000000000000000000000000000000000000000000000000000000000\n\
0000000000000000000000000000000000000000000000000000000000000000\n\
0000000000000000000000000000000000000000000000000000000000000000\n\
0000000000000000000000000000000000000000000000000000000000000000\n\
0000000000000000000000000000000000000000000000000000000000000000\n\
0000000000000000000000000000000000000000000000000000000000000000\n\
0000000000000000000000000000000000000000000000000000000000000000\n\
0000000000000000000000000000000000000000000000000000000000000000\n\
cleartomark\n)
readonly def
/type1read2		% <left> type1read2 <string> <left'>
 { DEBUG { (read2 ) print } if
   dup 0 eq
    { pop sectionstr 0 2 put
      stream /Length3 oget
      dup 0 eq
       { DEBUG { (trailer ) print } if
	 type1trailer exch
       }
       { type1read3
       }
      ifelse
    }
    { buffer2 type1readdata exch
      buffer /ASCIIHexEncode filter dup 3 -1 roll writestring closefile
      buffer (>) search pop exch pop exch pop exch
    }
   ifelse
 } bdef

% Read the next block of the final text portion.
% When finished, this procedure returns an empty string.
/type1read3		% <left> type1read3 <string> <left'>
 { DEBUG { (read3 ) print } if
   buffer type1readdata
 } bdef

% ---------------- Type 3 fonts ---------------- %

/.notdefEncoding 256 { /.notdef } repeat 256 packedarray def

/buildType3		% <Type3-font-resource> buildType3 <font>
  { 8 dict begin
    /FontType 3 def
    /FontBBox 1 index /FontBBox get cvx def
    /FontMatrix 1 index /FontMatrix oget def
    /CharProcs 1 index /CharProcs oget def
    /FontName 1 index /Name get genfontname def
    /Encoding .notdefEncoding 2 index getencoding def
    /BuildGlyph
     { exch /CharProcs get exch oget
       PDFfile fileposition exch
       false resolvestream
		% Don't let setgcolor set the color inside the BuildGlyph
		% procedure, because this causes an /undefined error.
       q_ null /FillColor gput null /StrokeColor gput
       pdfopdict .pdfrun
       Q_
       PDFfile exch setfileposition
     } bdef
    FontName currentdict end definefont exch pop
  } bdef

% ---------------- TrueType fonts ---------------- %

/TTfonts mark
  /Arial /Helvetica
  /Arial,Italic /Helvetica-Oblique
  /Arial,Bold /Helvetica-Bold
  /Arial,BoldItalic /Helvetica-BoldOblique
  /TimesNewRoman /Times-Roman
  /TimesNewRoman,Italic /Times-Italic
  /TimesNewRoman,Bold /Times-Bold
  /TimesNewRoman,BoldItalic /Times-BoldItalic
.dicttomark readonly def

/buildTrueType		% <TrueType-font-resource> buildTrueType <font>
 { dup /BaseFont get
   dup TTfonts exch .knownget { exch pop } if pdffindfont
 } bdef

% Read an embedded TrueType font.
/readtruetype		% <font-resource> <stream-dict> readtruetype <font>
 {		% This is much simpler than readtype1, because we don't
		% have to deal with the tripartite .PFB format.
   PDFfile fileposition 3 1 roll
   true resolvestream readfontfilter .loadttfont
   dup /FontName get exch definefont exch pop
   PDFfile 3 -1 roll setfileposition
 } bdef

% ---------------- Type 0 fonts ---------------- %
%**************** NOT ACTUALLY SUPPORTED YET

/buildType0		% <Type0-font-resource> buildType0 <font>
{ 10 dict begin
  /FontType 0 def
  /FontMatrix 1 index /FontMatrix knownoget not { matrix } if def
  /FontName 1 index /BaseFont get def
  /FMapType 9 def
  /Encoding [ 0 1 4 index /DescendantFonts oget length 1 sub { } for ] def
  /FDepVector [ 2 index /DescendantFonts oget { exec } forall ] def
  /CMap 1 index /Encoding oget
    dup type /nametype eq
     { dup Page /CMap rget
        { exch pop resolvestream } { /undefined signalerror } ifelse
     }
     { resolvestream
     }
    ifelse
  % FontName currentdict end definefont exch pop
  end pop /Times-Roman findfont
} bdef

% ---------------- Other embedded fonts ---------------- %

/fontloadprocs mark
  /Type1C /readType1C cvx
.dicttomark readonly def

% Read an embedded compressed font.
/readType1C		% <font-resource> <stream-dict> readType1C <font>
 { PDFfile fileposition 3 1 roll
   dup true resolvestream dup readfontfilter
		% Stack: pos resource streamdict stream filter
   3 index /FontDescriptor oget /FontName oget
   1 index FRD
   closefile closefile pop
   PDFfile 3 -1 roll setfileposition
   /FontDescriptor oget /FontName oget findfont
 } bdef

% ---------------- Font lookup ---------------- %

/fonttypeprocs mark		% <font-resource> -proc- <font>
  /Type0 /buildType0 cvx
  /Type1 /buildType1 cvx
  /MMType1 1 index
  /Type3 /buildType3 cvx
  /TrueType /buildTrueType cvx
.dicttomark readonly def

/resourcefont			% <font-resource> resourcefont <font>
 { dup /PSFont .knownget
    { /FID .knownget { type /fonttype eq } { false } ifelse }
    { false }
   ifelse
    { /PSFont get
    }
    { dup dup /FontDescriptor knownoget
       {	% Stack: font-res font-res font-desc
	 dup /FontFile knownoget
	  { exch pop 1 index 3 1 roll readtype1 adjustfont true }
	  { dup /FontFile2 knownoget
	     { exch pop 1 index 3 1 roll readtruetype adjustfont true }
	     { /FontFile3 knownoget
		{ 1 index exch dup /Subtype get fontloadprocs exch get exec adjustfont true }
		{ false }
	       ifelse
	     }
	    ifelse
	  }
	 ifelse
       }
       { false }
      ifelse
		% Stack: font-res font-res false
		%  -or-: font-res font true
      not
       { dup /Subtype get fonttypeprocs exch get exec }
      if
      2 copy /PSFont exch put
      exch pop
    }
   ifelse
 } bdef

drawopdict begin
  /d0 /setcharwidth load def
  /d1 /setcachedevice load def
  /Tf
   { 1 index Page /Font rget not { 1 index /undefinedfont signalerror } if
     resourcefont exch Tf pop
   } bdef
end

end			% pdfdict
end			% GS_PDF_ProcSet
.setglobal