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
|