summaryrefslogtreecommitdiff
path: root/gs/lib/t1tot2.ps
blob: e416387971ef5365e515db9153835bfb44134840 (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
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
%    Copyright (C) 1997 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.

% t1tot2.ps
% Convert a Type 1 font with Type 1 CharStrings to Type 2.
% **************** THIS FILE DOES NOT WORK. ****************
% **************** DON'T TRY TO USE IT. ****************

(type1ops.ps) runlibfile

% ---------------- CharString conversion ---------------- %

% In the following lists, implemented conversions are marked with a +.
% The following conversions are required for each CharString:
% +	Remove lenIV initial bytes and decrypt.
% +	Move width to first stem/moveto.
% +	Move all hstem/vstem commands to the beginning,
%	  including any from subroutines.
%	Fold side bearing into first moveto.
% +	Adjust Subr indices for bias.
% +	Remove all closepath.
%	Convert Flex othersubrs to new flex commands.
%	Convert hint replacement to -hm and hintmask.
%	Convert MM blend othersubrs to new blend command.
%	For seac, convert char bodies to subrs, add hint replacement.
% +	Make width relative to nominalWidthX, or omit if equal to
%	  defaultWidthX.
% The following patterns allow shortening CharStrings:
% +	rlineto+ => rlineto
% +	rlineto+ (hlineto | vlineto) rlineto+ => rlineto
% +	vlineto (hlineto vlineto)* [hlineto] => vlineto
% +	hlineto (vlineto hlineto)* [vlineto] => hlineto
% +	rrcurveto+ => rrcurveto
% +	rrcurveto+ rlineto => rcurveline
% +	rlineto+ rrcurveto => rlinecurve
% +	(vhcurveto hvcurveto)* [vhcurveto ["hrcurveto"] | "vrcurveto"] =>
%	  vhcurveto
% +	(hvcurveto vhcurveto)* [hvcurveto ["vrcurveto"] | "hrcurveto"] =>
%	  hvcurveto
%	"rvcurveto" (0 y1 x2 y2 0 y3 rrcurveto)* => vvcurveto
%	"hrcurveto" (x1 0 x2 y2 x3 0 rrcurveto)* => hhcurveto

% Convert a CharString from Type 1 to Type 2.
% Free variables: font, subrmap.

/t1tot2cs {		% <charstring1> <forsubr> t1tot2cs <charstring2>
  10 dict begin
  /forsubr exch def
	% Collect the hints, side bearing, and width.
  /vhints 10 dict def
  /hhints 10 dict def
  /hmcount null def
  /lsb null def
  /width null def
  forsubr not {
    dup t1hintops t1scan pop
  } if
  t1t2ops t1scan
  [
  forsubr not {
	% Insert the hints and width at the beginning.
    width dup font /nominalWidthX .knownget { sub } if
    exch font /defaultWidthX .knownget not { 0 } if
    eq { pop } if
    /hstem hhints hintlist
    /vstem vhints hintlist
  } if
  counttomark 2 add -1 roll aload pop ]
	% Convert the string back to encoded form.
  DEBUG {
    (++++ ) print [ 1 index { dup null eq { pop } if } forall ] == flush
  } if
  /lenIV 0 def		% for charproc_string
  charproc_string end
} bind def
/hintlist {		% <hintop> <dict> hintlist -
  dup length 0 eq {
    pop pop
  } {
    dup length array dup 3 -1 roll {
      exch put dup
    } forall pop
	% ****** SORT THE HINTS BY INCREASING v ******
    { dup length 24 le { exit } if
      dup 0 24 getinterval { aload pop 4 2 roll } forall
      dup length 24 sub 24 exch getinterval
    } loop
    { aload pop 3 2 roll } forall
  } ifelse
} bind def
/uneexec {		% <string> <lenIV> uneexec <string>
  dup 0 ge {
    2 copy mark /seed 4330 /lenIV 5 -1 roll .dicttomark /eexecDecode filter
			% Stack: string lenIV filter
    dup 4 -1 roll length 4 -1 roll sub string readstring pop
    exch closefile
  } {
    pop
  } ifelse
} bind def
/t1scan {		% <charstring> <opsdict> t1scan <tokens>
  5 dict begin
  /opsdict exch def
	% Remove encryption and convert to symbolic form for processing.
  font /lenIV .knownget not { 4 } if uneexec
  0 () /SubFileDecode filter /f exch def
  /cstr [ 20 { null } repeat f charstack_read /END 20 { null } repeat ] def
  DEBUG {
    (**** ) print [ cstr { dup null eq { pop } if } forall ] == flush
  } if
	% Scan the unpacked string.
  /i 20 def {
	% The /END token will exit from this loop.
    opsdict cstr i get .knownget { exec } if
    /i i 1 add def
  } loop
  f closefile cstr end
} bind def
/ciget {		% <di> ciget <token>
  i add cstr exch get
} bind def
/ciput {		% <di> <token> ciput -
  exch i add exch cstr 3 1 roll put
} bind def
/ciswap {		% <di> <dj> ciswap -
  2 copy exch ciget exch ciget 3 1 roll ciput ciput
} bind def
/ciskip {		% <di> ciskip -
  i add /i exch def
} bind def

% Hint scanning procedures.
/addhint {		% [<v> <dv>] <hintdict> addhint -
  dup 2 index known { pop pop } { dup length 3 -1 roll exch put } ifelse
} bind def

/t1hintops mark /END { 0 null ciput exit } bind

/vstem {
  cstr i 2 sub 2 getinterval vhints addhint
} bind
/hstem {
  cstr i 2 sub 2 getinterval hhints addhint
} bind
/callsubr {
	%**** DOESN'T HANDLE FLEX YET ****
  -1 ciget /pop eq {
	% This must be a <#> 1 3 /callothersubr /pop /callsubr sequence.
    hmcount null eq { /hmcount [ vhints length hhints length ] store } if
    -5 ciget
  } {
    -1 ciget
  } ifelse
  subrmap 1 index .knownget { exch pop } if
  dup null eq { pop } {
    font /Private get /Subrs get exch get
    t1hintops t1scan pop
  } ifelse
} bind
/hsbw {
  /lsb -2 ciget store
  /width -1 ciget store
} bind
/vstem3 {
  [ -6 ciget -5 ciget ] vhints addhint
  [ -4 ciget -3 ciget ] vhints addhint
  [ -2 ciget -1 ciget ] vhints addhint
} bind
/hstem3 {
  [ -6 ciget -5 ciget ] hhints addhint
  [ -4 ciget -3 ciget ] hhints addhint
  [ -2 ciget -1 ciget ] hhints addhint
} bind
/sbw {
	%**** WHAT ABOUT Y? ****
  /lsb -4 ciget store
  /width -2 ciget store
} bind

.dicttomark readonly def	% t1hintops

% Conversion procedures.
/t1t2ops mark /END { 0 null ciput exit } bind

/hstem {
	% We handled the hints separately, drop them here.
  -2 1 0 { null ciput } for
} bind
/vstem 1 index
/rlineto {
  3 ciget /rlineto eq {
    0 null ciput
  } {
    7 ciget /rrcurveto eq {
      0 null ciput
      7 /rlinecurve ciput
    } {
      5 ciget /rlineto eq {
	2 ciget /hlineto eq {
	  0 null ciput
	  2 0 ciput
	} {
	  2 ciget /vlineto eq {
	    0 0 ciput
	    2 null ciput
	  } if
	} ifelse
      } if
    } ifelse
  } ifelse
} bind
/vlineto {
  2 ciget /hlineto eq {
    0 null ciput
    2 4 ciget /vlineto eq { null } { /vlineto } ifelse ciput
  } if
} bind
/hlineto {
  2 ciget /vlineto eq {
    0 null ciput
    2 4 ciget /hlineto eq { null } { /hlineto } ifelse ciput
  } if
} bind
/rrcurveto {
  7 ciget /rrcurveto eq {
    0 null ciput
  } {
    3 ciget /rlineto eq {
      0 null ciput
      3 /rcurveline ciput
    } {
	%**** WRONG IF MULTIPLE RRCURVETO ****
      -6 ciget 0 eq {
	-6 null ciput
	0 /vhcurveto ciput
      } {
	-5 ciget 0 eq {
	  -5 null ciput
	  -1 -2 ciswap
	  0 /hvcurveto ciput
	} if
      } ifelse
    } ifelse
  } ifelse
} bind
/callsubr {
  -1 ciget subrmap 1 index .knownget { exch pop } if
	% If the Subr was deleted because it was empty, delete the call.
  dup null eq {
    0 null ciput
  } {
	% Subtract the subroutineNumberBias.
    107 sub
  } ifelse -1 exch ciput
} bind
/vhcurveto {
  5 ciget /hvcurveto eq {
    0 null ciput
    10 ciget /vhcurveto eq {
      5 null ciput
    } {
      12 ciget /rrcurveto eq 6 ciget 0 eq and {
	5 null ciput
	6 null ciput
	12 /vhcurveto ciput
	12 ciskip
      } {
	5 /vhcurveto ciput
	5 ciskip
      } ifelse
    } ifelse
  } {
    7 ciget /rrcurveto eq {
      1 ciget 0 eq {
	0 null ciput
	1 null ciput
	5 6 ciswap
	7 /vhcurveto ciput
	7 ciskip
      } if
    } if
  } ifelse
} bind
/hvcurveto {
  5 ciget /vhcurveto eq {
    0 null ciput
    10 ciget /hvcurveto eq {
      5 null ciput
    } {
      12 ciget /rrcurveto eq 7 ciget 0 eq and {
	5 null ciput
	7 null ciput
	10 11 ciswap
	12 /hvcurveto ciput
	12 ciskip
      } {
	5 /hvcurveto ciput
	5 ciskip
      } ifelse
    } ifelse
  } {
    7 ciget /rrcurveto eq {
      2 ciget 0 eq {
	0 null ciput
	2 null ciput
	7 /hvcurveto ciput
	7 ciskip
      } if
    } if
  } ifelse
} bind
/closepath {
  0 null ciput
} bind
/hsbw {
	% We handled this separately, drop it.
  -2 1 0 { null ciput } for
} bind
/dotsection {
	%**************** NYI ****************
} bind
/vstem3 {
	% We handled the hints separately, drop them here.
  -6 1 0 { null ciput } for
} bind
/hstem3 1 index
/seac {
	%**************** NYI ****************
} bind
/sbw {
	% We handled this separately, drop it.
  -4 1 0 { null ciput } for
} bind
/callothersubr {
  -1 ciget 3 eq {
	%**** HANDLE HINT REPLACEMENT ****
    -2 ciget 1 eq 1 ciget /pop eq and 2 ciget /callsubr eq and {
      1 -3 ciget ciput
      -3 1 0 { null ciput } for
    } {
      (**************** 3 callothersubr -- invalid call\n) print
      /t1tot2cs cvx /rangecheck signalerror
    } ifelse
  } if
} bind
/pop {
	%**************** NYI ****************
} bind
/setcurrentpoint {
	%**************** NYI ****************
} bind

.dicttomark readonly def	% t1t2ops

% ---------------- Font conversion ---------------- %

% Copy a font, and remove eexec encryption from it.
/decryptfont {			% <font> decryptfont <font'>
	% Copy the font, CharStrings, Private, and Private.Subrs
  dup length dict copy
  dup /CharStrings 2 copy get dup length dict copy put
  dup /Private 2 copy get dup length dict copy
    dup /Subrs 2 copy get dup length array copy put
  put
  dup /lenIV .knownget not { 4 } if
  1 index /CharStrings get
			% Stack: font' lenIV chars'
  dup { 3 index uneexec 2 index 3 1 roll put } forall pop
  1 index /Private get /Subrs get
			% Stack: font' lenIV Subrs'
  0 1 2 index length 1 sub {
    2 copy get dup type /stringtype eq {
			% Stack: font' lenIV Subrs' index subr
      3 index uneexec
    } if 2 index 3 1 roll put
  } for pop pop dup /lenIV -1 put
} def

% Convert an entire font from Type 1 to Type 2.
/t1tot2font {			% <font> t1tot2font <font'>
  10 dict begin
  /font exch def
  /niv font /lenIV .knownget not { 4 } if def

	% Print initial statistics.

  (lenIV = ) print niv =
  font /CharStrings get
  dup length =only ( CharStrings, ) print
  0 exch { exch pop length add } forall =only ( bytes) =
  font /Private get /Subrs get
  dup length =only ( Subrs, ) print
  0 exch { length add } forall =only ( bytes) =
  flush

	% Remove CharString encryption from the font.

  /font font decryptfont def
  /chars font /CharStrings get dup length dict copy def
  /subrs font /Private get /Subrs get def

	% Remove empty Subrs, including Subrs 0-3.

  /subrmap subrs length dict def
  0 1 3 { subrs exch <0b> put } for
  0 1 subrs length 1 sub {
    subrs 1 index get true t1tot2cs
    length 1 eq {
      subrs 1 index null put
      subrmap exch null put
    } {
      pop
    } ifelse
  } for

	% Remove duplicate Subrs (!).

	% Make an entry in subrdict for each distinct Subr:
	%   key = Subr charstring, value = (lowest) Subr index.
	% At the same time, make entries in subrmap for any duplicates:
	%   key = higher index, value = lowest index.
  /subrdict subrs length dict def
  0 0 1 subrs length 1 sub {
		% Stack: toindex fromindex
    subrs 1 index get subrdict 1 index .knownget {
		% Stack: toindex fromindex subr firstindex
      subrmap 4 -1 roll 3 -1 roll put pop
    } {
      dup null ne {
		% Stack: toindex fromindex subr
	subrmap 3 -1 roll 3 index put		% fromindex => toindex
	subrdict 1 index 3 index put		% subr => toindex
	subrs 2 index 3 -1 roll put		% toindex => subr
	1 add
      } {
	pop pop
      } ifelse
    } ifelse
  } for
  /subrs1 subrs 0 4 -1 roll getinterval def
  font /Private get /Subrs subrs1 put

	% Convert the font.

  /chars2 chars length dict def
  chars { false t1tot2cs chars2 3 1 roll put } forall
  /subrs2 subrs1 length array def
  0 1 subrs1 length 1 sub {
    subrs1 1 index get true t1tot2cs
    subrs2 3 1 roll put
  } for
  font /Private get /Subrs subrs2 put

	% Print final statistics.

  (CharStrings => ) print 0 chars2 { exch pop length add } forall =only
    ( bytes) =
  subrs2 length =only ( Subrs, ) print
  0 subrs2 { length add } forall =only ( bytes) =
  flush
  
	% Clean up the font.

  font /lenIV undef
  font /UniqueID undef
  font /FID undef
  font /CharStrings chars2 put
  font /CharstringType 2 put

  font end
} bind def