Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 2000 Aladdin Enterprises.  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
 
17
/* $Id: gdevpsfx.c,v 1.25 2005/07/30 02:39:45 alexcher Exp $ */
18
/* Convert Type 1 Charstrings to Type 2 */
19
#include "math_.h"
20
#include "memory_.h"
21
#include "gx.h"
22
#include "gserrors.h"
23
#include "gxfixed.h"
24
#include "gxmatrix.h"		/* for gsfont.h */
25
#include "gxfont.h"
26
#include "gxfont1.h"
27
#include "gxtype1.h"
28
#include "stream.h"
29
#include "gdevpsf.h"
30
 
31
/* ------ Type 1 Charstring parsing ------ */
32
 
33
/*
34
 * The parsing code handles numbers on its own; it reports callsubr and
35
 * return operators to the caller, but also executes them.
36
 *
37
 * Only the following elements of the Type 1 state are used:
38
 *	ostack, os_count, ipstack, ips_count
39
 */
40
 
41
#define CE_OFFSET 32		/* offset for extended opcodes */
42
 
43
typedef struct {
44
    fixed v0, v1;		/* coordinates */
45
    ushort index;		/* sequential index of hint */
46
} cv_stem_hint;
47
typedef struct {
48
    int count;
49
    int current;		/* cache cursor for search */
50
    /*
51
     * For dotsection and Type 1 Charstring hint replacement,
52
     * we store active hints at the bottom of the table, and
53
     * replaced hints at the top.
54
     */
55
    int replaced_count;		/* # of replaced hints at top */
56
    cv_stem_hint data[max_total_stem_hints];
57
} cv_stem_hint_table;
58
 
59
/* Skip over the initial bytes in a Charstring, if any. */
60
private void
61
skip_iv(gs_type1_state *pcis)
62
{
63
    int skip = pcis->pfont->data.lenIV;
64
    ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1];
65
    const byte *cip = ipsp->cs_data.bits.data;
66
    crypt_state state = crypt_charstring_seed;
67
 
68
    for (; skip > 0; ++cip, --skip)
69
	decrypt_skip_next(*cip, state);
70
    ipsp->ip = cip;
71
    ipsp->dstate = state;
72
}
73
 
74
/*
75
 * Set up for parsing a Type 1 Charstring.
76
 *
77
 * Only uses the following elements of *pfont:
78
 *	data.lenIV
79
 */
80
private void
81
type1_next_init(gs_type1_state *pcis, const gs_glyph_data_t *pgd,
82
		gs_font_type1 *pfont)
83
{
84
    gs_type1_interp_init(pcis, NULL, NULL, NULL, NULL, false, 0, pfont);
85
    pcis->flex_count = flex_max;
86
    pcis->ipstack[0].cs_data = *pgd;
87
    skip_iv(pcis);
88
}
89
 
90
/* Clear the Type 1 operand stack. */
91
inline private void
92
type1_clear(gs_type1_state *pcis)
93
{
94
    pcis->os_count = 0;
95
}
96
 
97
/* Execute a callsubr. */
98
private int
99
type1_callsubr(gs_type1_state *pcis, int index)
100
{
101
    gs_font_type1 *pfont = pcis->pfont;
102
    ip_state_t *ipsp1 = &pcis->ipstack[pcis->ips_count];
103
    int code = pfont->data.procs.subr_data(pfont, index, false,
104
					   &ipsp1->cs_data);
105
 
106
    if (code < 0)
107
	return_error(code);
108
    pcis->ips_count++;
109
    skip_iv(pcis);
110
    return code;
111
}
112
 
113
/* Add 1 or 3 stem hints. */
114
private int
115
type1_stem1(gs_type1_state *pcis, cv_stem_hint_table *psht, const fixed *pv,
116
	    fixed lsb, byte *active_hints)
117
{
118
    fixed v0 = pv[0] + lsb, v1 = v0 + pv[1];
119
    cv_stem_hint *bot = &psht->data[0];
120
    cv_stem_hint *orig_top = bot + psht->count;
121
    cv_stem_hint *top = orig_top;
122
 
123
    if (psht->count >= max_total_stem_hints)
124
	return_error(gs_error_limitcheck);
125
    while (top > bot &&
126
	   (v0 < top[-1].v0 || (v0 == top[-1].v0 && v1 < top[-1].v1))
127
	   ) {
128
	*top = top[-1];
129
	top--;
130
    }
131
    if (top > bot && v0 == top[-1].v0 && v1 == top[-1].v1) {
132
	/* Duplicate hint, don't add it. */
133
	memmove(top, top + 1, (char *)orig_top - (char *)top);
134
	if (active_hints) {
135
	    uint index = top[-1].index;
136
 
137
	    active_hints[index >> 3] |= 0x80 >> (index & 7);
138
	}
139
	return 0;
140
    }
141
    top->v0 = v0;
142
    top->v1 = v1;
143
    psht->count++;
144
    return 0;
145
}
146
private void
147
type1_stem3(gs_type1_state *pcis, cv_stem_hint_table *psht, const fixed *pv3,
148
	    fixed lsb, byte *active_hints)
149
{
150
    type1_stem1(pcis, psht, pv3, lsb, active_hints);
151
    type1_stem1(pcis, psht, pv3 + 2, lsb, active_hints);
152
    type1_stem1(pcis, psht, pv3 + 4, lsb, active_hints);
153
}
154
 
155
/*
156
 * Get the next operator from a Type 1 Charstring.  This procedure handles
157
 * numbers, div, blend, pop, and callsubr/return.
158
 */
159
private int
160
type1_next(gs_type1_state *pcis)
161
{
162
    ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1];
163
    const byte *cip, *cipe;
164
    crypt_state state;
165
#define CLEAR (csp = pcis->ostack - 1)
166
    fixed *csp = &pcis->ostack[pcis->os_count - 1];
167
    const bool encrypted = pcis->pfont->data.lenIV >= 0;
168
    int c, code, num_results, c0;
169
 
170
 load:
171
    cip = ipsp->ip;
172
    cipe = ipsp->cs_data.bits.data + ipsp->cs_data.bits.size;
173
    state = ipsp->dstate;
174
    for (;;) {
175
        if (cip >= cipe)
176
	    return_error(gs_error_invalidfont);
177
	c0 = *cip++;
178
	charstring_next(c0, state, c, encrypted);
179
	if (c >= c_num1) {
180
	    /* This is a number, decode it and push it on the stack. */
181
	    if (c < c_pos2_0) {	/* 1-byte number */
182
		decode_push_num1(csp, pcis->ostack, c);
183
	    } else if (c < cx_num4) {	/* 2-byte number */
184
		decode_push_num2(csp, pcis->ostack, c, cip, state, encrypted);
185
	    } else if (c == cx_num4) {	/* 4-byte number */
186
		long lw;
187
 
188
		decode_num4(lw, cip, state, encrypted);
189
		CS_CHECK_PUSH(csp, pcis->ostack);
190
		*++csp = int2fixed(lw);
191
	    } else		/* not possible */
192
		return_error(gs_error_invalidfont);
193
	    continue;
194
	}
195
#ifdef DEBUG
196
	if (gs_debug_c('1')) {
197
	    const fixed *p;
198
 
199
	    for (p = pcis->ostack; p <= csp; ++p)
200
		dprintf1(" %g", fixed2float(*p));
201
	    if (c == cx_escape) {
202
		crypt_state cstate = state;
203
		int cn;
204
 
205
		charstring_next(*cip, cstate, cn, encrypted);
206
		dprintf1(" [*%d]\n", cn);
207
	    } else
208
		dprintf1(" [%d]\n", c);
209
	}
210
#endif
211
	switch ((char_command) c) {
212
	default:
213
	    break;
214
	case c_undef0:
215
	case c_undef2:
216
	case c_undef17:
217
	    return_error(gs_error_invalidfont);
218
	case c_callsubr:
219
	    code = type1_callsubr(pcis, fixed2int_var(*csp) +
220
				  pcis->pfont->data.subroutineNumberBias);
221
	    if (code < 0)
222
		return_error(code);
223
	    ipsp->ip = cip, ipsp->dstate = state;
224
	    --csp;
225
	    ++ipsp;
226
	    goto load;
227
	case c_return:
228
	    gs_glyph_data_free(&ipsp->cs_data, "type1_next");
229
	    pcis->ips_count--;
230
	    --ipsp;
231
	    goto load;
232
	case c_undoc15:
233
	    /* See gstype1.h for information on this opcode. */
234
	    CLEAR;
235
	    continue;
236
	case cx_escape:
237
	    charstring_next(*cip, state, c, encrypted);
238
	    ++cip;
239
	    switch ((char1_extended_command) c) {
240
	    default:
241
		c += CE_OFFSET;
242
		break;
243
	    case ce1_div:
244
		csp[-1] = float2fixed((double)csp[-1] / (double)*csp);
245
		--csp;
246
		continue;
247
	    case ce1_undoc15:	/* see gstype1.h */
248
		CLEAR;
249
		continue;
250
	    case ce1_callothersubr:
251
		switch (fixed2int_var(*csp)) {
252
		case 0:
253
		    pcis->ignore_pops = 2;
254
		    break;	/* pass to caller */
255
		case 3:
256
		    pcis->ignore_pops = 1;
257
		    break;	/* pass to caller */
258
		case 14:
259
		    num_results = 1; goto blend;
260
		case 15:
261
		    num_results = 2; goto blend;
262
		case 16:
263
		    num_results = 3; goto blend;
264
		case 17:
265
		    num_results = 4; goto blend;
266
		case 18:
267
		    num_results = 6;
268
		blend:
269
		    code = gs_type1_blend(pcis, csp, num_results);
270
		    if (code < 0)
271
			return code;
272
		    csp -= code;
273
		    continue;
274
		default:
275
		    break;	/* pass to caller */
276
		}
277
		break;
278
	    case ce1_pop:
279
		if (pcis->ignore_pops != 0) {
280
		    pcis->ignore_pops--;
281
		    continue;
282
		}
283
		return_error(gs_error_rangecheck);
284
	    }
285
	    break;
286
	}
287
	break;
288
    }
289
    ipsp->ip = cip, ipsp->dstate = state;
290
    pcis->ips_count = ipsp + 1 - &pcis->ipstack[0];
291
    pcis->os_count = csp + 1 - &pcis->ostack[0];
292
    return c;
293
}
294
 
295
/* ------ Output ------ */
296
 
297
/* Put 2 or 4 bytes on a stream (big-endian). */
298
private void
299
sputc2(stream *s, int i)
300
{
301
    sputc(s, (byte)(i >> 8));
302
    sputc(s, (byte)i);
303
}
304
private void
305
sputc4(stream *s, int i)
306
{
307
    sputc2(s, i >> 16);
308
    sputc2(s, i);
309
}
310
 
311
/* Put a Type 2 operator on a stream. */
312
private void
313
type2_put_op(stream *s, int op)
314
{
315
    if (op >= CE_OFFSET) {
316
	spputc(s, cx_escape);
317
	spputc(s, (byte)(op - CE_OFFSET));
318
    } else
319
	sputc(s, (byte)op);
320
}
321
 
322
/* Put a Type 2 number on a stream. */
323
private void
324
type2_put_int(stream *s, int i)
325
{
326
    if (i >= -107 && i <= 107)
327
	sputc(s, (byte)(i + 139));
328
    else if (i <= 1131 && i >= 0)
329
	sputc2(s, (c_pos2_0 << 8) + i - 108);
330
    else if (i >= -1131 && i < 0)
331
	sputc2(s, (c_neg2_0 << 8) - i - 108);
332
    else if (i >= -32768 && i <= 32767) {
333
	spputc(s, c2_shortint);
334
	sputc2(s, i);
335
    } else {
336
	/*
337
	 * We can't represent this number directly: compute it.
338
	 * (This can be done much more efficiently in particular cases;
339
	 * we'll do this if it ever seems worthwhile.)
340
	 */
341
	type2_put_int(s, i >> 10);
342
	type2_put_int(s, 1024);
343
	type2_put_op(s, CE_OFFSET + ce2_mul);
344
	type2_put_int(s, i & 1023);
345
	type2_put_op(s, CE_OFFSET + ce2_add);
346
    }
347
}
348
 
349
/* Put a fixed value on a stream. */
350
private void
351
type2_put_fixed(stream *s, fixed v)
352
{
353
    if (fixed_is_int(v))
354
	type2_put_int(s, fixed2int_var(v));
355
    else if (v >= int2fixed(-32768) && v < int2fixed(32768)) {
356
	/* We can represent this as a 16:16 number. */
357
	spputc(s, cx_num4);
358
	sputc4(s, v << (16 - _fixed_shift));
359
    } else {
360
	type2_put_int(s, fixed2int_var(v));
361
	type2_put_fixed(s, fixed_fraction(v));
362
	type2_put_op(s, CE_OFFSET + ce2_add);
363
    }
364
}
365
 
366
/* Put a stem hint table on a stream. */
367
private void
368
type2_put_stems(stream *s, int os_count, const cv_stem_hint_table *psht, int op)
369
{
370
    fixed prev = 0;
371
    int pushed = os_count;
372
    int i;
373
 
374
    for (i = 0; i < psht->count; ++i, pushed += 2) {
375
	fixed v0 = psht->data[i].v0;
376
	fixed v1 = psht->data[i].v1;
377
 
378
	if (pushed > ostack_size - 2) {
379
	    type2_put_op(s, op);
380
	    pushed = 0;
381
	}
382
	type2_put_fixed(s, v0 - prev);
383
	type2_put_fixed(s, v1 - v0);
384
	prev = v1;
385
    }
386
    type2_put_op(s, op);
387
}
388
 
389
/* Put out a hintmask command. */
390
private void
391
type2_put_hintmask(stream *s, const byte *mask, uint size)
392
{
393
    uint ignore;
394
 
395
    type2_put_op(s, c2_hintmask);
396
    sputs(s, mask, size, &ignore);
397
}
398
 
399
/* ------ Main program ------ */
400
 
401
 
402
/*
403
 * Convert a Type 1 Charstring to (unencrypted) Type 2.
404
 * For simplicity, we expand all Subrs in-line.
405
 * We still need to optimize the output using these patterns:
406
 *	(vhcurveto hvcurveto)* (vhcurveto hrcurveto | vrcurveto) =>
407
 *	  vhcurveto
408
 *	(hvcurveto vhcurveto)* (hvcurveto vrcurveto | hrcurveto) =>
409
 *	  hvcurveto
410
 */
411
#define MAX_STACK ostack_size
412
int
413
psf_convert_type1_to_type2(stream *s, const gs_glyph_data_t *pgd,
414
			   gs_font_type1 *pfont)
415
{
416
    gs_type1_state cis;
417
    cv_stem_hint_table hstem_hints;	/* horizontal stem hints */
418
    cv_stem_hint_table vstem_hints;	/* vertical stem hints */
419
    bool first = true;
420
    bool replace_hints = false;
421
    bool hints_changed = false;
422
    enum {
423
	dotsection_in = 0,
424
	dotsection_out = -1
425
    } dotsection_flag = dotsection_out;
426
    byte active_hints[(max_total_stem_hints + 7) / 8];
427
    byte dot_save_hints[(max_total_stem_hints + 7) / 8];
428
    uint hintmask_size;
429
#define HINTS_CHANGED()\
430
  BEGIN\
431
    hints_changed = replace_hints;\
432
    if (hints_changed)\
433
	CHECK_OP();		/* see below */\
434
  END
435
#define CHECK_HINTS_CHANGED()\
436
  BEGIN\
437
    if (hints_changed) {\
438
	type2_put_hintmask(s, active_hints, hintmask_size);\
439
	hints_changed = false;\
440
    }\
441
  END
442
    /* 
443
     * In order to combine Type 1 operators, we usually delay writing
444
     * out operators (but not their operands).  We must keep track of
445
     * the stack depth so we don't exceed it when combining operators.
446
     */
447
    int depth;			/* of operands on stack */
448
    int prev_op;		/* operator to write, -1 if none */
449
#define CLEAR_OP()\
450
  (depth = 0, prev_op = -1)
451
#define CHECK_OP()\
452
  BEGIN\
453
    if (prev_op >= 0) {\
454
	type2_put_op(s, prev_op);\
455
	CLEAR_OP();\
456
    }\
457
  END
458
    fixed mx0 = 0, my0 = 0; /* See ce1_setcurrentpoint. */
459
 
460
    /*
461
     * Do a first pass to collect hints.  Note that we must also process
462
     * [h]sbw, because the hint coordinates are relative to the lsb.
463
     */
464
    hstem_hints.count = hstem_hints.replaced_count = hstem_hints.current = 0;
465
    vstem_hints.count = vstem_hints.replaced_count = vstem_hints.current = 0;
466
    type1_next_init(&cis, pgd, pfont);
467
    for (;;) {
468
	int c = type1_next(&cis);
469
	fixed *csp = &cis.ostack[cis.os_count - 1];
470
 
471
	switch (c) {
472
	default:
473
	    if (c < 0)
474
		return c;
475
	    type1_clear(&cis);
476
	    continue;
477
	case c1_hsbw:
478
	    gs_type1_sbw(&cis, cis.ostack[0], fixed_0, cis.ostack[1], fixed_0);
479
	    goto clear;
480
	case cx_hstem:
481
	    type1_stem1(&cis, &hstem_hints, csp - 1, cis.lsb.y, NULL);
482
	    goto clear;
483
	case cx_vstem:
484
	    type1_stem1(&cis, &vstem_hints, csp - 1, cis.lsb.x, NULL);
485
	    goto clear;
486
	case CE_OFFSET + ce1_sbw:
487
	    gs_type1_sbw(&cis, cis.ostack[0], cis.ostack[1],
488
			 cis.ostack[2], cis.ostack[3]);
489
	    goto clear;
490
	case CE_OFFSET + ce1_vstem3:
491
	    type1_stem3(&cis, &vstem_hints, csp - 5, cis.lsb.x, NULL);
492
	    goto clear;
493
	case CE_OFFSET + ce1_hstem3:
494
	    type1_stem3(&cis, &hstem_hints, csp - 5, cis.lsb.y, NULL);
495
	clear:
496
	    type1_clear(&cis);
497
	    continue;
498
	case ce1_callothersubr:
499
	    if (*csp == int2fixed(3))
500
		replace_hints = true;
501
	    cis.os_count -= 2;
502
	    continue;
503
	case CE_OFFSET + ce1_dotsection:
504
	    replace_hints = true;
505
	    continue;
506
	case CE_OFFSET + ce1_seac:
507
	case cx_endchar:
508
	    break;
509
	}
510
	break;
511
    }
512
    /*
513
     * Number the hints for hintmask.  We must do this even if we never
514
     * replace hints, because type1_stem# uses the index to set bits in
515
     * active_hints.
516
     */
517
    {
518
	int i;
519
 
520
	for (i = 0; i < hstem_hints.count; ++i)
521
	    hstem_hints.data[i].index = i;
522
	for (i = 0; i < vstem_hints.count; ++i)
523
	    vstem_hints.data[i].index = i + hstem_hints.count;
524
    }
525
    if (replace_hints) {
526
	hintmask_size =
527
	    (hstem_hints.count + vstem_hints.count + 7) / 8;
528
	memset(active_hints, 0, hintmask_size);
529
    } else 
530
	hintmask_size = 0;
531
 
532
    /* Do a second pass to write the result. */
533
    type1_next_init(&cis, pgd, pfont);
534
    CLEAR_OP();
535
    for (;;) {
536
	int c = type1_next(&cis);
537
	fixed *csp = &cis.ostack[cis.os_count - 1];
538
#define POP(n)\
539
  (csp -= (n), cis.os_count -= (n))
540
	int i;
541
	fixed mx, my;
542
 
543
	switch (c) {
544
	default:
545
	    if (c < 0)
546
		return c;
547
	    if (c >= CE_OFFSET)
548
		return_error(gs_error_rangecheck);
549
	    /* The Type 1 use of all other operators is the same in Type 2. */
550
	copy:
551
	    CHECK_OP();
552
	    CHECK_HINTS_CHANGED();
553
	put:
554
	    for (i = 0; i < cis.os_count; ++i)
555
		type2_put_fixed(s, cis.ostack[i]);
556
	    depth += cis.os_count;
557
	    prev_op = c;
558
	    type1_clear(&cis);
559
	    continue;
560
	case cx_hstem:
561
	    type1_stem1(&cis, &hstem_hints, csp - 1, cis.lsb.y, active_hints);
562
	hint:
563
	    HINTS_CHANGED();
564
	    type1_clear(&cis);
565
	    continue;
566
	case cx_vstem:
567
	    type1_stem1(&cis, &vstem_hints, csp - 1, cis.lsb.x, active_hints);
568
	    goto hint;
569
	case CE_OFFSET + ce1_vstem3:
570
	    type1_stem3(&cis, &vstem_hints, csp - 5, cis.lsb.x, active_hints);
571
	    goto hint;
572
	case CE_OFFSET + ce1_hstem3:
573
	    type1_stem3(&cis, &hstem_hints, csp - 5, cis.lsb.y, active_hints);
574
	    goto hint;
575
	case CE_OFFSET + ce1_dotsection:
576
	    if (dotsection_flag == dotsection_out) {
577
		memcpy(dot_save_hints, active_hints, hintmask_size);
578
		memset(active_hints, 0, hintmask_size);
579
		dotsection_flag = dotsection_in;
580
	    } else {
581
		memcpy(active_hints, dot_save_hints, hintmask_size);
582
		dotsection_flag = dotsection_out;
583
	    }
584
	    HINTS_CHANGED();
585
	    continue;
586
	case c1_closepath:
587
	    continue;
588
	case CE_OFFSET + ce1_setcurrentpoint:
589
	    if (first) {
590
		/*  A workaround for fonts which use ce1_setcurrentpoint 
591
		    in an illegal way for shifting a path. 
592
		    See t1_hinter__setcurrentpoint for more information. */
593
		mx0 = csp[-1], my0 = *csp;
594
	    }
595
	    continue;
596
	case cx_vmoveto:
597
	    mx = 0, my = *csp;
598
	    POP(1); goto move;
599
	case cx_hmoveto:
600
	    mx = *csp, my = 0;
601
	    POP(1); goto move;
602
	case cx_rmoveto:
603
	    mx = csp[-1], my = *csp;
604
	    POP(2);
605
	move:
606
	    CHECK_OP();
607
	    if (first) {
608
		if (cis.os_count)
609
		    type2_put_fixed(s, *csp); /* width */
610
		mx += cis.lsb.x + mx0, my += cis.lsb.y + my0;
611
		first = false;
612
	    }
613
	    if (cis.flex_count != flex_max) {
614
		/* We're accumulating points for a flex. */
615
		if (type1_next(&cis) != ce1_callothersubr)
616
		    return_error(gs_error_rangecheck);
617
		csp = &cis.ostack[cis.os_count - 1];
618
		if (*csp != int2fixed(2) || csp[-1] != fixed_0)
619
		    return_error(gs_error_rangecheck);
620
		cis.flex_count++;
621
		csp[-1] = mx, *csp = my;
622
		continue;
623
	    }
624
	    CHECK_HINTS_CHANGED();
625
	    if (mx == 0) {
626
		type2_put_fixed(s, my);
627
		depth = 1, prev_op = cx_vmoveto;
628
	    } else if (my == 0) {
629
		type2_put_fixed(s, mx);
630
		depth = 1, prev_op = cx_hmoveto;
631
	    } else {
632
		type2_put_fixed(s, mx);
633
		type2_put_fixed(s, my);
634
		depth = 2, prev_op = cx_rmoveto;
635
	    }
636
	    type1_clear(&cis);
637
	    continue;
638
	case c1_hsbw:
639
	    gs_type1_sbw(&cis, cis.ostack[0], fixed_0, cis.ostack[1], fixed_0);
640
	    /*
641
	     * Leave the l.s.b. on the operand stack for the initial hint,
642
	     * moveto, or endchar command.
643
	     */
644
	    cis.ostack[0] = cis.ostack[1];
645
	sbw:
646
	    if (cis.ostack[0] == pfont->data.defaultWidthX)
647
		cis.os_count = 0;
648
	    else {
649
		cis.ostack[0] -= pfont->data.nominalWidthX;
650
		cis.os_count = 1;
651
	    }
652
	    if (hstem_hints.count) {
653
		if (cis.os_count)
654
		    type2_put_fixed(s, cis.ostack[0]);
655
		type2_put_stems(s, cis.os_count, &hstem_hints,
656
				(replace_hints ? c2_hstemhm : cx_hstem));
657
		cis.os_count = 0;
658
	    }
659
	    if (vstem_hints.count) {
660
		if (cis.os_count)
661
		    type2_put_fixed(s, cis.ostack[0]);
662
		type2_put_stems(s, cis.os_count, &vstem_hints,
663
				(replace_hints ? c2_vstemhm : cx_vstem));
664
		cis.os_count = 0;
665
	    }
666
	    continue;
667
	case CE_OFFSET + ce1_seac:
668
	    /*
669
	     * It is an undocumented feature of the Type 2 CharString
670
	     * format that endchar + 4 or 5 operands is equivalent to
671
	     * seac with an implicit asb operand + endchar with 0 or 1
672
	     * operands.  Remove the asb argument from the stack, but
673
	     * adjust the adx argument to compensate for the fact that
674
	     * Type 2 CharStrings don't have any concept of l.s.b.
675
	     */
676
	    csp[-3] += cis.lsb.x - csp[-4];
677
	    memmove(csp - 4, csp - 3, sizeof(*csp) * 4);
678
	    POP(1);
679
	    /* (falls through) */
680
	case cx_endchar:
681
	    CHECK_OP();
682
	    for (i = 0; i < cis.os_count; ++i)
683
		type2_put_fixed(s, cis.ostack[i]);
684
	    type2_put_op(s, cx_endchar);
685
	    return 0;
686
	case CE_OFFSET + ce1_sbw:
687
	    gs_type1_sbw(&cis, cis.ostack[0], cis.ostack[1],
688
			 cis.ostack[2], cis.ostack[3]);
689
	    cis.ostack[0] = cis.ostack[2];
690
	    goto sbw;
691
	case ce1_callothersubr:
692
	    CHECK_OP();
693
	    switch (fixed2int_var(*csp)) {
694
	    default:
695
		return_error(gs_error_rangecheck);
696
	    case 0:
697
		/*
698
		 * The operand stack contains: delta to reference point,
699
		 * 6 deltas for the two curves, fd, final point, 3, 0.
700
		 */
701
		csp[-18] += csp[-16], csp[-17] += csp[-15];
702
		memmove(csp - 16, csp - 14, sizeof(*csp) * 11);
703
		cis.os_count -= 6, csp -= 6;
704
		/*
705
		 * We could optimize by using [h]flex[1],
706
		 * but it isn't worth the trouble.
707
		 */
708
		c = CE_OFFSET + ce2_flex;
709
		cis.flex_count = flex_max;	/* not inside flex */
710
		cis.ignore_pops = 2;
711
		goto copy;
712
	    case 1:
713
		cis.flex_count = 0;
714
		cis.os_count -= 2;
715
		continue;
716
	    /*case 2:*/		/* detected in *moveto */
717
	    case 3:
718
		memset(active_hints, 0, hintmask_size);
719
		HINTS_CHANGED();
720
		cis.ignore_pops = 1;
721
		cis.os_count -= 2;
722
		continue;
723
	    case 12:
724
	    case 13:
725
		/* Counter control is not implemented. */
726
		cis.os_count -= 2 + fixed2int(csp[-1]);
727
		continue;
728
	    }
729
	    /*
730
	     * The remaining cases are strictly for optimization.
731
	     */
732
	case cx_rlineto:
733
	    if (depth > MAX_STACK - 2)
734
		goto copy;
735
	    switch (prev_op) {
736
	    case cx_rlineto:	/* rlineto+ => rlineto */
737
		goto put;
738
	    case cx_rrcurveto:	/* rrcurveto+ rlineto => rcurveline */
739
		c = c2_rcurveline;
740
		goto put;
741
	    default:
742
		goto copy;
743
	    }
744
	case cx_hlineto:  /* hlineto (vlineto hlineto)* [vlineto] => hlineto */
745
	    if (depth > MAX_STACK - 1 ||
746
		prev_op != (depth & 1 ? cx_vlineto : cx_hlineto))
747
		goto copy;
748
	    c = prev_op;
749
	    goto put;
750
	case cx_vlineto:  /* vlineto (hlineto vlineto)* [hlineto] => vlineto */
751
	    if (depth > MAX_STACK - 1 ||
752
		prev_op != (depth & 1 ? cx_hlineto : cx_vlineto))
753
		goto copy;
754
	    c = prev_op;
755
	    goto put;
756
	case cx_hvcurveto: /* hvcurveto (vhcurveto hvcurveto)* => hvcurveto */
757
				/* (vhcurveto hvcurveto)+ => vhcurveto  */
758
	    /*
759
	     * We have to check (depth & 1) because the last curve might
760
	     * have 5 parameters rather than 4 (see rrcurveto below).
761
	     */
762
	    if ((depth & 1) || depth > MAX_STACK - 4 ||
763
		prev_op != (depth & 4 ? cx_vhcurveto : cx_hvcurveto))
764
		goto copy;
765
	    c = prev_op;
766
	    goto put;
767
	case cx_vhcurveto: /* vhcurveto (hvcurveto vhcurveto)* => vhcurveto */
768
				/* (hvcurveto vhcurveto)+ => hvcurveto  */
769
	    /* See above re the (depth & 1) check. */
770
	    if ((depth & 1) || depth > MAX_STACK - 4 ||
771
		prev_op != (depth & 4 ? cx_hvcurveto : cx_vhcurveto))
772
		goto copy;
773
	    c = prev_op;
774
	    goto put;
775
	case cx_rrcurveto:
776
	    if (depth == 0) {
777
		if (csp[-1] == 0) {
778
		    /* A|0 B C D 0 F rrcurveto => [A] B C D F vvcurveto */
779
		    c = c2_vvcurveto;
780
		    csp[-1] = csp[0];
781
		    if (csp[-5] == 0) {
782
			memmove(csp - 5, csp - 4, sizeof(*csp) * 4);
783
			POP(2);
784
		    } else
785
			POP(1);
786
		} else if (*csp == 0) {
787
		    /* A B|0 C D E 0 rrcurveto => [B] A C D E hhcurveto */
788
		    c = c2_hhcurveto;
789
		    if (csp[-4] == 0) {
790
			memmove(csp - 4, csp - 3, sizeof(*csp) * 3);
791
			POP(2);
792
		    } else {
793
			*csp = csp[-5], csp[-5] = csp[-4], csp[-4] = *csp;
794
			POP(1);
795
		    }
796
		}
797
		/*
798
		 * We could also optimize:
799
		 *   0 B C D E F|0 rrcurveto => B C D E [F] vhcurveto
800
		 *   A 0 C D E|0 F rrcurveto => A C D F [E] hvcurveto
801
		 * but this gets in the way of subsequent optimization
802
		 * of multiple rrcurvetos, so we don't do it.
803
		 */
804
		goto copy;
805
	    }
806
	    if (depth > MAX_STACK - 6)
807
		goto copy;
808
	    switch (prev_op) {
809
	    case c2_hhcurveto:	/* hrcurveto (x1 0 x2 y2 x3 0 rrcurveto)* => */
810
				/* hhcurveto */
811
		if (csp[-4] == 0 && *csp == 0) {
812
		    memmove(csp - 4, csp - 3, sizeof(*csp) * 3);
813
		    c = prev_op;
814
		    POP(2);
815
		    goto put;
816
		}
817
		goto copy;
818
	    case c2_vvcurveto:	/* rvcurveto (0 y1 x2 y2 0 y3 rrcurveto)* => */
819
				/* vvcurveto */
820
		if (csp[-5] == 0 && csp[-1] == 0) {
821
		    memmove(csp - 5, csp - 4, sizeof(*csp) * 3);
822
		    csp[-2] = *csp;
823
		    c = prev_op;
824
		    POP(2);
825
		    goto put;
826
		}
827
		goto copy;
828
	    case cx_hvcurveto:
829
		if (depth & 1)
830
		    goto copy;
831
		if (!(depth & 4))
832
		    goto hrc;
833
	    vrc:  /* (vhcurveto hvcurveto)+ vrcurveto => vhcurveto */
834
		/* hvcurveto (vhcurveto hvcurveto)* vrcurveto => hvcurveto */
835
		if (csp[-5] != 0)
836
		    goto copy;
837
		memmove(csp - 5, csp - 4, sizeof(*csp) * 5);
838
		c = prev_op;
839
		POP(1);
840
		goto put;
841
	    case cx_vhcurveto:
842
		if (depth & 1)
843
		    goto copy;
844
		if (!(depth & 4))
845
		    goto vrc;
846
	    hrc:  /* (hvcurveto vhcurveto)+ hrcurveto => hvcurveto */
847
		/* vhcurveto (hvcurveto vhcurveto)* hrcurveto => vhcurveto */
848
		if (csp[-4] != 0)
849
		    goto copy;
850
		/* A 0 C D E F => A C D F E */
851
		memmove(csp - 4, csp - 3, sizeof(*csp) * 2);
852
		csp[-2] = *csp;
853
		c = prev_op;
854
		POP(1);
855
		goto put;
856
	    case cx_rlineto:	/* rlineto+ rrcurveto => rlinecurve */
857
		c = c2_rlinecurve;
858
		goto put;
859
	    case cx_rrcurveto:	/* rrcurveto+ => rrcurveto */
860
		goto put;
861
	    default:
862
		goto copy;
863
	    }
864
	}
865
    }
866
}