beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luafontloader / fontforge / fontforge / psread.c
blobb54cbac638d9e7e400c57e3676bff288860916b2
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:
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
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.
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.
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.
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
38 int THdo_hint_guessing = 0;
39 int THdo_set_reversing = 0;
40 int THdo_catagorize = 0;
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;
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;
56 typedef struct growbuf {
57 char *pt;
58 char *base;
59 char *end;
60 } GrowBuf;
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];
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;
84 static void AddTok(GrowBuf *gb,char *buf,int islit) {
85 int len = islit + strlen(buf) + 1;
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++ = ' ';
96 static struct pskeyval *lookup(struct pskeydict *dict,char *tokbuf) {
97 int i;
99 for ( i=0; i<dict->cnt; ++i )
100 if ( strcmp(dict->entries[i].key,tokbuf)==0 )
101 return( &dict->entries[i] );
103 return( NULL );
106 static void dictfree(struct pskeydict *dict) {
107 int i;
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);
118 static void garbagefree(struct garbage *all) {
119 struct garbage *junk, *next;
120 int i,j;
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);
130 free(junk->entries[j]);
132 if ( junk!=all )
133 chunkfree(junk,sizeof(struct garbage));
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 */
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,
163 pt_imagemask,
165 pt_transform, pt_itransform, pt_dtransform, pt_idtransform,
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,
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,
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,
184 pt_opencurly, pt_closecurly, pt_openarray, pt_closearray, pt_string,
185 pt_number, pt_unknown, pt_namelit, pt_output, pt_outputd };
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",
208 "imagemask",
210 "transform", "itransform", "dtransform", "idtransform",
212 "gsave", "grestore", "save", "restore", "currentmatrix", "setmatrix",
213 "null",
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",
225 "mark", "counttomark", "cleartomark", "array", "aload", "astore",
226 "print", "cvi", "cvlit", "cvn", "cvr", "cvrs", "cvs", "cvx", "string",
228 "opencurly", "closecurly", "openarray", "closearray", "string",
229 "number", "unknown", "namelit", "=", "==",
231 NULL };
233 /* length (of string)
234 fill eofill stroke
235 gsave grestore
238 static int getfoghex(_IO *io) {
239 int ch,val;
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);
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);
262 return( val );
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 " };
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++) );
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));
309 wrapper->top = io->prev;
310 if ( io->isstopped )
311 wrapper->endedstopped = true;
312 free(io->start);
313 free(io);
314 io = wrapper->top;
316 return( EOF );
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;
332 static void pushio(IO *wrapper, FILE *ps, char *macro, int cnt) {
333 _IO *io = gcalloc(1,sizeof(_IO));
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;
349 wrapper->top = io;
352 static void pushfogio(IO *wrapper, FILE *fog) {
353 _IO *io = gcalloc(1,sizeof(_IO));
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;
363 static void ioescapeloop(IO *wrapper) {
364 _IO *io = wrapper->top, *iop;
365 int wasloop;
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;
376 io = iop;
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;
387 static int ioescapestopped(IO *wrapper, struct psstack *stack, int sp, const size_t bsize) {
388 _IO *io = wrapper->top, *iop;
389 int wasstopped;
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;
402 return(sp);
404 io = iop;
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 );
414 static int endedstopped(IO *wrapper) {
415 if ( wrapper->endedstopped ) {
416 wrapper->endedstopped = false;
417 return( true );
419 return( false );
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;
428 pt = tokbuf;
429 end = pt+tbsize-1;
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;
448 if ( ch==EOF )
449 return( pt_eof );
451 pt = tokbuf;
452 end = pt+tbsize-1;
453 *pt++ = ch; *pt='\0';
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;
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;
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 );
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;
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 );
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;
540 if ( *end=='\0' ) /* It's a real */
541 return( pt_number );
543 /* It's not a number */
544 for ( i=0; toknames[i]!=NULL; ++i )
545 if ( strcmp(tokbuf,toknames[i])==0 )
546 return( i );
548 return( pt_unknown );
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];
557 void MatMultiply(real m1[6], real m2[6], real to[6]) {
558 real trans[6];
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));
577 void MatInverse(real into[6], real orig[6]) {
578 real det = orig[0]*orig[3] - orig[1]*orig[2];
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];
593 static void ECCatagorizePoints( EntityChar *ec ) {
594 Entity *ent;
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 );
602 static int AddEntry(struct pskeydict *dict,struct psstack *stack, int sp) {
603 int i;
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));
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);
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;
635 dict->entries[i].type = stack[sp-1].type;
636 dict->entries[i].u = stack[sp-1].u;
637 return(sp-2);
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);
652 for ( i=forgets; i<sp; ++i )
653 stack[i-forgets] = stack[i];
654 return( sp-forgets );
657 static int rollstack(struct psstack *stack, int sp) {
658 int n,j,i;
659 struct psstack *temp;
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);
676 return( sp );
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;
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;
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);
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;
711 if ( a1==a2 )
712 return;
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;
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;
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;
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;
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;
761 circlearcto(last,a2,cx,cy,r,cur,transform);
765 static void collectgarbage(struct garbage *tofrees,struct pskeydict *to) {
766 struct garbage *into;
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;
777 into->cnts[ into->cnt ] = to->cnt;
778 into->entries[ into->cnt++ ] = to->entries;
781 static void copyarray(struct pskeydict *to,struct pskeydict *from, struct garbage *tofrees) {
782 int i;
783 struct pskeyval *oldent = from->entries;
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);
795 collectgarbage(tofrees,to);
798 static int aload(int sp, struct psstack *stack,int stacktop, struct garbage *tofrees) {
799 int i;
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;
819 if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
820 stack[sp].type = ps_array;
821 stack[sp].u.dict = dict;
822 ++sp;
825 return( sp );
828 static void printarray(struct pskeydict *dict) {
829 int i;
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;
857 printf(" ");
859 printf( "]" );
862 static void freestuff(struct psstack *stack, int sp, struct pskeydict *dict,
863 GrowBuf *gb, struct garbage *tofrees) {
864 int i;
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);
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
883 garbagefree(tofrees);
886 static void DoMatTransform(int tok,int sp,struct psstack *stack) {
887 real invt[6], t[6];
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));
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];
912 static int DoMatOp(int tok,int sp,struct psstack *stack) {
913 real temp[6], t[6];
914 int nsp=sp;
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;
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;
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;
957 break;
959 stack[nsp-1] = stack[sp-1];
961 return(nsp);
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 );
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;
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 */
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;
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;
1047 oldloc = setlocale(LC_NUMERIC,"C");
1049 memset(&gb,'\0',sizeof(GrowBuf));
1050 memset(&dict,'\0',sizeof(dict));
1051 tofrees.cnt = 0; tofrees.next = NULL;
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;
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;
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;
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 );
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);
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);
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;
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;
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;
1168 ref->orig_pos = stack[--sp].u.val;
1169 ref->next = ec->refs;
1170 ec->refs = ref;
1171 continue;
1173 } else if ( strcmp(tokbuf,"togNS_")==0 ) {
1174 wrapper->top->fogns = !wrapper->top->fogns;
1175 continue;
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;
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);
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;
1196 break;
1197 case pt_opencurly:
1198 ++ccnt;
1199 break;
1200 case pt_closecurly:
1201 --ccnt;
1202 if ( ccnt<0 ) {
1203 goto done;
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;
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);
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);
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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 */
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);
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);
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);
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;
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;
1432 stack[sp-2].type = ps_bool;
1433 --sp;
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;
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;
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;
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;
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;
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);
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);
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);
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;
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);
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);
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;
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);
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;
1542 break;
1543 case pt_for:
1544 if ( sp>=4 ) {
1545 real init, incr, limit;
1546 char *func;
1547 int cnt;
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; }
1562 pushio(wrapper,NULL,func,cnt);
1563 free(func);
1566 break;
1567 case pt_loop:
1568 if ( sp>=1 ) {
1569 char *func;
1570 int cnt;
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);
1580 break;
1581 case pt_repeat:
1582 if ( sp>=2 ) {
1583 char *func;
1584 int cnt;
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);
1594 break;
1595 case pt_exit:
1596 ioescapeloop(wrapper);
1597 break;
1598 case pt_stopped:
1599 if ( sp>=1 ) {
1600 char *func;
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);
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;
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;
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;
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;
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);
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);
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;
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];
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;
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];
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;
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;
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;
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;
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);
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;
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;
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;
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;
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;
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;
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;
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;
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;
1927 a1 = 3*3.1415926535897932/2+a1;
1928 a2 = 3.1415926535897932/2+a2;
1929 if ( !clockwise ) {
1930 a1 += 3.1415926535897932;
1931 a2 += 3.1415926535897932;
1933 circlearcsto(a1*180/3.1415926535897932,a2*180/3.1415926535897932,
1934 cx,cy,r,cur,transform,clockwise);
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;
1943 current.x = xt2; current.y = yt2;
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);
1959 CheckMake(cur->last,cur->first);
1960 SplineMake3(cur->last,cur->first);
1961 cur->last = cur->first;
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);
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;
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;
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];
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;
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.;
2019 break;
2020 case pt_setgray:
2021 if ( sp>=1 ) {
2022 fore = stack[--sp].u.val*255;
2023 fore *= 0x010101;
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;
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;
2065 stack[sp++].u.val = h;
2066 stack[sp++].u.val = s;
2067 stack[sp++].u.val = b;
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;
2101 fore = COLOR_CREATE(r,g,bl);
2103 sp -= 3;
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;
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.));
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;
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));
2159 } else {
2160 ent = EntityCreate(head,linecap,linejoin,linewidth,transform,clippath);
2161 ent->next = ec->splines;
2162 ec->splines = ent;
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;
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;
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;
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 */
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
2322 break;
2323 case pt_setglobal:
2324 /* pop one item on stack */
2325 if ( sp>=1 )
2326 --sp;
2327 break;
2329 case pt_openarray: case pt_mark:
2330 if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2331 stack[sp++].type = ps_mark;
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;
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);
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) */
2379 collectgarbage(&tofrees,&dict);
2380 sp = sp-i;
2381 stack[sp-1].type = ps_array;
2382 stack[sp-1].u.dict = dict;
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;
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;
2411 stack[sp].type = ps_array;
2412 stack[sp].u.dict = dict;
2413 ++sp;
2415 break;
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;
2451 if ( tok==pt_output || tok==pt_outputd )
2452 printf( "\n" );
2453 } else
2454 LogError( _("Nothing on stack to print\n") );
2455 break;
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;
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;
2471 case pt_cvn:
2472 if ( sp>=1 ) {
2473 if ( stack[sp-1].type==ps_string )
2474 stack[sp-1].type = ps_lit;
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;
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;
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;
2518 stack[sp-2] = stack[sp-1];
2519 --sp;
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);
2527 break;
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;
2534 break;
2536 default:
2537 break;
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;
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;
2558 while ( gsp>0 ) {
2559 --gsp;
2560 SplinePointListsFree(gsaves[gsp].clippath);
2562 SplinePointListsFree(clippath);
2563 ECCatagorizePoints(ec);
2564 if ( ec->width == UNDEFINED_WIDTH )
2565 ec->width = wrapper->advance_width;
2566 setlocale(LC_NUMERIC,oldloc);
2569 static void InterpretPS(FILE *ps, char *psstr, EntityChar *ec, RetStack *rs) {
2570 IO wrapper;
2572 memset(&wrapper,0,sizeof(wrapper));
2573 wrapper.advance_width = UNDEFINED_WIDTH;
2574 pushio(&wrapper,ps,psstr,0);
2575 _InterpretPS(&wrapper,ec,rs);
2578 static SplinePointList *EraseStroke(SplineChar *sc,SplinePointList *head,SplinePointList *erase) {
2579 SplineSet *spl, *last;
2580 SplinePoint *sp;
2582 if ( head==NULL ) {
2583 /* Pointless, but legal */
2584 SplinePointListsFree(erase);
2585 return( NULL );
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;
2598 last = spl;
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;
2610 last->next = erase;
2611 return( SplineSetRemoveOverlap(sc,head,over_exclude) );
2614 static Entity *EntityReverse(Entity *ent) {
2615 Entity *next, *last = NULL;
2617 while ( ent!=NULL ) {
2618 next = ent->next;
2619 ent->next = last;
2620 last = ent;
2621 ent = next;
2623 return( last );
2626 void SFSplinesFromLayers(SplineFont *sf, int tostroke) {
2627 (void)sf;
2628 (void)tostroke;
2631 static void EntityCharCorrectDir(EntityChar *ec) {
2632 SplineSet *ss;
2633 Entity *ent;
2634 int changed;
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);
2648 SplineSetsCorrect(ent->clippath,&changed);
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;
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;
2673 ent = ent->next;
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;
2686 EntityDefaultStrokeFill(ec->splines);
2688 if ( !is_stroked ) {
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;
2700 if ( ask )
2701 *flags = PsStrokeFlagsDlg();
2704 if ( *flags & sf_correctdir ) /* Will happen if flags still unset (-1) */
2705 EntityCharCorrectDir(ec);
2707 handle_eraser = *flags!=-1 && (*flags & sf_handle_eraser);
2708 if ( handle_eraser )
2709 ec->splines = EntityReverse(ec->splines);
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 );
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 );
2770 if ( si.toobigwarn )
2771 *flags |= sf_toobigwarn;
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 );
2791 SplinePointListsFree(ent->clippath);
2792 free(ent);
2794 return( head );
2798 static RefChar *revrefs(RefChar *cur) {
2799 RefChar *p, *n;
2801 if ( cur==NULL )
2802 return( NULL );
2804 p = NULL;
2805 for ( ; (n=cur->next)!=NULL; cur = n ) {
2806 cur->next = p;
2807 p = cur;
2809 cur->next = p;
2810 return( cur );
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;
2820 while ( isspace(ch = getc(ps)) );
2821 ungetc(ch,ps);
2823 memset(&wrapper,0,sizeof(wrapper));
2824 wrapper.advance_width = UNDEFINED_WIDTH;
2825 if ( ch!='<' ) {
2826 pushio(&wrapper,ps,NULL,0);
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);
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);
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;
2853 wrapper.top = NULL;
2854 wrapper.advance_width = UNDEFINED_WIDTH;
2855 pushio(&wrapper,ps,NULL,0);
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 *));
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);
2878 free(wrapper.top);
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);
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));
2933 CheckMake(cur->last,cur->first);
2934 SplineMake3(cur->last,cur->first);
2935 cur->last = cur->first;
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;
2947 static StemInfo *HintsAppend(StemInfo *to,StemInfo *extra) {
2948 StemInfo *h;
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 );
2959 static StemInfo *HintNew(double start,double width) {
2960 StemInfo *h;
2962 h = chunkalloc(sizeof(StemInfo));
2963 h->start = start;
2964 h->width = width;
2965 return( h );
2968 static void RemapHintMask(HintMask *hm,int mapping[96],int max) {
2969 HintMask rpl;
2970 int i, mb;
2972 if ( hm==NULL )
2973 return;
2975 if ( max>96 ) max = 96;
2976 mb = (max+7)>>3;
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);
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;
2994 for ( i=0; i<96; ++i ) mapping[i] = i;
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++;
3002 chunkfree(h->u.unblended,sizeof(real [2][MmMax]));
3003 h->u.unblended = NULL;
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++;
3010 chunkfree(h->u.unblended,sizeof(real [2][MmMax]));
3011 h->u.unblended = NULL;
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 */
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;
3034 int UnblendedCompare(real u1[MmMax], real u2[MmMax], int cnt) {
3035 int i;
3037 for ( i=0; i<cnt; ++i ) {
3038 if ( u1[i]!=u2[i] )
3039 return( u1[i]>u2[i]?1:-1 );
3041 return( 0 );
3044 static StemInfo *SameH(StemInfo *old,real start, real width,
3045 real unblended[2][MmMax], int instance_count) {
3046 StemInfo *sameh;
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];
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;
3065 return( sameh );
3068 static real Blend(real u[MmMax],struct pscontext *context) {
3069 real sum = u[0];
3070 int i;
3072 for ( i=1; i<context->instance_count; ++i )
3073 sum += context->blend_values[i]*u[i];
3074 return( sum );
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 */
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;
3112 if ( !is_type2 && context->instance_count>1 )
3113 memset(unblended,0,sizeof(unblended));
3115 ret->name = copy( name );
3116 ret->unicodeenc = -1;
3117 ret->width = (int16) 0x8000;
3118 if ( name==NULL ) name = "unnamed";
3119 ret->manualhints = true;
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;
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
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;
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);
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;
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);
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;
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 */
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;
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;
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 );
3444 --popsp;
3445 cur->next = NULL;
3446 SplinePointListsFree(spl);
3447 oldcur = NULL;
3448 } else
3449 LogError( _("Bad flex subroutine in %s\n"), name );
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)];
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;
3495 } break;
3497 sp = k+1;
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;
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;
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;
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;
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);
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];
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;
3622 break;
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;
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;
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]));
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);
3697 base+=2;
3698 coord = hint->start+hint->width;
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];
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]));
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);
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;
3752 sp = 0;
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;
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 );
3773 type1 += bytes;
3774 len -= bytes;
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;
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;
3832 if ( context->painttype!=2 )
3833 closepath(cur,true);
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;
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;
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;
3860 dy = stack[base++];
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;
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;
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;
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++];
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++];
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++];
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++];
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++];
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 );
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;
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;
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]];
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;
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;
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];
4064 /* there will always be fewer pushes than there were pops */
4065 /* so I don't bother to check the stack */
4066 sp += cnt;
4069 break;
4070 default:
4071 LogError( _("Uninterpreted opcode %d in %s\n"), v, name );
4072 break;
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);
4081 ret->hstem = HintsAppend(ret->hstem,activeh); activeh=NULL;
4082 ret->vstem = HintsAppend(ret->vstem,activev); activev=NULL;
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));
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;
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);
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);
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);
4127 if ( name!=NULL && strcmp(name,".notdef")!=0 )
4128 ret->widthset = true;
4129 return( ret );
4133 /* This finds the 'connect-the-dots' boundingbox of a Type2 charstring */
4134 /* It is a simplified version of PSCharStringToSplines, above */
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);
4142 DBasePoint current, ll, ur;
4143 real dx, dy, dx2, dy2, dx3, dy3, dx4, dy4, dx5, dy5, dx6=0, dy6;
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;
4150 real pops[30];
4151 int popsp=0;
4152 int base, polarity;
4154 struct pschars *s;
4155 int hint_cnt = 0;
4157 int last_was_b1=false, old_last_was_b1;
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);
4169 current.x = current.y = 0;
4170 ll.x = ll.y = (int16) 0x7FFF;
4171 ur.x = ur.y = (int16) -0x7FFF;
4173 while ( len>0 ) {
4174 if ( sp>48 ) {
4175 LogError( _("Stack got too big in %s\n"), name );
4176 sp = 48;
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.;
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 */
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;
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;
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;
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;
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;
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;
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);
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;
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;
4416 break;
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;
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;
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 */
4470 while ( sp-base>=2 ) {
4471 hint_cnt++;
4472 base+=2;
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];
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 */
4495 while ( sp-base>=2 ) {
4496 hint_cnt++;
4497 base+=2;
4499 sp = 0;
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 );
4509 type1 += bytes;
4510 len -= bytes;
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;
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;
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;
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;
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;
4585 dy = stack[base++];
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;
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;
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++];
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++];
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++];
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++];
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++];
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;
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;
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;
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]];
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;
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;
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];
4760 /* there will always be fewer pushes than there were pops */
4761 /* so I don't bother to check the stack */
4762 sp += cnt;
4765 break;
4766 default:
4767 LogError( _("Uninterpreted opcode %d in %s\n"), v, name );
4768 break;
4771 done:
4772 if ( pcsp!=0 )
4773 LogError( _("end of subroutine reached with no return in %s\n"), name );
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;
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;
4794 if (ret->layers[ly_fore].refs!=NULL) {
4795 RefCharsFree(ret->layers[ly_fore].refs);
4796 ret->layers[ly_fore].refs = NULL;
4798 return( ret );