1 /* Copyright (C) 2000-2008 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include "pfaedit.h"
28 #include <math.h>
29 #include <locale.h>
30 #include <ustring.h>
31 #include <utype.h>
32 #include "psfont.h"
33 #include "sd.h"
34 #ifdef HAVE_IEEEFP_H
35 # include <ieeefp.h>		/* Solaris defines isnan in ieeefp rather than math.h */
36 #endif
37 
38 int THdo_hint_guessing = 0;
39 int THdo_set_reversing = 0;
40 int THdo_catagorize = 0;
41 
42 typedef struct _io {
43     char *macro, *start;
44     FILE *ps, *fog;
45     char fogbuf[60];
46     int backedup, cnt, isloop, isstopped, fogns;
47     struct _io *prev;
48 } _IO;
49 
50 typedef struct io {
51     struct _io *top;
52     int endedstopped;
53     int advance_width;		/* Can be set from a PS comment by MF2PT1 */
54 } IO;
55 
56 typedef struct growbuf {
57     char *pt;
58     char *base;
59     char *end;
60 } GrowBuf;
61 
62 #define GARBAGE_MAX	64
63 struct garbage {
64     int cnt;
65     struct garbage *next;
66     struct pskeyval *entries[GARBAGE_MAX];
67     int16 cnts[GARBAGE_MAX];
68 };
69 
GrowBuffer(GrowBuf * gb,int len)70 static void GrowBuffer(GrowBuf *gb,int len) {
71     if ( len<400 ) len = 400;
72     if ( gb->base==NULL ) {
73 	gb->base = gb->pt = galloc(len);
74 	gb->end = gb->base + len;
75     } else {
76 	int off = gb->pt-gb->base;
77 	len += (gb->end-gb->base);
78 	gb->base = grealloc(gb->base,len);
79 	gb->end = gb->base + len;
80 	gb->pt = gb->base+off;
81     }
82 }
83 
AddTok(GrowBuf * gb,char * buf,int islit)84 static void AddTok(GrowBuf *gb,char *buf,int islit) {
85     int len = islit + strlen(buf) + 1;
86 
87     if ( gb->pt+len+1 >= gb->end )
88 	GrowBuffer(gb,len+1);
89     if ( islit )
90 	*(gb->pt++) = '/';
91     strcpy(gb->pt,buf);
92     gb->pt += strlen(buf);
93     *gb->pt++ = ' ';
94 }
95 
lookup(struct pskeydict * dict,char * tokbuf)96 static struct pskeyval *lookup(struct pskeydict *dict,char *tokbuf) {
97     int i;
98 
99     for ( i=0; i<dict->cnt; ++i )
100 	if ( strcmp(dict->entries[i].key,tokbuf)==0 )
101 return( &dict->entries[i] );
102 
103 return( NULL );
104 }
105 
dictfree(struct pskeydict * dict)106 static void dictfree(struct pskeydict *dict) {
107     int i;
108 
109     for ( i=0; i<dict->cnt; ++i ) {
110 	if ( dict->entries[i].type==ps_string || dict->entries[i].type==ps_instr ||
111 		dict->entries[i].type==ps_lit )
112 	    free(dict->entries[i].u.str);
113 	else if ( dict->entries[i].type==ps_array || dict->entries[i].type==ps_dict )
114 	    dictfree(&dict->entries[i].u.dict);
115     }
116 }
117 
garbagefree(struct garbage * all)118 static void garbagefree(struct garbage *all) {
119     struct garbage *junk, *next;
120     int i,j;
121 
122     for ( junk = all; junk!=NULL; junk = next ) {
123 	next = junk->next;
124 	for ( j=0; j<junk->cnt; ++j ) {
125 	    for ( i=0; i<junk->cnts[j]; ++i ) {
126 		if ( junk->entries[j][i].type==ps_string || junk->entries[j][i].type==ps_instr ||
127 			junk->entries[j][i].type==ps_lit )
128 		    free(junk->entries[j][i].u.str);
129 	    }
130 	    free(junk->entries[j]);
131 	}
132 	if ( junk!=all )
133 	    chunkfree(junk,sizeof(struct garbage));
134     }
135 }
136 /**************************** Postscript Importer *****************************/
137 /* It's really dumb. It ignores almost everything except linetos and curvetos */
138 /*  anything else, function calls, ... is thrown out, if this breaks a lineto */
139 /*  or curveto or moveto (if there aren't enough things on the stack) then we */
140 /*  ignore that too */
141 
142 enum pstoks { pt_eof=-1, pt_moveto, pt_rmoveto, pt_curveto, pt_rcurveto,
143     pt_lineto, pt_rlineto, pt_arc, pt_arcn, pt_arct, pt_arcto,
144     pt_newpath, pt_closepath, pt_dup, pt_pop, pt_index,
145     pt_exch, pt_roll, pt_clear, pt_copy, pt_count,
146     pt_setcachedevice, pt_setcharwidth,
147     pt_translate, pt_scale, pt_rotate, pt_concat, pt_end, pt_exec,
148     pt_add, pt_sub, pt_mul, pt_div, pt_idiv, pt_mod, pt_neg,
149     pt_abs, pt_round, pt_ceiling, pt_floor, pt_truncate, pt_max, pt_min,
150     pt_ne, pt_eq, pt_gt, pt_ge, pt_lt, pt_le, pt_and, pt_or, pt_xor, pt_not,
151     pt_exp, pt_sqrt, pt_ln, pt_log, pt_atan, pt_sin, pt_cos,
152     pt_true, pt_false,
153     pt_if, pt_ifelse, pt_for, pt_loop, pt_repeat, pt_exit,
154     pt_stopped, pt_stop,
155     pt_def, pt_bind, pt_load,
156     pt_setlinecap, pt_setlinejoin, pt_setlinewidth, pt_setdash,
157     pt_currentlinecap, pt_currentlinejoin, pt_currentlinewidth, pt_currentdash,
158     pt_setgray, pt_currentgray, pt_sethsbcolor, pt_currenthsbcolor,
159     pt_setrgbcolor, pt_currentrgbcolor, pt_setcmykcolor, pt_currentcmykcolor,
160     pt_currentpoint,
161     pt_fill, pt_stroke, pt_clip,
162 
163     pt_imagemask,
164 
165     pt_transform, pt_itransform, pt_dtransform, pt_idtransform,
166 
167     /* things we sort of pretend to do, but actually do something wrong */
168     pt_gsave, pt_grestore, pt_save, pt_restore, pt_currentmatrix, pt_setmatrix,
169     pt_null,
170 
171     pt_currentflat, pt_setflat,
172     pt_currentglobal, pt_setglobal,
173     pt_currentmiterlimit, pt_setmiterlimit,
174     pt_currentobjectformat, pt_setobjectformat,
175     pt_currentoverprint, pt_setoverprint,
176     pt_currentpacking, pt_setpacking,
177     pt_currentshared,
178     pt_currentsmoothness, pt_setsmoothness,
179     pt_currentstrokeadjust, pt_setstrokeadjust,
180 
181     pt_mark, pt_counttomark, pt_cleartomark, pt_array, pt_aload, pt_astore,
182     pt_print, pt_cvi, pt_cvlit, pt_cvn, pt_cvr, pt_cvrs, pt_cvs, pt_cvx, pt_stringop,
183 
184     pt_opencurly, pt_closecurly, pt_openarray, pt_closearray, pt_string,
185     pt_number, pt_unknown, pt_namelit, pt_output, pt_outputd };
186 
187 static char *toknames[] = { "moveto", "rmoveto", "curveto", "rcurveto",
188 	"lineto", "rlineto", "arc", "arcn", "arct", "arcto",
189 	"newpath", "closepath", "dup", "pop", "index",
190 	"exch", "roll", "clear", "copy", "count",
191 	"setcachedevice", "setcharwidth",
192 	"translate", "scale", "rotate", "concat", "end", "exec",
193 	"add", "sub", "mul", "div", "idiv", "mod", "neg",
194 	"abs", "round", "ceiling", "floor", "truncate", "max", "min",
195 	"ne", "eq", "gt", "ge", "lt", "le", "and", "or", "xor", "not",
196 	"exp", "sqrt", "ln", "log", "atan", "sin", "cos",
197 	"true", "false",
198 	"if", "ifelse", "for", "loop", "repeat", "exit",
199 	"stopped", "stop",
200 	"def", "bind", "load",
201 	"setlinecap", "setlinejoin", "setlinewidth", "setdash",
202 	"currentlinecap", "currentlinejoin", "currentlinewidth", "currentdash",
203 	"setgray", "currentgray", "sethsbcolor", "currenthsbcolor",
204 	"setrgbcolor", "currentrgbcolor", "setcmykcolor", "currentcmykcolor",
205 	"currentpoint",
206 	"fill", "stroke", "clip",
207 
208 	"imagemask",
209 
210 	"transform", "itransform", "dtransform", "idtransform",
211 
212 	"gsave", "grestore", "save", "restore", "currentmatrix", "setmatrix",
213 	"null",
214 
215 	"currentflat", "setflat",
216 	"currentglobal", "setglobal",
217 	"currentmiterlimit", "setmiterlimit",
218 	"currentobjectformat", "setobjectformat",
219 	"currentoverprint", "setoverprint",
220 	"currentpacking", "setpacking",
221 	"currentshared",
222 	"currentsmoothness", "setsmoothness",
223 	"currentstrokeadjust", "setstrokeadjust",
224 
225 	"mark", "counttomark", "cleartomark", "array", "aload", "astore",
226 	"print", "cvi", "cvlit", "cvn", "cvr", "cvrs", "cvs", "cvx", "string",
227 
228 	"opencurly", "closecurly", "openarray", "closearray", "string",
229 	"number", "unknown", "namelit", "=", "==",
230 
231 	NULL };
232 
233 /* length (of string)
234     fill eofill stroke
235     gsave grestore
236 */
237 
getfoghex(_IO * io)238 static int getfoghex(_IO *io) {
239     int ch,val;
240 
241     while ( isspace( ch = getc(io->fog)));
242     if ( isdigit(ch))
243 	val = ch-'0';
244     else if ( ch >= 'A' && ch <= 'F' )
245 	val = ch-'A'+10;
246     else if ( ch >= 'a' && ch <= 'f' )
247 	val = ch-'a'+10;
248     else
249 return(EOF);
250 
251     val <<= 4;
252     while ( isspace( ch = getc(io->fog)));
253     if ( isdigit(ch))
254 	val |= ch-'0';
255     else if ( ch >= 'A' && ch <= 'F' )
256 	val |= ch-'A'+10;
257     else if ( ch >= 'a' && ch <= 'f' )
258 	val |= ch-'a'+10;
259     else
260 return(EOF);
261 
262 return( val );
263 }
264 
nextch(IO * wrapper)265 static int nextch(IO *wrapper) {
266     int ch;
267     _IO *io = wrapper->top;
268 /* This works for fog 4.1. Fonts generated by 2.4 seem to use a different */
269 /*  vector, and a different number parsing scheme */
270     static char *foguvec[]= { "moveto ", "rlineto ", "rrcurveto ", " ", " ",
271 	"Cache ", "10 div setlinewidth ", "ShowInt ", " ", " ", " ", " ",
272 	"FillStroke ", " ", " ", "SetWid ", "100 mul add ", "togNS_ ",
273 	" ", "closepath ", " ", "SG " };
274 
275     while ( io!=NULL ) {
276 	if ( io->backedup!=EOF ) {
277 	    ch = io->backedup;
278 	    io->backedup = EOF;
279 return( ch );
280 	} else if ( io->ps!=NULL ) {
281 	    if ( (ch = getc(io->ps))!=EOF )
282 return( ch );
283 	} else if ( io->fog!=NULL ) {
284 	    if ( io->macro!=NULL && *io->macro!='\0' )
285 return( *(io->macro++) );
286 	    ch = getfoghex(io);
287 	    if ( ch>=233 ) {
288 		io->macro = foguvec[ch-233];
289 return( *(io->macro++) );
290 	    } else if ( ch!=EOF && ch<200 ) {
291 		sprintf( io->fogbuf, "%d ", ch-100);
292 		io->macro=io->fogbuf;
293 return( *(io->macro++) );
294 	    } else if (ch!=EOF) {
295 		sprintf( io->fogbuf, "%d %s ", ch-233+17, io->fogns
296 			? "2 exch exp 3 1 roll 100 mul add mul"
297 			: "100 mul add" );
298 		io->macro=io->fogbuf;
299 return( *(io->macro++) );
300 	    }
301 	} else {
302 	    if ( (ch = *(io->macro++))!='\0' )
303 return( ch );
304 	    if ( --io->cnt>0 ) {
305 		io->macro = io->start;
306 return( nextch(wrapper));
307 	    }
308 	}
309 	wrapper->top = io->prev;
310 	if ( io->isstopped )
311 	    wrapper->endedstopped = true;
312 	free(io->start);
313 	free(io);
314 	io = wrapper->top;
315     }
316 return( EOF );
317 }
318 
unnextch(int ch,IO * wrapper)319 static void unnextch(int ch,IO *wrapper) {
320     if ( ch==EOF )
321 return;
322     if ( wrapper->top==NULL )
323 	LogError( _("Can't back up with nothing on stack\n") );
324     else if ( wrapper->top->backedup!=EOF )
325 	LogError( _("Attempt to back up twice\n") );
326     else if ( wrapper->top->ps!=NULL )
327 	ungetc(ch,wrapper->top->ps);
328     else
329 	wrapper->top->backedup = ch;
330 }
331 
pushio(IO * wrapper,FILE * ps,char * macro,int cnt)332 static void pushio(IO *wrapper, FILE *ps, char *macro, int cnt) {
333     _IO *io = gcalloc(1,sizeof(_IO));
334 
335     io->prev = wrapper->top;
336     io->ps = ps;
337     io->macro = io->start = copy(macro);
338     io->backedup = EOF;
339     if ( cnt==-1 ) {
340 	io->cnt = 1;
341 	io->isstopped = true;
342     } else if ( cnt==0 ) {
343 	io->cnt = 1;
344 	io->isloop = false;
345     } else {
346 	io->cnt = cnt;
347 	io->isloop = true;
348     }
349     wrapper->top = io;
350 }
351 
pushfogio(IO * wrapper,FILE * fog)352 static void pushfogio(IO *wrapper, FILE *fog) {
353     _IO *io = gcalloc(1,sizeof(_IO));
354 
355     io->prev = wrapper->top;
356     io->fog = fog;
357     io->backedup = EOF;
358     io->cnt = 1;
359     io->isloop = false;
360     wrapper->top = io;
361 }
362 
ioescapeloop(IO * wrapper)363 static void ioescapeloop(IO *wrapper) {
364     _IO *io = wrapper->top, *iop;
365     int wasloop;
366 
367     while ( io->prev!=NULL && !io->isstopped ) {
368 	iop = io->prev;
369 	wasloop = io->isloop;
370 	free(io->start);
371 	free(io);
372 	if ( wasloop ) {
373 	    wrapper->top = iop;
374 return;
375 	}
376 	io = iop;
377     }
378 
379 /* GT: This is part of the PostScript language. "exit" should not be translated */
380 /* GT: as it is a PostScript keyword. (FF contains a small PostScript interpreter */
381 /* GT: so it can understand some PostScript fonts, and can generate errors when */
382 /* GT: handed bad PostScript). */
383     LogError( _("Use of \"exit\" when not in a loop\n") );
384     wrapper->top = io;
385 }
386 
ioescapestopped(IO * wrapper,struct psstack * stack,int sp,const size_t bsize)387 static int ioescapestopped(IO *wrapper, struct psstack *stack, int sp, const size_t bsize) {
388     _IO *io = wrapper->top, *iop;
389     int wasstopped;
390 
391     while ( io->prev!=NULL ) {
392 	iop = io->prev;
393 	wasstopped = io->isstopped;
394 	free(io->start);
395 	free(io);
396 	if ( wasstopped ) {
397 	    wrapper->top = iop;
398 	    if ( sp<(int)bsize ) {
399 		stack[sp].type = ps_bool;
400 		stack[sp++].u.tf = true;
401 	    }
402 return(sp);
403 	}
404 	io = iop;
405     }
406 
407 /* GT: This is part of the PostScript language. Neither "stop" nor "stopped" */
408 /* GT: should be translated as both are PostScript keywords. */
409     LogError( _("Use of \"stop\" when not in a stopped\n") );
410     wrapper->top = io;
411 return( sp );
412 }
413 
endedstopped(IO * wrapper)414 static int endedstopped(IO *wrapper) {
415     if ( wrapper->endedstopped ) {
416 	wrapper->endedstopped = false;
417 return( true );
418     }
419 return( false );
420 }
421 
422 
nextpstoken(IO * wrapper,real * val,char * tokbuf,int tbsize)423 static int nextpstoken(IO *wrapper, real *val, char *tokbuf, int tbsize) {
424     int ch, r, i;
425     char *pt, *end;
426     float mf2pt_advance_width;
427 
428     pt = tokbuf;
429     end = pt+tbsize-1;
430 
431     /* Eat whitespace and comments. Comments last to eol (or formfeed) */
432     while ( 1 ) {
433 	while ( isspace(ch = nextch(wrapper)) );
434 	if ( ch!='%' )
435     break;
436 	while ( (ch=nextch(wrapper))!=EOF && ch!='\r' && ch!='\n' && ch!='\f' )
437 	    if ( pt<end )
438 		*pt++ = ch;
439 	*pt='\0';
440 	/* Some comments have meanings (that we care about) */
441 	if ( sscanf( tokbuf, " MF2PT1: bbox %*g %*g %g %*g", &mf2pt_advance_width )==1 )
442 	    wrapper->advance_width = mf2pt_advance_width;
443 	else if ( sscanf( tokbuf, " MF2PT1: glyph_dimensions %*g %*g %g %*g", &mf2pt_advance_width )==1 )
444 	    wrapper->advance_width = mf2pt_advance_width;
445 	pt = tokbuf;
446     }
447 
448     if ( ch==EOF )
449 return( pt_eof );
450 
451     pt = tokbuf;
452     end = pt+tbsize-1;
453     *pt++ = ch; *pt='\0';
454 
455     if ( ch=='(' ) {
456 	int nest=1, quote=0;
457 	while ( (ch=nextch(wrapper))!=EOF ) {
458 	    if ( pt<end ) *pt++ = ch;
459 	    if ( quote )
460 		quote=0;
461 	    else if ( ch=='(' )
462 		++nest;
463 	    else if ( ch==')' ) {
464 		if ( --nest==0 )
465 	break;
466 	    } else if ( ch=='\\' )
467 		quote = 1;
468 	}
469 	*pt='\0';
470 return( pt_string );
471     } else if ( ch=='<' ) {
472 	ch = nextch(wrapper);
473 	if ( pt<end ) *pt++ = ch;
474 	if ( ch=='>' )
475 	    /* Done */;
476 	else if ( ch!='~' ) {
477 	    while ( (ch=nextch(wrapper))!=EOF && ch!='>' )
478 		if ( pt<end ) *pt++ = ch;
479 	} else {
480 	    int twiddle=0;
481 	    while ( (ch=nextch(wrapper))!=EOF ) {
482 		if ( pt<end ) *pt++ = ch;
483 		if ( ch=='~' ) twiddle = 1;
484 		else if ( twiddle && ch=='>' )
485 	    break;
486 		else twiddle = 0;
487 	    }
488 	}
489 	*pt='\0';
490 return( pt_string );
491     } else if ( ch==')' || ch=='>' || ch=='[' || ch==']' || ch=='{' || ch=='}' ) {
492 	if ( ch=='{' )
493 return( pt_opencurly );
494 	else if ( ch=='}' )
495 return( pt_closecurly );
496 	if ( ch=='[' )
497 return( pt_openarray );
498 	else if ( ch==']' )
499 return( pt_closearray );
500 
501 return( pt_unknown );	/* single character token */
502     } else if ( ch=='/' ) {
503 	pt = tokbuf;
504 	while ( (ch=nextch(wrapper))!=EOF && !isspace(ch) && ch!='%' &&
505 		ch!='(' && ch!=')' && ch!='<' && ch!='>' && ch!='[' && ch!=']' &&
506 		ch!='{' && ch!='}' && ch!='/' )
507 	    if ( pt<tokbuf+tbsize-2 )
508 		*pt++ = ch;
509 	*pt = '\0';
510 	unnextch(ch,wrapper);
511 return( pt_namelit );	/* name literal */
512     } else {
513 	while ( (ch=nextch(wrapper))!=EOF && !isspace(ch) && ch!='%' &&
514 		ch!='(' && ch!=')' && ch!='<' && ch!='>' && ch!='[' && ch!=']' &&
515 		ch!='{' && ch!='}' && ch!='/' ) {
516 	    if ( pt<tokbuf+tbsize-2 )
517 		*pt++ = ch;
518 	}
519 	*pt = '\0';
520 	unnextch(ch,wrapper);
521 	r = strtol(tokbuf,&end,10);
522 	pt = end;
523 	if ( *pt=='\0' ) {		/* It's a normal integer */
524 	    *val = r;
525 return( pt_number );
526 	} else if ( *pt=='#' ) {
527 	    r = strtol(pt+1,&end,r);
528 	    if ( *end=='\0' ) {		/* It's a radix integer */
529 		*val = r;
530 return( pt_number );
531 	    }
532 	} else {
533 	    *val = strtod(tokbuf,&end);
534 	    if ( !finite(*val) ) {
535 /* GT: NaN is a concept in IEEE floating point which means "Not a Number" */
536 /* GT: it is used to represent errors like 0/0 or sqrt(-1). */
537 		LogError( _("Bad number, infinity or nan: %s\n"), tokbuf );
538 		*val = 0;
539 	    }
540 	    if ( *end=='\0' )		/* It's a real */
541 return( pt_number );
542 	}
543 	/* It's not a number */
544 	for ( i=0; toknames[i]!=NULL; ++i )
545 	    if ( strcmp(tokbuf,toknames[i])==0 )
546 return( i );
547 
548 return( pt_unknown );
549     }
550 }
551 
Transform(BasePoint * to,DBasePoint * from,real trans[6])552 static void Transform(BasePoint *to, DBasePoint *from, real trans[6]) {
553     to->x = trans[0]*from->x+trans[2]*from->y+trans[4];
554     to->y = trans[1]*from->x+trans[3]*from->y+trans[5];
555 }
556 
MatMultiply(real m1[6],real m2[6],real to[6])557 void MatMultiply(real m1[6], real m2[6], real to[6]) {
558     real trans[6];
559 
560     trans[0] = m1[0]*m2[0] +
561 		m1[1]*m2[2];
562     trans[1] = m1[0]*m2[1] +
563 		m1[1]*m2[3];
564     trans[2] = m1[2]*m2[0] +
565 		m1[3]*m2[2];
566     trans[3] = m1[2]*m2[1] +
567 		m1[3]*m2[3];
568     trans[4] = m1[4]*m2[0] +
569 		m1[5]*m2[2] +
570 		m2[4];
571     trans[5] = m1[4]*m2[1] +
572 		m1[5]*m2[3] +
573 		m2[5];
574     memcpy(to,trans,sizeof(trans));
575 }
576 
MatInverse(real into[6],real orig[6])577 void MatInverse(real into[6], real orig[6]) {
578     real det = orig[0]*orig[3] - orig[1]*orig[2];
579 
580     if ( det==0 ) {
581 	LogError( _("Attempt to invert a singular matrix\n") );
582 	memset(into,0,sizeof(*into));
583     } else {
584 	into[0] =  orig[3]/det;
585 	into[1] = -orig[1]/det;
586 	into[2] = -orig[2]/det;
587 	into[3] =  orig[0]/det;
588 	into[4] = -orig[4]*into[0] - orig[5]*into[2];
589 	into[5] = -orig[4]*into[1] - orig[5]*into[3];
590     }
591 }
592 
ECCatagorizePoints(EntityChar * ec)593 static void ECCatagorizePoints( EntityChar *ec ) {
594     Entity *ent;
595 
596     for ( ent=ec->splines; ent!=NULL; ent=ent->next ) if ( ent->type == et_splines ) {
597 	SPLCatagorizePoints( ent->u.splines.splines );
598 	SPLCatagorizePoints( ent->clippath );
599     }
600 }
601 
AddEntry(struct pskeydict * dict,struct psstack * stack,int sp)602 static int AddEntry(struct pskeydict *dict,struct psstack *stack, int sp) {
603     int i;
604 
605     if ( dict->cnt>=dict->max ) {
606 	if ( dict->cnt==0 ) {
607 	    dict->max = 30;
608 	    dict->entries = galloc(dict->max*sizeof(struct pskeyval));
609 	} else {
610 	    dict->max += 30;
611 	    dict->entries = grealloc(dict->entries,dict->max*sizeof(struct pskeyval));
612 	}
613     }
614     if ( sp<2 )
615 return(sp);
616     if ( stack[sp-2].type!=ps_string && stack[sp-2].type!=ps_lit ) {
617 /* GT: Here "def" is a PostScript keyword, (meaning define). */
618 /* GT: This "def" should not be translated as it is part of the PostScript language. */
619 	LogError( _("Key for a def must be a string or name literal\n") );
620 return(sp-2);
621     }
622     for ( i=0; i<dict->cnt; ++i )
623 	if ( strcmp(dict->entries[i].key,stack[sp-2].u.str)==0 )
624     break;
625     if ( i!=dict->cnt ) {
626 	free(stack[sp-2].u.str);
627 	if ( dict->entries[i].type==ps_string || dict->entries[i].type==ps_instr ||
628 		dict->entries[i].type==ps_lit )
629 	    free(dict->entries[i].u.str);
630     } else {
631 	memset(&dict->entries[i],'\0',sizeof(struct pskeyval));
632 	dict->entries[i].key = stack[sp-2].u.str;
633 	++dict->cnt;
634     }
635     dict->entries[i].type = stack[sp-1].type;
636     dict->entries[i].u = stack[sp-1].u;
637 return(sp-2);
638 }
639 
forgetstack(struct psstack * stack,int forgets,int sp)640 static int forgetstack(struct psstack *stack, int forgets, int sp) {
641     /* forget the bottom most "forgets" entries on the stack */
642     /* we presume they are garbage that has accumulated because we */
643     /*  don't understand all of PS */
644     int i;
645     for ( i=0; i<forgets; ++i ) {
646 	if ( stack[i].type==ps_string || stack[i].type==ps_instr ||
647 		stack[i].type==ps_lit )
648 	    free(stack[i].u.str);
649 	else if ( stack[i].type==ps_array || stack[i].type==ps_dict )
650 	    dictfree(&stack[i].u.dict);
651     }
652     for ( i=forgets; i<sp; ++i )
653 	stack[i-forgets] = stack[i];
654 return( sp-forgets );
655 }
656 
rollstack(struct psstack * stack,int sp)657 static int rollstack(struct psstack *stack, int sp) {
658     int n,j,i;
659     struct psstack *temp;
660 
661     if ( sp>1 ) {
662 	n = stack[sp-2].u.val;
663 	j = stack[sp-1].u.val;
664 	sp-=2;
665 	if ( sp>=n && n>0 ) {
666 	    j %= n;
667 	    if ( j<0 ) j += n;
668 	    temp = galloc(n*sizeof(struct psstack));
669 	    for ( i=0; i<n; ++i )
670 		temp[i] = stack[sp-n+i];
671 	    for ( i=0; i<n; ++i )
672 		stack[sp-n+(i+j)%n] = temp[i];
673 	    free(temp);
674 	}
675     }
676 return( sp );
677 }
678 
CheckMakeB(BasePoint * test,BasePoint * good)679 static void CheckMakeB(BasePoint *test, BasePoint *good) {
680     if ( !finite(test->x) || test->x>100000 || test->x<-100000 ) {
681 	LogError( _("Value out of bounds in spline.\n") );
682 	if ( good!=NULL )
683 	    test->x = good->x;
684 	else
685 	    test->x = 0;
686     }
687     if ( !finite(test->y) || test->y>100000 || test->y<-100000 ) {
688 	LogError( _("Value out of bounds in spline.\n") );
689 	if ( good!=NULL )
690 	    test->y = good->y;
691 	else
692 	    test->y = 0;
693     }
694 }
695 
CheckMake(SplinePoint * from,SplinePoint * to)696 static void CheckMake(SplinePoint *from, SplinePoint *to) {
697     CheckMakeB(&from->me,NULL);
698     CheckMakeB(&from->nextcp,&from->me);
699     CheckMakeB(&to->prevcp,&from->nextcp);
700     CheckMakeB(&to->me,&to->prevcp);
701 }
702 
circlearcto(real a1,real a2,real cx,real cy,real r,SplineSet * cur,real * transform)703 static void circlearcto(real a1, real a2, real cx, real cy, real r,
704 	SplineSet *cur, real *transform ) {
705     SplinePoint *pt;
706     DBasePoint temp, base, cp;
707     real cplen;
708     int sign=1;
709     real s1, s2, c1, c2;
710 
711     if ( a1==a2 )
712 return;
713 
714     cplen = (a2-a1)/90 * r * .552;
715     a1 *= 3.1415926535897932/180; a2 *= 3.1415926535897932/180;
716     s1 = sin(a1); s2 = sin(a2); c1 = cos(a1); c2 = cos(a2);
717     temp.x = cx+r*c2; temp.y = cy+r*s2;
718     base.x = cx+r*c1; base.y = cy+r*s1;
719     pt = chunkalloc(sizeof(SplinePoint));
720     Transform(&pt->me,&temp,transform);
721     cp.x = temp.x-cplen*s2; cp.y = temp.y + cplen*c2;
722     if ( (cp.x-base.x)*(cp.x-base.x)+(cp.y-base.y)*(cp.y-base.y) >
723 	     (temp.x-base.x)*(temp.x-base.x)+(temp.y-base.y)*(temp.y-base.y) ) {
724 	sign = -1;
725 	cp.x = temp.x+cplen*s2; cp.y = temp.y - cplen*c2;
726     }
727     Transform(&pt->prevcp,&cp,transform);
728     pt->nonextcp = true;
729     cp.x = base.x + sign*cplen*s1; cp.y = base.y - sign*cplen*c1;
730     Transform(&cur->last->nextcp,&cp,transform);
731     cur->last->nonextcp = false;
732     CheckMake(cur->last,pt);
733     SplineMake3(cur->last,pt);
734     cur->last = pt;
735 }
736 
circlearcsto(real a1,real a2,real cx,real cy,real r,SplineSet * cur,real * transform,int clockwise)737 static void circlearcsto(real a1, real a2, real cx, real cy, real r,
738 	SplineSet *cur, real *transform, int clockwise ) {
739     int a;
740     real last;
741 
742     while ( a1<0 ) { a1 += 360; a2 +=360;} while ( a2-a1<=-360 ) a2 += 360;
743     while ( a1>360 ) { a1 -= 360; a2 -= 360; } while ( a2-a1>360 ) a2 -= 360;
744     if ( !clockwise ) {
745 	if ( a1>a2 )
746 	    a2 += 360;
747 	last = a1;
748 	for ( a=((int) (a1+90)/90)*90; a<a2; a += 90 ) {
749 	    circlearcto(last,a,cx,cy,r,cur,transform);
750 	    last = a;
751 	}
752 	circlearcto(last,a2,cx,cy,r,cur,transform);
753     } else {
754 	if ( a2>a1 )
755 	    a1 += 360;
756 	last = a1;
757 	for ( a=((int) (a1-90)/90)*90+90; a>a2; a -= 90 ) {
758 	    circlearcto(last,a,cx,cy,r,cur,transform);
759 	    last = a;
760 	}
761 	circlearcto(last,a2,cx,cy,r,cur,transform);
762     }
763 }
764 
collectgarbage(struct garbage * tofrees,struct pskeydict * to)765 static void collectgarbage(struct garbage *tofrees,struct pskeydict *to) {
766     struct garbage *into;
767 
768     /* Garbage collection pointers */
769     into = tofrees;
770     if ( tofrees->cnt>=GARBAGE_MAX && tofrees->next!=NULL )
771 	into = tofrees->next;
772     if ( into->cnt>=GARBAGE_MAX ) {
773 	into = chunkalloc(sizeof(struct garbage));
774 	into->next = tofrees->next;
775 	tofrees->next = into;
776     }
777     into->cnts[    into->cnt   ] = to->cnt;
778     into->entries[ into->cnt++ ] = to->entries;
779 }
780 
copyarray(struct pskeydict * to,struct pskeydict * from,struct garbage * tofrees)781 static void copyarray(struct pskeydict *to,struct pskeydict *from, struct garbage *tofrees) {
782     int i;
783     struct pskeyval *oldent = from->entries;
784 
785     *to = *from;
786     to->entries = gcalloc(to->cnt,sizeof(struct pskeyval));
787     for ( i=0; i<to->cnt; ++i ) {
788 	to->entries[i] = oldent[i];
789 	if ( to->entries[i].type==ps_string || to->entries[i].type==ps_instr ||
790 		to->entries[i].type==ps_lit )
791 	    to->entries[i].u.str = copy(to->entries[i].u.str);
792 	else if ( to->entries[i].type==ps_array || to->entries[i].type==ps_dict )
793 	    copyarray(&to->entries[i].u.dict,&oldent[i].u.dict,tofrees);
794     }
795     collectgarbage(tofrees,to);
796 }
797 
aload(int sp,struct psstack * stack,int stacktop,struct garbage * tofrees)798 static int aload(int sp, struct psstack *stack,int stacktop, struct garbage *tofrees) {
799     int i;
800 
801     if ( sp>=1 && stack[sp-1].type==ps_array ) {
802 	struct pskeydict dict;
803 	--sp;
804 	dict = stack[sp].u.dict;
805 	for ( i=0; i<dict.cnt; ++i ) {
806 	    if ( sp<stacktop ) {
807 		stack[sp].type = dict.entries[i].type;
808 		stack[sp].u = dict.entries[i].u;
809 		if ( stack[sp].type==ps_string || stack[sp].type==ps_instr ||
810 			stack[sp].type==ps_lit )
811 		    stack[sp].u.str = copy(stack[sp].u.str);
812 /* The following is incorrect behavior, but as I don't do garbage collection */
813 /*  and I'm not going to implement reference counts, this will work in most cases */
814 		else if ( stack[sp].type==ps_array )
815 		    copyarray(&stack[sp].u.dict,&stack[sp].u.dict,tofrees);
816 		++sp;
817 	    }
818 	}
819 	if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
820 	    stack[sp].type = ps_array;
821 	    stack[sp].u.dict = dict;
822 	    ++sp;
823 	}
824     }
825 return( sp );
826 }
827 
printarray(struct pskeydict * dict)828 static void printarray(struct pskeydict *dict) {
829     int i;
830 
831     printf("[" );
832     for ( i=0; i<dict->cnt; ++i ) {
833 	switch ( dict->entries[i].type ) {
834 	  case ps_num:
835 	    printf( "%g", (double) dict->entries[i].u.val );
836 	  break;
837 	  case ps_bool:
838 	    printf( "%s", dict->entries[i].u.tf ? "true" : "false" );
839 	  break;
840 	  case ps_string: case ps_instr: case ps_lit:
841 	    printf( dict->entries[i].type==ps_lit ? "/" :
842 		    dict->entries[i].type==ps_string ? "(" : "{" );
843 	    printf( "%s", dict->entries[i].u.str );
844 	    printf( dict->entries[i].type==ps_lit ? "" :
845 		    dict->entries[i].type==ps_string ? ")" : "}" );
846 	  break;
847 	  case ps_array:
848 	    printarray(&dict->entries[i].u.dict);
849 	  break;
850 	  case ps_void:
851 	    printf( "-- void --" );
852 	  break;
853 	  default:
854 	    printf( "-- nostringval --" );
855 	  break;
856 	}
857 	printf(" ");
858     }
859     printf( "]" );
860 }
861 
freestuff(struct psstack * stack,int sp,struct pskeydict * dict,GrowBuf * gb,struct garbage * tofrees)862 static void freestuff(struct psstack *stack, int sp, struct pskeydict *dict,
863 	GrowBuf *gb, struct garbage *tofrees) {
864     int i;
865 
866     free(gb->base);
867     for ( i=0; i<dict->cnt; ++i ) {
868 	if ( dict->entries[i].type==ps_string || dict->entries[i].type==ps_instr ||
869 		dict->entries[i].type==ps_lit )
870 	    free(dict->entries[i].u.str);
871 	free(dict->entries[i].key);
872     }
873     free( dict->entries );
874     for ( i=0; i<sp; ++i ) {
875 	if ( stack[i].type==ps_string || stack[i].type==ps_instr ||
876 		stack[i].type==ps_lit )
877 	    free(stack[i].u.str);
878 #if 0		/* Garbage collection should get these */
879 	else if ( stack[i].type==ps_array || stack[i].type==ps_dict )
880 	    dictfree(&stack[i].u.dict);
881 #endif
882     }
883     garbagefree(tofrees);
884 }
885 
DoMatTransform(int tok,int sp,struct psstack * stack)886 static void DoMatTransform(int tok,int sp,struct psstack *stack) {
887     real invt[6], t[6];
888 
889     if ( stack[sp-1].u.dict.cnt==6 && stack[sp-1].u.dict.entries[0].type==ps_num ) {
890 	double x = stack[sp-3].u.val, y = stack[sp-2].u.val;
891 	--sp;
892 	t[5] = stack[sp].u.dict.entries[5].u.val;
893 	t[4] = stack[sp].u.dict.entries[4].u.val;
894 	t[3] = stack[sp].u.dict.entries[3].u.val;
895 	t[2] = stack[sp].u.dict.entries[2].u.val;
896 	t[1] = stack[sp].u.dict.entries[1].u.val;
897 	t[0] = stack[sp].u.dict.entries[0].u.val;
898 	dictfree(&stack[sp].u.dict);
899 	if ( tok==pt_itransform || tok==pt_idtransform ) {
900 	    MatInverse(invt,t);
901 	    memcpy(t,invt,sizeof(t));
902 	}
903 	stack[sp-2].u.val = t[0]*x + t[1]*y;
904 	stack[sp-1].u.val = t[2]*x + t[3]*y;
905 	if ( tok==pt_transform || tok==pt_itransform ) {
906 	    stack[sp-2].u.val += t[4];
907 	    stack[sp-1].u.val += t[5];
908 	}
909     }
910 }
911 
DoMatOp(int tok,int sp,struct psstack * stack)912 static int DoMatOp(int tok,int sp,struct psstack *stack) {
913     real temp[6], t[6];
914     int nsp=sp;
915 
916     if ( stack[sp-1].u.dict.cnt==6 && stack[sp-1].u.dict.entries[0].type==ps_num ) {
917 	t[5] = stack[sp-1].u.dict.entries[5].u.val;
918 	t[4] = stack[sp-1].u.dict.entries[4].u.val;
919 	t[3] = stack[sp-1].u.dict.entries[3].u.val;
920 	t[2] = stack[sp-1].u.dict.entries[2].u.val;
921 	t[1] = stack[sp-1].u.dict.entries[1].u.val;
922 	t[0] = stack[sp-1].u.dict.entries[0].u.val;
923 	switch ( tok ) {
924 	  case pt_translate:
925 	    if ( sp>=3 ) {
926 		stack[sp-1].u.dict.entries[5].u.val += stack[sp-3].u.val*t[0]+stack[sp-2].u.val*t[2];
927 		stack[sp-1].u.dict.entries[4].u.val += stack[sp-3].u.val*t[1]+stack[sp-2].u.val*t[3];
928 		nsp = sp-2;
929 	    }
930 	  break;
931 	  case pt_scale:
932 	    if ( sp>=2 ) {
933 		stack[sp-1].u.dict.entries[0].u.val *= stack[sp-3].u.val;
934 		stack[sp-1].u.dict.entries[1].u.val *= stack[sp-3].u.val;
935 		stack[sp-1].u.dict.entries[2].u.val *= stack[sp-2].u.val;
936 		stack[sp-1].u.dict.entries[3].u.val *= stack[sp-2].u.val;
937 		/* transform[4,5] are unchanged */
938 		nsp = sp-2;
939 	    }
940 	  break;
941 	  case pt_rotate:
942 	    if ( sp>=1 ) {
943 		--sp;
944 		temp[0] = temp[3] = cos(stack[sp].u.val);
945 		temp[1] = sin(stack[sp].u.val);
946 		temp[2] = -temp[1];
947 		temp[4] = temp[5] = 0;
948 		MatMultiply(temp,t,t);
949 		stack[sp-1].u.dict.entries[5].u.val = t[5];
950 		stack[sp-1].u.dict.entries[4].u.val = t[4];
951 		stack[sp-1].u.dict.entries[3].u.val = t[3];
952 		stack[sp-1].u.dict.entries[2].u.val = t[2];
953 		stack[sp-1].u.dict.entries[1].u.val = t[1];
954 		stack[sp-1].u.dict.entries[0].u.val = t[0];
955 		nsp = sp-1;
956 	    }
957 	  break;
958 	}
959 	stack[nsp-1] = stack[sp-1];
960     }
961 return(nsp);
962 }
963 
EntityCreate(SplinePointList * head,int linecap,int linejoin,real linewidth,real * transform,SplineSet * clippath)964 static Entity *EntityCreate(SplinePointList *head,int linecap,int linejoin,
965 	real linewidth, real *transform, SplineSet *clippath) {
966     Entity *ent = gcalloc(1,sizeof(Entity));
967     ent->type = et_splines;
968     ent->u.splines.splines = head;
969     ent->u.splines.cap = linecap;
970     ent->u.splines.join = linejoin;
971     ent->u.splines.stroke_width = linewidth;
972     ent->u.splines.fill.col = 0xffffffff;
973     ent->u.splines.stroke.col = 0xffffffff;
974     ent->u.splines.fill.opacity = 1.0;
975     ent->u.splines.stroke.opacity = 1.0;
976     ent->clippath = SplinePointListCopy(clippath);
977     memcpy(ent->u.splines.transform,transform,6*sizeof(real));
978 return( ent );
979 }
980 
981 
HandleType3Reference(IO * wrapper,EntityChar * ec,real transform[6],char * tokbuf,int toksize)982 static void HandleType3Reference(IO *wrapper,EntityChar *ec,real transform[6],
983 	char *tokbuf, int toksize) {
984     int tok;
985     real dval;
986     char *glyphname;
987     RefChar *ref;
988 
989    tok = nextpstoken(wrapper,&dval,tokbuf,toksize);
990    if ( strcmp(tokbuf,"get")!=0 )
991 return;		/* Hunh. I don't understand it. I give up */
992    tok = nextpstoken(wrapper,&dval,tokbuf,toksize);
993    if ( tok!=pt_namelit )
994 return;		/* Hunh. I don't understand it. I give up */
995     glyphname = copy(tokbuf);
996    tok = nextpstoken(wrapper,&dval,tokbuf,toksize);
997    if ( strcmp(tokbuf,"get")!=0 )
998 return;		/* Hunh. I don't understand it. I give up */
999    tok = nextpstoken(wrapper,&dval,tokbuf,toksize);
1000    if ( strcmp(tokbuf,"exec")!=0 )
1001 return;		/* Hunh. I don't understand it. I give up */
1002 
1003     /* Ok, it looks very much like a reference to glyphname */
1004     ref = RefCharCreate();
1005     memcpy(ref->transform,transform,sizeof(ref->transform));
1006     ref->sc = (SplineChar *) glyphname;
1007     ref->next = ec->refs;
1008     ec->refs = ref;
1009 }
1010 
_InterpretPS(IO * wrapper,EntityChar * ec,RetStack * rs)1011 static void _InterpretPS(IO *wrapper, EntityChar *ec, RetStack *rs) {
1012     SplinePointList *cur=NULL, *head=NULL;
1013     DBasePoint current, temp;
1014     int tok, i, j;
1015     struct psstack stack[100];
1016     real dval;
1017     int sp=0;
1018     SplinePoint *pt;
1019     RefChar *ref, *lastref=NULL;
1020     real transform[6], t[6];
1021     struct graphicsstate {
1022 	real transform[6];
1023 	DBasePoint current;
1024 	real linewidth;
1025 	int linecap, linejoin;
1026 	Color fore;
1027 	DashType dashes[DASH_MAX];
1028 	SplineSet *clippath;
1029     } gsaves[30];
1030     int gsp = 0;
1031     int ccnt=0;
1032     GrowBuf gb;
1033     struct pskeydict dict;
1034     struct pskeyval *kv;
1035     Color fore=COLOR_INHERITED;
1036     int linecap=lc_inherited, linejoin=lj_inherited; real linewidth=WIDTH_INHERITED;
1037     DashType dashes[DASH_MAX];
1038     int dash_offset = 0;
1039     Entity *ent;
1040     char *oldloc;
1041     int warned = 0;
1042     struct garbage tofrees;
1043     SplineSet *clippath = NULL;
1044     char tokbuf[100];
1045     const int tokbufsize = 100;
1046 
1047     oldloc = setlocale(LC_NUMERIC,"C");
1048 
1049     memset(&gb,'\0',sizeof(GrowBuf));
1050     memset(&dict,'\0',sizeof(dict));
1051     tofrees.cnt = 0; tofrees.next = NULL;
1052 
1053     transform[0] = transform[3] = 1.0;
1054     transform[1] = transform[2] = transform[4] = transform[5] = 0;
1055     current.x = current.y = 0;
1056     dashes[0] = 0; dashes[1] = DASH_INHERITED;
1057 
1058     if ( ec->fromtype3 ) {
1059 	/* My type3 fonts have two things pushed on the stack when they */
1060 	/*  start. One is a dictionary, the other a flag (number). If the */
1061 	/*  flag is non-zero then we are a nested call (a reference char) */
1062 	/*  if 0, we're normal. We don't want to do setcachedevice for */
1063 	/*  reference chars.  We can't represent a dictionary on the stack */
1064 	/*  so just push two 0s */
1065 	stack[0].type = stack[1].type = ps_num;
1066 	stack[0].u.val = stack[1].u.val = 0;
1067 	sp = 2;
1068     }
1069 
1070     while ( (tok = nextpstoken(wrapper,&dval,tokbuf,tokbufsize))!=pt_eof ) {
1071 	if ( endedstopped(wrapper)) {
1072 	  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1073 		stack[sp].type = ps_bool;
1074 		stack[sp++].u.tf = false;
1075 	    }
1076 	}
1077 	if ( sp>(int)(sizeof(stack)/sizeof(stack[0])*4/5) ) {
1078 	    /* We don't interpret all of postscript */
1079 	    /* Sometimes we leave garbage on the stack that a real PS interp */
1080 	    /*  would have handled. If the stack gets too deep, clean out the */
1081 	    /*  oldest entries */
1082 	    sp = forgetstack(stack,sizeof(stack)/sizeof(stack[0])/3,sp );
1083 	}
1084 	if ( ccnt>0 ) {
1085 	    if ( tok==pt_closecurly )
1086 		--ccnt;
1087 	    else if ( tok==pt_opencurly )
1088 		++ccnt;
1089 	    if ( ccnt>0 )
1090 		AddTok(&gb,tokbuf,tok==pt_namelit);
1091 	    else {
1092 	      if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1093 		    stack[sp].type = ps_instr;
1094 		    if ( gb.pt==NULL )
1095 			stack[sp++].u.str = copy("");
1096 		    else {
1097 			*gb.pt = '\0'; gb.pt = gb.base;
1098 			stack[sp++].u.str = copy(gb.base);
1099 		    }
1100 		}
1101 	    }
1102 	} else if ( tok==pt_unknown && (kv=lookup(&dict,tokbuf))!=NULL ) {
1103 	    if ( kv->type == ps_instr )
1104 		pushio(wrapper,NULL,copy(kv->u.str),0);
1105 	    else if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1106 		stack[sp].type = kv->type;
1107 		stack[sp++].u = kv->u;
1108 		if ( kv->type==ps_instr || kv->type==ps_lit || kv->type==ps_string )
1109 		    stack[sp-1].u.str = copy(stack[sp-1].u.str);
1110 		else if ( kv->type==ps_array || kv->type==ps_dict ) {
1111 		    copyarray(&stack[sp-1].u.dict,&stack[sp-1].u.dict,&tofrees);
1112 		    if ( stack[sp-1].u.dict.is_executable )
1113 			sp = aload(sp,stack,sizeof(stack)/sizeof(stack[0]),&tofrees);
1114 		}
1115 	    }
1116 	} else {
1117 	if ( tok==pt_unknown ) {
1118 	    if ( strcmp(tokbuf,"Cache")==0 )	/* Fontographer type3s */
1119 		tok = pt_setcachedevice;
1120 	    else if ( strcmp(tokbuf,"SetWid")==0 ) {
1121 		tok = pt_setcharwidth;
1122 		if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1123 		    stack[sp].type = ps_num;
1124 		    stack[sp++].u.val = 0;
1125 		}
1126 	    } else if ( strcmp(tokbuf,"rrcurveto")==0 ) {
1127 		if ( sp>=6 ) {
1128 		    stack[sp-4].u.val += stack[sp-6].u.val;
1129 		    stack[sp-3].u.val += stack[sp-5].u.val;
1130 		    stack[sp-2].u.val += stack[sp-4].u.val;
1131 		    stack[sp-1].u.val += stack[sp-3].u.val;
1132 		    tok = pt_rcurveto;
1133 		}
1134 	    } else if ( strcmp(tokbuf,"FillStroke")==0 ) {
1135 		if ( sp>0 )
1136 		    --sp;
1137 		tok = linewidth!=WIDTH_INHERITED ? pt_stroke : pt_fill;
1138 		if ( wrapper->top!=NULL && wrapper->top->ps!=NULL &&
1139 			linewidth!=WIDTH_INHERITED )
1140 		    linewidth /= 10.0;	/* bug in Fontographer's unencrypted type3 fonts */
1141 	    } else if ( strcmp(tokbuf,"SG")==0 ) {
1142 		if ( linewidth!=WIDTH_INHERITED && sp>1 )
1143 		    stack[sp-2].u.val = stack[sp-1].u.val;
1144 		if ( sp>0 )
1145 		    --sp;
1146 		if ( sp>0 )
1147 		    stack[sp-1].u.val = (stack[sp-1].u.val+99)/198.0;
1148 		tok = pt_setgray;
1149 	    } else if ( strcmp(tokbuf,"ShowInt")==0 ) {
1150 	    	/* Fontographer reference */
1151 		if ( (!wrapper->top->fogns && sp>0 && stack[sp-1].type == ps_num &&
1152 			 stack[sp-1].u.val>=0 && stack[sp-1].u.val<=255 ) ||
1153 			(wrapper->top->fogns && sp>6 && stack[sp-7].type == ps_num &&
1154 			 stack[sp-7].u.val>=0 && stack[sp-7].u.val<=255 )) {
1155 		    ref = RefCharCreate();
1156 		    memcpy(ref->transform,transform,sizeof(ref->transform));
1157 		    if ( wrapper->top->fogns ) {
1158 			sp -= 6;
1159 			t[0] = stack[sp+0].u.val;
1160 			t[1] = stack[sp+1].u.val;
1161 			t[2] = stack[sp+2].u.val;
1162 			t[3] = stack[sp+3].u.val;
1163 			t[4] = stack[sp+4].u.val;
1164 			t[5] = stack[sp+5].u.val;
1165 			MatMultiply(t,ref->transform,ref->transform);
1166 			wrapper->top->fogns = false;
1167 		    }
1168 		    ref->orig_pos = stack[--sp].u.val;
1169 		    ref->next = ec->refs;
1170 		    ec->refs = ref;
1171     continue;
1172 		}
1173 	    } else if ( strcmp(tokbuf,"togNS_")==0 ) {
1174 		wrapper->top->fogns = !wrapper->top->fogns;
1175     continue;
1176 	    }
1177 	}
1178 	switch ( tok ) {
1179 	  case pt_number:
1180 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1181 		stack[sp].type = ps_num;
1182 		stack[sp++].u.val = dval;
1183 	    }
1184 	  break;
1185 	  case pt_string:
1186 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1187 		stack[sp].type = ps_string;
1188 		stack[sp++].u.str = copyn(tokbuf+1,strlen(tokbuf)-2);
1189 	    }
1190 	  break;
1191 	  case pt_true: case pt_false:
1192 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1193 		stack[sp].type = ps_bool;
1194 		stack[sp++].u.tf = tok==pt_true;
1195 	    }
1196 	  break;
1197 	  case pt_opencurly:
1198 	    ++ccnt;
1199 	  break;
1200 	  case pt_closecurly:
1201 	    --ccnt;
1202 	    if ( ccnt<0 ) {
1203  goto done;
1204 	    }
1205 	  break;
1206 	  case pt_count:
1207 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1208 		stack[sp].type = ps_num;
1209 		stack[sp].u.val = sp;
1210 		++sp;
1211 	    }
1212 	  break;
1213 	  case pt_pop:
1214 	    if ( sp>0 ) {
1215 		--sp;
1216 		if ( stack[sp].type==ps_string || stack[sp].type==ps_instr ||
1217 			stack[sp].type==ps_lit )
1218 		    free(stack[sp].u.str);
1219 		else if ( stack[sp].type==ps_array || stack[sp].type==ps_dict )
1220 		    dictfree(&stack[sp].u.dict);
1221 	    }
1222 	  break;
1223 	  case pt_clear:
1224 	    while ( sp>0 ) {
1225 		--sp;
1226 		if ( stack[sp].type==ps_string || stack[sp].type==ps_instr ||
1227 			stack[sp].type==ps_lit )
1228 		    free(stack[sp].u.str);
1229 		else if ( stack[sp].type==ps_array || stack[sp].type==ps_dict )
1230 		    dictfree(&stack[sp].u.dict);
1231 	    }
1232 	  break;
1233 	  case pt_dup:
1234 	    if ( sp>0 && sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1235 		stack[sp] = stack[sp-1];
1236 		if ( stack[sp].type==ps_string || stack[sp].type==ps_instr ||
1237 			stack[sp].type==ps_lit )
1238 		    stack[sp].u.str = copy(stack[sp].u.str);
1239     /* The following is incorrect behavior, but as I don't do garbage collection */
1240     /*  and I'm not going to implement reference counts, this will work in most cases */
1241 		else if ( stack[sp].type==ps_array )
1242 		    copyarray(&stack[sp].u.dict,&stack[sp].u.dict,&tofrees);
1243 		++sp;
1244 	    }
1245 	  break;
1246 	  case pt_copy:
1247 	    if ( sp>0 ) {
1248 		int n = stack[--sp].u.val;
1249 		if ( n+sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1250 		    int i;
1251 		    for ( i=0; i<n; ++i ) {
1252 			stack[sp] = stack[sp-n];
1253 			if ( stack[sp].type==ps_string || stack[sp].type==ps_instr ||
1254 				stack[sp].type==ps_lit )
1255 			    stack[sp].u.str = copy(stack[sp].u.str);
1256     /* The following is incorrect behavior, but as I don't do garbage collection */
1257     /*  and I'm not going to implement reference counts, this will work in most cases */
1258 			else if ( stack[sp].type==ps_array )
1259 			    copyarray(&stack[sp].u.dict,&stack[sp].u.dict,&tofrees);
1260 			++sp;
1261 		    }
1262 		}
1263 	    }
1264 	  break;
1265 	  case pt_exch:
1266 	    if ( sp>1 ) {
1267 		struct psstack temp;
1268 		temp = stack[sp-1];
1269 		stack[sp-1] = stack[sp-2];
1270 		stack[sp-2] = temp;
1271 	    }
1272 	  break;
1273 	  case pt_roll:
1274 	    sp = rollstack(stack,sp);
1275 	  break;
1276 	  case pt_index:
1277 	    if ( sp>0 ) {
1278 		i = stack[--sp].u.val;
1279 		if ( sp>i && i>=0 ) {
1280 		    stack[sp] = stack[sp-i-1];
1281 		    if ( stack[sp].type==ps_string || stack[sp].type==ps_instr ||
1282 			    stack[sp].type==ps_lit )
1283 			stack[sp].u.str = copy(stack[sp].u.str);
1284     /* The following is incorrect behavior, but as I don't do garbage collection */
1285     /*  and I'm not going to implement reference counts, this will work in most cases */
1286 		    else if ( stack[sp].type==ps_array )
1287 			copyarray(&stack[sp].u.dict,&stack[sp].u.dict,&tofrees);
1288 		    ++sp;
1289 		}
1290 	    }
1291 	  break;
1292 	  case pt_add:
1293 	    if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1294 		stack[sp-2].u.val += stack[sp-1].u.val;
1295 		--sp;
1296 	    }
1297 	  break;
1298 	  case pt_sub:
1299 	    if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1300 		stack[sp-2].u.val -= stack[sp-1].u.val;
1301 		--sp;
1302 	    }
1303 	  break;
1304 	  case pt_mul:
1305 	    if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1306 		stack[sp-2].u.val *= stack[sp-1].u.val;
1307 		--sp;
1308 	    }
1309 	  break;
1310 	  case pt_div:
1311 	    if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1312 		if ( stack[sp-1].u.val == 0 )
1313 		    LogError( _("Divide by zero in postscript code.\n" ));
1314 		else
1315 		    stack[sp-2].u.val /= stack[sp-1].u.val;
1316 		--sp;
1317 	    }
1318 	  break;
1319 	  case pt_idiv:
1320 	    if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1321 		if ( stack[sp-1].u.val == 0 )
1322 		    LogError( _("Divide by zero in postscript code.\n" ));
1323 		else
1324 		    stack[sp-2].u.val = ((int) stack[sp-2].u.val) / ((int) stack[sp-1].u.val);
1325 		--sp;
1326 	    }
1327 	  break;
1328 	  case pt_mod:
1329 	    if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1330 		if ( stack[sp-1].u.val == 0 )
1331 		    LogError( _("Divide by zero in postscript code.\n" ));
1332 		else
1333 		    stack[sp-2].u.val = ((int) stack[sp-2].u.val) % ((int) stack[sp-1].u.val);
1334 		--sp;
1335 	    }
1336 	  break;
1337 	  case pt_max:
1338 	    if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1339 		if ( stack[sp-2].u.val < stack[sp-1].u.val )
1340 		    stack[sp-2].u.val = stack[sp-1].u.val;
1341 		--sp;
1342 	    }
1343 	  break;
1344 	  case pt_min:
1345 	    if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1346 		if ( stack[sp-2].u.val > stack[sp-1].u.val )
1347 		    stack[sp-2].u.val = stack[sp-1].u.val;
1348 		--sp;
1349 	    }
1350 	  break;
1351 	  case pt_neg:
1352 	    if ( sp>=1 ) {
1353 		if ( stack[sp-1].type == ps_num )
1354 		    stack[sp-1].u.val = -stack[sp-1].u.val;
1355 	    }
1356 	  break;
1357 	  case pt_abs:
1358 	    if ( sp>=1 ) {
1359 		if ( stack[sp-1].type == ps_num )
1360 		    if ( stack[sp-1].u.val < 0 )
1361 			stack[sp-1].u.val = -stack[sp-1].u.val;
1362 	    }
1363 	  break;
1364 	  case pt_round:
1365 	    if ( sp>=1 ) {
1366 		if ( stack[sp-1].type == ps_num )
1367 		    stack[sp-1].u.val = rint(stack[sp-1].u.val);
1368 		    /* rint isn't quite right, round will take 6.5 to 7, 5.5 to 6, etc. while rint() will take both to 6 */
1369 	    }
1370 	  break;
1371 	  case pt_floor:
1372 	    if ( sp>=1 ) {
1373 		if ( stack[sp-1].type == ps_num )
1374 		    stack[sp-1].u.val = floor(stack[sp-1].u.val);
1375 	    }
1376 	  break;
1377 	  case pt_ceiling:
1378 	    if ( sp>=1 ) {
1379 		if ( stack[sp-1].type == ps_num )
1380 		    stack[sp-1].u.val = ceil(stack[sp-1].u.val);
1381 	    }
1382 	  break;
1383 	  case pt_truncate:
1384 	    if ( sp>=1 ) {
1385 		if ( stack[sp-1].type == ps_num ) {
1386 		    if ( stack[sp-1].u.val<0 )
1387 			stack[sp-1].u.val = ceil(stack[sp-1].u.val);
1388 		    else
1389 			stack[sp-1].u.val = floor(stack[sp-1].u.val);
1390 		}
1391 	    }
1392 	  break;
1393 	  case pt_ne: case pt_eq:
1394 	    if ( sp>=2 ) {
1395 		if ( stack[sp-2].type!=stack[sp-1].type )
1396 		    stack[sp-2].u.tf = false;
1397 		else if ( stack[sp-2].type==ps_num )
1398 		    stack[sp-2].u.tf = (stack[sp-2].u.val == stack[sp-1].u.val);
1399 		else if ( stack[sp-2].type==ps_bool )
1400 		    stack[sp-2].u.tf = (stack[sp-2].u.tf == stack[sp-1].u.tf);
1401 		else
1402 		    stack[sp-2].u.tf = strcmp(stack[sp-2].u.str,stack[sp-1].u.str)==0 ;
1403 		stack[sp-2].type = ps_bool;
1404 		if ( tok==pt_ne ) stack[sp-2].u.tf = !stack[sp-2].u.tf;
1405 		--sp;
1406 	    }
1407 	  break;
1408 	  case pt_gt: case pt_le: case pt_lt: case pt_ge:
1409 	    if ( sp>=2 ) {
1410 		if ( stack[sp-2].type!=stack[sp-1].type )
1411 		    stack[sp-2].u.tf = false;
1412 		else if ( stack[sp-2].type==ps_array )
1413 		    LogError( _("Can't compare arrays\n" ));
1414 		else {
1415 		    int cmp;
1416 		    if ( stack[sp-2].type==ps_num )
1417 			cmp = (stack[sp-2].u.val > stack[sp-1].u.val)?1:
1418 				(stack[sp-2].u.val == stack[sp-1].u.val)?0:-1;
1419 		    else if ( stack[sp-2].type==ps_bool )
1420 			cmp = (stack[sp-2].u.tf - stack[sp-1].u.tf);
1421 		    else
1422 			cmp = strcmp(stack[sp-2].u.str,stack[sp-1].u.str);
1423 		    if ( tok==pt_gt )
1424 			stack[sp-2].u.tf = cmp>0;
1425 		    else if ( tok==pt_lt )
1426 			stack[sp-2].u.tf = cmp<0;
1427 		    else if ( tok==pt_le )
1428 			stack[sp-2].u.tf = cmp<=0;
1429 		    else
1430 			stack[sp-2].u.tf = cmp>=0;
1431 		}
1432 		stack[sp-2].type = ps_bool;
1433 		--sp;
1434 	    }
1435 	  break;
1436 	  case pt_not:
1437 	    if ( sp>=1 ) {
1438 		if ( stack[sp-1].type == ps_bool )
1439 		    stack[sp-1].u.tf = !stack[sp-1].u.tf;
1440 	    }
1441 	  break;
1442 	  case pt_and:
1443 	    if ( sp>=2 ) {
1444 		if ( stack[sp-2].type == ps_num )
1445 		    stack[sp-2].u.val = ((int) stack[sp-1].u.val) & (int) stack[sp-1].u.val;
1446 		else if ( stack[sp-2].type == ps_bool )
1447 		    stack[sp-2].u.tf &= stack[sp-1].u.tf;
1448 		--sp;
1449 	    }
1450 	  break;
1451 	  case pt_or:
1452 	    if ( sp>=2 ) {
1453 		if ( stack[sp-2].type == ps_num )
1454 		    stack[sp-2].u.val = ((int) stack[sp-1].u.val) | (int) stack[sp-1].u.val;
1455 		else if ( stack[sp-2].type == ps_bool )
1456 		    stack[sp-2].u.tf |= stack[sp-1].u.tf;
1457 		--sp;
1458 	    }
1459 	  break;
1460 	  case pt_xor:
1461 	    if ( sp>=2 ) {
1462 		if ( stack[sp-2].type == ps_num )
1463 		    stack[sp-2].u.val = ((int) stack[sp-1].u.val) ^ (int) stack[sp-1].u.val;
1464 		else if ( stack[sp-2].type == ps_bool )
1465 		    stack[sp-2].u.tf ^= stack[sp-1].u.tf;
1466 		--sp;
1467 	    }
1468 	  break;
1469 	  case pt_exp:
1470 	    if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1471 		stack[sp-2].u.val = pow(stack[sp-2].u.val,stack[sp-1].u.val);
1472 		--sp;
1473 	    }
1474 	  break;
1475 	  case pt_sqrt:
1476 	    if ( sp>=1 && stack[sp-1].type==ps_num ) {
1477 		stack[sp-1].u.val = sqrt(stack[sp-1].u.val);
1478 	    }
1479 	  break;
1480 	  case pt_ln:
1481 	    if ( sp>=1 && stack[sp-1].type==ps_num ) {
1482 		stack[sp-1].u.val = log(stack[sp-1].u.val);
1483 	    }
1484 	  break;
1485 	  case pt_log:
1486 	    if ( sp>=1 && stack[sp-1].type==ps_num ) {
1487 		stack[sp-1].u.val = log10(stack[sp-1].u.val);
1488 	    }
1489 	  break;
1490 	  case pt_atan:
1491 	    if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1492 		stack[sp-2].u.val = atan2(stack[sp-2].u.val,stack[sp-1].u.val)*
1493 			180/3.1415926535897932;
1494 		--sp;
1495 	    }
1496 	  break;
1497 	  case pt_sin:
1498 	    if ( sp>=1 && stack[sp-1].type==ps_num ) {
1499 		stack[sp-1].u.val = sin(stack[sp-1].u.val*3.1415926535897932/180);
1500 	    }
1501 	  break;
1502 	  case pt_cos:
1503 	    if ( sp>=1 && stack[sp-1].type==ps_num ) {
1504 		stack[sp-1].u.val = cos(stack[sp-1].u.val*3.1415926535897932/180);
1505 	    }
1506 	  break;
1507 	  case pt_if:
1508 	    if ( sp>=2 ) {
1509 		if ( ((stack[sp-2].type == ps_bool && stack[sp-2].u.tf) ||
1510 			(stack[sp-2].type == ps_num && strstr(stack[sp-1].u.str,"setcachedevice")!=NULL)) &&
1511 			stack[sp-1].type==ps_instr )
1512 		    pushio(wrapper,NULL,stack[sp-1].u.str,0);
1513 		if ( stack[sp-1].type==ps_string || stack[sp-1].type==ps_instr || stack[sp-1].type==ps_lit )
1514 		    free(stack[sp-1].u.str);
1515 		sp -= 2;
1516 	    } else if ( sp==1 && stack[sp-1].type==ps_instr ) {
1517 		/*This can happen when reading our type3 fonts, we get passed */
1518 		/* values on the stack which the interpreter knows nothing */
1519 		/* about, but the interp needs to learn the width of the char */
1520 		if ( strstr(stack[sp-1].u.str,"setcachedevice")!=NULL ||
1521 			strstr(stack[sp-1].u.str,"setcharwidth")!=NULL )
1522 		    pushio(wrapper,NULL,stack[sp-1].u.str,0);
1523 		free(stack[sp-1].u.str);
1524 		sp = 0;
1525 	    }
1526 	  break;
1527 	  case pt_ifelse:
1528 	    if ( sp>=3 ) {
1529 		if ( stack[sp-3].type == ps_bool && stack[sp-3].u.tf ) {
1530 		    if ( stack[sp-2].type==ps_instr )
1531 			pushio(wrapper,NULL,stack[sp-2].u.str,0);
1532 		} else {
1533 		    if ( stack[sp-1].type==ps_instr )
1534 			pushio(wrapper,NULL,stack[sp-1].u.str,0);
1535 		}
1536 		if ( stack[sp-1].type==ps_string || stack[sp-1].type==ps_instr || stack[sp-1].type==ps_lit )
1537 		    free(stack[sp-1].u.str);
1538 		if ( stack[sp-2].type==ps_string || stack[sp-2].type==ps_instr || stack[sp-2].type==ps_lit )
1539 		    free(stack[sp-2].u.str);
1540 		sp -= 3;
1541 	    }
1542 	  break;
1543 	  case pt_for:
1544 	    if ( sp>=4 ) {
1545 		real init, incr, limit;
1546 		char *func;
1547 		int cnt;
1548 
1549 		if ( stack[sp-4].type == ps_num && stack[sp-3].type==ps_num &&
1550 			stack[sp-2].type==ps_num && stack[sp-1].type==ps_instr ) {
1551 		    init = stack[sp-4].u.val;
1552 		    incr = stack[sp-3].u.val;
1553 		    limit = stack[sp-2].u.val;
1554 		    func = stack[sp-1].u.str;
1555 		    sp -= 4;
1556 		    cnt = 0;
1557 		    if ( incr>0 ) {
1558 			while ( init<=limit ) { ++cnt; init += incr; }
1559 		    } else if ( incr<0 ) {
1560 			while ( init>=limit ) { ++cnt; init += incr; }
1561 		    }
1562 		    pushio(wrapper,NULL,func,cnt);
1563 		    free(func);
1564 		}
1565 	    }
1566 	  break;
1567 	  case pt_loop:
1568 	    if ( sp>=1 ) {
1569 		char *func;
1570 		int cnt;
1571 
1572 		if ( stack[sp-1].type==ps_instr ) {
1573 		    cnt = 0x7fffffff;		/* Loop for ever */
1574 		    func = stack[sp-1].u.str;
1575 		    --sp;
1576 		    pushio(wrapper,NULL,func,cnt);
1577 		    free(func);
1578 		}
1579 	    }
1580 	  break;
1581 	  case pt_repeat:
1582 	    if ( sp>=2 ) {
1583 		char *func;
1584 		int cnt;
1585 
1586 		if ( stack[sp-2].type==ps_num && stack[sp-1].type==ps_instr ) {
1587 		    cnt = stack[sp-2].u.val;
1588 		    func = stack[sp-1].u.str;
1589 		    sp -= 2;
1590 		    pushio(wrapper,NULL,func,cnt);
1591 		    free(func);
1592 		}
1593 	    }
1594 	  break;
1595 	  case pt_exit:
1596 	    ioescapeloop(wrapper);
1597 	  break;
1598 	  case pt_stopped:
1599 	    if ( sp>=1 ) {
1600 		char *func;
1601 
1602 		if ( stack[sp-1].type==ps_instr ) {
1603 		    func = stack[sp-1].u.str;
1604 		    --sp;
1605 		    pushio(wrapper,NULL,func,-1);
1606 		    free(func);
1607 		}
1608 	    }
1609 	  break;
1610 	  case pt_stop:
1611 	    sp = ioescapestopped(wrapper,stack,sp,sizeof(stack)/sizeof(stack[0]));
1612 	  break;
1613 	  case pt_load:
1614 	    if ( sp>=1 && stack[sp-1].type==ps_lit ) {
1615 		kv = lookup(&dict,stack[sp-1].u.str);
1616 		if ( kv!=NULL ) {
1617 		    free( stack[sp-1].u.str );
1618 		    stack[sp-1].type = kv->type;
1619 		    stack[sp-1].u = kv->u;
1620 		    if ( kv->type==ps_instr || kv->type==ps_lit )
1621 			stack[sp-1].u.str = copy(stack[sp-1].u.str);
1622 		} else
1623 		    stack[sp-1].type = ps_instr;
1624 	    }
1625 	  break;
1626 	  case pt_def:
1627 	    sp = AddEntry(&dict,stack,sp);
1628 	  break;
1629 	  case pt_bind:
1630 	    /* a noop in this context */
1631 	  break;
1632 	  case pt_setcachedevice:
1633 	    if ( sp>=6 ) {
1634 		ec->width = stack[sp-6].u.val;
1635 		ec->vwidth = stack[sp-5].u.val;
1636 		/* I don't care about the bounding box */
1637 		sp-=6;
1638 	    }
1639 	  break;
1640 	  case pt_setcharwidth:
1641 	    if ( sp>=2 )
1642 		ec->width = stack[sp-=2].u.val;
1643 	  break;
1644 	  case pt_translate:
1645 	    if ( sp>=1 && stack[sp-1].type==ps_array )
1646 		sp = DoMatOp(tok,sp,stack);
1647 	    else if ( sp>=2 ) {
1648 		transform[4] += stack[sp-2].u.val*transform[0]+stack[sp-1].u.val*transform[2];
1649 		transform[5] += stack[sp-2].u.val*transform[1]+stack[sp-1].u.val*transform[3];
1650 		sp -= 2;
1651 	    }
1652 	  break;
1653 	  case pt_scale:
1654 	    if ( sp>=1 && stack[sp-1].type==ps_array )
1655 		sp = DoMatOp(tok,sp,stack);
1656 	    else if ( sp>=2 ) {
1657 		transform[0] *= stack[sp-2].u.val;
1658 		transform[1] *= stack[sp-2].u.val;
1659 		transform[2] *= stack[sp-1].u.val;
1660 		transform[3] *= stack[sp-1].u.val;
1661 		/* transform[4,5] are unchanged */
1662 		sp -= 2;
1663 	    }
1664 	  break;
1665 	  case pt_rotate:
1666 	    if ( sp>=1 && stack[sp-1].type==ps_array )
1667 		sp = DoMatOp(tok,sp,stack);
1668 	    else if ( sp>=1 ) {
1669 		--sp;
1670 		t[0] = t[3] = cos(stack[sp].u.val);
1671 		t[1] = sin(stack[sp].u.val);
1672 		t[2] = -t[1];
1673 		t[4] = t[5] = 0;
1674 		MatMultiply(t,transform,transform);
1675 	    }
1676 	  break;
1677 	  case pt_concat:
1678 	    if ( sp>=1 ) {
1679 		if ( stack[sp-1].type==ps_array ) {
1680 		    if ( stack[sp-1].u.dict.cnt==6 && stack[sp-1].u.dict.entries[0].type==ps_num ) {
1681 			--sp;
1682 			t[5] = stack[sp].u.dict.entries[5].u.val;
1683 			t[4] = stack[sp].u.dict.entries[4].u.val;
1684 			t[3] = stack[sp].u.dict.entries[3].u.val;
1685 			t[2] = stack[sp].u.dict.entries[2].u.val;
1686 			t[1] = stack[sp].u.dict.entries[1].u.val;
1687 			t[0] = stack[sp].u.dict.entries[0].u.val;
1688 			dictfree(&stack[sp].u.dict);
1689 			MatMultiply(t,transform,transform);
1690 		    }
1691 		}
1692 	    }
1693 	  break;
1694 	  case pt_transform:
1695 	    if ( sp>=1 && stack[sp-1].type==ps_array ) {
1696 		if ( sp>=3 ) {
1697 		    DoMatTransform(tok,sp,stack);
1698 		    --sp;
1699 		}
1700 	    } else if ( sp>=2 ) {
1701 		double x = stack[sp-2].u.val, y = stack[sp-1].u.val;
1702 		stack[sp-2].u.val = transform[0]*x + transform[1]*y + transform[4];
1703 		stack[sp-1].u.val = transform[2]*x + transform[3]*y + transform[5];
1704 	    }
1705 	  break;
1706 	  case pt_itransform:
1707 	    if ( sp>=1 && stack[sp-1].type==ps_array ) {
1708 		if ( sp>=3 ) {
1709 		    DoMatTransform(tok,sp,stack);
1710 		    --sp;
1711 		}
1712 	    } else if ( sp>=2 ) {
1713 		double x = stack[sp-2].u.val, y = stack[sp-1].u.val;
1714 		MatInverse(t,transform);
1715 		stack[sp-2].u.val = t[0]*x + t[1]*y + t[4];
1716 		stack[sp-1].u.val = t[2]*x + t[3]*y + t[5];
1717 	    }
1718 	  break;
1719 	  case pt_dtransform:
1720 	    if ( sp>=1 && stack[sp-1].type==ps_array ) {
1721 		if ( sp>=3 ) {
1722 		    DoMatTransform(tok,sp,stack);
1723 		    --sp;
1724 		}
1725 	    } else if ( sp>=2 ) {
1726 		double x = stack[sp-2].u.val, y = stack[sp-1].u.val;
1727 		stack[sp-2].u.val = transform[0]*x + transform[1]*y;
1728 		stack[sp-1].u.val = transform[2]*x + transform[3]*y;
1729 	    }
1730 	  break;
1731 	  case pt_idtransform:
1732 	    if ( sp>=1 && stack[sp-1].type==ps_array ) {
1733 		if ( sp>=3 ) {
1734 		    DoMatTransform(tok,sp,stack);
1735 		    --sp;
1736 		}
1737 	    } else if ( sp>=2 ) {
1738 		double x = stack[sp-2].u.val, y = stack[sp-1].u.val;
1739 		MatInverse(t,transform);
1740 		stack[sp-2].u.val = t[0]*x + t[1]*y;
1741 		stack[sp-1].u.val = t[2]*x + t[3]*y;
1742 	    }
1743 	  break;
1744 	  case pt_namelit:
1745 	    if ( strcmp(tokbuf,"CharProcs")==0 && ec!=NULL ) {
1746 		HandleType3Reference(wrapper,ec,transform,tokbuf,tokbufsize);
1747 	    } else if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1748 		stack[sp].type = ps_lit;
1749 		stack[sp++].u.str = copy(tokbuf);
1750 	    }
1751 	  break;
1752 	  case pt_exec:
1753 	    if ( sp>0 && stack[sp-1].type == ps_lit ) {
1754 		ref = RefCharCreate();
1755 		ref->sc = (SplineChar *) stack[--sp].u.str;
1756 		memcpy(ref->transform,transform,sizeof(transform));
1757 		if ( ec->refs==NULL )
1758 		    ec->refs = ref;
1759 		else
1760 		    lastref->next = ref;
1761 		lastref = ref;
1762 	    }
1763 	  break;
1764 	  case pt_newpath:
1765 	    SplinePointListsFree(head);
1766 	    head = NULL;
1767 	    cur = NULL;
1768 	  break;
1769 	  case pt_lineto: case pt_rlineto:
1770 	  case pt_moveto: case pt_rmoveto:
1771 	    if ( sp>=2 || tok==pt_newpath ) {
1772 		if ( tok==pt_rlineto || tok==pt_rmoveto ) {
1773 		    current.x += stack[sp-2].u.val;
1774 		    current.y += stack[sp-1].u.val;
1775 		    sp -= 2;
1776 		} else if ( tok==pt_lineto || tok == pt_moveto ) {
1777 		    current.x = stack[sp-2].u.val;
1778 		    current.y = stack[sp-1].u.val;
1779 		    sp -= 2;
1780 		}
1781 		pt = chunkalloc(sizeof(SplinePoint));
1782 		Transform(&pt->me,&current,transform);
1783 		pt->noprevcp = true; pt->nonextcp = true;
1784 		if ( tok==pt_moveto || tok==pt_rmoveto ) {
1785 		    SplinePointList *spl = chunkalloc(sizeof(SplinePointList));
1786 		    spl->first = spl->last = pt;
1787 		    if ( cur!=NULL )
1788 			cur->next = spl;
1789 		    else
1790 			head = spl;
1791 		    cur = spl;
1792 		} else {
1793 		    if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
1794 			CheckMake(cur->last,pt);
1795 			SplineMake3(cur->last,pt);
1796 			cur->last = pt;
1797 		    }
1798 		}
1799 	    } else
1800 		sp = 0;
1801 	  break;
1802 	  case pt_curveto: case pt_rcurveto:
1803 	    if ( sp>=6 ) {
1804 		if ( tok==pt_rcurveto ) {
1805 		    stack[sp-1].u.val += current.y;
1806 		    stack[sp-3].u.val += current.y;
1807 		    stack[sp-5].u.val += current.y;
1808 		    stack[sp-2].u.val += current.x;
1809 		    stack[sp-4].u.val += current.x;
1810 		    stack[sp-6].u.val += current.x;
1811 		}
1812 		current.x = stack[sp-2].u.val;
1813 		current.y = stack[sp-1].u.val;
1814 		if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
1815 		    temp.x = stack[sp-6].u.val; temp.y = stack[sp-5].u.val;
1816 		    Transform(&cur->last->nextcp,&temp,transform);
1817 		    cur->last->nonextcp = false;
1818 		    pt = chunkalloc(sizeof(SplinePoint));
1819 		    temp.x = stack[sp-4].u.val; temp.y = stack[sp-3].u.val;
1820 		    Transform(&pt->prevcp,&temp,transform);
1821 		    Transform(&pt->me,&current,transform);
1822 		    pt->nonextcp = true;
1823 		    CheckMake(cur->last,pt);
1824 		    SplineMake3(cur->last,pt);
1825 		    cur->last = pt;
1826 		}
1827 		sp -= 6;
1828 	    } else
1829 		sp = 0;
1830 	  break;
1831 	  case pt_arc: case pt_arcn:
1832 	    if ( sp>=5 ) {
1833 		real cx, cy, r, a1, a2;
1834 		cx = stack[sp-5].u.val;
1835 		cy = stack[sp-4].u.val;
1836 		r = stack[sp-3].u.val;
1837 		a1 = stack[sp-2].u.val;
1838 		a2 = stack[sp-1].u.val;
1839 		sp -= 5;
1840 		temp.x = cx+r*cos(a1/180 * 3.1415926535897932);
1841 		temp.y = cy+r*sin(a1/180 * 3.1415926535897932);
1842 		if ( temp.x!=current.x || temp.y!=current.y ||
1843 			!( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) )) {
1844 		    pt = chunkalloc(sizeof(SplinePoint));
1845 		    Transform(&pt->me,&temp,transform);
1846 		    pt->noprevcp = true; pt->nonextcp = true;
1847 		    if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
1848 			CheckMake(cur->last,pt);
1849 			SplineMake3(cur->last,pt);
1850 			cur->last = pt;
1851 		    } else {	/* if no current point, then start here */
1852 			SplinePointList *spl = chunkalloc(sizeof(SplinePointList));
1853 			spl->first = spl->last = pt;
1854 			if ( cur!=NULL )
1855 			    cur->next = spl;
1856 			else
1857 			    head = spl;
1858 			cur = spl;
1859 		    }
1860 		}
1861 		circlearcsto(a1,a2,cx,cy,r,cur,transform,tok==pt_arcn);
1862 		current.x = cx+r*cos(a2/180 * 3.1415926535897932);
1863 		current.y = cy+r*sin(a2/180 * 3.1415926535897932);
1864 	    } else
1865 		sp = 0;
1866 	  break;
1867 	  case pt_arct: case pt_arcto:
1868 	    if ( sp>=5 ) {
1869 		real x1, y1, x2, y2, r;
1870 		real xt1, xt2, yt1, yt2;
1871 		x1 = stack[sp-5].u.val;
1872 		y1 = stack[sp-4].u.val;
1873 		x2 = stack[sp-3].u.val;
1874 		y2 = stack[sp-2].u.val;
1875 		r = stack[sp-1].u.val;
1876 		sp -= 5;
1877 
1878 		xt1 = xt2 = x1; yt1 = yt2 = y1;
1879 		if ( cur==NULL || cur->first==NULL || (cur->first==cur->last && cur->first->next!=NULL) )
1880 		    /* Error */;
1881 		else if ( current.x==x1 && current.y==y1 )
1882 		    /* Error */;
1883 		else if (( x1==x2 && y1==y2 ) ||
1884 			(current.x-x1)*(y2-y1) == (x2-x1)*(current.y-y1) ) {
1885 		    /* Degenerate case */
1886 		    current.x = x1; current.y = y1;
1887 		    pt = chunkalloc(sizeof(SplinePoint));
1888 		    Transform(&pt->me,&current,transform);
1889 		    pt->noprevcp = true; pt->nonextcp = true;
1890 		    CheckMake(cur->last,pt);
1891 		    SplineMake3(cur->last,pt);
1892 		    cur->last = pt;
1893 		} else {
1894 		    real l1 = sqrt((current.x-x1)*(current.x-x1)+(current.y-y1)*(current.y-y1));
1895 		    real l2 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
1896 		    real dx = ((current.x-x1)/l1 + (x2-x1)/l2);
1897 		    real dy = ((current.y-y1)/l1 + (y2-y1)/l2);
1898 		    /* the line from (x1,y1) to (x1+dx,y1+dy) contains the center*/
1899 		    real l3 = sqrt(dx*dx+dy*dy);
1900 		    real cx, cy, t, tmid;
1901 		    real a1, amid, a2;
1902 		    int clockwise = true;
1903 		    dx /= l3; dy /= l3;
1904 		    a1 = atan2(current.y-y1,current.x-x1);
1905 		    a2 = atan2(y2-y1,x2-x1);
1906 		    amid = atan2(dy,dx) - a1;
1907 		    tmid = r/sin(amid);
1908 		    t = r/tan(amid);
1909 		    if ( t<0 ) {
1910 			clockwise = false;
1911 			t = -t;
1912 			tmid = -tmid;
1913 		    }
1914 		    cx = x1+ tmid*dx; cy = y1 + tmid*dy;
1915 		    xt1 = x1 + t*(current.x-x1)/l1; yt1 = y1 + t*(current.y-y1)/l1;
1916 		    xt2 = x1 + t*(x2-x1)/l2; yt2 = y1 + t*(y2-y1)/l2;
1917 		    if ( xt1!=current.x || yt1!=current.y ) {
1918 			DBasePoint temp;
1919 			temp.x = xt1; temp.y = yt1;
1920 			pt = chunkalloc(sizeof(SplinePoint));
1921 			Transform(&pt->me,&temp,transform);
1922 			pt->noprevcp = true; pt->nonextcp = true;
1923 			CheckMake(cur->last,pt);
1924 			SplineMake3(cur->last,pt);
1925 			cur->last = pt;
1926 		    }
1927 		    a1 = 3*3.1415926535897932/2+a1;
1928 		    a2 = 3.1415926535897932/2+a2;
1929 		    if ( !clockwise ) {
1930 			a1 += 3.1415926535897932;
1931 			a2 += 3.1415926535897932;
1932 		    }
1933 		    circlearcsto(a1*180/3.1415926535897932,a2*180/3.1415926535897932,
1934 			    cx,cy,r,cur,transform,clockwise);
1935 		}
1936 		if ( tok==pt_arcto ) {
1937 		    stack[sp].type = stack[sp+1].type = stack[sp+2].type = stack[sp+3].type = ps_num;
1938 		    stack[sp++].u.val = xt1;
1939 		    stack[sp++].u.val = yt1;
1940 		    stack[sp++].u.val = xt2;
1941 		    stack[sp++].u.val = yt2;
1942 		}
1943 		current.x = xt2; current.y = yt2;
1944 	    }
1945 	  break;
1946 	  case pt_closepath:
1947 	    if ( cur!=NULL && cur->first!=NULL && cur->first!=cur->last ) {
1948 		if ( RealNear(cur->first->me.x,cur->last->me.x) && RealNear(cur->first->me.y,cur->last->me.y) ) {
1949 		    SplinePoint *oldlast = cur->last;
1950 		    cur->first->prevcp = oldlast->prevcp;
1951 		    cur->first->prevcp.x += (cur->first->me.x-oldlast->me.x);
1952 		    cur->first->prevcp.y += (cur->first->me.y-oldlast->me.y);
1953 		    cur->first->noprevcp = oldlast->noprevcp;
1954 		    oldlast->prev->from->next = NULL;
1955 		    cur->last = oldlast->prev->from;
1956 		    SplineFree(oldlast->prev);
1957 		    SplinePointFree(oldlast);
1958 		}
1959 		CheckMake(cur->last,cur->first);
1960 		SplineMake3(cur->last,cur->first);
1961 		cur->last = cur->first;
1962 	    }
1963 	  break;
1964 	  case pt_setlinecap:
1965 	    if ( sp>=1 )
1966 		linecap = stack[--sp].u.val;
1967 	  break;
1968 	  case pt_setlinejoin:
1969 	    if ( sp>=1 )
1970 		linejoin = stack[--sp].u.val;
1971 	  break;
1972 	  case pt_setlinewidth:
1973 	    if ( sp>=1 )
1974 		linewidth = stack[--sp].u.val;
1975 	  break;
1976 	  case pt_setdash:
1977 	    if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_array ) {
1978 		sp -= 2;
1979 		dash_offset = stack[sp+1].u.val;
1980 		for ( i=0; i<DASH_MAX && i<stack[sp].u.dict.cnt; ++i )
1981 		    dashes[i] = stack[sp].u.dict.entries[i].u.val;
1982 		dictfree(&stack[sp].u.dict);
1983 	    }
1984 	  break;
1985 	  case pt_currentlinecap: case pt_currentlinejoin:
1986 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1987 		stack[sp].type = ps_num;
1988 		stack[sp++].u.val = tok==pt_currentlinecap?linecap:linejoin;
1989 	    }
1990 	  break;
1991 	  case pt_currentlinewidth:
1992 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1993 		stack[sp].type = ps_num;
1994 		stack[sp++].u.val = linewidth;
1995 	    }
1996 	  break;
1997 	  case pt_currentdash:
1998 	    if ( sp+1<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1999 		struct pskeydict dict;
2000 		dict.is_executable = 0;
2001 		for ( i=0; i<DASH_MAX && dashes[i]!=0; ++i );
2002 		dict.cnt = dict.max = i;
2003 		dict.entries = gcalloc(i,sizeof(struct pskeyval));
2004 		for ( j=0; j<i; ++j ) {
2005 		    dict.entries[j].type = ps_num;
2006 		    dict.entries[j].u.val = dashes[j];
2007 		}
2008 		stack[sp].type = ps_array;
2009 		stack[sp++].u.dict = dict;
2010 		stack[sp].type = ps_num;
2011 		stack[sp++].u.val = dash_offset;
2012 	    }
2013 	  break;
2014 	  case pt_currentgray:
2015 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2016 		stack[sp].type = ps_num;
2017 		stack[sp++].u.val = (3*((fore>>16)&0xff) + 6*((fore>>8)&0xff) + (fore&0xff))/2550.;
2018 	    }
2019 	  break;
2020 	  case pt_setgray:
2021 	    if ( sp>=1 ) {
2022 		fore = stack[--sp].u.val*255;
2023 		fore *= 0x010101;
2024 	    }
2025 	  break;
2026 	  case pt_setrgbcolor:
2027 	    if ( sp>=3 ) {
2028 		fore = (((int) (stack[sp-3].u.val*255))<<16) +
2029 			(((int) (stack[sp-2].u.val*255))<<8) +
2030 			(int) (stack[sp-1].u.val*255);
2031 		sp -= 3;
2032 	    }
2033 	  break;
2034 	  case pt_currenthsbcolor: case pt_currentrgbcolor:
2035 	    if ( sp+2<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2036 		stack[sp].type = stack[sp+1].type = stack[sp+2].type = ps_num;
2037 		if ( tok==pt_currentrgbcolor ) {
2038 		    stack[sp++].u.val = ((fore>>16)&0xff)/255.;
2039 		    stack[sp++].u.val = ((fore>>8)&0xff)/255.;
2040 		    stack[sp++].u.val = (fore&0xff)/255.;
2041 		} else {
2042 		    int r=fore>>16, g=(fore>>8)&0xff, bl=fore&0xff;
2043 		    int mx, mn;
2044 		    real h, s, b;
2045 		    mx = mn = r;
2046 		    if ( mx>g ) mn=g; else mx=g;
2047 		    if ( mx<bl ) mx = bl; if ( mn>bl ) mn = bl;
2048 		    b = mx/255.;
2049 		    s = h = 0;
2050 		    if ( mx>0 )
2051 			s = ((real) (mx-mn))/mx;
2052 		    if ( s!=0 ) {
2053 			real rdiff = ((real) (mx-r))/(mx-mn);
2054 			real gdiff = ((real) (mx-g))/(mx-mn);
2055 			real bdiff = ((real) (mx-bl))/(mx-mn);
2056 			if ( rdiff==0 )
2057 			    h = bdiff-gdiff;
2058 			else if ( gdiff==0 )
2059 			    h = 2 + rdiff-bdiff;
2060 			else
2061 			    h = 4 + gdiff-rdiff;
2062 			h /= 6;
2063 			if ( h<0 ) h += 1;
2064 		    }
2065 		    stack[sp++].u.val = h;
2066 		    stack[sp++].u.val = s;
2067 		    stack[sp++].u.val = b;
2068 		}
2069 	    }
2070 	  break;
2071 	  case pt_sethsbcolor:
2072 	    if ( sp>=3 ) {
2073 		real h = stack[sp-3].u.val, s = stack[sp-2].u.val, b = stack[sp-1].u.val;
2074 		int r=0,g=0,bl=0;
2075 		if ( s==0 )	/* it's grey */
2076 		    fore = ((int) (b*255)) * 0x010101;
2077 		else {
2078 		    real sextant = (h-floor(h))*6;
2079 		    real mod = sextant-floor(sextant);
2080 		    real p = b*(1-s), q = b*(1-s*mod), t = b*(1-s*(1-mod));
2081 		    switch( (int) sextant) {
2082 		      case 0:
2083 			r = b*255.; g = t*255.; bl = p*255.;
2084 		      break;
2085 		      case 1:
2086 			r = q*255.; g = b*255.; bl = p*255.;
2087 		      break;
2088 		      case 2:
2089 			r = p*255.; g = b*255.; bl = t*255.;
2090 		      break;
2091 		      case 3:
2092 			r = p*255.; g = q*255.; bl = b*255.;
2093 		      break;
2094 		      case 4:
2095 			r = t*255.; g = p*255.; bl = b*255.;
2096 		      break;
2097 		      case 5:
2098 			r = b*255.; g = p*255.; bl = q*255.;
2099 		      break;
2100 		    }
2101 		    fore = COLOR_CREATE(r,g,bl);
2102 		}
2103 		sp -= 3;
2104 	    }
2105 	  break;
2106 	  case pt_currentcmykcolor:
2107 	    if ( sp+3<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2108 		real c,m,y,k;
2109 		stack[sp].type = stack[sp+1].type = stack[sp+2].type = stack[sp+3].type = ps_num;
2110 		y = 1.-(fore&0xff)/255.;
2111 		m = 1.-((fore>>8)&0xff)/255.;
2112 		c = 1.-((fore>>16)&0xff)/255.;
2113 		k = y; if ( k>m ) k=m; if ( k>c ) k=c;
2114 		if ( k!=1 ) {
2115 		    y = (y-k)/(1-k);
2116 		    m = (m-k)/(1-k);
2117 		    c = (c-k)/(1-k);
2118 		} else
2119 		    y = m = c = 0;
2120 		stack[sp++].u.val = c;
2121 		stack[sp++].u.val = m;
2122 		stack[sp++].u.val = y;
2123 		stack[sp++].u.val = k;
2124 	    }
2125 	  break;
2126 	  case pt_setcmykcolor:
2127 	    if ( sp>=4 ) {
2128 		real c=stack[sp-4].u.val,m=stack[sp-3].u.val,y=stack[sp-2].u.val,k=stack[sp-1].u.val;
2129 		sp -= 4;
2130 		if ( k==1 )
2131 		    fore = 0x000000;
2132 		else {
2133 		    if (( y = (1-k)*y+k )<0 ) y=0; else if ( y>1 ) y=1;
2134 		    if (( m = (1-k)*m+k )<0 ) m=0; else if ( m>1 ) m=1;
2135 		    if (( c = (1-k)*c+k )<0 ) c=0; else if ( c>1 ) c=1;
2136 		    fore = ((int) ((1-c)*255.)<<16) |
2137 			    ((int) ((1-m)*255.)<<8) |
2138 			    ((int) ((1-y)*255.));
2139 		}
2140 	    }
2141 	  break;
2142 	  case pt_currentpoint:
2143 	    if ( sp+1<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2144 		stack[sp].type = ps_num;
2145 		stack[sp++].u.val = current.x;
2146 		stack[sp].type = ps_num;
2147 		stack[sp++].u.val = current.y;
2148 	    }
2149 	  break;
2150 	  case pt_fill: case pt_stroke:
2151 	    if ( head==NULL && ec->splines!=NULL ) {
2152 		/* assume they did a "gsave fill grestore stroke" (or reverse)*/
2153 		ent = ec->splines;
2154 		if ( tok==pt_stroke ) {
2155 		    ent->u.splines.cap = linecap; ent->u.splines.join = linejoin;
2156 		    ent->u.splines.stroke_width = linewidth;
2157 		    memcpy(ent->u.splines.transform,transform,sizeof(transform));
2158 		}
2159 	    } else {
2160 		ent = EntityCreate(head,linecap,linejoin,linewidth,transform,clippath);
2161 		ent->next = ec->splines;
2162 		ec->splines = ent;
2163 	    }
2164 	    if ( tok==pt_fill )
2165 		ent->u.splines.fill.col = fore;
2166 	    else
2167 		ent->u.splines.stroke.col = fore;
2168 	    head = NULL; cur = NULL;
2169 	  break;
2170 	  case pt_clip:
2171 	    /* I really should intersect the old clip path with the new, but */
2172 	    /*  I don't trust my intersect routine, crashes too often */
2173 	    SplinePointListsFree(clippath);
2174 	    clippath = SplinePointListCopy(head);
2175 	    if ( clippath!=NULL && clippath->first!=clippath->last ) {
2176 		SplineMake3(clippath->last,clippath->first);
2177 		clippath->last = clippath->first;
2178 	    }
2179 	  break;
2180 	  case pt_imagemask:
2181 	    LogError( _("This version of FontForge does not support the imagemask operator.\nFor support configure --with-multilayer.\n") );
2182 	    if ( sp>=5 && (stack[sp-1].type==ps_instr || stack[sp-1].type==ps_string))
2183 		sp -= 5;
2184 	  break;
2185 
2186 	  /* We don't do these right, but at least we'll avoid some errors with this hack */
2187 	  case pt_save: case pt_currentmatrix:
2188 	    /* push some junk on the stack */
2189 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2190 		stack[sp].type = ps_num;
2191 		stack[sp++].u.val = 0;
2192 	    }
2193 	  /* Fall through into gsave */;
2194 	  case pt_gsave:
2195 	    if ( gsp<30 ) {
2196 		memcpy(gsaves[gsp].transform,transform,sizeof(transform));
2197 		gsaves[gsp].current = current;
2198 		gsaves[gsp].linewidth = linewidth;
2199 		gsaves[gsp].linecap = linecap;
2200 		gsaves[gsp].linejoin = linejoin;
2201 		gsaves[gsp].fore = fore;
2202 		gsaves[gsp].clippath = SplinePointListCopy(clippath);
2203 		++gsp;
2204 		/* I should be saving the "current path" too, but that's too hard */
2205 	    }
2206 	  break;
2207 	  case pt_restore: case pt_setmatrix:
2208 	    /* pop some junk off the stack */
2209 	    if ( sp>=1 )
2210 		--sp;
2211 	  /* Fall through into grestore */;
2212 	  case pt_grestore:
2213 	    if ( gsp>0 ) {
2214 		--gsp;
2215 		memcpy(transform,gsaves[gsp].transform,sizeof(transform));
2216 		current = gsaves[gsp].current;
2217 		linewidth = gsaves[gsp].linewidth;
2218 		linecap = gsaves[gsp].linecap;
2219 		linejoin = gsaves[gsp].linejoin;
2220 		fore = gsaves[gsp].fore;
2221 		SplinePointListsFree(clippath);
2222 		clippath = gsaves[gsp].clippath;
2223 	    }
2224 	  break;
2225 	  case pt_null:
2226 	    /* push a 0. I don't handle pointers properly */
2227 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2228 		stack[sp].u.val = 0;
2229 		stack[sp++].type = ps_num;
2230 	    }
2231 	  break;
2232 	  case pt_currentoverprint:
2233 	    /* push false. I don't handle this properly */
2234 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2235 		stack[sp].u.val = 0;
2236 		stack[sp++].type = ps_bool;
2237 	    }
2238 	  break;
2239 	  case pt_setoverprint:
2240 	    /* pop one item on stack */
2241 	    if ( sp>=1 )
2242 		--sp;
2243 	  break;
2244 	  case pt_currentflat:
2245 	    /* push 1.0 (default value). I don't handle this properly */
2246 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0]) )) {
2247 		stack[sp].u.val = 1.0;
2248 		stack[sp++].type = ps_num;
2249 	    }
2250 	  break;
2251 	  case pt_setflat:
2252 	    /* pop one item on stack */
2253 	    if ( sp>=1 )
2254 		--sp;
2255 	  break;
2256 	  case pt_currentmiterlimit:
2257 	    /* push 10.0 (default value). I don't handle this properly */
2258 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2259 		stack[sp].u.val = 10.0;
2260 		stack[sp++].type = ps_num;
2261 	    }
2262 	  break;
2263 	  case pt_setmiterlimit:
2264 	    /* pop one item off stack */
2265 	    if ( sp>=1 )
2266 		--sp;
2267 	  break;
2268 	  case pt_currentpacking:
2269 	    /* push false (default value). I don't handle this properly */
2270 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2271 		stack[sp].u.val = 0;
2272 		stack[sp++].type = ps_bool;
2273 	    }
2274 	  break;
2275 	  case pt_setpacking:
2276 	    /* pop one item on stack */
2277 	    if ( sp>=1 )
2278 		--sp;
2279 	  break;
2280 	  case pt_currentstrokeadjust:
2281 	    /* push false (default value). I don't handle this properly */
2282 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2283 		stack[sp].u.val = 0;
2284 		stack[sp++].type = ps_bool;
2285 	    }
2286 	  break;
2287 	  case pt_setstrokeadjust:
2288 	    /* pop one item on stack */
2289 	    if ( sp>=1 )
2290 		--sp;
2291 	  break;
2292 	  case pt_currentsmoothness:
2293 	    /* default value is installation dependant. I don't handle this properly */
2294 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2295 		stack[sp].u.val = 1.0;
2296 		stack[sp++].type = ps_num;
2297 	    }
2298 	  break;
2299 	  case pt_setsmoothness:
2300 	    /* pop one item on stack */
2301 	    if ( sp>=1 )
2302 		--sp;
2303 	  break;
2304 	  case pt_currentobjectformat:
2305 	    /* default value is installation dependant. I don't handle this properly */
2306 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2307 		stack[sp].u.val = 0.0;
2308 		stack[sp++].type = ps_num;
2309 	    }
2310 	  break;
2311 	  case pt_setobjectformat:
2312 	    /* pop one item on stack */
2313 	    if ( sp>=1 )
2314 		--sp;
2315 	  break;
2316 	  case pt_currentglobal: case pt_currentshared:
2317 	    /* push false (default value). I don't handle this properly */
2318 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2319 		stack[sp].u.val = 0;
2320 		stack[sp++].type = ps_bool;
2321 	    }
2322 	  break;
2323 	  case pt_setglobal:
2324 	    /* pop one item on stack */
2325 	    if ( sp>=1 )
2326 		--sp;
2327 	  break;
2328 
2329 	  case pt_openarray: case pt_mark:
2330 	    if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2331 		stack[sp++].type = ps_mark;
2332 	    }
2333 	  break;
2334 	  case pt_counttomark:
2335 	    for ( i=0; i<sp; ++i )
2336 		if ( stack[sp-1-i].type==ps_mark )
2337 	    break;
2338 	    if ( i==sp )
2339 		LogError( _("No mark in counttomark\n") );
2340 	    else if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2341 		stack[sp].type = ps_num;
2342 		stack[sp++].u.val = i;
2343 	    }
2344 	  break;
2345 	  case pt_cleartomark:
2346 	    for ( i=0; i<sp; ++i )
2347 		if ( stack[sp-1-i].type==ps_mark )
2348 	    break;
2349 	    if ( i==sp )
2350 		LogError( _("No mark in cleartomark\n") );
2351 	    else {
2352 		while ( sp>=i ) {
2353 		    --sp;
2354 		    if ( stack[sp].type==ps_string || stack[sp].type==ps_instr ||
2355 			    stack[sp].type==ps_lit )
2356 			free(stack[sp].u.str);
2357 		    else if ( stack[sp].type==ps_array || stack[sp].type==ps_dict )
2358 			dictfree(&stack[sp].u.dict);
2359 		}
2360 	    }
2361 	  break;
2362 	  case pt_closearray:
2363 	    for ( i=0; i<sp; ++i )
2364 		if ( stack[sp-1-i].type==ps_mark )
2365 	    break;
2366 	    if ( i==sp )
2367 		LogError( _("No mark in ] (close array)\n") );
2368 	    else {
2369 		struct pskeydict dict;
2370 		dict.is_executable = 0;
2371 		dict.cnt = dict.max = i;
2372 		dict.entries = gcalloc(i,sizeof(struct pskeyval));
2373 		for ( j=0; j<i; ++j ) {
2374 		    dict.entries[j].type = stack[sp-i+j].type;
2375 		    dict.entries[j].u = stack[sp-i+j].u;
2376 		    /* don't need to copy because the things on the stack */
2377 		    /*  are being popped (don't need to free either) */
2378 		}
2379 		collectgarbage(&tofrees,&dict);
2380 		sp = sp-i;
2381 		stack[sp-1].type = ps_array;
2382 		stack[sp-1].u.dict = dict;
2383 	    }
2384 	  break;
2385 	  case pt_array:
2386 	    if ( sp>=1 && stack[sp-1].type==ps_num ) {
2387 		struct pskeydict dict;
2388 		dict.is_executable = 0;
2389 		dict.cnt = dict.max = stack[sp-1].u.val;
2390 		dict.entries = gcalloc(dict.cnt,sizeof(struct pskeyval));
2391 		/* all entries are inited to void */
2392 		stack[sp-1].type = ps_array;
2393 		stack[sp-1].u.dict = dict;
2394 	    }
2395 	  break;
2396 	  case pt_aload:
2397 	    sp = aload(sp,stack,sizeof(stack)/sizeof(stack[0]),&tofrees);
2398 	  break;
2399 	  case pt_astore:
2400 	    if ( sp>=1 && stack[sp-1].type==ps_array ) {
2401 		struct pskeydict dict;
2402 		--sp;
2403 		dict = stack[sp].u.dict;
2404 		if ( sp>=dict.cnt ) {
2405 		    for ( i=dict.cnt-1; i>=0 ; --i ) {
2406 			--sp;
2407 			dict.entries[i].type = stack[sp].type;
2408 			dict.entries[i].u = stack[sp].u;
2409 		    }
2410 		}
2411 		stack[sp].type = ps_array;
2412 		stack[sp].u.dict = dict;
2413 		++sp;
2414 	    }
2415 	  break;
2416 
2417 	  case pt_output: case pt_outputd: case pt_print:
2418 	    if ( sp>=1 ) {
2419 		--sp;
2420 		switch ( stack[sp].type ) {
2421 		  case ps_num:
2422 		    printf( "%g", (double) stack[sp].u.val );
2423 		  break;
2424 		  case ps_bool:
2425 		    printf( "%s", stack[sp].u.tf ? "true" : "false" );
2426 		  break;
2427 		  case ps_string: case ps_instr: case ps_lit:
2428 		    if ( tok==pt_outputd )
2429 			printf( stack[sp].type==ps_lit ? "/" :
2430 				stack[sp].type==ps_string ? "(" : "{" );
2431 		    printf( "%s", stack[sp].u.str );
2432 		    if ( tok==pt_outputd )
2433 			printf( stack[sp].type==ps_lit ? "" :
2434 				stack[sp].type==ps_string ? ")" : "}" );
2435 		    free(stack[sp].u.str);
2436 		  break;
2437 		  case ps_void:
2438 		    printf( "-- void --" );
2439 		  break;
2440 		  case ps_array:
2441 		    if ( tok==pt_outputd ) {
2442 			printarray(&stack[sp].u.dict);
2443 			dictfree(&stack[sp].u.dict);
2444 		  break;
2445 		    } /* else fall through */
2446 		    dictfree(&stack[sp].u.dict);
2447 		  default:
2448 		    printf( "-- nostringval --" );
2449 		  break;
2450 		}
2451 		if ( tok==pt_output || tok==pt_outputd )
2452 		    printf( "\n" );
2453 	    } else
2454 		LogError( _("Nothing on stack to print\n") );
2455 	  break;
2456 
2457 	  case pt_cvi: case pt_cvr:
2458 	    /* I shan't distinguish between integers and reals */
2459 	    if ( sp>=1 && stack[sp-1].type==ps_string ) {
2460 		double val = strtod(stack[sp-1].u.str,NULL);
2461 		free(stack[sp-1].u.str);
2462 		stack[sp-1].u.val = val;
2463 		stack[sp-1].type = ps_num;
2464 	    }
2465 	  break;
2466 	  case pt_cvlit:
2467 	    if ( sp>=1 ) {
2468 		if ( stack[sp-1].type==ps_array )
2469 		    stack[sp-1].u.dict.is_executable = false;
2470 	    }
2471 	  case pt_cvn:
2472 	    if ( sp>=1 ) {
2473 		if ( stack[sp-1].type==ps_string )
2474 		    stack[sp-1].type = ps_lit;
2475 	    }
2476 	  case pt_cvx:
2477 	    if ( sp>=1 ) {
2478 		if ( stack[sp-1].type==ps_array )
2479 		    stack[sp-1].u.dict.is_executable = true;
2480 	    }
2481 	  break;
2482 	  case pt_cvrs:
2483 	    if ( sp>=3 && stack[sp-1].type==ps_string &&
2484 		    stack[sp-2].type==ps_num &&
2485 		    stack[sp-3].type==ps_num ) {
2486 		if ( stack[sp-2].u.val==8 )
2487 		    sprintf( stack[sp-1].u.str, "%o", (int) stack[sp-3].u.val );
2488 		else if ( stack[sp-2].u.val==16 )
2489 		    sprintf( stack[sp-1].u.str, "%X", (int) stack[sp-3].u.val );
2490 		else /* default to radix 10 no matter what they asked for */
2491 		    sprintf( stack[sp-1].u.str, "%g", (double) stack[sp-3].u.val );
2492 		stack[sp-3] = stack[sp-1];
2493 		sp-=2;
2494 	    }
2495 	  break;
2496 	  case pt_cvs:
2497 	    if ( sp>=2 && stack[sp-1].type==ps_string ) {
2498 		switch ( stack[sp].type ) {
2499 		  case ps_num:
2500 		    sprintf( stack[sp-1].u.str, "%g", (double) stack[sp-2].u.val );
2501 		  break;
2502 		  case ps_bool:
2503 		    sprintf( stack[sp-1].u.str, "%s", stack[sp-2].u.tf ? "true" : "false" );
2504 		  break;
2505 		  case ps_string: case ps_instr: case ps_lit:
2506 		    sprintf( stack[sp-1].u.str, "%s", stack[sp-2].u.str );
2507 		    free(stack[sp].u.str);
2508 		  break;
2509 		  case ps_void:
2510 		    printf( "-- void --" );
2511 		  break;
2512 		  case ps_array:
2513 		    dictfree(&stack[sp].u.dict);
2514 		  default:
2515 		    sprintf( stack[sp-1].u.str, "-- nostringval --" );
2516 		  break;
2517 		}
2518 		stack[sp-2] = stack[sp-1];
2519 		--sp;
2520 	    }
2521 	  break;
2522 	  case pt_stringop:	/* the string keyword, not the () thingy */
2523 	    if ( sp>=1 && stack[sp-1].type==ps_num ) {
2524 		stack[sp-1].type = ps_string;
2525 		stack[sp-1].u.str = gcalloc(stack[sp-1].u.val+1,1);
2526 	    }
2527 	  break;
2528 
2529 	  case pt_unknown:
2530 	    if ( !warned ) {
2531 		LogError( _("Warning: Unable to parse token %s, some features may be lost\n"), tokbuf );
2532 		warned = true;
2533 	    }
2534 	  break;
2535 
2536 	  default:
2537 	  break;
2538 	}}
2539     }
2540  done:
2541     if ( rs!=NULL ) {
2542 	int i, cnt, j;
2543 	for ( i=sp-1; i>=0; --i )
2544 	    if ( stack[i].type!=ps_num )
2545 	break;
2546 	cnt = sp-1-i;
2547 	if ( cnt>rs->max ) cnt = rs->max;
2548 	rs->cnt = cnt;
2549 	for ( j=i+1; j<sp; ++j )
2550 	    rs->stack[j-i-1] = stack[j].u.val;
2551     }
2552     freestuff(stack,sp,&dict,&gb,&tofrees);
2553     if ( head!=NULL ) {
2554 	ent = EntityCreate(head,linecap,linejoin,linewidth,transform,clippath);
2555 	ent->next = ec->splines;
2556 	ec->splines = ent;
2557     }
2558     while ( gsp>0 ) {
2559 	--gsp;
2560 	SplinePointListsFree(gsaves[gsp].clippath);
2561     }
2562     SplinePointListsFree(clippath);
2563     ECCatagorizePoints(ec);
2564     if ( ec->width == UNDEFINED_WIDTH )
2565 	ec->width = wrapper->advance_width;
2566     setlocale(LC_NUMERIC,oldloc);
2567 }
2568 
InterpretPS(FILE * ps,char * psstr,EntityChar * ec,RetStack * rs)2569 static void InterpretPS(FILE *ps, char *psstr, EntityChar *ec, RetStack *rs) {
2570     IO wrapper;
2571 
2572     memset(&wrapper,0,sizeof(wrapper));
2573     wrapper.advance_width = UNDEFINED_WIDTH;
2574     pushio(&wrapper,ps,psstr,0);
2575     _InterpretPS(&wrapper,ec,rs);
2576 }
2577 
EraseStroke(SplineChar * sc,SplinePointList * head,SplinePointList * erase)2578 static SplinePointList *EraseStroke(SplineChar *sc,SplinePointList *head,SplinePointList *erase) {
2579     SplineSet *spl, *last;
2580     SplinePoint *sp;
2581 
2582     if ( head==NULL ) {
2583 	/* Pointless, but legal */
2584 	SplinePointListsFree(erase);
2585 return( NULL );
2586     }
2587 
2588     last = NULL;
2589     for ( spl=head; spl!=NULL; spl=spl->next ) {
2590 	for ( sp=spl->first; sp!=NULL; ) {
2591 	    sp->selected = false;
2592 	    if ( sp->next==NULL )
2593 	break;
2594 	    sp = sp->next->to;
2595 	    if ( sp==spl->first )
2596 	break;
2597 	}
2598 	last = spl;
2599     }
2600     for ( spl=erase; spl!=NULL; spl=spl->next ) {
2601 	for ( sp=spl->first; sp!=NULL; ) {
2602 	    sp->selected = true;
2603 	    if ( sp->next==NULL )
2604 	break;
2605 	    sp = sp->next->to;
2606 	    if ( sp==spl->first )
2607 	break;
2608 	}
2609     }
2610     last->next = erase;
2611 return( SplineSetRemoveOverlap(sc,head,over_exclude) );
2612 }
2613 
EntityReverse(Entity * ent)2614 static Entity *EntityReverse(Entity *ent) {
2615     Entity *next, *last = NULL;
2616 
2617     while ( ent!=NULL ) {
2618 	next = ent->next;
2619 	ent->next = last;
2620 	last = ent;
2621 	ent = next;
2622     }
2623 return( last );
2624 }
2625 
SFSplinesFromLayers(SplineFont * sf,int tostroke)2626 void SFSplinesFromLayers(SplineFont *sf, int tostroke) {
2627   (void)sf;
2628   (void)tostroke;
2629 }
2630 
EntityCharCorrectDir(EntityChar * ec)2631 static void EntityCharCorrectDir(EntityChar *ec) {
2632     SplineSet *ss;
2633     Entity *ent;
2634     int changed;
2635 
2636     for ( ent=ec->splines; ent!=NULL; ent = ent->next ) {
2637 	/* ignore splines which are only stoked, but not filled */
2638 	if ( ent->type == et_splines && ent->u.splines.fill.col!=0xffffffff ) {
2639 	    /* Correct the direction of each stroke or fill with respect to */
2640 	    /*  the splines in it */
2641 	    SplineSetsCorrect(ent->u.splines.splines,&changed);
2642 	    if ( ent->u.splines.fill.col==0xffffff ) {
2643 		/* If they are filling with white, then assume they mean */
2644 		/*  an internal area that should be drawn backwards */
2645 		for ( ss=ent->u.splines.splines; ss!=NULL; ss=ss->next )
2646 		    SplineSetReverse(ss);
2647 	    }
2648 	    SplineSetsCorrect(ent->clippath,&changed);
2649 	}
2650     }
2651 }
2652 
EntityDefaultStrokeFill(Entity * ent)2653 static void EntityDefaultStrokeFill(Entity *ent) {
2654     while ( ent!=NULL ) {
2655 	if ( ent->type == et_splines &&
2656 		ent->u.splines.stroke.col==0xffffffff &&
2657 		ent->u.splines.fill.col==0xffffffff ) {
2658 	    SplineSet *spl;
2659 	    int all=1;
2660 	    for ( spl=ent->u.splines.splines; spl!=NULL; spl=spl->next )
2661 		if ( spl->first->prev!=NULL ) {
2662 		    all = false;
2663 	    break;
2664 		}
2665 	    if ( all && ent->u.splines.splines!=NULL &&
2666 		    (ent->u.splines.stroke_width==0 || ent->u.splines.stroke_width==WIDTH_INHERITED))
2667 		ent->u.splines.stroke_width=40;		/* random guess */
2668 	    if (ent->u.splines.stroke_width==0 || ent->u.splines.stroke_width==WIDTH_INHERITED)
2669 		ent->u.splines.fill.col = COLOR_INHERITED;
2670 	    else
2671 		ent->u.splines.stroke.col = COLOR_INHERITED;
2672 	}
2673 	ent = ent->next;
2674     }
2675 }
2676 
SplinesFromEntityChar(EntityChar * ec,int * flags,int is_stroked)2677 static SplinePointList *SplinesFromEntityChar(EntityChar *ec,int *flags,int is_stroked) {
2678     Entity *ent, *next;
2679     SplinePointList *head=NULL, *last=NULL, *new, *nlast=NULL, *temp, *each, *transed;
2680     StrokeInfo si;
2681     real inversetrans[6];
2682     /*SplineSet *spl;*/
2683     int handle_eraser = false;
2684     int ask = false;
2685 
2686     EntityDefaultStrokeFill(ec->splines);
2687 
2688     if ( !is_stroked ) {
2689 
2690 	if ( *flags==-1 ) {
2691 	    for ( ent=ec->splines; ent!=NULL; ent = ent->next ) {
2692 		if ( ent->type == et_splines &&
2693 			(ent->u.splines.fill.col==0xffffff ||
2694 			 /*ent->u.splines.clippath!=NULL ||*/
2695 			 (ent->u.splines.stroke_width!=0 && ent->u.splines.stroke.col!=0xffffffff))) {
2696 		    ask = true;
2697 	    break;
2698 		}
2699 	    }
2700 	    if ( ask )
2701 		*flags = PsStrokeFlagsDlg();
2702 	}
2703 
2704 	if ( *flags & sf_correctdir )		/* Will happen if flags still unset (-1) */
2705 	    EntityCharCorrectDir(ec);
2706 
2707 	handle_eraser = *flags!=-1 && (*flags & sf_handle_eraser);
2708 	if ( handle_eraser )
2709 	    ec->splines = EntityReverse(ec->splines);
2710     }
2711 
2712     for ( ent=ec->splines; ent!=NULL; ent = next ) {
2713 	next = ent->next;
2714 	if ( ent->type == et_splines && is_stroked ) {
2715 	    if ( head==NULL )
2716 		head = ent->u.splines.splines;
2717 	    else
2718 		last->next = ent->u.splines.splines;
2719 	    if ( ent->u.splines.splines!=NULL )
2720 		for ( last = ent->u.splines.splines; last->next!=NULL; last=last->next );
2721 	    ent->u.splines.splines = NULL;
2722 	} else if ( ent->type == et_splines ) {
2723 	    if ( ent->u.splines.stroke.col!=0xffffffff &&
2724 		    (ent->u.splines.fill.col==0xffffffff || ent->u.splines.stroke_width!=0)) {
2725 		/* What does a stroke width of 0 mean? PS Says minimal width line */
2726 		/* How do we implement that? Special case: If filled and stroked 0, then */
2727 		/*  ignore the stroke. This idiom is used by MetaPost sometimes and means */
2728 		/*  no stroke */
2729 		memset(&si,'\0',sizeof(si));
2730 		si.toobigwarn = *flags & sf_toobigwarn ? 1 : 0;
2731 		si.join = ent->u.splines.join;
2732 		si.cap = ent->u.splines.cap;
2733 		si.removeoverlapifneeded = *flags & sf_removeoverlap ? 1 : 0;
2734 		si.radius = ent->u.splines.stroke_width/2;
2735 		if ( ent->u.splines.stroke_width==WIDTH_INHERITED )
2736 		    si.radius = .5;
2737 		if ( si.cap == lc_inherited ) si.cap = lc_butt;
2738 		if ( si.join == lc_inherited ) si.join = lj_miter;
2739 		new = NULL;
2740 #if 0
2741 		SSBisectTurners(ent->u.splines.splines);
2742 #endif
2743 		MatInverse(inversetrans,ent->u.splines.transform);
2744 		transed = SplinePointListTransform(SplinePointListCopy(
2745 			ent->u.splines.splines),inversetrans,true);
2746 		for ( each = transed; each!=NULL; each=each->next ) {
2747 		    temp = SplineSetStroke(each,&si,ec->sc);
2748 		    if ( new==NULL )
2749 			new=temp;
2750 		    else
2751 			nlast->next = temp;
2752 		    if ( temp!=NULL )
2753 			for ( nlast=temp; nlast->next!=NULL; nlast=nlast->next );
2754 		}
2755 		new = SplinePointListTransform(new,ent->u.splines.transform,true);
2756 		SplinePointListsFree(transed);
2757 		if ( handle_eraser && ent->u.splines.stroke.col==0xffffff ) {
2758 		    head = EraseStroke(ec->sc,head,new);
2759 		    last = head;
2760 		    if ( last!=NULL )
2761 			for ( ; last->next!=NULL; last=last->next );
2762 		} else {
2763 		    if ( head==NULL )
2764 			head = new;
2765 		    else
2766 			last->next = new;
2767 		    if ( new!=NULL )
2768 			for ( last = new; last->next!=NULL; last=last->next );
2769 		}
2770 		if ( si.toobigwarn )
2771 		    *flags |= sf_toobigwarn;
2772 	    }
2773 	    /* If they have neither a stroke nor a fill, pretend they said fill */
2774 	    if ( ent->u.splines.fill.col==0xffffffff && ent->u.splines.stroke.col!=0xffffffff )
2775 		SplinePointListsFree(ent->u.splines.splines);
2776 	    else if ( handle_eraser && ent->u.splines.fill.col==0xffffff ) {
2777 		head = EraseStroke(ec->sc,head,ent->u.splines.splines);
2778 		last = head;
2779 		if ( last!=NULL )
2780 		    for ( ; last->next!=NULL; last=last->next );
2781 	    } else {
2782 		new = ent->u.splines.splines;
2783 		if ( head==NULL )
2784 		    head = new;
2785 		else
2786 		    last->next = new;
2787 		if ( new!=NULL )
2788 		    for ( last = new; last->next!=NULL; last=last->next );
2789 	    }
2790 	}
2791 	SplinePointListsFree(ent->clippath);
2792 	free(ent);
2793     }
2794 return( head );
2795 }
2796 
2797 
revrefs(RefChar * cur)2798 static RefChar *revrefs(RefChar *cur) {
2799     RefChar *p, *n;
2800 
2801     if ( cur==NULL )
2802 return( NULL );
2803 
2804     p = NULL;
2805     for ( ; (n=cur->next)!=NULL; cur = n ) {
2806 	cur->next = p;
2807 	p = cur;
2808     }
2809     cur->next = p;
2810 return( cur );
2811 }
2812 
SCInterpretPS(FILE * ps,SplineChar * sc,int * flags)2813 static void SCInterpretPS(FILE *ps,SplineChar *sc, int *flags) {
2814     EntityChar ec;
2815     real dval;
2816     char tokbuf[10];
2817     IO wrapper;
2818     int ch;
2819 
2820     while ( isspace(ch = getc(ps)) );
2821     ungetc(ch,ps);
2822 
2823     memset(&wrapper,0,sizeof(wrapper));
2824     wrapper.advance_width = UNDEFINED_WIDTH;
2825     if ( ch!='<' ) {
2826 	pushio(&wrapper,ps,NULL,0);
2827 
2828 	if ( nextpstoken(&wrapper,&dval,tokbuf,sizeof(tokbuf))!=pt_opencurly )
2829 	    LogError( _("We don't understand this font\n") );
2830     } else {
2831 	(void) getc(ps);
2832 	pushfogio(&wrapper,ps);
2833     }
2834     memset(&ec,'\0',sizeof(ec));
2835     ec.fromtype3 = true;
2836     ec.sc = sc;
2837     _InterpretPS(&wrapper,&ec,NULL);
2838     sc->width = ec.width;
2839     sc->layers[ly_fore].splines = SplinesFromEntityChar(&ec,flags,false);
2840     sc->layers[ly_fore].refs = revrefs(ec.refs);
2841     free(wrapper.top);
2842 }
2843 
PSFontInterpretPS(FILE * ps,struct charprocs * cp,char ** encoding)2844 void PSFontInterpretPS(FILE *ps,struct charprocs *cp,char **encoding) {
2845     char tokbuf[100];
2846     int tok,i, j;
2847     real dval;
2848     SplineChar *sc; EntityChar dummy;
2849     RefChar *p, *ref, *next;
2850     IO wrapper;
2851     int flags = -1;
2852 
2853     wrapper.top = NULL;
2854     wrapper.advance_width = UNDEFINED_WIDTH;
2855     pushio(&wrapper,ps,NULL,0);
2856 
2857     while ( (tok = nextpstoken(&wrapper,&dval,tokbuf,sizeof(tokbuf)))!=pt_eof && tok!=pt_end ) {
2858 	if ( tok==pt_namelit ) {
2859 	    if ( cp->next>=cp->cnt ) {
2860 		++cp->cnt;
2861 		cp->keys = grealloc(cp->keys,cp->cnt*sizeof(char *));
2862 		cp->values = grealloc(cp->values,cp->cnt*sizeof(char *));
2863 	    }
2864 	    if ( cp->next<cp->cnt ) {
2865 		sc = SplineCharCreate(2);
2866 		cp->keys[cp->next] = copy(tokbuf);
2867 		cp->values[cp->next++] = sc;
2868 		sc->name = copy(tokbuf);
2869 		SCInterpretPS(ps,sc,&flags);
2870        		ff_progress_next();
2871 	    } else {
2872 		memset(&dummy,0,sizeof(dummy));
2873 		dummy.fromtype3 = true;
2874 		InterpretPS(ps,NULL,&dummy,NULL);
2875 	    }
2876 	}
2877     }
2878     free(wrapper.top);
2879 
2880     /* References were done by name in the postscript. we stored the names in */
2881     /*  ref->sc (which is a hack). Now look up all those names and replace */
2882     /*  with the appropriate splinechar. If we can't find anything then throw */
2883     /*  out the reference */
2884     /* Further fixups come later, where all ps refs are fixedup */
2885     for ( i=0; i<cp->next; ++i ) {
2886 	for ( p=NULL, ref=cp->values[i]->layers[ly_fore].refs; ref!=NULL; ref=next ) {
2887 	    char *refname = (char *) (ref->sc);
2888 	    next = ref->next;
2889 	    if ( ref->sc==NULL )
2890 		refname=encoding[ref->orig_pos];
2891 	    for ( j=0; j<cp->next; ++j )
2892 		if ( strcmp(cp->keys[j],refname)==0 )
2893 	    break;
2894 	    free(ref->sc);	/* a string, not a splinechar */
2895 	    if ( j!=cp->next ) {
2896 		ref->sc = cp->values[j];
2897 		SCMakeDependent(cp->values[i],ref->sc);
2898 		ref->adobe_enc = getAdobeEnc(ref->sc->name);
2899 		ref->checked = true;
2900 		p = ref;
2901 	    } else {
2902 		if ( p==NULL )
2903 		    cp->values[i]->layers[ly_fore].refs = next;
2904 		else
2905 		    p->next = next;
2906 		ref->next = NULL;
2907 		RefCharFree(ref);
2908 	    }
2909 	}
2910     }
2911 }
2912 
closepath(SplinePointList * cur,int is_type2)2913 static void closepath(SplinePointList *cur, int is_type2) {
2914     if ( cur!=NULL && cur->first==cur->last && cur->first->prev==NULL && is_type2 )
2915 return;		/* The "path" is just a single point created by a moveto */
2916 		/* Probably we're just doing another moveto */
2917     if ( cur!=NULL && cur->first!=NULL && cur->first!=cur->last ) {
2918 /* I allow for greater errors here than I do in the straight postscript code */
2919 /*  because: 1) the rel-rel operators will accumulate more rounding errors   */
2920 /*  2) I only output 2 decimal digits after the decimal in type1 output */
2921 	if ( RealWithin(cur->first->me.x,cur->last->me.x,.05) && RealWithin(cur->first->me.y,cur->last->me.y,.05) ) {
2922 	    SplinePoint *oldlast = cur->last;
2923 	    cur->first->prevcp = oldlast->prevcp;
2924 	    cur->first->prevcp.x += (cur->first->me.x-oldlast->me.x);
2925 	    cur->first->prevcp.y += (cur->first->me.y-oldlast->me.y);
2926 	    cur->first->noprevcp = oldlast->noprevcp;
2927 	    oldlast->prev->from->next = NULL;
2928 	    cur->last = oldlast->prev->from;
2929 	    chunkfree(oldlast->prev,sizeof(*oldlast));
2930 	    chunkfree(oldlast->hintmask,sizeof(HintMask));
2931 	    chunkfree(oldlast,sizeof(*oldlast));
2932 	}
2933 	CheckMake(cur->last,cur->first);
2934 	SplineMake3(cur->last,cur->first);
2935 	cur->last = cur->first;
2936     }
2937 }
2938 
UnblendFree(StemInfo * h)2939 static void UnblendFree(StemInfo *h ) {
2940     while ( h!=NULL ) {
2941 	chunkfree(h->u.unblended,sizeof(real [2][MmMax]));
2942 	h->u.unblended = NULL;
2943 	h = h->next;
2944     }
2945 }
2946 
HintsAppend(StemInfo * to,StemInfo * extra)2947 static StemInfo *HintsAppend(StemInfo *to,StemInfo *extra) {
2948     StemInfo *h;
2949 
2950     if ( to==NULL )
2951 return( extra );
2952     if ( extra==NULL )
2953 return( to );
2954     for ( h=to; h->next!=NULL; h=h->next );
2955     h->next = extra;
2956 return( to );
2957 }
2958 
HintNew(double start,double width)2959 static StemInfo *HintNew(double start,double width) {
2960     StemInfo *h;
2961 
2962     h = chunkalloc(sizeof(StemInfo));
2963     h->start = start;
2964     h->width = width;
2965 return( h );
2966 }
2967 
RemapHintMask(HintMask * hm,int mapping[96],int max)2968 static void RemapHintMask(HintMask *hm,int mapping[96],int max) {
2969     HintMask rpl;
2970     int i, mb;
2971 
2972     if ( hm==NULL )
2973 return;
2974 
2975     if ( max>96 ) max = 96;
2976     mb = (max+7)>>3;
2977 
2978     memset(&rpl,0,mb);
2979     for ( i=0; i<max; ++i ) if ( (*hm)[i>>3]&(0x80>>(i&0x7)) )
2980 	rpl[mapping[i]>>3] |= (0x80>>(mapping[i]&0x7));
2981     memcpy(hm,&rpl,mb);
2982 }
2983 
HintsRenumber(SplineChar * sc)2984 static void HintsRenumber(SplineChar *sc) {
2985     /* In a type1 font the hints may get added to our hint list in a semi- */
2986     /*  random order. In an incorrect type2 font the same thing could happen. */
2987     /*  Force the order to be correct, and then update all masks */
2988     int mapping[96];
2989     int i, max;
2990     StemInfo *h;
2991     SplineSet *spl;
2992     SplinePoint *sp;
2993 
2994     for ( i=0; i<96; ++i ) mapping[i] = i;
2995 
2996     i = 0;
2997     for ( h=sc->hstem; h!=NULL; h=h->next ) {
2998 	if ( h->hintnumber<96 && i<96 ) {
2999 	    mapping[h->hintnumber] = i;
3000 	    h->hintnumber = i++;
3001 	}
3002 	chunkfree(h->u.unblended,sizeof(real [2][MmMax]));
3003 	h->u.unblended = NULL;
3004     }
3005     for ( h=sc->vstem; h!=NULL; h=h->next ) {
3006 	if ( h->hintnumber<96 && i<96 ) {
3007 	    mapping[h->hintnumber] = i;
3008 	    h->hintnumber = i++;
3009 	}
3010 	chunkfree(h->u.unblended,sizeof(real [2][MmMax]));
3011 	h->u.unblended = NULL;
3012     }
3013     max = i;
3014     for ( i=0; i<max; ++i )
3015 	if ( mapping[i]!=i )
3016     break;
3017     if ( i==max )
3018 return;				/* Didn't change the order */
3019 
3020     for ( i=0; i<sc->countermask_cnt; ++i )
3021 	RemapHintMask(&sc->countermasks[i],mapping,max);
3022     for ( spl = sc->layers[ly_fore].splines; spl!=NULL; spl=spl->next ) {
3023 	for ( sp = spl->first; ; ) {
3024 	    RemapHintMask(sp->hintmask,mapping,max);
3025 	    if ( sp->next==NULL )
3026 	break;
3027 	    sp = sp->next->to;
3028 	    if ( sp==spl->first )
3029 	break;
3030 	}
3031     }
3032 }
3033 
UnblendedCompare(real u1[MmMax],real u2[MmMax],int cnt)3034 int UnblendedCompare(real u1[MmMax], real u2[MmMax], int cnt) {
3035     int i;
3036 
3037     for ( i=0; i<cnt; ++i ) {
3038 	if ( u1[i]!=u2[i] )
3039 return( u1[i]>u2[i]?1:-1 );
3040     }
3041 return( 0 );
3042 }
3043 
SameH(StemInfo * old,real start,real width,real unblended[2][MmMax],int instance_count)3044 static StemInfo *SameH(StemInfo *old,real start, real width,
3045 	real unblended[2][MmMax], int instance_count) {
3046     StemInfo *sameh;
3047 
3048     if ( instance_count==0 ) {
3049 	for ( sameh=old; sameh!=NULL; sameh=sameh->next )
3050 	    if ( sameh->start==start && sameh->width==width)
3051 	break;
3052     } else { int j;
3053 	for ( j=1; j<instance_count; ++j ) {
3054 	    unblended[0][j] += unblended[0][j-1];
3055 	    unblended[1][j] += unblended[1][j-1];
3056 	}
3057 	for ( sameh=old; sameh!=NULL; sameh=sameh->next ) {
3058 	    if ( (*sameh->u.unblended)[0] == NULL || (*sameh->u.unblended)[1]==NULL )
3059 	continue;
3060 	    if ( UnblendedCompare((*sameh->u.unblended)[0],unblended[0],instance_count)==0 &&
3061 		    UnblendedCompare((*sameh->u.unblended)[1],unblended[1],instance_count)==0)
3062 	break;
3063 	}
3064     }
3065 return( sameh );
3066 }
3067 
Blend(real u[MmMax],struct pscontext * context)3068 static real Blend(real u[MmMax],struct pscontext *context) {
3069     real sum = u[0];
3070     int i;
3071 
3072     for ( i=1; i<context->instance_count; ++i )
3073 	sum += context->blend_values[i]*u[i];
3074 return( sum );
3075 }
3076 
3077 /* this handles either Type1 or Type2 charstrings. Type2 charstrings have */
3078 /*  more operators than Type1s and the old operators have extended meanings */
3079 /*  (ie. the rlineto operator can produce more than one line). But pretty */
3080 /*  much it's a superset and if we parse for type2 (with a few additions) */
3081 /*  we'll get it right */
3082 /* Char width is done differently. Moveto starts a newpath. 0xff starts a 16.16*/
3083 /*  number rather than a 32 bit number */
PSCharStringToSplines(uint8 * type1,int len,struct pscontext * context,struct pschars * subrs,struct pschars * gsubrs,const char * name)3084 SplineChar *PSCharStringToSplines(uint8 *type1, int len, struct pscontext *context,
3085 	struct pschars *subrs, struct pschars *gsubrs, const char *name) {
3086     int is_type2 = context->is_type2;
3087     real stack[50]; int sp=0, v;		/* Type1 stack is about 25 long, Type2 stack is 48 */
3088     real transient[32];
3089     SplineChar *ret = SplineCharCreate(2);
3090     SplinePointList *cur=NULL, *oldcur=NULL;
3091     RefChar *r1, *r2, *rlast=NULL;
3092     DBasePoint current;
3093     real dx, dy, dx2, dy2, dx3, dy3, dx4, dy4, dx5, dy5, dx6=0, dy6;
3094     SplinePoint *pt;
3095     /* subroutines may be nested to a depth of 10 */
3096     struct substate { unsigned char *type1; int len; int subnum; } pcstack[11];
3097     int pcsp=0;
3098     StemInfo *hint, *hp;
3099     real pops[30];
3100     int popsp=0;
3101     int base, polarity;
3102     real coord;
3103     struct pschars *s;
3104     int hint_cnt = 0;
3105     StemInfo *activeh=NULL, *activev=NULL, *sameh;
3106     HintMask *pending_hm = NULL;
3107     HintMask *counters[96];
3108     int cp=0;
3109     real unblended[2][MmMax];
3110     int last_was_b1=false, old_last_was_b1;
3111 
3112     if ( !is_type2 && context->instance_count>1 )
3113 	memset(unblended,0,sizeof(unblended));
3114 
3115     ret->name = copy( name );
3116     ret->unicodeenc = -1;
3117     ret->width = (int16) 0x8000;
3118     if ( name==NULL ) name = "unnamed";
3119     ret->manualhints = true;
3120 
3121     current.x = current.y = 0;
3122     while ( len>0 ) {
3123 	if ( sp>48 ) {
3124 	    LogError( _("Stack got too big in %s\n"), name );
3125 	    sp = 48;
3126 	}
3127 	base = 0;
3128 	--len;
3129 	if ( (v = *type1++)>=32 ) {
3130 	    if ( v<=246) {
3131 		stack[sp++] = v - 139;
3132 	    } else if ( v<=250 ) {
3133 		stack[sp++] = (v-247)*256 + *type1++ + 108;
3134 		--len;
3135 	    } else if ( v<=254 ) {
3136 		stack[sp++] = -(v-251)*256 - *type1++ - 108;
3137 		--len;
3138 	    } else {
3139 		int val = (*type1<<24) | (type1[1]<<16) | (type1[2]<<8) | type1[3];
3140 		stack[sp++] = val;
3141 		type1 += 4;
3142 		len -= 4;
3143 		if ( is_type2 ) {
3144 #ifndef PSFixed_Is_TTF	/* The type2 spec is contradictory. It says this is a */
3145 			/*  two's complement number, but it also says it is a */
3146 			/*  Fixed, which in truetype is not two's complement */
3147 			/*  (mantisa is always unsigned) */
3148 		    stack[sp-1] /= 65536.;
3149 #else
3150 		    int mant = val&0xffff;
3151 		    stack[sp-1] = (val>>16) + mant/65536.;
3152 #endif
3153 		}
3154 	    }
3155 	} else if ( v==28 ) {
3156 	    stack[sp++] = (short) ((type1[0]<<8) | type1[1]);
3157 	    type1 += 2;
3158 	    len -= 2;
3159 	/* In the Dict tables of CFF, a 5byte fixed value is prefixed by a */
3160 	/*  29 code. In Type2 strings the prefix is 255. */
3161 	} else if ( v==12 ) {
3162 	    old_last_was_b1 = last_was_b1; last_was_b1 = false;
3163 	    v = *type1++;
3164 	    --len;
3165 	    switch ( v ) {
3166 	      case 0: /* dotsection */
3167 		sp = 0;
3168 	      break;
3169 	      case 1: /* vstem3 */	/* specifies three v hints zones at once */
3170 		if ( sp<6 ) LogError( _("Stack underflow on vstem3 in %s\n"), name );
3171 		/* according to the standard, if there is a vstem3 there can't */
3172 		/*  be any vstems, so there can't be any confusion about hint order */
3173 		/*  so we don't need to worry about unblended stuff */
3174 		sameh = NULL;
3175 		if ( !is_type2 )
3176 		    sameh = SameH(ret->vstem,stack[0] + ret->lsidebearing,stack[1],
3177 				unblended,0);
3178 		hint = HintNew(stack[0] + ret->lsidebearing,stack[1]);
3179 		hint->hintnumber = sameh!=NULL ? sameh->hintnumber : hint_cnt++;
3180 		if ( activev==NULL )
3181 		    activev = hp = hint;
3182 		else {
3183 		    for ( hp=activev; hp->next!=NULL; hp = hp->next );
3184 		    hp->next = hint;
3185 		    hp = hint;
3186 		}
3187 		sameh = NULL;
3188 		if ( !is_type2 )
3189 		    sameh = SameH(ret->vstem,stack[2] + ret->lsidebearing,stack[3],
3190 				unblended,0);
3191 		hp->next = HintNew(stack[2] + ret->lsidebearing,stack[3]);
3192 		hp->next->hintnumber = sameh!=NULL ? sameh->hintnumber : hint_cnt++;
3193 		if ( !is_type2 )
3194 		    sameh = SameH(ret->vstem,stack[4] + ret->lsidebearing,stack[5],
3195 				unblended,0);
3196 		hp->next->next = HintNew(stack[4] + ret->lsidebearing,stack[5]);
3197 		hp->next->next->hintnumber = sameh!=NULL ? sameh->hintnumber : hint_cnt++;
3198 		if ( !is_type2 && hp->next->next->hintnumber<96 ) {
3199 		    if ( pending_hm==NULL )
3200 			pending_hm = chunkalloc(sizeof(HintMask));
3201 		    (*pending_hm)[hint->hintnumber>>3] |= 0x80>>(hint->hintnumber&0x7);
3202 		    (*pending_hm)[hint->next->hintnumber>>3] |= 0x80>>(hint->next->hintnumber&0x7);
3203 		    (*pending_hm)[hint->next->next->hintnumber>>3] |= 0x80>>(hint->next->next->hintnumber&0x7);
3204 		}
3205 		hp = hp->next->next;
3206 		sp = 0;
3207 	      break;
3208 	      case 2: /* hstem3 */	/* specifies three h hints zones at once */
3209 		if ( sp<6 ) LogError( _("Stack underflow on hstem3 in %s\n"), name );
3210 		sameh = NULL;
3211 		if ( !is_type2 )
3212 		    sameh = SameH(ret->hstem,stack[0],stack[1], unblended,0);
3213 		hint = HintNew(stack[0],stack[1]);
3214 		hint->hintnumber = sameh!=NULL ? sameh->hintnumber : hint_cnt++;
3215 		if ( activeh==NULL )
3216 		    activeh = hp = hint;
3217 		else {
3218 		    for ( hp=activeh; hp->next!=NULL; hp = hp->next );
3219 		    hp->next = hint;
3220 		    hp = hint;
3221 		}
3222 		sameh = NULL;
3223 		if ( !is_type2 )
3224 		    sameh = SameH(ret->hstem,stack[2],stack[3], unblended,0);
3225 		hp->next = HintNew(stack[2],stack[3]);
3226 		hp->next->hintnumber = sameh!=NULL ? sameh->hintnumber : hint_cnt++;
3227 		sameh = NULL;
3228 		if ( !is_type2 )
3229 		    sameh = SameH(ret->hstem,stack[4],stack[5], unblended,0);
3230 		hp->next->next = HintNew(stack[4],stack[5]);
3231 		hp->next->next->hintnumber = sameh!=NULL ? sameh->hintnumber : hint_cnt++;
3232 		if ( !is_type2 && hp->next->next->hintnumber<96 ) {
3233 		    if ( pending_hm==NULL )
3234 			pending_hm = chunkalloc(sizeof(HintMask));
3235 		    (*pending_hm)[hint->hintnumber>>3] |= 0x80>>(hint->hintnumber&0x7);
3236 		    (*pending_hm)[hint->next->hintnumber>>3] |= 0x80>>(hint->next->hintnumber&0x7);
3237 		    (*pending_hm)[hint->next->next->hintnumber>>3] |= 0x80>>(hint->next->next->hintnumber&0x7);
3238 		}
3239 		hp = hp->next->next;
3240 		sp = 0;
3241 	      break;
3242 	      case 6: /* seac */	/* build accented characters */
3243  seac:
3244 		if ( sp<5 ) LogError( _("Stack underflow on seac in %s\n"), name );
3245 		/* stack[0] must be the lsidebearing of the accent. I'm not sure why */
3246 		r1 = RefCharCreate();
3247 		r2 = RefCharCreate();
3248 		r2->transform[0] = 1; r2->transform[3]=1;
3249 		r2->transform[4] = stack[1] - (stack[0]-ret->lsidebearing);
3250 		r2->transform[5] = stack[2];
3251 		/* the translation of the accent here is said to be relative */
3252 		/*  to the origins of the base character. I think they place */
3253 		/*  the origin at the left bearing. And they don't mean the  */
3254 		/*  base char at all, they mean the current char's lbearing  */
3255 		/*  (which is normally the same as the base char's, except   */
3256 		/*  when I has a big accent (like diaerisis) */
3257 		r1->transform[0] = 1; r1->transform[3]=1;
3258 		r1->adobe_enc = stack[3];
3259 		r2->adobe_enc = stack[4];
3260 		if ( stack[3]<0 || stack[3]>=256 || stack[4]<0 || stack[4]>=256 ) {
3261 		    LogError( _("Reference encoding out of bounds in %s\n"), name );
3262 		    r1->adobe_enc = 0;
3263 		    r2->adobe_enc = 0;
3264 		}
3265 		r1->next = r2;
3266 		if ( rlast!=NULL ) rlast->next = r1;
3267 		else ret->layers[ly_fore].refs = r1;
3268 		ret->changedsincelasthinted = true;	/* seac glyphs contain no hints */
3269 		rlast = r2;
3270 		sp = 0;
3271 	      break;
3272 	      case 7: /* sbw */		/* generalized width/sidebearing command */
3273 		if ( sp<4 ) LogError( _("Stack underflow on sbw in %s\n"), name );
3274 		ret->lsidebearing = stack[0];
3275 		/* stack[1] is lsidebearing y (only for vertical writing styles, CJK) */
3276 		ret->width = stack[2];
3277 		/* stack[3] is height (for vertical writing styles, CJK) */
3278 		sp = 0;
3279 	      break;
3280 	      case 5: case 9: case 14: case 26:
3281 		if ( sp<1 ) LogError( _("Stack underflow on unary operator in %s\n"), name );
3282 		switch ( v ) {
3283 		  case 5: stack[sp-1] = (stack[sp-1]==0); break;	/* not */
3284 		  case 9: if ( stack[sp-1]<0 ) stack[sp-1]= -stack[sp-1]; break;	/* abs */
3285 		  case 14: stack[sp-1] = -stack[sp-1]; break;		/* neg */
3286 		  case 26: stack[sp-1] = sqrt(stack[sp-1]); break;	/* sqrt */
3287 		}
3288 	      break;
3289 	      case 3: case 4: case 10: case 11: case 12: case 15: case 24:
3290 		if ( sp<2 ) LogError( _("Stack underflow on binary operator in %s\n"), name );
3291 		else switch ( v ) {
3292 		  case 3: /* and */
3293 		    stack[sp-2] = (stack[sp-1]!=0 && stack[sp-2]!=0);
3294 		  break;
3295 		  case 4: /* and */
3296 		    stack[sp-2] = (stack[sp-1]!=0 || stack[sp-2]!=0);
3297 		  break;
3298 		  case 10: /* add */
3299 		    stack[sp-2] += stack[sp-1];
3300 		  break;
3301 		  case 11: /* sub */
3302 		    stack[sp-2] -= stack[sp-1];
3303 		  break;
3304 		  case 12: /* div */
3305 		    stack[sp-2] /= stack[sp-1];
3306 		  break;
3307 		  case 24: /* mul */
3308 		    stack[sp-2] *= stack[sp-1];
3309 		  break;
3310 		  case 15: /* eq */
3311 		    stack[sp-2] = (stack[sp-1]==stack[sp-2]);
3312 		  break;
3313 		}
3314 		--sp;
3315 	      break;
3316 	      case 22: /* ifelse */
3317 		if ( sp<4 ) LogError( _("Stack underflow on ifelse in %s\n"), name );
3318 		else {
3319 		    if ( stack[sp-2]>stack[sp-1] )
3320 			stack[sp-4] = stack[sp-3];
3321 		    sp -= 3;
3322 		}
3323 	      break;
3324 	      case 23: /* random */
3325 		/* This function returns something (0,1]. It's not clear to me*/
3326 		/*  if rand includes 0 and RAND_MAX or not, but this approach */
3327 		/*  should work no matter what */
3328 		do {
3329 		    stack[sp] = (rand()/(RAND_MAX-1));
3330 		} while ( stack[sp]==0 || stack[sp]>1 );
3331 		++sp;
3332 	      break;
3333 	      case 16: /* callothersubr */
3334 		/* stack[sp-1] is the number of the thing to call in the othersubr array */
3335 		/* stack[sp-2] is the number of args to grab off our stack and put on the */
3336 		/*  real postscript stack */
3337 		if ( is_type2 )
3338 		    LogError( _("Type2 fonts do not support the Type1 callothersubrs operator") );
3339 		if ( sp<2 || sp < 2+stack[sp-2] ) {
3340 		    LogError( _("Stack underflow on callothersubr in %s\n"), name );
3341 		    sp = 0;
3342 		} else {
3343 		    int tot = stack[sp-2], i, k, j;
3344 		    popsp = 0;
3345 		    for ( k=sp-3; k>=sp-2-tot; --k )
3346 			pops[popsp++] = stack[k];
3347 		    /* othersubrs 0-3 must be interpretted. 0-2 are Flex, 3 is Hint Replacement */
3348 		    /* othersubrs 12,13 are for counter hints. We don't need to */
3349 		    /*  do anything to ignore them */
3350 		    /* Subroutines 14-18 are multiple master blenders. We need */
3351 		    /*  to pay attention to them too */
3352 		    switch ( (int) stack[sp-1] ) {
3353 		      case 3: {
3354 			/* when we weren't capabable of hint replacement we */
3355 			/*  punted by putting 3 on the stack (T1 spec page 70) */
3356 			/*  subroutine 3 is a noop */
3357 			/*pops[popsp-1] = 3;*/
3358 			ret->manualhints = false;
3359 			/* We can manage hint substitution from hintmask though*/
3360 			/*  well enough that we needn't clear the manualhints bit */
3361 			ret->hstem = HintsAppend(ret->hstem,activeh); activeh=NULL;
3362 			ret->vstem = HintsAppend(ret->vstem,activev); activev=NULL;
3363 		      } break;
3364 		      case 1: {
3365 			/* Essentially what we want to do is draw a line from */
3366 			/*  where we are at the beginning to where we are at */
3367 			/*  the end. So we save the beginning here (this starts*/
3368 			/*  the flex sequence), we ignore all calls to othersub*/
3369 			/*  2, and when we get to othersub 0 we put everything*/
3370 			/*  back to where it should be and free up whatever */
3371 			/*  extranious junk we created along the way and draw */
3372 			/*  our line. */
3373 			/* Let's punt a little less, and actually figure out */
3374 			/*  the appropriate rrcurveto commands and put in a */
3375 			/*  dished serif */
3376 			/* We should never get here in a type2 font. But we did*/
3377 			/*  this code won't work if we follow type2 conventions*/
3378 			/*  so turn off type2 until we get 0 callothersubrs */
3379 			/*  which marks the end of the flex sequence */
3380 			is_type2 = false;
3381 			if ( cur!=NULL ) {
3382 			    oldcur = cur;
3383 			    cur->next = NULL;
3384 			} else
3385 			    LogError( _("Bad flex subroutine in %s\n"), name );
3386 		      } break;
3387 		      case 2: {
3388 			/* No op */;
3389 		      } break;
3390 		      case 0: if ( oldcur!=NULL ) {
3391 			SplinePointList *spl = oldcur->next;
3392 			if ( spl!=NULL && spl->next!=NULL &&
3393 				spl->next->next!=NULL &&
3394 				spl->next->next->next!=NULL &&
3395 				spl->next->next->next->next!=NULL &&
3396 				spl->next->next->next->next->next!=NULL &&
3397 				spl->next->next->next->next->next->next!=NULL ) {
3398 			    BasePoint old_nextcp, mid_prevcp, mid, mid_nextcp,
3399 				    end_prevcp, end;
3400 			    old_nextcp	= spl->next->first->me;
3401 			    mid_prevcp	= spl->next->next->first->me;
3402 			    mid		= spl->next->next->next->first->me;
3403 			    mid_nextcp	= spl->next->next->next->next->first->me;
3404 			    end_prevcp	= spl->next->next->next->next->next->first->me;
3405 			    end		= spl->next->next->next->next->next->next->first->me;
3406 			    cur = oldcur;
3407 			    if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
3408 				cur->last->nextcp = old_nextcp;
3409 				cur->last->nonextcp = false;
3410 				pt = chunkalloc(sizeof(SplinePoint));
3411 			        pt->hintmask = pending_hm; pending_hm = NULL;
3412 				pt->prevcp = mid_prevcp;
3413 				pt->me = mid;
3414 				pt->nextcp = mid_nextcp;
3415 				/*pt->flex = pops[2];*/
3416 			        CheckMake(cur->last,pt);
3417 				SplineMake3(cur->last,pt);
3418 				cur->last = pt;
3419 				pt = chunkalloc(sizeof(SplinePoint));
3420 				pt->prevcp = end_prevcp;
3421 				pt->me = end;
3422 				pt->nonextcp = true;
3423 			        CheckMake(cur->last,pt);
3424 				SplineMake3(cur->last,pt);
3425 				cur->last = pt;
3426 			    } else
3427 				LogError( _("No previous point on path in curveto from flex 0 in %s\n"), name );
3428 			} else {
3429 			    /* Um, something's wrong. Let's just draw a line */
3430 			    /* do the simple method, which consists of creating */
3431 			    /*  the appropriate line */
3432 			    pt = chunkalloc(sizeof(SplinePoint));
3433 			    pt->me.x = pops[1]; pt->me.y = pops[0];
3434 			    pt->noprevcp = true; pt->nonextcp = true;
3435 			    SplinePointListFree(oldcur->next); oldcur->next = NULL; spl = NULL;
3436 			    cur = oldcur;
3437 			    if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
3438 				CheckMake(cur->last,pt);
3439 				SplineMake3(cur->last,pt);
3440 				cur->last = pt;
3441 			    } else
3442 				LogError( _("No previous point on path in lineto from flex 0 in %s\n"), name );
3443 			}
3444 			--popsp;
3445 			cur->next = NULL;
3446 			SplinePointListsFree(spl);
3447 			oldcur = NULL;
3448 		      } else
3449 			LogError( _("Bad flex subroutine in %s\n"), name );
3450 
3451 			is_type2 = context->is_type2;
3452 			/* If we found a type2 font with a type1 flex sequence */
3453 			/*  (an illegal idea, but never mind, someone gave us one)*/
3454 			/*  then we had to turn off type2 untill the end of the */
3455 			/*  flex sequence. Which is here */
3456 		      break;
3457 		      case 14: 		/* results in 1 blended value */
3458 		      case 15:		/* results in 2 blended values */
3459 		      case 16:		/* results in 3 blended values */
3460 		      case 17:		/* results in 4 blended values */
3461 		      case 18: {	/* results in 6 blended values */
3462 			int cnt = stack[sp-1]-13;
3463 			if ( cnt==5 ) cnt=6;
3464 			if ( context->instance_count==0 )
3465 			    LogError( _("Attempt to use a multiple master subroutine in a non-mm font in %s.\n"), name );
3466 			else if ( tot!=cnt*context->instance_count )
3467 			    LogError( _("Multiple master subroutine called with the wrong number of arguments in %s.\n"), name );
3468 			else {
3469 			    /* Hints need to keep track of the original blends */
3470 			    if ( cnt==1 && !is_type2 ) {
3471 				if ( sp-2-tot>=1 && (!old_last_was_b1 || stack[0]!=Blend(unblended[1],context))) {
3472 				    unblended[0][0] = stack[0];
3473 				    for ( i=1; i<context->instance_count; ++i )
3474 					unblended[0][i] = 0;
3475 			        } else
3476 				    memcpy(unblended,unblended+1,context->instance_count*sizeof(real));
3477 			        for ( j=0; j<context->instance_count; ++j )
3478 				    unblended[1][j] = stack[sp-2-tot+j];
3479 			    } else if ( cnt==2 && !is_type2 ) {
3480 				unblended[0][0] = stack[sp-2-tot];
3481 				unblended[1][0] = stack[sp-2-tot+1];
3482 				for ( i=0; i<2; ++i )
3483 				    for ( j=1; j<context->instance_count; ++j )
3484 					unblended[i][j] = stack[sp-2-tot+2+i*(context->instance_count-1)+(j-1)];
3485 			    }
3486 			    popsp = 0;
3487 			    for ( i=0; i<cnt; ++i ) {
3488 				double sum = stack[sp-2-tot+ i];
3489 				for ( j=1; j<context->instance_count; ++j )
3490 				    sum += context->blend_values[j]*
3491 					    stack[sp-2-tot+ cnt +i*(context->instance_count-1)+ j-1];
3492 				pops[cnt-1-popsp++] = sum;
3493 			    }
3494 			}
3495 		      } break;
3496 		    }
3497 		    sp = k+1;
3498 		}
3499 	      break;
3500 	      case 20: /* put */
3501 		if ( sp<2 ) LogError( _("Too few items on stack for put in %s\n"), name );
3502 		else if ( stack[sp-1]<0 || stack[sp-1]>=32 ) LogError( _("Reference to transient memory out of bounds in put in %s\n"), name );
3503 		else {
3504 		    transient[(int)stack[sp-1]] = stack[sp-2];
3505 		    sp -= 2;
3506 		}
3507 	      break;
3508 	      case 21: /* get */
3509 		if ( sp<1 ) LogError( _("Too few items on stack for get in %s\n"), name );
3510 		else if ( stack[sp-1]<0 || stack[sp-1]>=32 ) LogError( _("Reference to transient memory out of bounds in put in %s\n"), name );
3511 		else
3512 		    stack[sp-1] = transient[(int)stack[sp-1]];
3513 	      break;
3514 	      case 17: /* pop */
3515 		/* pops something from the postscript stack and pushes it on ours */
3516 		/* used to get a return value from an othersubr call */
3517 		/* Bleah. Adobe wants the pops to return the arguments if we */
3518 		/*  don't understand the call. What use is the subroutine then?*/
3519 		if ( popsp<=0 )
3520 		    LogError( _("Pop stack underflow on pop in %s\n"), name );
3521 		else
3522 		    stack[sp++] = pops[--popsp];
3523 	      break;
3524 	      case 18: /* drop */
3525 		if ( sp>0 ) --sp;
3526 	      break;
3527 	      case 27: /* dup */
3528 		if ( sp>=1 ) {
3529 		    stack[sp] = stack[sp-1];
3530 		    ++sp;
3531 		}
3532 	      break;
3533 	      case 28: /* exch */
3534 		if ( sp>=2 ) {
3535 		    real temp = stack[sp-1];
3536 		    stack[sp-1] = stack[sp-2]; stack[sp-2] = temp;
3537 		}
3538 	      break;
3539 	      case 29: /* index */
3540 		if ( sp>=1 ) {
3541 		    int index = stack[--sp];
3542 		    if ( index<0 || sp<index+1 )
3543 			LogError( _("Index out of range in %s\n"), name );
3544 		    else {
3545 			stack[sp] = stack[sp-index-1];
3546 			++sp;
3547 		    }
3548 		}
3549 	      break;
3550 	      case 30: /* roll */
3551 		if ( sp>=2 ) {
3552 		    int j = stack[sp-1], N=stack[sp-2];
3553 		    if ( N>sp || j>=N || j<0 || N<0 )
3554 			LogError( _("roll out of range in %s\n"), name );
3555 		    else if ( j==0 || N==0 )
3556 			/* No op */;
3557 		    else {
3558 			real *temp = galloc(N*sizeof(real));
3559 			int i;
3560 			for ( i=0; i<N; ++i )
3561 			    temp[i] = stack[sp-N+i];
3562 			for ( i=0; i<N; ++i )
3563 			    stack[sp-N+i] = temp[(i+j)%N];
3564 			free(temp);
3565 		    }
3566 		}
3567 	      break;
3568 	      case 33: /* setcurrentpoint */
3569 		if ( sp<2 ) LogError( _("Stack underflow on setcurrentpoint in %s\n"), name );
3570 		else {
3571 		    current.x = stack[0];
3572 		    current.y = stack[1];
3573 		}
3574 		sp = 0;
3575 	      break;
3576 	      case 34:	/* hflex */
3577 	      case 35:	/* flex */
3578 	      case 36:	/* hflex1 */
3579 	      case 37:	/* flex1 */
3580 		dy = dy3 = dy4 = dy5 = dy6 = 0;
3581 		dx = stack[base++];
3582 		if ( v!=34 )
3583 		    dy = stack[base++];
3584 		dx2 = stack[base++];
3585 		dy2 = stack[base++];
3586 		dx3 = stack[base++];
3587 		if ( v!=34 && v!=36 )
3588 		    dy3 = stack[base++];
3589 		dx4 = stack[base++];
3590 		if ( v!=34 && v!=36 )
3591 		    dy4 = stack[base++];
3592 		dx5 = stack[base++];
3593 		if ( v==34 )
3594 		    dy5 = -dy2;
3595 		else
3596 		    dy5 = stack[base++];
3597 		switch ( v ) {
3598 		    real xt, yt;
3599 		    case 35:    /* flex */
3600 			dx6 = stack[base++];
3601 			dy6 = stack[base++];
3602 			break;
3603 		    case 34:    /* hflex */
3604 			dx6 = stack[base++];
3605 			break;
3606 		    case 36:    /* hflex1 */
3607 			dx6 = stack[base++];
3608 			dy6 = -dy-dy2-dy5;
3609 			break;
3610 		    case 37:    /* flex1 */
3611 			xt = dx+dx2+dx3+dx4+dx5;
3612 			yt = dy+dy2+dy3+dy4+dy5;
3613 			if ( xt<0 ) xt= -xt;
3614 			if ( yt<0 ) yt= -yt;
3615 			if ( xt>yt ) {
3616 			    dx6 = stack[base++];
3617 			    dy6 = -dy-dy2-dy3-dy4-dy5;
3618 			} else {
3619 			    dy6 = stack[base++];
3620 			    dx6 = -dx-dx2-dx3-dx4-dx5;
3621 			}
3622 			break;
3623 		}
3624 		if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
3625 		    current.x = rint((current.x+dx)*1024)/1024; current.y = rint((current.y+dy)*1024)/1024;
3626 		    cur->last->nextcp.x = current.x; cur->last->nextcp.y = current.y;
3627 		    cur->last->nonextcp = false;
3628 		    current.x = rint((current.x+dx2)*1024)/1024; current.y = rint((current.y+dy2)*1024)/1024;
3629 		    pt = chunkalloc(sizeof(SplinePoint));
3630 		    pt->hintmask = pending_hm; pending_hm = NULL;
3631 		    pt->prevcp.x = current.x; pt->prevcp.y = current.y;
3632 		    current.x = rint((current.x+dx3)*1024)/1024; current.y = rint((current.y+dy3)*1024)/1024;
3633 		    pt->me.x = current.x; pt->me.y = current.y;
3634 		    pt->nonextcp = true;
3635 		    CheckMake(cur->last,pt);
3636 		    SplineMake3(cur->last,pt);
3637 		    cur->last = pt;
3638 
3639 		    current.x = rint((current.x+dx4)*1024)/1024; current.y = rint((current.y+dy4)*1024)/1024;
3640 		    cur->last->nextcp.x = current.x; cur->last->nextcp.y = current.y;
3641 		    cur->last->nonextcp = false;
3642 		    current.x = rint((current.x+dx5)*1024)/1024; current.y = rint((current.y+dy5)*1024)/1024;
3643 		    pt = chunkalloc(sizeof(SplinePoint));
3644 		    pt->prevcp.x = current.x; pt->prevcp.y = current.y;
3645 		    current.x = rint((current.x+dx6)*1024)/1024; current.y = rint((current.y+dy6)*1024)/1024;
3646 		    pt->me.x = current.x; pt->me.y = current.y;
3647 		    pt->nonextcp = true;
3648 		    CheckMake(cur->last,pt);
3649 		    SplineMake3(cur->last,pt);
3650 		    cur->last = pt;
3651 		} else
3652 		    LogError( _("No previous point on path in flex operator in %s\n"), name );
3653 		sp = 0;
3654 	      break;
3655 	      default:
3656 		LogError( _("Uninterpreted opcode 12,%d in %s\n"), v, name );
3657 	      break;
3658 	    }
3659 	} else { last_was_b1 = false; switch ( v ) {
3660 	  case 1: /* hstem */
3661 	  case 18: /* hstemhm */
3662 	    base = 0;
3663 	    if ( (sp&1) && ret->width == (int16) 0x8000 )
3664 		ret->width = stack[0];
3665 	    if ( sp&1 )
3666 		base=1;
3667 	    if ( sp-base<2 )
3668 		LogError( _("Stack underflow on hstem in %s\n"), name );
3669 	    /* stack[0] is absolute y for start of horizontal hint */
3670 	    /*	(actually relative to the y specified as lsidebearing y in sbw*/
3671 	    /* stack[1] is relative y for height of hint zone */
3672 	    coord = 0;
3673 	    hp = NULL;
3674 	    if ( activeh!=NULL )
3675 		for ( hp=activeh; hp->next!=NULL; hp = hp->next );
3676 	    while ( sp-base>=2 ) {
3677 		sameh = NULL;
3678 		if ( !is_type2 )
3679 		    sameh = SameH(ret->hstem,stack[base]+coord,stack[base+1],
3680 				unblended,context->instance_count);
3681 		hint = HintNew(stack[base]+coord,stack[base+1]);
3682 		hint->hintnumber = sameh!=NULL ? sameh->hintnumber : hint_cnt++;
3683 		if ( !is_type2 && context->instance_count!=0 ) {
3684 		    hint->u.unblended = chunkalloc(sizeof(real [2][MmMax]));
3685 		    memcpy(hint->u.unblended,unblended,sizeof(real [2][MmMax]));
3686 		}
3687 		if ( activeh==NULL )
3688 		    activeh = hint;
3689 		else
3690 		    hp->next = hint;
3691 		hp = hint;
3692 		if ( !is_type2 && hint->hintnumber<96 ) {
3693 		    if ( pending_hm==NULL )
3694 			pending_hm = chunkalloc(sizeof(HintMask));
3695 		    (*pending_hm)[hint->hintnumber>>3] |= 0x80>>(hint->hintnumber&0x7);
3696 		}
3697 		base+=2;
3698 		coord = hint->start+hint->width;
3699 	    }
3700 	    sp = 0;
3701 	  break;
3702 	  case 19: /* hintmask */
3703 	  case 20: /* cntrmask */
3704 	    /* If there's anything on the stack treat it as a vstem hint */
3705 	  case 3: /* vstem */
3706 	  case 23: /* vstemhm */
3707 	    base = 0;
3708 	    if ( cur==NULL || v==3 || v==23 ) {
3709 		if ( (sp&1) && is_type2 && ret->width == (int16) 0x8000 ) {
3710 		    ret->width = stack[0];
3711 		}
3712 		if ( sp&1 )
3713 		    base=1;
3714 		/* I've seen a vstemhm with no arguments. I've no idea what that */
3715 		/*  means. It came right after a hintmask */
3716 		/* I'm confused about v/hstemhm because the manual says it needs */
3717 		/*  to be used if one uses a hintmask, but that's not what the */
3718 		/*  examples show.  Or I'm not understanding. */
3719 		if ( sp-base<2 && v!=19 && v!=20 )
3720 		    LogError( _("Stack underflow on vstem in %s\n"), name );
3721 		/* stack[0] is absolute x for start of vertical hint */
3722 		/*	(actually relative to the x specified as lsidebearing in h/sbw*/
3723 		/* stack[1] is relative x for height of hint zone */
3724 		coord = ret->lsidebearing;
3725 		hp = NULL;
3726 		if ( activev!=NULL )
3727 		    for ( hp=activev; hp->next!=NULL; hp = hp->next );
3728 		while ( sp-base>=2 ) {
3729 		    sameh = NULL;
3730 		    if ( !is_type2 )
3731 			sameh = SameH(ret->vstem,stack[base]+coord,stack[base+1],
3732 				    unblended,context->instance_count);
3733 		    hint = HintNew(stack[base]+coord,stack[base+1]);
3734 		    hint->hintnumber = sameh!=NULL ? sameh->hintnumber : hint_cnt++;
3735 		    if ( !is_type2 && context->instance_count!=0 ) {
3736 			hint->u.unblended = chunkalloc(sizeof(real [2][MmMax]));
3737 			memcpy(hint->u.unblended,unblended,sizeof(real [2][MmMax]));
3738 		    }
3739 		    if ( !is_type2 && hint->hintnumber<96 ) {
3740 			if ( pending_hm==NULL )
3741 			    pending_hm = chunkalloc(sizeof(HintMask));
3742 			(*pending_hm)[hint->hintnumber>>3] |= 0x80>>(hint->hintnumber&0x7);
3743 		    }
3744 		    if ( activev==NULL )
3745 			activev = hint;
3746 		    else
3747 			hp->next = hint;
3748 		    hp = hint;
3749 		    base+=2;
3750 		    coord = hint->start+hint->width;
3751 		}
3752 		sp = 0;
3753 	    }
3754 	    if ( v==19 || v==20 ) {		/* hintmask, cntrmask */
3755 	      unsigned bytes = (hint_cnt+7)/8;
3756 		if ( bytes>sizeof(HintMask) ) bytes = sizeof(HintMask);
3757 		if ( v==19 ) {
3758 		    ret->hstem = HintsAppend(ret->hstem,activeh); activeh=NULL;
3759 		    ret->vstem = HintsAppend(ret->vstem,activev); activev=NULL;
3760 		    if ( pending_hm==NULL )
3761 			pending_hm = chunkalloc(sizeof(HintMask));
3762 		    memcpy(pending_hm,type1,bytes);
3763 		} else if ( cp<(int)(sizeof(counters)/sizeof(counters[0])) ) {
3764 		    counters[cp] = chunkalloc(sizeof(HintMask));
3765 		    memcpy(counters[cp],type1,bytes);
3766 		    ++cp;
3767 		}
3768 		if ( bytes!=(unsigned)hint_cnt/8 ) {
3769 		    int mask = 0xff>>(hint_cnt&7);
3770 		    if ( type1[bytes-1]&mask )
3771 			LogError( _("Hint mask (or counter mask) with too many hints in %s\n"), name );
3772 		}
3773 		type1 += bytes;
3774 		len -= bytes;
3775 	    }
3776 	  break;
3777 	  case 14: /* endchar */
3778 	    /* endchar is allowed to terminate processing even within a subroutine */
3779 	    if ( (sp&1) && is_type2 && ret->width == (int16) 0x8000 )
3780 		ret->width = stack[0];
3781 	    if ( context->painttype!=2 )
3782 		closepath(cur,is_type2);
3783 	    pcsp = 0;
3784 	    if ( sp==4 ) {
3785 		/* In Type2 strings endchar has a depreciated function of doing */
3786 		/*  a seac (which doesn't exist at all). Except enchar takes */
3787 		/*  4 args and seac takes 5. Bleah */
3788 		stack[4] = stack[3]; stack[3] = stack[2]; stack[2] = stack[1]; stack[1] = stack[0];
3789 		stack[0] = 0;
3790 		sp = 5;
3791   goto seac;
3792 	    } else if ( sp==5 ) {
3793 		/* same as above except also specified a width */
3794 		stack[0] = 0;
3795   goto seac;
3796 	    }
3797 	    /* the docs say that endchar must be the last command in a char */
3798 	    /*  (or the last command in a subroutine which is the last in the */
3799 	    /*  char) So in theory if there's anything left we should complain*/
3800 	    /*  In practice though, the EuroFont has a return statement after */
3801 	    /*  the endchar in a subroutine. So we won't try to catch that err*/
3802 	    /*  and just stop. */
3803 	    /* Adobe says it's not an error, but I can't understand their */
3804 	    /*  logic */
3805   goto done;
3806 	  break;
3807 	  case 13: /* hsbw (set left sidebearing and width) */
3808 	    if ( sp<2 ) LogError( _("Stack underflow on hsbw in %s\n"), name );
3809 	    ret->lsidebearing = stack[0];
3810 	    current.x = stack[0];		/* sets the current point too */
3811 	    ret->width = stack[1];
3812 	    sp = 0;
3813 	  break;
3814 	  case 9: /* closepath */
3815 	    sp = 0;
3816 	    closepath(cur,is_type2);
3817 	  break;
3818 	  case 21: /* rmoveto */
3819 	  case 22: /* hmoveto */
3820 	  case 4: /* vmoveto */
3821 	    if ( is_type2 ) {
3822 		if (( (v==21 && sp==3) || (v!=21 && sp==2))  && ret->width == (int16) 0x8000 )
3823 		    /* Character's width may be specified on the first moveto */
3824 		    ret->width = stack[0];
3825 		if ( v==21 && sp>2 ) {
3826 		    stack[0] = stack[sp-2]; stack[1] = stack[sp-1];
3827 		    sp = 2;
3828 		} else if ( v!=21 && sp>1 ) {
3829 		    stack[0] = stack[sp-1];
3830 		    sp = 1;
3831 		}
3832 		if ( context->painttype!=2 )
3833 		    closepath(cur,true);
3834 	    }
3835 	  case 5: /* rlineto */
3836 	  case 6: /* hlineto */
3837 	  case 7: /* vlineto */
3838 	    polarity = 0;
3839 	    base = 0;
3840 	    while ( base<sp ) {
3841 		dx = dy = 0;
3842 		if ( v==5 || v==21 ) {
3843 		    if ( sp<base+2 ) {
3844 			LogError( _("Stack underflow on rlineto/rmoveto in %s\n"), name );
3845 	    break;
3846 		    }
3847 		    dx = stack[base++];
3848 		    dy = stack[base++];
3849 		} else if ( (v==6 && !(polarity&1)) || (v==7 && (polarity&1)) || v==22 ) {
3850 		    if ( sp<=base ) {
3851 			LogError( _("Stack underflow on hlineto/hmoveto in %s\n"), name );
3852 	    break;
3853 		    }
3854 		    dx = stack[base++];
3855 		} else /*if ( (v==7 && !(parity&1)) || (v==6 && (parity&1) || v==4 )*/ {
3856 		    if ( sp<=base ) {
3857 			LogError( _("Stack underflow on vlineto/vmoveto in %s\n"), name );
3858 	    break;
3859 		    }
3860 		    dy = stack[base++];
3861 		}
3862 		++polarity;
3863 		current.x = rint((current.x+dx)*1024)/1024; current.y = rint((current.y+dy)*1024)/1024;
3864 		pt = chunkalloc(sizeof(SplinePoint));
3865 		pt->hintmask = pending_hm; pending_hm = NULL;
3866 		pt->me.x = current.x; pt->me.y = current.y;
3867 		pt->noprevcp = true; pt->nonextcp = true;
3868 		if ( v==4 || v==21 || v==22 ) {
3869 		    if ( cur!=NULL && cur->first==cur->last && cur->first->prev==NULL && is_type2 ) {
3870 			/* Two adjacent movetos should not create single point paths */
3871 			cur->first->me.x = current.x; cur->first->me.y = current.y;
3872 			SplinePointFree(pt);
3873 		    } else {
3874 			SplinePointList *spl = chunkalloc(sizeof(SplinePointList));
3875 			spl->first = spl->last = pt;
3876 			if ( cur!=NULL )
3877 			    cur->next = spl;
3878 			else
3879 			    ret->layers[ly_fore].splines = spl;
3880 			cur = spl;
3881 		    }
3882 	    break;
3883 		} else {
3884 		    if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
3885 			CheckMake(cur->last,pt);
3886 			SplineMake3(cur->last,pt);
3887 			cur->last = pt;
3888 		    } else
3889 			LogError( _("No previous point on path in lineto in %s\n"), name );
3890 		    if ( !is_type2 )
3891 	    break;
3892 		}
3893 	    }
3894 	    sp = 0;
3895 	  break;
3896 	  case 25: /* rlinecurve */
3897 	    base = 0;
3898 	    while ( sp>base+6 ) {
3899 		current.x = rint((current.x+stack[base++])*1024)/1024; current.y = rint((current.y+stack[base++])*1024)/1024;
3900 		if ( cur!=NULL ) {
3901 		    pt = chunkalloc(sizeof(SplinePoint));
3902 		    pt->hintmask = pending_hm; pending_hm = NULL;
3903 		    pt->me.x = current.x; pt->me.y = current.y;
3904 		    pt->noprevcp = true; pt->nonextcp = true;
3905 		    CheckMake(cur->last,pt);
3906 		    SplineMake3(cur->last,pt);
3907 		    cur->last = pt;
3908 		}
3909 	    }
3910 	  case 24: /* rcurveline */
3911 	  case 8:  /* rrcurveto */
3912 	  case 31: /* hvcurveto */
3913 	  case 30: /* vhcurveto */
3914 	  case 27: /* hhcurveto */
3915 	  case 26: /* vvcurveto */
3916 	    polarity = 0;
3917 	    while ( sp>base+2 ) {
3918 		dx = dy = dx2 = dy2 = dx3 = dy3 = 0;
3919 		if ( v==8 || v==25 || v==24 ) {
3920 		    if ( sp<6+base ) {
3921 			LogError( _("Stack underflow on rrcurveto in %s\n"), name );
3922 			base = sp;
3923 		    } else {
3924 			dx = stack[base++];
3925 			dy = stack[base++];
3926 			dx2 = stack[base++];
3927 			dy2 = stack[base++];
3928 			dx3 = stack[base++];
3929 			dy3 = stack[base++];
3930 		    }
3931 		} else if ( v==27 ) {		/* hhcurveto */
3932 		    if ( sp<4+base ) {
3933 			LogError( _("Stack underflow on hhcurveto in %s\n"), name );
3934 			base = sp;
3935 		    } else {
3936 			if ( (sp-base)&1 ) dy = stack[base++];
3937 			dx = stack[base++];
3938 			dx2 = stack[base++];
3939 			dy2 = stack[base++];
3940 			dx3 = stack[base++];
3941 		    }
3942 		} else if ( v==26 ) {		/* vvcurveto */
3943 		    if ( sp<4+base ) {
3944 			LogError( _("Stack underflow on hhcurveto in %s\n"), name );
3945 			base = sp;
3946 		    } else {
3947 			if ( (sp-base)&1 ) dx = stack[base++];
3948 			dy = stack[base++];
3949 			dx2 = stack[base++];
3950 			dy2 = stack[base++];
3951 			dy3 = stack[base++];
3952 		    }
3953 		} else if ( (v==31 && !(polarity&1)) || (v==30 && (polarity&1)) ) {
3954 		    if ( sp<4+base ) {
3955 			LogError( _("Stack underflow on hvcurveto in %s\n"), name );
3956 			base = sp;
3957 		    } else {
3958 			dx = stack[base++];
3959 			dx2 = stack[base++];
3960 			dy2 = stack[base++];
3961 			dy3 = stack[base++];
3962 			if ( sp==base+1 )
3963 			    dx3 = stack[base++];
3964 		    }
3965 		} else /*if ( (v==30 && !(polarity&1)) || (v==31 && (polarity&1)) )*/ {
3966 		    if ( sp<4+base ) {
3967 			LogError( _("Stack underflow on vhcurveto in %s\n"), name );
3968 			base = sp;
3969 		    } else {
3970 			dy = stack[base++];
3971 			dx2 = stack[base++];
3972 			dy2 = stack[base++];
3973 			dx3 = stack[base++];
3974 			if ( sp==base+1 )
3975 			    dy3 = stack[base++];
3976 		    }
3977 		}
3978 		++polarity;
3979 		if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
3980 		    current.x = rint((current.x+dx)*1024)/1024; current.y = rint((current.y+dy)*1024)/1024;
3981 		    cur->last->nextcp.x = current.x; cur->last->nextcp.y = current.y;
3982 		    cur->last->nonextcp = false;
3983 		    current.x = rint((current.x+dx2)*1024)/1024; current.y = rint((current.y+dy2)*1024)/1024;
3984 		    pt = chunkalloc(sizeof(SplinePoint));
3985 		    pt->hintmask = pending_hm; pending_hm = NULL;
3986 		    pt->prevcp.x = current.x; pt->prevcp.y = current.y;
3987 		    current.x = rint((current.x+dx3)*1024)/1024; current.y = rint((current.y+dy3)*1024)/1024;
3988 		    pt->me.x = current.x; pt->me.y = current.y;
3989 		    pt->nonextcp = true;
3990 		    CheckMake(cur->last,pt);
3991 		    SplineMake3(cur->last,pt);
3992 		    cur->last = pt;
3993 		} else
3994 		    LogError( _("No previous point on path in curveto in %s\n"), name );
3995 	    }
3996 	    if ( v==24 ) {
3997 		current.x = rint((current.x+stack[base++])*1024)/1024; current.y = rint((current.y+stack[base++])*1024)/1024;
3998 		if ( cur!=NULL ) {	/* In legal code, cur can't be null here, but I got something illegal... */
3999 		    pt = chunkalloc(sizeof(SplinePoint));
4000 		    pt->hintmask = pending_hm; pending_hm = NULL;
4001 		    pt->me.x = current.x; pt->me.y = current.y;
4002 		    pt->noprevcp = true; pt->nonextcp = true;
4003 		    CheckMake(cur->last,pt);
4004 		    SplineMake3(cur->last,pt);
4005 		    cur->last = pt;
4006 		}
4007 	    }
4008 	    sp = 0;
4009 	  break;
4010 	  case 29: /* callgsubr */
4011 	  case 10: /* callsubr */
4012 	    /* stack[sp-1] contains the number of the subroutine to call */
4013 	    if ( sp<1 ) {
4014 		LogError( _("Stack underflow on callsubr in %s\n"), name );
4015 	  break;
4016 	    } else if ( pcsp>10 ) {
4017 		LogError( _("Too many subroutine calls in %s\n"), name );
4018 	  break;
4019 	    }
4020 	    s=subrs; if ( v==29 ) s = gsubrs;
4021 	    if ( s!=NULL ) stack[sp-1] += s->bias;
4022 	    /* Type2 subrs have a bias that must be added to the subr-number */
4023 	    /* Type1 subrs do not. We set the bias on them to 0 */
4024 	    if ( s==NULL || stack[sp-1]>=s->cnt || stack[sp-1]<0 ||
4025 		    s->values[(int) stack[sp-1]]==NULL )
4026 		LogError( _("Subroutine number out of bounds in %s\n"), name );
4027 	    else {
4028 		pcstack[pcsp].type1 = type1;
4029 		pcstack[pcsp].len = len;
4030 		pcstack[pcsp].subnum = stack[sp-1];
4031 		++pcsp;
4032 		type1 = s->values[(int) stack[sp-1]];
4033 		len = s->lens[(int) stack[sp-1]];
4034 	    }
4035 	    if ( --sp<0 ) sp = 0;
4036 	  break;
4037 	  case 11: /* return */
4038 	    /* return from a subr outine */
4039 	    if ( pcsp<1 ) LogError( _("return when not in subroutine in %s\n"), name );
4040 	    else {
4041 		--pcsp;
4042 		type1 = pcstack[pcsp].type1;
4043 		len = pcstack[pcsp].len;
4044 	    }
4045 	  break;
4046 	  case 16: { /* blend -- obsolete type 2 multiple master operator */
4047 	    int cnt,i,j;
4048 	    if ( context->instance_count==0 )
4049 		LogError( _("Attempt to use a multiple master subroutine in a non-mm font.\n") );
4050 	    else if ( sp<1 || sp<context->instance_count*stack[sp-1]+1 )
4051 		LogError( _("Too few items on stack for blend in %s\n"), name );
4052 	    else {
4053 		if ( !context->blend_warn ) {
4054 		    LogError( _("Use of obsolete blend operator.\n") );
4055 		    context->blend_warn = true;
4056 		}
4057 		cnt = stack[sp-1];
4058 		sp -= context->instance_count*stack[sp-1]+1;
4059 		for ( i=0; i<cnt; ++i ) {
4060 		    for ( j=1; j<context->instance_count; ++j )
4061 			stack[sp+i] += context->blend_values[j]*stack[sp+
4062 				cnt+ i*(context->instance_count-1)+ j-1];
4063 		}
4064 		/* there will always be fewer pushes than there were pops */
4065 		/*  so I don't bother to check the stack */
4066 		sp += cnt;
4067 	    }
4068 	  }
4069 	  break;
4070 	  default:
4071 	    LogError( _("Uninterpreted opcode %d in %s\n"), v, name );
4072 	  break;
4073 	}}
4074     }
4075   done:
4076     if ( pcsp!=0 )
4077 	LogError( _("end of subroutine reached with no return in %s\n"), name );
4078     if (THdo_catagorize)
4079       SCCatagorizePoints(ret);
4080 
4081     ret->hstem = HintsAppend(ret->hstem,activeh); activeh=NULL;
4082     ret->vstem = HintsAppend(ret->vstem,activev); activev=NULL;
4083 
4084     if ( cp!=0 ) { int i;
4085 	ret->countermasks = galloc(cp*sizeof(HintMask));
4086 	ret->countermask_cnt = cp;
4087 	for ( i=0; i<cp; ++i ) {
4088 	    memcpy(&ret->countermasks[i],counters[i],sizeof(HintMask));
4089 	    chunkfree(counters[i],sizeof(HintMask));
4090 	}
4091     }
4092 
4093     /* Even in type1 fonts all paths should be closed. But if we close them at*/
4094     /*  the obvious moveto, that breaks flex hints. So we have a hack here at */
4095     /*  the end which closes any open paths. */
4096     /* If we do have a PaintType 2 font, then presumably the difference between*/
4097     /*  open and closed paths matters */
4098     if ( !is_type2 && !context->painttype )
4099 	for ( cur = ret->layers[ly_fore].splines; cur!=NULL; cur = cur->next ) if ( cur->first->prev==NULL ) {
4100 	    CheckMake(cur->last,cur->first);
4101 	    SplineMake3(cur->last,cur->first);
4102 	    cur->last = cur->first;
4103 	}
4104     /* Oh, I see. PS and TT disagree on which direction to use, so Fontographer*/
4105     /*  chose the TT direction and we must reverse postscript */
4106     if (THdo_set_reversing) {
4107       for ( cur = ret->layers[ly_fore].splines; cur!=NULL; cur = cur->next )
4108 	SplineSetReverse(cur);
4109     }
4110     if ( ret->hstem==NULL && ret->vstem==NULL )
4111 	ret->manualhints = false;
4112     if ( !is_type2 && context->instance_count!=0 ) {
4113 	UnblendFree(ret->hstem);
4114 	UnblendFree(ret->vstem);
4115     }
4116     if (THdo_hint_guessing) {
4117       ret->hstem = HintCleanup(ret->hstem,true,context->instance_count);
4118       ret->vstem = HintCleanup(ret->vstem,true,context->instance_count);
4119       SCGuessHHintInstancesList(ret,ly_fore);
4120       SCGuessVHintInstancesList(ret,ly_fore);
4121       ret->hconflicts = StemListAnyConflicts(ret->hstem);
4122       ret->vconflicts = StemListAnyConflicts(ret->vstem);
4123       if ( context->instance_count==1 && !ret->hconflicts && !ret->vconflicts )
4124 	SCClearHintMasks(ret,ly_fore,false);
4125       HintsRenumber(ret);
4126     }
4127     if ( name!=NULL && strcmp(name,".notdef")!=0 )
4128 	ret->widthset = true;
4129 return( ret );
4130 }
4131 
4132 
4133 /* This finds the 'connect-the-dots' boundingbox of a Type2 charstring */
4134 /* It is a simplified version of PSCharStringToSplines, above */
4135 
PSCharStringToBB(uint8 * type1,int len,struct pscontext * context,struct pschars * subrs,struct pschars * gsubrs,const char * name)4136 SplineChar *PSCharStringToBB(uint8 *type1, int len, struct pscontext *context,
4137 			     struct pschars *subrs, struct pschars *gsubrs, const char *name) {
4138     real stack[50]; int sp=0, v;		/* Type1 stack is about 25 long, Type2 stack is 48 */
4139     real transient[32];
4140     SplineChar *ret = SplineCharCreate(2);
4141 
4142     DBasePoint current, ll, ur;
4143     real dx, dy, dx2, dy2, dx3, dy3, dx4, dy4, dx5, dy5, dx6=0, dy6;
4144 
4145     int first = 1; /* to flag extra set width */
4146     /* subroutines may be nested to a depth of 10 */
4147     struct substate { unsigned char *type1; int len; int subnum; } pcstack[11];
4148     int pcsp=0;
4149 
4150     real pops[30];
4151     int popsp=0;
4152     int base, polarity;
4153 
4154     struct pschars *s;
4155     int hint_cnt = 0;
4156 
4157     int last_was_b1=false, old_last_was_b1;
4158 
4159     ret->name = copy( name );
4160     ret->unicodeenc = -1;
4161     ret->width = (int16) 0x8000;
4162     if ( name==NULL ) name = "unnamed";
4163     ret->manualhints = true;
4164     if ( !context->is_type2 ) {
4165 	LogError( _("Quick boundingbox mode only does CFF charstrings, not Type1 (font %s)\n"), name );
4166 	return (ret);
4167     }
4168 
4169     current.x = current.y = 0;
4170     ll.x = ll.y = (int16) 0x7FFF;
4171     ur.x = ur.y = (int16) -0x7FFF;
4172 
4173     while ( len>0 ) {
4174 	if ( sp>48 ) {
4175 	    LogError( _("Stack got too big in %s\n"), name );
4176 	    sp = 48;
4177 	}
4178 	base = 0;
4179 	--len;
4180 	if ( (v = *type1++)>=32 ) {
4181 	    if ( v<=246) {
4182 		stack[sp++] = v - 139;
4183 	    } else if ( v<=250 ) {
4184 		stack[sp++] = (v-247)*256 + *type1++ + 108;
4185 		--len;
4186 	    } else if ( v<=254 ) {
4187 		stack[sp++] = -(v-251)*256 - *type1++ - 108;
4188 		--len;
4189 	    } else {
4190 		int val = (*type1<<24) | (type1[1]<<16) | (type1[2]<<8) | type1[3];
4191 		stack[sp++] = val;
4192 		type1 += 4;
4193 		len -= 4;
4194 		stack[sp-1] /= 65536.;
4195 	    }
4196 	} else if ( v==28 ) {
4197 	    stack[sp++] = (short) ((type1[0]<<8) | type1[1]);
4198 	    type1 += 2;
4199 	    len -= 2;
4200 	    /* In the Dict tables of CFF, a 5byte fixed value is prefixed by a */
4201 	    /*  29 code. In Type2 strings the prefix is 255. */
4202 	} else if ( v==12 ) {
4203 	    old_last_was_b1 = last_was_b1; last_was_b1 = false;
4204 	    v = *type1++;
4205 	    --len;
4206 	    switch ( v ) {
4207 	    case 0: /* dotsection */
4208 		sp = 0;
4209 		break;
4210 	    case 1: /* vstem3 */	/* specifies three v hints zones at once */
4211 		if ( sp<6 ) LogError( _("Stack underflow on vstem3 in %s\n"), name );
4212 		/* according to the standard, if there is a vstem3 there can't */
4213 		/*  be any vstems, so there can't be any confusion about hint order */
4214 		/*  so we don't need to worry about unblended stuff */
4215 		hint_cnt+=3;
4216 		sp = 0;
4217 		break;
4218 	    case 2: /* hstem3 */	/* specifies three h hints zones at once */
4219 		if ( sp<6 ) LogError( _("Stack underflow on hstem3 in %s\n"), name );
4220 		hint_cnt+=3;
4221 		sp = 0;
4222 		break;
4223 	    case 6: /* seac */	/* build accented characters */
4224 	    seac:
4225 		if ( sp<5 ) LogError( _("Stack underflow on seac in %s\n"), name );
4226 		/* stack[0] must be the lsidebearing of the accent. I'm not sure why */
4227 		sp = 0;
4228 		break;
4229 	    case 7: /* sbw */		/* generalized width/sidebearing command */
4230 		if ( sp<4 ) LogError( _("Stack underflow on sbw in %s\n"), name );
4231 		ret->lsidebearing = stack[0];
4232 		/* stack[1] is lsidebearing y (only for vertical writing styles, CJK) */
4233 		ret->width = stack[2];
4234 		/* stack[3] is height (for vertical writing styles, CJK) */
4235 		sp = 0;
4236 		break;
4237 	    case 5: case 9: case 14: case 26:
4238 		if ( sp<1 ) LogError( _("Stack underflow on unary operator in %s\n"), name );
4239 		switch ( v ) {
4240 		case 5: stack[sp-1] = (stack[sp-1]==0); break;	/* not */
4241 		case 9: if ( stack[sp-1]<0 ) stack[sp-1]= -stack[sp-1]; break;	/* abs */
4242 		case 14: stack[sp-1] = -stack[sp-1]; break;		/* neg */
4243 		case 26: stack[sp-1] = sqrt(stack[sp-1]); break;	/* sqrt */
4244 		}
4245 		break;
4246 	    case 3: case 4: case 10: case 11: case 12: case 15: case 24:
4247 		if ( sp<2 ) LogError( _("Stack underflow on binary operator in %s\n"), name );
4248 		else switch ( v ) {
4249 		case 3: /* and */
4250 		    stack[sp-2] = (stack[sp-1]!=0 && stack[sp-2]!=0);
4251 		    break;
4252 		case 4: /* and */
4253 		    stack[sp-2] = (stack[sp-1]!=0 || stack[sp-2]!=0);
4254 		    break;
4255 		case 10: /* add */
4256 		    stack[sp-2] += stack[sp-1];
4257 		    break;
4258 		case 11: /* sub */
4259 		    stack[sp-2] -= stack[sp-1];
4260 		    break;
4261 		case 12: /* div */
4262 		    stack[sp-2] /= stack[sp-1];
4263 		    break;
4264 		case 24: /* mul */
4265 		    stack[sp-2] *= stack[sp-1];
4266 		    break;
4267 		case 15: /* eq */
4268 		    stack[sp-2] = (stack[sp-1]==stack[sp-2]);
4269 		    break;
4270 		}
4271 		--sp;
4272 		break;
4273 	    case 22: /* ifelse */
4274 		if ( sp<4 ) LogError( _("Stack underflow on ifelse in %s\n"), name );
4275 		else {
4276 		    if ( stack[sp-2]>stack[sp-1] )
4277 			stack[sp-4] = stack[sp-3];
4278 		    sp -= 3;
4279 		}
4280 		break;
4281 	    case 23: /* random */
4282 		/* This function returns something (0,1]. It's not clear to me*/
4283 		/*  if rand includes 0 and RAND_MAX or not, but this approach */
4284 		/*  should work no matter what */
4285 		do {
4286 		    stack[sp] = (rand()/(RAND_MAX-1));
4287 		} while ( stack[sp]==0 || stack[sp]>1 );
4288 		++sp;
4289 		break;
4290 	    case 20: /* put */
4291 		if ( sp<2 ) LogError( _("Too few items on stack for put in %s\n"), name );
4292 		else if ( stack[sp-1]<0 || stack[sp-1]>=32 ) LogError( _("Reference to transient memory out of bounds in put in %s\n"), name );
4293 		else {
4294 		    transient[(int)stack[sp-1]] = stack[sp-2];
4295 		    sp -= 2;
4296 		}
4297 		break;
4298 	    case 21: /* get */
4299 		if ( sp<1 ) LogError( _("Too few items on stack for get in %s\n"), name );
4300 		else if ( stack[sp-1]<0 || stack[sp-1]>=32 ) LogError( _("Reference to transient memory out of bounds in put in %s\n"), name );
4301 		else
4302 		    stack[sp-1] = transient[(int)stack[sp-1]];
4303 		break;
4304 	    case 17: /* pop */
4305 		/* pops something from the postscript stack and pushes it on ours */
4306 		/* used to get a return value from an othersubr call */
4307 		/* Bleah. Adobe wants the pops to return the arguments if we */
4308 		/*  don't understand the call. What use is the subroutine then?*/
4309 		if ( popsp<=0 )
4310 		    LogError( _("Pop stack underflow on pop in %s\n"), name );
4311 		else
4312 		    stack[sp++] = pops[--popsp];
4313 		break;
4314 	    case 18: /* drop */
4315 		if ( sp>0 ) --sp;
4316 		break;
4317 	    case 27: /* dup */
4318 		if ( sp>=1 ) {
4319 		    stack[sp] = stack[sp-1];
4320 		    ++sp;
4321 		}
4322 		break;
4323 	    case 28: /* exch */
4324 		if ( sp>=2 ) {
4325 		    real temp = stack[sp-1];
4326 		    stack[sp-1] = stack[sp-2]; stack[sp-2] = temp;
4327 		}
4328 		break;
4329 	    case 29: /* index */
4330 		if ( sp>=1 ) {
4331 		    int index = stack[--sp];
4332 		    if ( index<0 || sp<index+1 )
4333 			LogError( _("Index out of range in %s\n"), name );
4334 		    else {
4335 			stack[sp] = stack[sp-index-1];
4336 			++sp;
4337 		    }
4338 		}
4339 		break;
4340 	    case 30: /* roll */
4341 		if ( sp>=2 ) {
4342 		    int j = stack[sp-1], N=stack[sp-2];
4343 		    if ( N>sp || j>=N || j<0 || N<0 )
4344 			LogError( _("roll out of range in %s\n"), name );
4345 		    else if ( j==0 || N==0 )
4346 			/* No op */;
4347 		    else {
4348 			real *temp = galloc(N*sizeof(real));
4349 			int i;
4350 			for ( i=0; i<N; ++i )
4351 			    temp[i] = stack[sp-N+i];
4352 			for ( i=0; i<N; ++i )
4353 			    stack[sp-N+i] = temp[(i+j)%N];
4354 			free(temp);
4355 		    }
4356 		}
4357 		break;
4358 	    case 33: /* setcurrentpoint */
4359 		if ( sp<2 ) LogError( _("Stack underflow on setcurrentpoint in %s\n"), name );
4360 		else {
4361 		    current.x = stack[0];
4362 		    current.y = stack[1];
4363 		    if (ll.y>current.y) ll.y = current.y;
4364 		    if (ur.y<current.y) ur.y = current.y;
4365 		    if (ll.x>current.x) ll.x = current.x;
4366 		    if (ur.x<current.x) ur.x = current.x;
4367 		}
4368 		sp = 0;
4369 		break;
4370 	    case 34:	/* hflex */
4371 	    case 35:	/* flex */
4372 	    case 36:	/* hflex1 */
4373 	    case 37:	/* flex1 */
4374 		dy = dy3 = dy4 = dy5 = dy6 = 0;
4375 		dx = stack[base++];
4376 		if ( v!=34 )
4377 		    dy = stack[base++];
4378 		dx2 = stack[base++];
4379 		dy2 = stack[base++];
4380 		dx3 = stack[base++];
4381 		if ( v!=34 && v!=36 )
4382 		    dy3 = stack[base++];
4383 		dx4 = stack[base++];
4384 		if ( v!=34 && v!=36 )
4385 		    dy4 = stack[base++];
4386 		dx5 = stack[base++];
4387 		if ( v==34 )
4388 		    dy5 = -dy2;
4389 		else
4390 		    dy5 = stack[base++];
4391 		switch ( v ) {
4392 		    real xt, yt;
4393 		case 35:    /* flex */
4394 		    dx6 = stack[base++];
4395 		    dy6 = stack[base++];
4396 		    break;
4397 		case 34:    /* hflex */
4398 		    dx6 = stack[base++];
4399 		    break;
4400 		case 36:    /* hflex1 */
4401 		    dx6 = stack[base++];
4402 		    dy6 = -dy-dy2-dy5;
4403 		    break;
4404 		case 37:    /* flex1 */
4405 		    xt = dx+dx2+dx3+dx4+dx5;
4406 		    yt = dy+dy2+dy3+dy4+dy5;
4407 		    if ( xt<0 ) xt= -xt;
4408 		    if ( yt<0 ) yt= -yt;
4409 		    if ( xt>yt ) {
4410 			dx6 = stack[base++];
4411 			dy6 = -dy-dy2-dy3-dy4-dy5;
4412 		    } else {
4413 			dy6 = stack[base++];
4414 			dx6 = -dx-dx2-dx3-dx4-dx5;
4415 		    }
4416 		    break;
4417 		}
4418 		current.x = current.x+dx; current.y = current.y+dy;
4419 		if (ll.y>current.y) ll.y = current.y;
4420 		if (ur.y<current.y) ur.y = current.y;
4421 		if (ll.x>current.x) ll.x = current.x;
4422 		if (ur.x<current.x) ur.x = current.x;
4423 		current.x = current.x+dx2; current.y = current.y+dy2;
4424 		if (ll.y>current.y) ll.y = current.y;
4425 		if (ur.y<current.y) ur.y = current.y;
4426 		if (ll.x>current.x) ll.x = current.x;
4427 		if (ur.x<current.x) ur.x = current.x;
4428 		current.x = current.x+dx3; current.y = current.y+dy3;
4429 		if (ll.y>current.y) ll.y = current.y;
4430 		if (ur.y<current.y) ur.y = current.y;
4431 		if (ll.x>current.x) ll.x = current.x;
4432 		if (ur.x<current.x) ur.x = current.x;
4433 
4434 		current.x = current.x+dx4; current.y = current.y+dy4;
4435 		if (ll.y>current.y) ll.y = current.y;
4436 		if (ur.y<current.y) ur.y = current.y;
4437 		if (ll.x>current.x) ll.x = current.x;
4438 		if (ur.x<current.x) ur.x = current.x;
4439 		current.x = current.x+dx5; current.y = current.y+dy5;
4440 		if (ll.y>current.y) ll.y = current.y;
4441 		if (ur.y<current.y) ur.y = current.y;
4442 		if (ll.x>current.x) ll.x = current.x;
4443 		if (ur.x<current.x) ur.x = current.x;
4444 		current.x = current.x+dx6; current.y = current.y+dy6;
4445 		if (ll.y>current.y) ll.y = current.y;
4446 		if (ur.y<current.y) ur.y = current.y;
4447 		if (ll.x>current.x) ll.x = current.x;
4448 		if (ur.x<current.x) ur.x = current.x;
4449 		sp = 0;
4450 		break;
4451 	    default:
4452 		LogError( _("Uninterpreted opcode 12,%d in %s\n"), v, name );
4453 		break;
4454 	    }
4455 	} else { last_was_b1 = false; switch ( v ) {
4456 		 case 1: /* hstem */
4457 		 case 18: /* hstemhm */
4458 		     base = 0;
4459 		     if ( (sp&1) && ret->width == (int16) 0x8000 )
4460 			 ret->width = stack[0];
4461 		     if ( sp&1 )
4462 			 base=1;
4463 		     if ( sp-base<2 )
4464 			 LogError( _("Stack underflow on hstem in %s\n"), name );
4465 		     /* stack[0] is absolute y for start of horizontal hint */
4466 		     /*	(actually relative to the y specified as lsidebearing y in sbw*/
4467 		     /* stack[1] is relative y for height of hint zone */
4468 
4469 
4470 		     while ( sp-base>=2 ) {
4471 			 hint_cnt++;
4472 			 base+=2;
4473 		     }
4474 		     sp = 0;
4475 		     break;
4476 		 case 19: /* hintmask */
4477 		 case 20: /* cntrmask */
4478 		     /* If there's anything on the stack treat it as a vstem hint */
4479 		 case 3: /* vstem */
4480 		 case 23: /* vstemhm */
4481 		     base = 0;
4482 		     if ( first || v==3 || v==23 ) {
4483 			 if ( (sp&1) && ret->width == (int16) 0x8000 ) {
4484 			     ret->width = stack[0];
4485 			 }
4486 			 if ( sp&1 )
4487 			     base=1;
4488 			 if ( sp-base<2 && v!=19 && v!=20 )
4489 			     LogError( _("Stack underflow on vstem in %s\n"), name );
4490 			 /* stack[0] is absolute x for start of vertical hint */
4491 			 /*	(actually relative to the x specified as lsidebearing in h/sbw*/
4492 			 /* stack[1] is relative x for height of hint zone */
4493 
4494 
4495 			 while ( sp-base>=2 ) {
4496 			     hint_cnt++;
4497 			     base+=2;
4498 			 }
4499 			 sp = 0;
4500 		     }
4501 		     if ( v==19 || v==20 ) {		/* hintmask, cntrmask */
4502 			 unsigned bytes = (hint_cnt+7)/8;
4503 			 if ( bytes>sizeof(HintMask) ) bytes = sizeof(HintMask);
4504 			 if ( bytes!=(unsigned)hint_cnt/8 ) {
4505 			     int mask = 0xff>>(hint_cnt&7);
4506 			     if ( type1[bytes-1]&mask )
4507 				 LogError( _("Hint mask (or counter mask) with too many hints in %s\n"), name );
4508 			 }
4509 			 type1 += bytes;
4510 			 len -= bytes;
4511 		     }
4512 		     break;
4513 		 case 14: /* endchar */
4514 		     /* endchar is allowed to terminate processing even within a subroutine */
4515 		     if ( (sp&1) && ret->width == (int16) 0x8000 )
4516 			 ret->width = stack[0];
4517 		     pcsp = 0;
4518 		     if ( sp==4 ) {
4519 			 /* In Type2 strings endchar has a depreciated function of doing */
4520 			 /*  a seac (which doesn't exist at all). Except enchar takes */
4521 			 /*  4 args and seac takes 5. Bleah */
4522 			 stack[4] = stack[3]; stack[3] = stack[2]; stack[2] = stack[1]; stack[1] = stack[0];
4523 			 stack[0] = 0;
4524 			 sp = 5;
4525 			 goto seac;
4526 		     } else if ( sp==5 ) {
4527 			 /* same as above except also specified a width */
4528 			 stack[0] = 0;
4529 			 goto seac;
4530 		     }
4531 		     /* the docs say that endchar must be the last command in a char */
4532 		     goto done;
4533 		     break;
4534 		 case 13: /* hsbw (set left sidebearing and width) */
4535 		     if ( sp<2 ) LogError( _("Stack underflow on hsbw in %s\n"), name );
4536 		     ret->lsidebearing = stack[0];
4537 		     current.x = stack[0];		/* sets the current point too */
4538 		     if (ll.x>current.x) ll.x = current.x;
4539 		     if (ur.x<current.x) ur.x = current.x;
4540 		     ret->width = stack[1];
4541 		     sp = 0;
4542 		     break;
4543 		 case 9: /* closepath */
4544 		     sp = 0;
4545 		     break;
4546 		 case 21: /* rmoveto */
4547 		 case 22: /* hmoveto */
4548 		 case 4: /* vmoveto */
4549 			 if (( (v==21 && sp==3) || (v!=21 && sp==2))  && ret->width == (int16) 0x8000 )
4550 			     /* Character's width may be specified on the first moveto */
4551 			     ret->width = stack[0];
4552 			 if ( v==21 && sp>2 ) {
4553 			     stack[0] = stack[sp-2]; stack[1] = stack[sp-1];
4554 			     sp = 2;
4555 			 } else if ( v!=21 && sp>1 ) {
4556 			     stack[0] = stack[sp-1];
4557 			     sp = 1;
4558 			 }
4559 			 /* fall through */
4560 		 case 5: /* rlineto */
4561 		 case 6: /* hlineto */
4562 		 case 7: /* vlineto */
4563 		     polarity = 0;
4564 		     base = 0;
4565 		     while ( base<sp ) {
4566 			 dx = dy = 0;
4567 			 if ( v==5 || v==21 ) {
4568 			     if ( sp<base+2 ) {
4569 				 LogError( _("Stack underflow on rlineto/rmoveto in %s\n"), name );
4570 				 break;
4571 			     }
4572 			     dx = stack[base++];
4573 			     dy = stack[base++];
4574 			 } else if ( (v==6 && !(polarity&1)) || (v==7 && (polarity&1)) || v==22 ) {
4575 			     if ( sp<=base ) {
4576 				 LogError( _("Stack underflow on hlineto/hmoveto in %s\n"), name );
4577 				 break;
4578 			     }
4579 			     dx = stack[base++];
4580 			 } else /*if ( (v==7 && !(parity&1)) || (v==6 && (parity&1) || v==4 )*/ {
4581 			     if ( sp<=base ) {
4582 				 LogError( _("Stack underflow on vlineto/vmoveto in %s\n"), name );
4583 				 break;
4584 			     }
4585 			     dy = stack[base++];
4586 			 }
4587 			 ++polarity;
4588 			 current.x = current.x+dx; current.y = current.y+dy;
4589 			 if (ll.y>current.y) ll.y = current.y;
4590 			 if (ur.y<current.y) ur.y = current.y;
4591 			 if (ll.x>current.x) ll.x = current.x;
4592 			 if (ur.x<current.x) ur.x = current.x;
4593 			 if ( v==4 || v==21 || v==22 ) {
4594 			     first = 0;
4595 			     break;
4596 			 } else {
4597 			     first = 0;
4598 			 }
4599 		     }
4600 		     sp = 0;
4601 		     break;
4602 		 case 25: /* rlinecurve */
4603 		     base = 0;
4604 		     while ( sp>base+6 ) {
4605 			 current.x = current.x+stack[base++]; current.y = current.y+stack[base++];
4606 			 if (ll.y>current.y) ll.y = current.y;
4607 			 if (ur.y<current.y) ur.y = current.y;
4608 			 if (ll.x>current.x) ll.x = current.x;
4609 			 if (ur.x<current.x) ur.x = current.x;
4610 			 first = 0;
4611 		     }
4612 		 case 24: /* rcurveline */
4613 		 case 8:  /* rrcurveto */
4614 		 case 31: /* hvcurveto */
4615 		 case 30: /* vhcurveto */
4616 		 case 27: /* hhcurveto */
4617 		 case 26: /* vvcurveto */
4618 		     polarity = 0;
4619 		     while ( sp>base+2 ) {
4620 			 dx = dy = dx2 = dy2 = dx3 = dy3 = 0;
4621 			 if ( v==8 || v==25 || v==24 ) {
4622 			     if ( sp<6+base ) {
4623 				 LogError( _("Stack underflow on rrcurveto in %s\n"), name );
4624 				 base = sp;
4625 			     } else {
4626 				 dx = stack[base++];
4627 				 dy = stack[base++];
4628 				 dx2 = stack[base++];
4629 				 dy2 = stack[base++];
4630 				 dx3 = stack[base++];
4631 				 dy3 = stack[base++];
4632 			     }
4633 			 } else if ( v==27 ) {		/* hhcurveto */
4634 			     if ( sp<4+base ) {
4635 				 LogError( _("Stack underflow on hhcurveto in %s\n"), name );
4636 				 base = sp;
4637 			     } else {
4638 				 if ( (sp-base)&1 ) dy = stack[base++];
4639 				 dx = stack[base++];
4640 				 dx2 = stack[base++];
4641 				 dy2 = stack[base++];
4642 				 dx3 = stack[base++];
4643 			     }
4644 			 } else if ( v==26 ) {		/* vvcurveto */
4645 			     if ( sp<4+base ) {
4646 				 LogError( _("Stack underflow on hhcurveto in %s\n"), name );
4647 				 base = sp;
4648 			     } else {
4649 				 if ( (sp-base)&1 ) dx = stack[base++];
4650 				 dy = stack[base++];
4651 				 dx2 = stack[base++];
4652 				 dy2 = stack[base++];
4653 				 dy3 = stack[base++];
4654 			     }
4655 			 } else if ( (v==31 && !(polarity&1)) || (v==30 && (polarity&1)) ) {
4656 			     if ( sp<4+base ) {
4657 				 LogError( _("Stack underflow on hvcurveto in %s\n"), name );
4658 				 base = sp;
4659 			     } else {
4660 				 dx = stack[base++];
4661 				 dx2 = stack[base++];
4662 				 dy2 = stack[base++];
4663 				 dy3 = stack[base++];
4664 				 if ( sp==base+1 )
4665 				     dx3 = stack[base++];
4666 			     }
4667 			 } else /*if ( (v==30 && !(polarity&1)) || (v==31 && (polarity&1)) )*/ {
4668 			     if ( sp<4+base ) {
4669 				 LogError( _("Stack underflow on vhcurveto in %s\n"), name );
4670 				 base = sp;
4671 			     } else {
4672 				 dy = stack[base++];
4673 				 dx2 = stack[base++];
4674 				 dy2 = stack[base++];
4675 				 dx3 = stack[base++];
4676 				 if ( sp==base+1 )
4677 				     dy3 = stack[base++];
4678 			     }
4679 			 }
4680 			 ++polarity;
4681 			 current.x = current.x+dx; current.y = current.y+dy;
4682 			 if (ll.y>current.y) ll.y = current.y;
4683 			 if (ur.y<current.y) ur.y = current.y;
4684 			 if (ll.x>current.x) ll.x = current.x;
4685 			 if (ur.x<current.x) ur.x = current.x;
4686 			 current.x = current.x+dx2; current.y = current.y+dy2;
4687 			 if (ll.y>current.y) ll.y = current.y;
4688 			 if (ur.y<current.y) ur.y = current.y;
4689 			 if (ll.x>current.x) ll.x = current.x;
4690 			 if (ur.x<current.x) ur.x = current.x;
4691 			 current.x = current.x+dx3; current.y = current.y+dy3;
4692 			 if (ll.y>current.y) ll.y = current.y;
4693 			 if (ur.y<current.y) ur.y = current.y;
4694 			 if (ll.x>current.x) ll.x = current.x;
4695 			 if (ur.x<current.x) ur.x = current.x;
4696 		     }
4697 		     if ( v==24 ) {
4698 			 current.x = current.x+stack[base++]; current.y = current.y+stack[base++];
4699 			 if (ll.y>current.y) ll.y = current.y;
4700 			 if (ur.y<current.y) ur.y = current.y;
4701 			 if (ll.x>current.x) ll.x = current.x;
4702 			 if (ur.x<current.x) ur.x = current.x;
4703 		     }
4704 		     sp = 0;
4705 		     break;
4706 		 case 29: /* callgsubr */
4707 		 case 10: /* callsubr */
4708 		     /* stack[sp-1] contains the number of the subroutine to call */
4709 		     if ( sp<1 ) {
4710 			 LogError( _("Stack underflow on callsubr in %s\n"), name );
4711 			 break;
4712 		     } else if ( pcsp>10 ) {
4713 			 LogError( _("Too many subroutine calls in %s\n"), name );
4714 			 break;
4715 		     }
4716 		     s=subrs; if ( v==29 ) s = gsubrs;
4717 		     if ( s!=NULL ) stack[sp-1] += s->bias;
4718 		     /* Type2 subrs have a bias that must be added to the subr-number */
4719 		     /* Type1 subrs do not. We set the bias on them to 0 */
4720 		     if ( s==NULL || stack[sp-1]>=s->cnt || stack[sp-1]<0 ||
4721 			  s->values[(int) stack[sp-1]]==NULL )
4722 			 LogError( _("Subroutine number out of bounds in %s\n"), name );
4723 		     else {
4724 			 pcstack[pcsp].type1 = type1;
4725 			 pcstack[pcsp].len = len;
4726 			 pcstack[pcsp].subnum = stack[sp-1];
4727 			 ++pcsp;
4728 			 type1 = s->values[(int) stack[sp-1]];
4729 			 len = s->lens[(int) stack[sp-1]];
4730 		     }
4731 		     if ( --sp<0 ) sp = 0;
4732 		     break;
4733 		 case 11: /* return */
4734 		     /* return from a subr outine */
4735 		     if ( pcsp<1 ) LogError( _("return when not in subroutine in %s\n"), name );
4736 		     else {
4737 			 --pcsp;
4738 			 type1 = pcstack[pcsp].type1;
4739 			 len = pcstack[pcsp].len;
4740 		     }
4741 		     break;
4742 		 case 16: { /* blend -- obsolete type 2 multiple master operator */
4743 		     int cnt,i,j;
4744 		     if ( context->instance_count==0 )
4745 			 LogError( _("Attempt to use a multiple master subroutine in a non-mm font.\n") );
4746 		     else if ( sp<1 || sp<context->instance_count*stack[sp-1]+1 )
4747 			 LogError( _("Too few items on stack for blend in %s\n"), name );
4748 		     else {
4749 			 if ( !context->blend_warn ) {
4750 			     LogError( _("Use of obsolete blend operator.\n") );
4751 			     context->blend_warn = true;
4752 			 }
4753 			 cnt = stack[sp-1];
4754 			 sp -= context->instance_count*stack[sp-1]+1;
4755 			 for ( i=0; i<cnt; ++i ) {
4756 			     for ( j=1; j<context->instance_count; ++j )
4757 				 stack[sp+i] += context->blend_values[j]*stack[sp+
4758 									       cnt+ i*(context->instance_count-1)+ j-1];
4759 			 }
4760 			 /* there will always be fewer pushes than there were pops */
4761 			 /*  so I don't bother to check the stack */
4762 			 sp += cnt;
4763 		     }
4764 		 }
4765 		     break;
4766 		 default:
4767 		     LogError( _("Uninterpreted opcode %d in %s\n"), v, name );
4768 		     break;
4769 		 }}
4770     }
4771 done:
4772     if ( pcsp!=0 )
4773 	LogError( _("end of subroutine reached with no return in %s\n"), name );
4774 
4775     if ( name!=NULL && strcmp(name,".notdef")!=0 )
4776 	ret->widthset = true;
4777     if (ur.x == -0x7FFF) ur.x = 0;
4778     if (ur.y == -0x7FFF) ur.y = 0;
4779     if (ll.x == 0x7FFF) ll.x = 0;
4780     if (ll.y == 0x7FFF) ll.y = 0;
4781     if (ll.x>ur.x) ll.x = ur.x;
4782     if (ll.y>ur.y) ll.y = ur.y;
4783 
4784 
4785     ret->xmin = rint(ll.x);
4786     ret->ymin = rint(ll.y);
4787     ret->xmax = rint(ur.x);
4788     ret->ymax = rint(ur.y);
4789     /* free the curves */
4790     if (ret->layers!=NULL && ret->layers[ly_fore].splines != NULL) {
4791 	SplinePointListsFree(ret->layers[ly_fore].splines);
4792 	ret->layers[ly_fore].splines=NULL;
4793     }
4794     if (ret->layers[ly_fore].refs!=NULL) {
4795 	RefCharsFree(ret->layers[ly_fore].refs);
4796 	ret->layers[ly_fore].refs = NULL;
4797     }
4798     return( ret );
4799 }
4800