w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

psread.c
Go to the documentation of this file.
1 /* Copyright (C) 2000-2008 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include "pfaedit.h"
28 #include <math.h>
29 #include <locale.h>
30 #include <ustring.h>
31 #include <utype.h>
32 #include "psfont.h"
33 #include "sd.h"
34 #ifdef HAVE_IEEEFP_H
35 # include <ieeefp.h> /* Solaris defines isnan in ieeefp rather than math.h */
36 #endif
37 
41 
42 typedef struct _io {
43  char *macro, *start;
44  FILE *ps, *fog;
45  char fogbuf[60];
47  struct _io *prev;
48 } _IO;
49 
50 typedef struct io {
51  struct _io *top;
52  int endedstopped;
53  int advance_width; /* Can be set from a PS comment by MF2PT1 */
54 } IO;
55 
56 typedef struct growbuf {
57  char *pt;
58  char *base;
59  char *end;
61 
62 #define GARBAGE_MAX 64
63 struct garbage {
64  int cnt;
65  struct garbage *next;
68 };
69 
70 static void GrowBuffer(GrowBuf *gb,int len) {
71  if ( len<400 ) len = 400;
72  if ( gb->base==NULL ) {
73  gb->base = gb->pt = galloc(len);
74  gb->end = gb->base + len;
75  } else {
76  int off = gb->pt-gb->base;
77  len += (gb->end-gb->base);
78  gb->base = grealloc(gb->base,len);
79  gb->end = gb->base + len;
80  gb->pt = gb->base+off;
81  }
82 }
83 
84 static void AddTok(GrowBuf *gb,char *buf,int islit) {
85  int len = islit + strlen(buf) + 1;
86 
87  if ( gb->pt+len+1 >= gb->end )
88  GrowBuffer(gb,len+1);
89  if ( islit )
90  *(gb->pt++) = '/';
91  strcpy(gb->pt,buf);
92  gb->pt += strlen(buf);
93  *gb->pt++ = ' ';
94 }
95 
96 static struct pskeyval *lookup(struct pskeydict *dict,char *tokbuf) {
97  int i;
98 
99  for ( i=0; i<dict->cnt; ++i )
100  if ( strcmp(dict->entries[i].key,tokbuf)==0 )
101 return( &dict->entries[i] );
102 
103 return( NULL );
104 }
105 
106 static void dictfree(struct pskeydict *dict) {
107  int i;
108 
109  for ( i=0; i<dict->cnt; ++i ) {
110  if ( dict->entries[i].type==ps_string || dict->entries[i].type==ps_instr ||
111  dict->entries[i].type==ps_lit )
112  free(dict->entries[i].u.str);
113  else if ( dict->entries[i].type==ps_array || dict->entries[i].type==ps_dict )
114  dictfree(&dict->entries[i].u.dict);
115  }
116 }
117 
118 static void garbagefree(struct garbage *all) {
119  struct garbage *junk, *next;
120  int i,j;
121 
122  for ( junk = all; junk!=NULL; junk = next ) {
123  next = junk->next;
124  for ( j=0; j<junk->cnt; ++j ) {
125  for ( i=0; i<junk->cnts[j]; ++i ) {
126  if ( junk->entries[j][i].type==ps_string || junk->entries[j][i].type==ps_instr ||
127  junk->entries[j][i].type==ps_lit )
128  free(junk->entries[j][i].u.str);
129  }
130  free(junk->entries[j]);
131  }
132  if ( junk!=all )
133  chunkfree(junk,sizeof(struct garbage));
134  }
135 }
136 /**************************** Postscript Importer *****************************/
137 /* It's really dumb. It ignores almost everything except linetos and curvetos */
138 /* anything else, function calls, ... is thrown out, if this breaks a lineto */
139 /* or curveto or moveto (if there aren't enough things on the stack) then we */
140 /* ignore that too */
141 
162 
164 
166 
167  /* things we sort of pretend to do, but actually do something wrong */
170 
180 
183 
186 
187 static char *toknames[] = { "moveto", "rmoveto", "curveto", "rcurveto",
188  "lineto", "rlineto", "arc", "arcn", "arct", "arcto",
189  "newpath", "closepath", "dup", "pop", "index",
190  "exch", "roll", "clear", "copy", "count",
191  "setcachedevice", "setcharwidth",
192  "translate", "scale", "rotate", "concat", "end", "exec",
193  "add", "sub", "mul", "div", "idiv", "mod", "neg",
194  "abs", "round", "ceiling", "floor", "truncate", "max", "min",
195  "ne", "eq", "gt", "ge", "lt", "le", "and", "or", "xor", "not",
196  "exp", "sqrt", "ln", "log", "atan", "sin", "cos",
197  "true", "false",
198  "if", "ifelse", "for", "loop", "repeat", "exit",
199  "stopped", "stop",
200  "def", "bind", "load",
201  "setlinecap", "setlinejoin", "setlinewidth", "setdash",
202  "currentlinecap", "currentlinejoin", "currentlinewidth", "currentdash",
203  "setgray", "currentgray", "sethsbcolor", "currenthsbcolor",
204  "setrgbcolor", "currentrgbcolor", "setcmykcolor", "currentcmykcolor",
205  "currentpoint",
206  "fill", "stroke", "clip",
207 
208  "imagemask",
209 
210  "transform", "itransform", "dtransform", "idtransform",
211 
212  "gsave", "grestore", "save", "restore", "currentmatrix", "setmatrix",
213  "null",
214 
215  "currentflat", "setflat",
216  "currentglobal", "setglobal",
217  "currentmiterlimit", "setmiterlimit",
218  "currentobjectformat", "setobjectformat",
219  "currentoverprint", "setoverprint",
220  "currentpacking", "setpacking",
221  "currentshared",
222  "currentsmoothness", "setsmoothness",
223  "currentstrokeadjust", "setstrokeadjust",
224 
225  "mark", "counttomark", "cleartomark", "array", "aload", "astore",
226  "print", "cvi", "cvlit", "cvn", "cvr", "cvrs", "cvs", "cvx", "string",
227 
228  "opencurly", "closecurly", "openarray", "closearray", "string",
229  "number", "unknown", "namelit", "=", "==",
230 
231  NULL };
232 
233 /* length (of string)
234  fill eofill stroke
235  gsave grestore
236 */
237 
238 static int getfoghex(_IO *io) {
239  int ch,val;
240 
241  while ( isspace( ch = getc(io->fog)));
242  if ( isdigit(ch))
243  val = ch-'0';
244  else if ( ch >= 'A' && ch <= 'F' )
245  val = ch-'A'+10;
246  else if ( ch >= 'a' && ch <= 'f' )
247  val = ch-'a'+10;
248  else
249 return(EOF);
250 
251  val <<= 4;
252  while ( isspace( ch = getc(io->fog)));
253  if ( isdigit(ch))
254  val |= ch-'0';
255  else if ( ch >= 'A' && ch <= 'F' )
256  val |= ch-'A'+10;
257  else if ( ch >= 'a' && ch <= 'f' )
258  val |= ch-'a'+10;
259  else
260 return(EOF);
261 
262 return( val );
263 }
264 
265 static int nextch(IO *wrapper) {
266  int ch;
267  _IO *io = wrapper->top;
268 /* This works for fog 4.1. Fonts generated by 2.4 seem to use a different */
269 /* vector, and a different number parsing scheme */
270  static char *foguvec[]= { "moveto ", "rlineto ", "rrcurveto ", " ", " ",
271  "Cache ", "10 div setlinewidth ", "ShowInt ", " ", " ", " ", " ",
272  "FillStroke ", " ", " ", "SetWid ", "100 mul add ", "togNS_ ",
273  " ", "closepath ", " ", "SG " };
274 
275  while ( io!=NULL ) {
276  if ( io->backedup!=EOF ) {
277  ch = io->backedup;
278  io->backedup = EOF;
279 return( ch );
280  } else if ( io->ps!=NULL ) {
281  if ( (ch = getc(io->ps))!=EOF )
282 return( ch );
283  } else if ( io->fog!=NULL ) {
284  if ( io->macro!=NULL && *io->macro!='\0' )
285 return( *(io->macro++) );
286  ch = getfoghex(io);
287  if ( ch>=233 ) {
288  io->macro = foguvec[ch-233];
289 return( *(io->macro++) );
290  } else if ( ch!=EOF && ch<200 ) {
291  sprintf( io->fogbuf, "%d ", ch-100);
292  io->macro=io->fogbuf;
293 return( *(io->macro++) );
294  } else if (ch!=EOF) {
295  sprintf( io->fogbuf, "%d %s ", ch-233+17, io->fogns
296  ? "2 exch exp 3 1 roll 100 mul add mul"
297  : "100 mul add" );
298  io->macro=io->fogbuf;
299 return( *(io->macro++) );
300  }
301  } else {
302  if ( (ch = *(io->macro++))!='\0' )
303 return( ch );
304  if ( --io->cnt>0 ) {
305  io->macro = io->start;
306 return( nextch(wrapper));
307  }
308  }
309  wrapper->top = io->prev;
310  if ( io->isstopped )
311  wrapper->endedstopped = true;
312  free(io->start);
313  free(io);
314  io = wrapper->top;
315  }
316 return( EOF );
317 }
318 
319 static void unnextch(int ch,IO *wrapper) {
320  if ( ch==EOF )
321 return;
322  if ( wrapper->top==NULL )
323  LogError( _("Can't back up with nothing on stack\n") );
324  else if ( wrapper->top->backedup!=EOF )
325  LogError( _("Attempt to back up twice\n") );
326  else if ( wrapper->top->ps!=NULL )
327  ungetc(ch,wrapper->top->ps);
328  else
329  wrapper->top->backedup = ch;
330 }
331 
332 static void pushio(IO *wrapper, FILE *ps, char *macro, int cnt) {
333  _IO *io = gcalloc(1,sizeof(_IO));
334 
335  io->prev = wrapper->top;
336  io->ps = ps;
337  io->macro = io->start = copy(macro);
338  io->backedup = EOF;
339  if ( cnt==-1 ) {
340  io->cnt = 1;
341  io->isstopped = true;
342  } else if ( cnt==0 ) {
343  io->cnt = 1;
344  io->isloop = false;
345  } else {
346  io->cnt = cnt;
347  io->isloop = true;
348  }
349  wrapper->top = io;
350 }
351 
352 static void pushfogio(IO *wrapper, FILE *fog) {
353  _IO *io = gcalloc(1,sizeof(_IO));
354 
355  io->prev = wrapper->top;
356  io->fog = fog;
357  io->backedup = EOF;
358  io->cnt = 1;
359  io->isloop = false;
360  wrapper->top = io;
361 }
362 
363 static void ioescapeloop(IO *wrapper) {
364  _IO *io = wrapper->top, *iop;
365  int wasloop;
366 
367  while ( io->prev!=NULL && !io->isstopped ) {
368  iop = io->prev;
369  wasloop = io->isloop;
370  free(io->start);
371  free(io);
372  if ( wasloop ) {
373  wrapper->top = iop;
374 return;
375  }
376  io = iop;
377  }
378 
379 /* GT: This is part of the PostScript language. "exit" should not be translated */
380 /* GT: as it is a PostScript keyword. (FF contains a small PostScript interpreter */
381 /* GT: so it can understand some PostScript fonts, and can generate errors when */
382 /* GT: handed bad PostScript). */
383  LogError( _("Use of \"exit\" when not in a loop\n") );
384  wrapper->top = io;
385 }
386 
387 static int ioescapestopped(IO *wrapper, struct psstack *stack, int sp, const size_t bsize) {
388  _IO *io = wrapper->top, *iop;
389  int wasstopped;
390 
391  while ( io->prev!=NULL ) {
392  iop = io->prev;
393  wasstopped = io->isstopped;
394  free(io->start);
395  free(io);
396  if ( wasstopped ) {
397  wrapper->top = iop;
398  if ( sp<(int)bsize ) {
399  stack[sp].type = ps_bool;
400  stack[sp++].u.tf = true;
401  }
402 return(sp);
403  }
404  io = iop;
405  }
406 
407 /* GT: This is part of the PostScript language. Neither "stop" nor "stopped" */
408 /* GT: should be translated as both are PostScript keywords. */
409  LogError( _("Use of \"stop\" when not in a stopped\n") );
410  wrapper->top = io;
411 return( sp );
412 }
413 
414 static int endedstopped(IO *wrapper) {
415  if ( wrapper->endedstopped ) {
416  wrapper->endedstopped = false;
417 return( true );
418  }
419 return( false );
420 }
421 
422 
423 static int nextpstoken(IO *wrapper, real *val, char *tokbuf, int tbsize) {
424  int ch, r, i;
425  char *pt, *end;
426  float mf2pt_advance_width;
427 
428  pt = tokbuf;
429  end = pt+tbsize-1;
430 
431  /* Eat whitespace and comments. Comments last to eol (or formfeed) */
432  while ( 1 ) {
433  while ( isspace(ch = nextch(wrapper)) );
434  if ( ch!='%' )
435  break;
436  while ( (ch=nextch(wrapper))!=EOF && ch!='\r' && ch!='\n' && ch!='\f' )
437  if ( pt<end )
438  *pt++ = ch;
439  *pt='\0';
440  /* Some comments have meanings (that we care about) */
441  if ( sscanf( tokbuf, " MF2PT1: bbox %*g %*g %g %*g", &mf2pt_advance_width )==1 )
442  wrapper->advance_width = mf2pt_advance_width;
443  else if ( sscanf( tokbuf, " MF2PT1: glyph_dimensions %*g %*g %g %*g", &mf2pt_advance_width )==1 )
444  wrapper->advance_width = mf2pt_advance_width;
445  pt = tokbuf;
446  }
447 
448  if ( ch==EOF )
449 return( pt_eof );
450 
451  pt = tokbuf;
452  end = pt+tbsize-1;
453  *pt++ = ch; *pt='\0';
454 
455  if ( ch=='(' ) {
456  int nest=1, quote=0;
457  while ( (ch=nextch(wrapper))!=EOF ) {
458  if ( pt<end ) *pt++ = ch;
459  if ( quote )
460  quote=0;
461  else if ( ch=='(' )
462  ++nest;
463  else if ( ch==')' ) {
464  if ( --nest==0 )
465  break;
466  } else if ( ch=='\\' )
467  quote = 1;
468  }
469  *pt='\0';
470 return( pt_string );
471  } else if ( ch=='<' ) {
472  ch = nextch(wrapper);
473  if ( pt<end ) *pt++ = ch;
474  if ( ch=='>' )
475  /* Done */;
476  else if ( ch!='~' ) {
477  while ( (ch=nextch(wrapper))!=EOF && ch!='>' )
478  if ( pt<end ) *pt++ = ch;
479  } else {
480  int twiddle=0;
481  while ( (ch=nextch(wrapper))!=EOF ) {
482  if ( pt<end ) *pt++ = ch;
483  if ( ch=='~' ) twiddle = 1;
484  else if ( twiddle && ch=='>' )
485  break;
486  else twiddle = 0;
487  }
488  }
489  *pt='\0';
490 return( pt_string );
491  } else if ( ch==')' || ch=='>' || ch=='[' || ch==']' || ch=='{' || ch=='}' ) {
492  if ( ch=='{' )
493 return( pt_opencurly );
494  else if ( ch=='}' )
495 return( pt_closecurly );
496  if ( ch=='[' )
497 return( pt_openarray );
498  else if ( ch==']' )
499 return( pt_closearray );
500 
501 return( pt_unknown ); /* single character token */
502  } else if ( ch=='/' ) {
503  pt = tokbuf;
504  while ( (ch=nextch(wrapper))!=EOF && !isspace(ch) && ch!='%' &&
505  ch!='(' && ch!=')' && ch!='<' && ch!='>' && ch!='[' && ch!=']' &&
506  ch!='{' && ch!='}' && ch!='/' )
507  if ( pt<tokbuf+tbsize-2 )
508  *pt++ = ch;
509  *pt = '\0';
510  unnextch(ch,wrapper);
511 return( pt_namelit ); /* name literal */
512  } else {
513  while ( (ch=nextch(wrapper))!=EOF && !isspace(ch) && ch!='%' &&
514  ch!='(' && ch!=')' && ch!='<' && ch!='>' && ch!='[' && ch!=']' &&
515  ch!='{' && ch!='}' && ch!='/' ) {
516  if ( pt<tokbuf+tbsize-2 )
517  *pt++ = ch;
518  }
519  *pt = '\0';
520  unnextch(ch,wrapper);
521  r = strtol(tokbuf,&end,10);
522  pt = end;
523  if ( *pt=='\0' ) { /* It's a normal integer */
524  *val = r;
525 return( pt_number );
526  } else if ( *pt=='#' ) {
527  r = strtol(pt+1,&end,r);
528  if ( *end=='\0' ) { /* It's a radix integer */
529  *val = r;
530 return( pt_number );
531  }
532  } else {
533  *val = strtod(tokbuf,&end);
534  if ( !isfinite(*val) ) {
535 /* GT: NaN is a concept in IEEE floating point which means "Not a Number" */
536 /* GT: it is used to represent errors like 0/0 or sqrt(-1). */
537  LogError( _("Bad number, infinity or nan: %s\n"), tokbuf );
538  *val = 0;
539  }
540  if ( *end=='\0' ) /* It's a real */
541 return( pt_number );
542  }
543  /* It's not a number */
544  for ( i=0; toknames[i]!=NULL; ++i )
545  if ( strcmp(tokbuf,toknames[i])==0 )
546 return( i );
547 
548 return( pt_unknown );
549  }
550 }
551 
552 static void Transform(BasePoint *to, DBasePoint *from, real trans[6]) {
553  to->x = trans[0]*from->x+trans[2]*from->y+trans[4];
554  to->y = trans[1]*from->x+trans[3]*from->y+trans[5];
555 }
556 
557 void MatMultiply(real m1[6], real m2[6], real to[6]) {
558  real trans[6];
559 
560  trans[0] = m1[0]*m2[0] +
561  m1[1]*m2[2];
562  trans[1] = m1[0]*m2[1] +
563  m1[1]*m2[3];
564  trans[2] = m1[2]*m2[0] +
565  m1[3]*m2[2];
566  trans[3] = m1[2]*m2[1] +
567  m1[3]*m2[3];
568  trans[4] = m1[4]*m2[0] +
569  m1[5]*m2[2] +
570  m2[4];
571  trans[5] = m1[4]*m2[1] +
572  m1[5]*m2[3] +
573  m2[5];
574  memcpy(to,trans,sizeof(trans));
575 }
576 
577 void MatInverse(real into[6], real orig[6]) {
578  real det = orig[0]*orig[3] - orig[1]*orig[2];
579 
580  if ( det==0 ) {
581  LogError( _("Attempt to invert a singular matrix\n") );
582  memset(into,0,sizeof(*into));
583  } else {
584  into[0] = orig[3]/det;
585  into[1] = -orig[1]/det;
586  into[2] = -orig[2]/det;
587  into[3] = orig[0]/det;
588  into[4] = -orig[4]*into[0] - orig[5]*into[2];
589  into[5] = -orig[4]*into[1] - orig[5]*into[3];
590  }
591 }
592 
594  Entity *ent;
595 
596  for ( ent=ec->splines; ent!=NULL; ent=ent->next ) if ( ent->type == et_splines ) {
599  }
600 }
601 
602 static int AddEntry(struct pskeydict *dict,struct psstack *stack, int sp) {
603  int i;
604 
605  if ( dict->cnt>=dict->max ) {
606  if ( dict->cnt==0 ) {
607  dict->max = 30;
608  dict->entries = galloc(dict->max*sizeof(struct pskeyval));
609  } else {
610  dict->max += 30;
611  dict->entries = grealloc(dict->entries,dict->max*sizeof(struct pskeyval));
612  }
613  }
614  if ( sp<2 )
615 return(sp);
616  if ( stack[sp-2].type!=ps_string && stack[sp-2].type!=ps_lit ) {
617 /* GT: Here "def" is a PostScript keyword, (meaning define). */
618 /* GT: This "def" should not be translated as it is part of the PostScript language. */
619  LogError( _("Key for a def must be a string or name literal\n") );
620 return(sp-2);
621  }
622  for ( i=0; i<dict->cnt; ++i )
623  if ( strcmp(dict->entries[i].key,stack[sp-2].u.str)==0 )
624  break;
625  if ( i!=dict->cnt ) {
626  free(stack[sp-2].u.str);
627  if ( dict->entries[i].type==ps_string || dict->entries[i].type==ps_instr ||
628  dict->entries[i].type==ps_lit )
629  free(dict->entries[i].u.str);
630  } else {
631  memset(&dict->entries[i],'\0',sizeof(struct pskeyval));
632  dict->entries[i].key = stack[sp-2].u.str;
633  ++dict->cnt;
634  }
635  dict->entries[i].type = stack[sp-1].type;
636  dict->entries[i].u = stack[sp-1].u;
637 return(sp-2);
638 }
639 
640 static int forgetstack(struct psstack *stack, int forgets, int sp) {
641  /* forget the bottom most "forgets" entries on the stack */
642  /* we presume they are garbage that has accumulated because we */
643  /* don't understand all of PS */
644  int i;
645  for ( i=0; i<forgets; ++i ) {
646  if ( stack[i].type==ps_string || stack[i].type==ps_instr ||
647  stack[i].type==ps_lit )
648  free(stack[i].u.str);
649  else if ( stack[i].type==ps_array || stack[i].type==ps_dict )
650  dictfree(&stack[i].u.dict);
651  }
652  for ( i=forgets; i<sp; ++i )
653  stack[i-forgets] = stack[i];
654 return( sp-forgets );
655 }
656 
657 static int rollstack(struct psstack *stack, int sp) {
658  int n,j,i;
659  struct psstack *temp;
660 
661  if ( sp>1 ) {
662  n = stack[sp-2].u.val;
663  j = stack[sp-1].u.val;
664  sp-=2;
665  if ( sp>=n && n>0 ) {
666  j %= n;
667  if ( j<0 ) j += n;
668  temp = galloc(n*sizeof(struct psstack));
669  for ( i=0; i<n; ++i )
670  temp[i] = stack[sp-n+i];
671  for ( i=0; i<n; ++i )
672  stack[sp-n+(i+j)%n] = temp[i];
673  free(temp);
674  }
675  }
676 return( sp );
677 }
678 
679 static void CheckMakeB(BasePoint *test, BasePoint *good) {
680  if ( !isfinite(test->x) || test->x>100000 || test->x<-100000 ) {
681  LogError( _("Value out of bounds in spline.\n") );
682  if ( good!=NULL )
683  test->x = good->x;
684  else
685  test->x = 0;
686  }
687  if ( !isfinite(test->y) || test->y>100000 || test->y<-100000 ) {
688  LogError( _("Value out of bounds in spline.\n") );
689  if ( good!=NULL )
690  test->y = good->y;
691  else
692  test->y = 0;
693  }
694 }
695 
696 static void CheckMake(SplinePoint *from, SplinePoint *to) {
697  CheckMakeB(&from->me,NULL);
698  CheckMakeB(&from->nextcp,&from->me);
699  CheckMakeB(&to->prevcp,&from->nextcp);
700  CheckMakeB(&to->me,&to->prevcp);
701 }
702 
704  SplineSet *cur, real *transform ) {
705  SplinePoint *pt;
707  real cplen;
708  int sign=1;
709  real s1, s2, c1, c2;
710 
711  if ( a1==a2 )
712 return;
713 
714  cplen = (a2-a1)/90 * r * .552;
715  a1 *= 3.1415926535897932/180; a2 *= 3.1415926535897932/180;
716  s1 = sin(a1); s2 = sin(a2); c1 = cos(a1); c2 = cos(a2);
717  temp.x = cx+r*c2; temp.y = cy+r*s2;
718  base.x = cx+r*c1; base.y = cy+r*s1;
719  pt = chunkalloc(sizeof(SplinePoint));
720  Transform(&pt->me,&temp,transform);
721  cp.x = temp.x-cplen*s2; cp.y = temp.y + cplen*c2;
722  if ( (cp.x-base.x)*(cp.x-base.x)+(cp.y-base.y)*(cp.y-base.y) >
723  (temp.x-base.x)*(temp.x-base.x)+(temp.y-base.y)*(temp.y-base.y) ) {
724  sign = -1;
725  cp.x = temp.x+cplen*s2; cp.y = temp.y - cplen*c2;
726  }
727  Transform(&pt->prevcp,&cp,transform);
728  pt->nonextcp = true;
729  cp.x = base.x + sign*cplen*s1; cp.y = base.y - sign*cplen*c1;
730  Transform(&cur->last->nextcp,&cp,transform);
731  cur->last->nonextcp = false;
732  CheckMake(cur->last,pt);
733  SplineMake3(cur->last,pt);
734  cur->last = pt;
735 }
736 
738  SplineSet *cur, real *transform, int clockwise ) {
739  int a;
740  real last;
741 
742  while ( a1<0 ) { a1 += 360; a2 +=360;} while ( a2-a1<=-360 ) a2 += 360;
743  while ( a1>360 ) { a1 -= 360; a2 -= 360; } while ( a2-a1>360 ) a2 -= 360;
744  if ( !clockwise ) {
745  if ( a1>a2 )
746  a2 += 360;
747  last = a1;
748  for ( a=((int) (a1+90)/90)*90; a<a2; a += 90 ) {
750  last = a;
751  }
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 ) {
759  last = a;
760  }
762  }
763 }
764 
765 static void collectgarbage(struct garbage *tofrees,struct pskeydict *to) {
766  struct garbage *into;
767 
768  /* Garbage collection pointers */
769  into = tofrees;
770  if ( tofrees->cnt>=GARBAGE_MAX && tofrees->next!=NULL )
771  into = tofrees->next;
772  if ( into->cnt>=GARBAGE_MAX ) {
773  into = chunkalloc(sizeof(struct garbage));
774  into->next = tofrees->next;
775  tofrees->next = into;
776  }
777  into->cnts[ into->cnt ] = to->cnt;
778  into->entries[ into->cnt++ ] = to->entries;
779 }
780 
781 static void copyarray(struct pskeydict *to,struct pskeydict *from, struct garbage *tofrees) {
782  int i;
783  struct pskeyval *oldent = from->entries;
784 
785  *to = *from;
786  to->entries = gcalloc(to->cnt,sizeof(struct pskeyval));
787  for ( i=0; i<to->cnt; ++i ) {
788  to->entries[i] = oldent[i];
789  if ( to->entries[i].type==ps_string || to->entries[i].type==ps_instr ||
790  to->entries[i].type==ps_lit )
791  to->entries[i].u.str = copy(to->entries[i].u.str);
792  else if ( to->entries[i].type==ps_array || to->entries[i].type==ps_dict )
793  copyarray(&to->entries[i].u.dict,&oldent[i].u.dict,tofrees);
794  }
795  collectgarbage(tofrees,to);
796 }
797 
798 static int aload(int sp, struct psstack *stack,int stacktop, struct garbage *tofrees) {
799  int i;
800 
801  if ( sp>=1 && stack[sp-1].type==ps_array ) {
802  struct pskeydict dict;
803  --sp;
804  dict = stack[sp].u.dict;
805  for ( i=0; i<dict.cnt; ++i ) {
806  if ( sp<stacktop ) {
807  stack[sp].type = dict.entries[i].type;
808  stack[sp].u = dict.entries[i].u;
809  if ( stack[sp].type==ps_string || stack[sp].type==ps_instr ||
810  stack[sp].type==ps_lit )
811  stack[sp].u.str = copy(stack[sp].u.str);
812 /* The following is incorrect behavior, but as I don't do garbage collection */
813 /* and I'm not going to implement reference counts, this will work in most cases */
814  else if ( stack[sp].type==ps_array )
815  copyarray(&stack[sp].u.dict,&stack[sp].u.dict,tofrees);
816  ++sp;
817  }
818  }
819  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
820  stack[sp].type = ps_array;
821  stack[sp].u.dict = dict;
822  ++sp;
823  }
824  }
825 return( sp );
826 }
827 
828 static void printarray(struct pskeydict *dict) {
829  int i;
830 
831  printf("[" );
832  for ( i=0; i<dict->cnt; ++i ) {
833  switch ( dict->entries[i].type ) {
834  case ps_num:
835  printf( "%g", (double) dict->entries[i].u.val );
836  break;
837  case ps_bool:
838  printf( "%s", dict->entries[i].u.tf ? "true" : "false" );
839  break;
840  case ps_string: case ps_instr: case ps_lit:
841  printf( dict->entries[i].type==ps_lit ? "/" :
842  dict->entries[i].type==ps_string ? "(" : "{" );
843  printf( "%s", dict->entries[i].u.str );
844  printf( dict->entries[i].type==ps_lit ? "" :
845  dict->entries[i].type==ps_string ? ")" : "}" );
846  break;
847  case ps_array:
848  printarray(&dict->entries[i].u.dict);
849  break;
850  case ps_void:
851  printf( "-- void --" );
852  break;
853  default:
854  printf( "-- nostringval --" );
855  break;
856  }
857  printf(" ");
858  }
859  printf( "]" );
860 }
861 
862 static void freestuff(struct psstack *stack, int sp, struct pskeydict *dict,
863  GrowBuf *gb, struct garbage *tofrees) {
864  int i;
865 
866  free(gb->base);
867  for ( i=0; i<dict->cnt; ++i ) {
868  if ( dict->entries[i].type==ps_string || dict->entries[i].type==ps_instr ||
869  dict->entries[i].type==ps_lit )
870  free(dict->entries[i].u.str);
871  free(dict->entries[i].key);
872  }
873  free( dict->entries );
874  for ( i=0; i<sp; ++i ) {
875  if ( stack[i].type==ps_string || stack[i].type==ps_instr ||
876  stack[i].type==ps_lit )
877  free(stack[i].u.str);
878 #if 0 /* Garbage collection should get these */
879  else if ( stack[i].type==ps_array || stack[i].type==ps_dict )
880  dictfree(&stack[i].u.dict);
881 #endif
882  }
883  garbagefree(tofrees);
884 }
885 
886 static void DoMatTransform(int tok,int sp,struct psstack *stack) {
887  real invt[6], t[6];
888 
889  if ( stack[sp-1].u.dict.cnt==6 && stack[sp-1].u.dict.entries[0].type==ps_num ) {
890  double x = stack[sp-3].u.val, y = stack[sp-2].u.val;
891  --sp;
892  t[5] = stack[sp].u.dict.entries[5].u.val;
893  t[4] = stack[sp].u.dict.entries[4].u.val;
894  t[3] = stack[sp].u.dict.entries[3].u.val;
895  t[2] = stack[sp].u.dict.entries[2].u.val;
896  t[1] = stack[sp].u.dict.entries[1].u.val;
897  t[0] = stack[sp].u.dict.entries[0].u.val;
898  dictfree(&stack[sp].u.dict);
899  if ( tok==pt_itransform || tok==pt_idtransform ) {
900  MatInverse(invt,t);
901  memcpy(t,invt,sizeof(t));
902  }
903  stack[sp-2].u.val = t[0]*x + t[1]*y;
904  stack[sp-1].u.val = t[2]*x + t[3]*y;
905  if ( tok==pt_transform || tok==pt_itransform ) {
906  stack[sp-2].u.val += t[4];
907  stack[sp-1].u.val += t[5];
908  }
909  }
910 }
911 
912 static int DoMatOp(int tok,int sp,struct psstack *stack) {
913  real temp[6], t[6];
914  int nsp=sp;
915 
916  if ( stack[sp-1].u.dict.cnt==6 && stack[sp-1].u.dict.entries[0].type==ps_num ) {
917  t[5] = stack[sp-1].u.dict.entries[5].u.val;
918  t[4] = stack[sp-1].u.dict.entries[4].u.val;
919  t[3] = stack[sp-1].u.dict.entries[3].u.val;
920  t[2] = stack[sp-1].u.dict.entries[2].u.val;
921  t[1] = stack[sp-1].u.dict.entries[1].u.val;
922  t[0] = stack[sp-1].u.dict.entries[0].u.val;
923  switch ( tok ) {
924  case pt_translate:
925  if ( sp>=3 ) {
926  stack[sp-1].u.dict.entries[5].u.val += stack[sp-3].u.val*t[0]+stack[sp-2].u.val*t[2];
927  stack[sp-1].u.dict.entries[4].u.val += stack[sp-3].u.val*t[1]+stack[sp-2].u.val*t[3];
928  nsp = sp-2;
929  }
930  break;
931  case pt_scale:
932  if ( sp>=2 ) {
933  stack[sp-1].u.dict.entries[0].u.val *= stack[sp-3].u.val;
934  stack[sp-1].u.dict.entries[1].u.val *= stack[sp-3].u.val;
935  stack[sp-1].u.dict.entries[2].u.val *= stack[sp-2].u.val;
936  stack[sp-1].u.dict.entries[3].u.val *= stack[sp-2].u.val;
937  /* transform[4,5] are unchanged */
938  nsp = sp-2;
939  }
940  break;
941  case pt_rotate:
942  if ( sp>=1 ) {
943  --sp;
944  temp[0] = temp[3] = cos(stack[sp].u.val);
945  temp[1] = sin(stack[sp].u.val);
946  temp[2] = -temp[1];
947  temp[4] = temp[5] = 0;
948  MatMultiply(temp,t,t);
949  stack[sp-1].u.dict.entries[5].u.val = t[5];
950  stack[sp-1].u.dict.entries[4].u.val = t[4];
951  stack[sp-1].u.dict.entries[3].u.val = t[3];
952  stack[sp-1].u.dict.entries[2].u.val = t[2];
953  stack[sp-1].u.dict.entries[1].u.val = t[1];
954  stack[sp-1].u.dict.entries[0].u.val = t[0];
955  nsp = sp-1;
956  }
957  break;
958  }
959  stack[nsp-1] = stack[sp-1];
960  }
961 return(nsp);
962 }
963 
965  real linewidth, real *transform, SplineSet *clippath) {
966  Entity *ent = gcalloc(1,sizeof(Entity));
967  ent->type = et_splines;
968  ent->u.splines.splines = head;
969  ent->u.splines.cap = linecap;
970  ent->u.splines.join = linejoin;
971  ent->u.splines.stroke_width = linewidth;
972  ent->u.splines.fill.col = 0xffffffff;
973  ent->u.splines.stroke.col = 0xffffffff;
974  ent->u.splines.fill.opacity = 1.0;
975  ent->u.splines.stroke.opacity = 1.0;
976  ent->clippath = SplinePointListCopy(clippath);
977  memcpy(ent->u.splines.transform,transform,6*sizeof(real));
978 return( ent );
979 }
980 
981 
983  char *tokbuf, int toksize) {
984  int tok;
985  real dval;
986  char *glyphname;
987  RefChar *ref;
988 
989  tok = nextpstoken(wrapper,&dval,tokbuf,toksize);
990  if ( strcmp(tokbuf,"get")!=0 )
991 return; /* Hunh. I don't understand it. I give up */
992  tok = nextpstoken(wrapper,&dval,tokbuf,toksize);
993  if ( tok!=pt_namelit )
994 return; /* Hunh. I don't understand it. I give up */
995  glyphname = copy(tokbuf);
996  tok = nextpstoken(wrapper,&dval,tokbuf,toksize);
997  if ( strcmp(tokbuf,"get")!=0 )
998 return; /* Hunh. I don't understand it. I give up */
999  tok = nextpstoken(wrapper,&dval,tokbuf,toksize);
1000  if ( strcmp(tokbuf,"exec")!=0 )
1001 return; /* Hunh. I don't understand it. I give up */
1002 
1003  /* Ok, it looks very much like a reference to glyphname */
1004  ref = RefCharCreate();
1005  memcpy(ref->transform,transform,sizeof(ref->transform));
1006  ref->sc = (SplineChar *) glyphname;
1007  ref->next = ec->refs;
1008  ec->refs = ref;
1009 }
1010 
1011 static void _InterpretPS(IO *wrapper, EntityChar *ec, RetStack *rs) {
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];
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;
1037  DashType dashes[DASH_MAX];
1038  int dash_offset = 0;
1039  Entity *ent;
1040  char *oldloc;
1041  int warned = 0;
1042  struct garbage tofrees;
1043  SplineSet *clippath = NULL;
1044  char tokbuf[100];
1045  const int tokbufsize = 100;
1046 
1047  oldloc = setlocale(LC_NUMERIC,"C");
1048 
1049  memset(&gb,'\0',sizeof(GrowBuf));
1050  memset(&dict,'\0',sizeof(dict));
1051  tofrees.cnt = 0; tofrees.next = NULL;
1052 
1053  transform[0] = transform[3] = 1.0;
1054  transform[1] = transform[2] = transform[4] = transform[5] = 0;
1055  current.x = current.y = 0;
1056  dashes[0] = 0; dashes[1] = DASH_INHERITED;
1057 
1058  if ( ec->fromtype3 ) {
1059  /* My type3 fonts have two things pushed on the stack when they */
1060  /* start. One is a dictionary, the other a flag (number). If the */
1061  /* flag is non-zero then we are a nested call (a reference char) */
1062  /* if 0, we're normal. We don't want to do setcachedevice for */
1063  /* reference chars. We can't represent a dictionary on the stack */
1064  /* so just push two 0s */
1065  stack[0].type = stack[1].type = ps_num;
1066  stack[0].u.val = stack[1].u.val = 0;
1067  sp = 2;
1068  }
1069 
1070  while ( (tok = nextpstoken(wrapper,&dval,tokbuf,tokbufsize))!=pt_eof ) {
1071  if ( endedstopped(wrapper)) {
1072  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1073  stack[sp].type = ps_bool;
1074  stack[sp++].u.tf = false;
1075  }
1076  }
1077  if ( sp>(int)(sizeof(stack)/sizeof(stack[0])*4/5) ) {
1078  /* We don't interpret all of postscript */
1079  /* Sometimes we leave garbage on the stack that a real PS interp */
1080  /* would have handled. If the stack gets too deep, clean out the */
1081  /* oldest entries */
1082  sp = forgetstack(stack,sizeof(stack)/sizeof(stack[0])/3,sp );
1083  }
1084  if ( ccnt>0 ) {
1085  if ( tok==pt_closecurly )
1086  --ccnt;
1087  else if ( tok==pt_opencurly )
1088  ++ccnt;
1089  if ( ccnt>0 )
1090  AddTok(&gb,tokbuf,tok==pt_namelit);
1091  else {
1092  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1093  stack[sp].type = ps_instr;
1094  if ( gb.pt==NULL )
1095  stack[sp++].u.str = copy("");
1096  else {
1097  *gb.pt = '\0'; gb.pt = gb.base;
1098  stack[sp++].u.str = copy(gb.base);
1099  }
1100  }
1101  }
1102  } else if ( tok==pt_unknown && (kv=lookup(&dict,tokbuf))!=NULL ) {
1103  if ( kv->type == ps_instr )
1104  pushio(wrapper,NULL,copy(kv->u.str),0);
1105  else if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1106  stack[sp].type = kv->type;
1107  stack[sp++].u = kv->u;
1108  if ( kv->type==ps_instr || kv->type==ps_lit || kv->type==ps_string )
1109  stack[sp-1].u.str = copy(stack[sp-1].u.str);
1110  else if ( kv->type==ps_array || kv->type==ps_dict ) {
1111  copyarray(&stack[sp-1].u.dict,&stack[sp-1].u.dict,&tofrees);
1112  if ( stack[sp-1].u.dict.is_executable )
1113  sp = aload(sp,stack,sizeof(stack)/sizeof(stack[0]),&tofrees);
1114  }
1115  }
1116  } else {
1117  if ( tok==pt_unknown ) {
1118  if ( strcmp(tokbuf,"Cache")==0 ) /* Fontographer type3s */
1120  else if ( strcmp(tokbuf,"SetWid")==0 ) {
1121  tok = pt_setcharwidth;
1122  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1123  stack[sp].type = ps_num;
1124  stack[sp++].u.val = 0;
1125  }
1126  } else if ( strcmp(tokbuf,"rrcurveto")==0 ) {
1127  if ( sp>=6 ) {
1128  stack[sp-4].u.val += stack[sp-6].u.val;
1129  stack[sp-3].u.val += stack[sp-5].u.val;
1130  stack[sp-2].u.val += stack[sp-4].u.val;
1131  stack[sp-1].u.val += stack[sp-3].u.val;
1132  tok = pt_rcurveto;
1133  }
1134  } else if ( strcmp(tokbuf,"FillStroke")==0 ) {
1135  if ( sp>0 )
1136  --sp;
1137  tok = linewidth!=WIDTH_INHERITED ? pt_stroke : pt_fill;
1138  if ( wrapper->top!=NULL && wrapper->top->ps!=NULL &&
1139  linewidth!=WIDTH_INHERITED )
1140  linewidth /= 10.0; /* bug in Fontographer's unencrypted type3 fonts */
1141  } else if ( strcmp(tokbuf,"SG")==0 ) {
1142  if ( linewidth!=WIDTH_INHERITED && sp>1 )
1143  stack[sp-2].u.val = stack[sp-1].u.val;
1144  if ( sp>0 )
1145  --sp;
1146  if ( sp>0 )
1147  stack[sp-1].u.val = (stack[sp-1].u.val+99)/198.0;
1148  tok = pt_setgray;
1149  } else if ( strcmp(tokbuf,"ShowInt")==0 ) {
1150  /* Fontographer reference */
1151  if ( (!wrapper->top->fogns && sp>0 && stack[sp-1].type == ps_num &&
1152  stack[sp-1].u.val>=0 && stack[sp-1].u.val<=255 ) ||
1153  (wrapper->top->fogns && sp>6 && stack[sp-7].type == ps_num &&
1154  stack[sp-7].u.val>=0 && stack[sp-7].u.val<=255 )) {
1155  ref = RefCharCreate();
1156  memcpy(ref->transform,transform,sizeof(ref->transform));
1157  if ( wrapper->top->fogns ) {
1158  sp -= 6;
1159  t[0] = stack[sp+0].u.val;
1160  t[1] = stack[sp+1].u.val;
1161  t[2] = stack[sp+2].u.val;
1162  t[3] = stack[sp+3].u.val;
1163  t[4] = stack[sp+4].u.val;
1164  t[5] = stack[sp+5].u.val;
1165  MatMultiply(t,ref->transform,ref->transform);
1166  wrapper->top->fogns = false;
1167  }
1168  ref->orig_pos = stack[--sp].u.val;
1169  ref->next = ec->refs;
1170  ec->refs = ref;
1171  continue;
1172  }
1173  } else if ( strcmp(tokbuf,"togNS_")==0 ) {
1174  wrapper->top->fogns = !wrapper->top->fogns;
1175  continue;
1176  }
1177  }
1178  switch ( tok ) {
1179  case pt_number:
1180  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1181  stack[sp].type = ps_num;
1182  stack[sp++].u.val = dval;
1183  }
1184  break;
1185  case pt_string:
1186  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1187  stack[sp].type = ps_string;
1188  stack[sp++].u.str = copyn(tokbuf+1,strlen(tokbuf)-2);
1189  }
1190  break;
1191  case pt_true: case pt_false:
1192  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1193  stack[sp].type = ps_bool;
1194  stack[sp++].u.tf = tok==pt_true;
1195  }
1196  break;
1197  case pt_opencurly:
1198  ++ccnt;
1199  break;
1200  case pt_closecurly:
1201  --ccnt;
1202  if ( ccnt<0 ) {
1203  goto done;
1204  }
1205  break;
1206  case pt_count:
1207  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1208  stack[sp].type = ps_num;
1209  stack[sp].u.val = sp;
1210  ++sp;
1211  }
1212  break;
1213  case pt_pop:
1214  if ( sp>0 ) {
1215  --sp;
1216  if ( stack[sp].type==ps_string || stack[sp].type==ps_instr ||
1217  stack[sp].type==ps_lit )
1218  free(stack[sp].u.str);
1219  else if ( stack[sp].type==ps_array || stack[sp].type==ps_dict )
1220  dictfree(&stack[sp].u.dict);
1221  }
1222  break;
1223  case pt_clear:
1224  while ( sp>0 ) {
1225  --sp;
1226  if ( stack[sp].type==ps_string || stack[sp].type==ps_instr ||
1227  stack[sp].type==ps_lit )
1228  free(stack[sp].u.str);
1229  else if ( stack[sp].type==ps_array || stack[sp].type==ps_dict )
1230  dictfree(&stack[sp].u.dict);
1231  }
1232  break;
1233  case pt_dup:
1234  if ( sp>0 && sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1235  stack[sp] = stack[sp-1];
1236  if ( stack[sp].type==ps_string || stack[sp].type==ps_instr ||
1237  stack[sp].type==ps_lit )
1238  stack[sp].u.str = copy(stack[sp].u.str);
1239  /* The following is incorrect behavior, but as I don't do garbage collection */
1240  /* and I'm not going to implement reference counts, this will work in most cases */
1241  else if ( stack[sp].type==ps_array )
1242  copyarray(&stack[sp].u.dict,&stack[sp].u.dict,&tofrees);
1243  ++sp;
1244  }
1245  break;
1246  case pt_copy:
1247  if ( sp>0 ) {
1248  int n = stack[--sp].u.val;
1249  if ( n+sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1250  int i;
1251  for ( i=0; i<n; ++i ) {
1252  stack[sp] = stack[sp-n];
1253  if ( stack[sp].type==ps_string || stack[sp].type==ps_instr ||
1254  stack[sp].type==ps_lit )
1255  stack[sp].u.str = copy(stack[sp].u.str);
1256  /* The following is incorrect behavior, but as I don't do garbage collection */
1257  /* and I'm not going to implement reference counts, this will work in most cases */
1258  else if ( stack[sp].type==ps_array )
1259  copyarray(&stack[sp].u.dict,&stack[sp].u.dict,&tofrees);
1260  ++sp;
1261  }
1262  }
1263  }
1264  break;
1265  case pt_exch:
1266  if ( sp>1 ) {
1267  struct psstack temp;
1268  temp = stack[sp-1];
1269  stack[sp-1] = stack[sp-2];
1270  stack[sp-2] = temp;
1271  }
1272  break;
1273  case pt_roll:
1274  sp = rollstack(stack,sp);
1275  break;
1276  case pt_index:
1277  if ( sp>0 ) {
1278  i = stack[--sp].u.val;
1279  if ( sp>i && i>=0 ) {
1280  stack[sp] = stack[sp-i-1];
1281  if ( stack[sp].type==ps_string || stack[sp].type==ps_instr ||
1282  stack[sp].type==ps_lit )
1283  stack[sp].u.str = copy(stack[sp].u.str);
1284  /* The following is incorrect behavior, but as I don't do garbage collection */
1285  /* and I'm not going to implement reference counts, this will work in most cases */
1286  else if ( stack[sp].type==ps_array )
1287  copyarray(&stack[sp].u.dict,&stack[sp].u.dict,&tofrees);
1288  ++sp;
1289  }
1290  }
1291  break;
1292  case pt_add:
1293  if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1294  stack[sp-2].u.val += stack[sp-1].u.val;
1295  --sp;
1296  }
1297  break;
1298  case pt_sub:
1299  if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1300  stack[sp-2].u.val -= stack[sp-1].u.val;
1301  --sp;
1302  }
1303  break;
1304  case pt_mul:
1305  if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1306  stack[sp-2].u.val *= stack[sp-1].u.val;
1307  --sp;
1308  }
1309  break;
1310  case pt_div:
1311  if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1312  if ( stack[sp-1].u.val == 0 )
1313  LogError( _("Divide by zero in postscript code.\n" ));
1314  else
1315  stack[sp-2].u.val /= stack[sp-1].u.val;
1316  --sp;
1317  }
1318  break;
1319  case pt_idiv:
1320  if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1321  if ( stack[sp-1].u.val == 0 )
1322  LogError( _("Divide by zero in postscript code.\n" ));
1323  else
1324  stack[sp-2].u.val = ((int) stack[sp-2].u.val) / ((int) stack[sp-1].u.val);
1325  --sp;
1326  }
1327  break;
1328  case pt_mod:
1329  if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1330  if ( stack[sp-1].u.val == 0 )
1331  LogError( _("Divide by zero in postscript code.\n" ));
1332  else
1333  stack[sp-2].u.val = ((int) stack[sp-2].u.val) % ((int) stack[sp-1].u.val);
1334  --sp;
1335  }
1336  break;
1337  case pt_max:
1338  if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1339  if ( stack[sp-2].u.val < stack[sp-1].u.val )
1340  stack[sp-2].u.val = stack[sp-1].u.val;
1341  --sp;
1342  }
1343  break;
1344  case pt_min:
1345  if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1346  if ( stack[sp-2].u.val > stack[sp-1].u.val )
1347  stack[sp-2].u.val = stack[sp-1].u.val;
1348  --sp;
1349  }
1350  break;
1351  case pt_neg:
1352  if ( sp>=1 ) {
1353  if ( stack[sp-1].type == ps_num )
1354  stack[sp-1].u.val = -stack[sp-1].u.val;
1355  }
1356  break;
1357  case pt_abs:
1358  if ( sp>=1 ) {
1359  if ( stack[sp-1].type == ps_num )
1360  if ( stack[sp-1].u.val < 0 )
1361  stack[sp-1].u.val = -stack[sp-1].u.val;
1362  }
1363  break;
1364  case pt_round:
1365  if ( sp>=1 ) {
1366  if ( stack[sp-1].type == ps_num )
1367  stack[sp-1].u.val = rint(stack[sp-1].u.val);
1368  /* rint isn't quite right, round will take 6.5 to 7, 5.5 to 6, etc. while rint() will take both to 6 */
1369  }
1370  break;
1371  case pt_floor:
1372  if ( sp>=1 ) {
1373  if ( stack[sp-1].type == ps_num )
1374  stack[sp-1].u.val = floor(stack[sp-1].u.val);
1375  }
1376  break;
1377  case pt_ceiling:
1378  if ( sp>=1 ) {
1379  if ( stack[sp-1].type == ps_num )
1380  stack[sp-1].u.val = ceil(stack[sp-1].u.val);
1381  }
1382  break;
1383  case pt_truncate:
1384  if ( sp>=1 ) {
1385  if ( stack[sp-1].type == ps_num ) {
1386  if ( stack[sp-1].u.val<0 )
1387  stack[sp-1].u.val = ceil(stack[sp-1].u.val);
1388  else
1389  stack[sp-1].u.val = floor(stack[sp-1].u.val);
1390  }
1391  }
1392  break;
1393  case pt_ne: case pt_eq:
1394  if ( sp>=2 ) {
1395  if ( stack[sp-2].type!=stack[sp-1].type )
1396  stack[sp-2].u.tf = false;
1397  else if ( stack[sp-2].type==ps_num )
1398  stack[sp-2].u.tf = (stack[sp-2].u.val == stack[sp-1].u.val);
1399  else if ( stack[sp-2].type==ps_bool )
1400  stack[sp-2].u.tf = (stack[sp-2].u.tf == stack[sp-1].u.tf);
1401  else
1402  stack[sp-2].u.tf = strcmp(stack[sp-2].u.str,stack[sp-1].u.str)==0 ;
1403  stack[sp-2].type = ps_bool;
1404  if ( tok==pt_ne ) stack[sp-2].u.tf = !stack[sp-2].u.tf;
1405  --sp;
1406  }
1407  break;
1408  case pt_gt: case pt_le: case pt_lt: case pt_ge:
1409  if ( sp>=2 ) {
1410  if ( stack[sp-2].type!=stack[sp-1].type )
1411  stack[sp-2].u.tf = false;
1412  else if ( stack[sp-2].type==ps_array )
1413  LogError( _("Can't compare arrays\n" ));
1414  else {
1415  int cmp;
1416  if ( stack[sp-2].type==ps_num )
1417  cmp = (stack[sp-2].u.val > stack[sp-1].u.val)?1:
1418  (stack[sp-2].u.val == stack[sp-1].u.val)?0:-1;
1419  else if ( stack[sp-2].type==ps_bool )
1420  cmp = (stack[sp-2].u.tf - stack[sp-1].u.tf);
1421  else
1422  cmp = strcmp(stack[sp-2].u.str,stack[sp-1].u.str);
1423  if ( tok==pt_gt )
1424  stack[sp-2].u.tf = cmp>0;
1425  else if ( tok==pt_lt )
1426  stack[sp-2].u.tf = cmp<0;
1427  else if ( tok==pt_le )
1428  stack[sp-2].u.tf = cmp<=0;
1429  else
1430  stack[sp-2].u.tf = cmp>=0;
1431  }
1432  stack[sp-2].type = ps_bool;
1433  --sp;
1434  }
1435  break;
1436  case pt_not:
1437  if ( sp>=1 ) {
1438  if ( stack[sp-1].type == ps_bool )
1439  stack[sp-1].u.tf = !stack[sp-1].u.tf;
1440  }
1441  break;
1442  case pt_and:
1443  if ( sp>=2 ) {
1444  if ( stack[sp-2].type == ps_num )
1445  stack[sp-2].u.val = ((int) stack[sp-1].u.val) & (int) stack[sp-1].u.val;
1446  else if ( stack[sp-2].type == ps_bool )
1447  stack[sp-2].u.tf &= stack[sp-1].u.tf;
1448  --sp;
1449  }
1450  break;
1451  case pt_or:
1452  if ( sp>=2 ) {
1453  if ( stack[sp-2].type == ps_num )
1454  stack[sp-2].u.val = ((int) stack[sp-1].u.val) | (int) stack[sp-1].u.val;
1455  else if ( stack[sp-2].type == ps_bool )
1456  stack[sp-2].u.tf |= stack[sp-1].u.tf;
1457  --sp;
1458  }
1459  break;
1460  case pt_xor:
1461  if ( sp>=2 ) {
1462  if ( stack[sp-2].type == ps_num )
1463  stack[sp-2].u.val = ((int) stack[sp-1].u.val) ^ (int) stack[sp-1].u.val;
1464  else if ( stack[sp-2].type == ps_bool )
1465  stack[sp-2].u.tf ^= stack[sp-1].u.tf;
1466  --sp;
1467  }
1468  break;
1469  case pt_exp:
1470  if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1471  stack[sp-2].u.val = pow(stack[sp-2].u.val,stack[sp-1].u.val);
1472  --sp;
1473  }
1474  break;
1475  case pt_sqrt:
1476  if ( sp>=1 && stack[sp-1].type==ps_num ) {
1477  stack[sp-1].u.val = sqrt(stack[sp-1].u.val);
1478  }
1479  break;
1480  case pt_ln:
1481  if ( sp>=1 && stack[sp-1].type==ps_num ) {
1482  stack[sp-1].u.val = log(stack[sp-1].u.val);
1483  }
1484  break;
1485  case pt_log:
1486  if ( sp>=1 && stack[sp-1].type==ps_num ) {
1487  stack[sp-1].u.val = log10(stack[sp-1].u.val);
1488  }
1489  break;
1490  case pt_atan:
1491  if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_num ) {
1492  stack[sp-2].u.val = atan2(stack[sp-2].u.val,stack[sp-1].u.val)*
1493  180/3.1415926535897932;
1494  --sp;
1495  }
1496  break;
1497  case pt_sin:
1498  if ( sp>=1 && stack[sp-1].type==ps_num ) {
1499  stack[sp-1].u.val = sin(stack[sp-1].u.val*3.1415926535897932/180);
1500  }
1501  break;
1502  case pt_cos:
1503  if ( sp>=1 && stack[sp-1].type==ps_num ) {
1504  stack[sp-1].u.val = cos(stack[sp-1].u.val*3.1415926535897932/180);
1505  }
1506  break;
1507  case pt_if:
1508  if ( sp>=2 ) {
1509  if ( ((stack[sp-2].type == ps_bool && stack[sp-2].u.tf) ||
1510  (stack[sp-2].type == ps_num && strstr(stack[sp-1].u.str,"setcachedevice")!=NULL)) &&
1511  stack[sp-1].type==ps_instr )
1512  pushio(wrapper,NULL,stack[sp-1].u.str,0);
1513  if ( stack[sp-1].type==ps_string || stack[sp-1].type==ps_instr || stack[sp-1].type==ps_lit )
1514  free(stack[sp-1].u.str);
1515  sp -= 2;
1516  } else if ( sp==1 && stack[sp-1].type==ps_instr ) {
1517  /*This can happen when reading our type3 fonts, we get passed */
1518  /* values on the stack which the interpreter knows nothing */
1519  /* about, but the interp needs to learn the width of the char */
1520  if ( strstr(stack[sp-1].u.str,"setcachedevice")!=NULL ||
1521  strstr(stack[sp-1].u.str,"setcharwidth")!=NULL )
1522  pushio(wrapper,NULL,stack[sp-1].u.str,0);
1523  free(stack[sp-1].u.str);
1524  sp = 0;
1525  }
1526  break;
1527  case pt_ifelse:
1528  if ( sp>=3 ) {
1529  if ( stack[sp-3].type == ps_bool && stack[sp-3].u.tf ) {
1530  if ( stack[sp-2].type==ps_instr )
1531  pushio(wrapper,NULL,stack[sp-2].u.str,0);
1532  } else {
1533  if ( stack[sp-1].type==ps_instr )
1534  pushio(wrapper,NULL,stack[sp-1].u.str,0);
1535  }
1536  if ( stack[sp-1].type==ps_string || stack[sp-1].type==ps_instr || stack[sp-1].type==ps_lit )
1537  free(stack[sp-1].u.str);
1538  if ( stack[sp-2].type==ps_string || stack[sp-2].type==ps_instr || stack[sp-2].type==ps_lit )
1539  free(stack[sp-2].u.str);
1540  sp -= 3;
1541  }
1542  break;
1543  case pt_for:
1544  if ( sp>=4 ) {
1545  real init, incr, limit;
1546  char *func;
1547  int cnt;
1548 
1549  if ( stack[sp-4].type == ps_num && stack[sp-3].type==ps_num &&
1550  stack[sp-2].type==ps_num && stack[sp-1].type==ps_instr ) {
1551  init = stack[sp-4].u.val;
1552  incr = stack[sp-3].u.val;
1553  limit = stack[sp-2].u.val;
1554  func = stack[sp-1].u.str;
1555  sp -= 4;
1556  cnt = 0;
1557  if ( incr>0 ) {
1558  while ( init<=limit ) { ++cnt; init += incr; }
1559  } else if ( incr<0 ) {
1560  while ( init>=limit ) { ++cnt; init += incr; }
1561  }
1562  pushio(wrapper,NULL,func,cnt);
1563  free(func);
1564  }
1565  }
1566  break;
1567  case pt_loop:
1568  if ( sp>=1 ) {
1569  char *func;
1570  int cnt;
1571 
1572  if ( stack[sp-1].type==ps_instr ) {
1573  cnt = 0x7fffffff; /* Loop for ever */
1574  func = stack[sp-1].u.str;
1575  --sp;
1576  pushio(wrapper,NULL,func,cnt);
1577  free(func);
1578  }
1579  }
1580  break;
1581  case pt_repeat:
1582  if ( sp>=2 ) {
1583  char *func;
1584  int cnt;
1585 
1586  if ( stack[sp-2].type==ps_num && stack[sp-1].type==ps_instr ) {
1587  cnt = stack[sp-2].u.val;
1588  func = stack[sp-1].u.str;
1589  sp -= 2;
1590  pushio(wrapper,NULL,func,cnt);
1591  free(func);
1592  }
1593  }
1594  break;
1595  case pt_exit:
1596  ioescapeloop(wrapper);
1597  break;
1598  case pt_stopped:
1599  if ( sp>=1 ) {
1600  char *func;
1601 
1602  if ( stack[sp-1].type==ps_instr ) {
1603  func = stack[sp-1].u.str;
1604  --sp;
1605  pushio(wrapper,NULL,func,-1);
1606  free(func);
1607  }
1608  }
1609  break;
1610  case pt_stop:
1611  sp = ioescapestopped(wrapper,stack,sp,sizeof(stack)/sizeof(stack[0]));
1612  break;
1613  case pt_load:
1614  if ( sp>=1 && stack[sp-1].type==ps_lit ) {
1615  kv = lookup(&dict,stack[sp-1].u.str);
1616  if ( kv!=NULL ) {
1617  free( stack[sp-1].u.str );
1618  stack[sp-1].type = kv->type;
1619  stack[sp-1].u = kv->u;
1620  if ( kv->type==ps_instr || kv->type==ps_lit )
1621  stack[sp-1].u.str = copy(stack[sp-1].u.str);
1622  } else
1623  stack[sp-1].type = ps_instr;
1624  }
1625  break;
1626  case pt_def:
1627  sp = AddEntry(&dict,stack,sp);
1628  break;
1629  case pt_bind:
1630  /* a noop in this context */
1631  break;
1632  case pt_setcachedevice:
1633  if ( sp>=6 ) {
1634  ec->width = stack[sp-6].u.val;
1635  ec->vwidth = stack[sp-5].u.val;
1636  /* I don't care about the bounding box */
1637  sp-=6;
1638  }
1639  break;
1640  case pt_setcharwidth:
1641  if ( sp>=2 )
1642  ec->width = stack[sp-=2].u.val;
1643  break;
1644  case pt_translate:
1645  if ( sp>=1 && stack[sp-1].type==ps_array )
1646  sp = DoMatOp(tok,sp,stack);
1647  else if ( sp>=2 ) {
1648  transform[4] += stack[sp-2].u.val*transform[0]+stack[sp-1].u.val*transform[2];
1649  transform[5] += stack[sp-2].u.val*transform[1]+stack[sp-1].u.val*transform[3];
1650  sp -= 2;
1651  }
1652  break;
1653  case pt_scale:
1654  if ( sp>=1 && stack[sp-1].type==ps_array )
1655  sp = DoMatOp(tok,sp,stack);
1656  else if ( sp>=2 ) {
1657  transform[0] *= stack[sp-2].u.val;
1658  transform[1] *= stack[sp-2].u.val;
1659  transform[2] *= stack[sp-1].u.val;
1660  transform[3] *= stack[sp-1].u.val;
1661  /* transform[4,5] are unchanged */
1662  sp -= 2;
1663  }
1664  break;
1665  case pt_rotate:
1666  if ( sp>=1 && stack[sp-1].type==ps_array )
1667  sp = DoMatOp(tok,sp,stack);
1668  else if ( sp>=1 ) {
1669  --sp;
1670  t[0] = t[3] = cos(stack[sp].u.val);
1671  t[1] = sin(stack[sp].u.val);
1672  t[2] = -t[1];
1673  t[4] = t[5] = 0;
1675  }
1676  break;
1677  case pt_concat:
1678  if ( sp>=1 ) {
1679  if ( stack[sp-1].type==ps_array ) {
1680  if ( stack[sp-1].u.dict.cnt==6 && stack[sp-1].u.dict.entries[0].type==ps_num ) {
1681  --sp;
1682  t[5] = stack[sp].u.dict.entries[5].u.val;
1683  t[4] = stack[sp].u.dict.entries[4].u.val;
1684  t[3] = stack[sp].u.dict.entries[3].u.val;
1685  t[2] = stack[sp].u.dict.entries[2].u.val;
1686  t[1] = stack[sp].u.dict.entries[1].u.val;
1687  t[0] = stack[sp].u.dict.entries[0].u.val;
1688  dictfree(&stack[sp].u.dict);
1690  }
1691  }
1692  }
1693  break;
1694  case pt_transform:
1695  if ( sp>=1 && stack[sp-1].type==ps_array ) {
1696  if ( sp>=3 ) {
1698  --sp;
1699  }
1700  } else if ( sp>=2 ) {
1701  double x = stack[sp-2].u.val, y = stack[sp-1].u.val;
1702  stack[sp-2].u.val = transform[0]*x + transform[1]*y + transform[4];
1703  stack[sp-1].u.val = transform[2]*x + transform[3]*y + transform[5];
1704  }
1705  break;
1706  case pt_itransform:
1707  if ( sp>=1 && stack[sp-1].type==ps_array ) {
1708  if ( sp>=3 ) {
1710  --sp;
1711  }
1712  } else if ( sp>=2 ) {
1713  double x = stack[sp-2].u.val, y = stack[sp-1].u.val;
1715  stack[sp-2].u.val = t[0]*x + t[1]*y + t[4];
1716  stack[sp-1].u.val = t[2]*x + t[3]*y + t[5];
1717  }
1718  break;
1719  case pt_dtransform:
1720  if ( sp>=1 && stack[sp-1].type==ps_array ) {
1721  if ( sp>=3 ) {
1723  --sp;
1724  }
1725  } else if ( sp>=2 ) {
1726  double x = stack[sp-2].u.val, y = stack[sp-1].u.val;
1727  stack[sp-2].u.val = transform[0]*x + transform[1]*y;
1728  stack[sp-1].u.val = transform[2]*x + transform[3]*y;
1729  }
1730  break;
1731  case pt_idtransform:
1732  if ( sp>=1 && stack[sp-1].type==ps_array ) {
1733  if ( sp>=3 ) {
1735  --sp;
1736  }
1737  } else if ( sp>=2 ) {
1738  double x = stack[sp-2].u.val, y = stack[sp-1].u.val;
1740  stack[sp-2].u.val = t[0]*x + t[1]*y;
1741  stack[sp-1].u.val = t[2]*x + t[3]*y;
1742  }
1743  break;
1744  case pt_namelit:
1745  if ( strcmp(tokbuf,"CharProcs")==0 && ec!=NULL ) {
1746  HandleType3Reference(wrapper,ec,transform,tokbuf,tokbufsize);
1747  } else if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1748  stack[sp].type = ps_lit;
1749  stack[sp++].u.str = copy(tokbuf);
1750  }
1751  break;
1752  case pt_exec:
1753  if ( sp>0 && stack[sp-1].type == ps_lit ) {
1754  ref = RefCharCreate();
1755  ref->sc = (SplineChar *) stack[--sp].u.str;
1756  memcpy(ref->transform,transform,sizeof(transform));
1757  if ( ec->refs==NULL )
1758  ec->refs = ref;
1759  else
1760  lastref->next = ref;
1761  lastref = ref;
1762  }
1763  break;
1764  case pt_newpath:
1766  head = NULL;
1767  cur = NULL;
1768  break;
1769  case pt_lineto: case pt_rlineto:
1770  case pt_moveto: case pt_rmoveto:
1771  if ( sp>=2 || tok==pt_newpath ) {
1772  if ( tok==pt_rlineto || tok==pt_rmoveto ) {
1773  current.x += stack[sp-2].u.val;
1774  current.y += stack[sp-1].u.val;
1775  sp -= 2;
1776  } else if ( tok==pt_lineto || tok == pt_moveto ) {
1777  current.x = stack[sp-2].u.val;
1778  current.y = stack[sp-1].u.val;
1779  sp -= 2;
1780  }
1781  pt = chunkalloc(sizeof(SplinePoint));
1782  Transform(&pt->me,&current,transform);
1783  pt->noprevcp = true; pt->nonextcp = true;
1784  if ( tok==pt_moveto || tok==pt_rmoveto ) {
1785  SplinePointList *spl = chunkalloc(sizeof(SplinePointList));
1786  spl->first = spl->last = pt;
1787  if ( cur!=NULL )
1788  cur->next = spl;
1789  else
1790  head = spl;
1791  cur = spl;
1792  } else {
1793  if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
1794  CheckMake(cur->last,pt);
1795  SplineMake3(cur->last,pt);
1796  cur->last = pt;
1797  }
1798  }
1799  } else
1800  sp = 0;
1801  break;
1802  case pt_curveto: case pt_rcurveto:
1803  if ( sp>=6 ) {
1804  if ( tok==pt_rcurveto ) {
1805  stack[sp-1].u.val += current.y;
1806  stack[sp-3].u.val += current.y;
1807  stack[sp-5].u.val += current.y;
1808  stack[sp-2].u.val += current.x;
1809  stack[sp-4].u.val += current.x;
1810  stack[sp-6].u.val += current.x;
1811  }
1812  current.x = stack[sp-2].u.val;
1813  current.y = stack[sp-1].u.val;
1814  if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
1815  temp.x = stack[sp-6].u.val; temp.y = stack[sp-5].u.val;
1816  Transform(&cur->last->nextcp,&temp,transform);
1817  cur->last->nonextcp = false;
1818  pt = chunkalloc(sizeof(SplinePoint));
1819  temp.x = stack[sp-4].u.val; temp.y = stack[sp-3].u.val;
1820  Transform(&pt->prevcp,&temp,transform);
1821  Transform(&pt->me,&current,transform);
1822  pt->nonextcp = true;
1823  CheckMake(cur->last,pt);
1824  SplineMake3(cur->last,pt);
1825  cur->last = pt;
1826  }
1827  sp -= 6;
1828  } else
1829  sp = 0;
1830  break;
1831  case pt_arc: case pt_arcn:
1832  if ( sp>=5 ) {
1833  real cx, cy, r, a1, a2;
1834  cx = stack[sp-5].u.val;
1835  cy = stack[sp-4].u.val;
1836  r = stack[sp-3].u.val;
1837  a1 = stack[sp-2].u.val;
1838  a2 = stack[sp-1].u.val;
1839  sp -= 5;
1840  temp.x = cx+r*cos(a1/180 * 3.1415926535897932);
1841  temp.y = cy+r*sin(a1/180 * 3.1415926535897932);
1842  if ( temp.x!=current.x || temp.y!=current.y ||
1843  !( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) )) {
1844  pt = chunkalloc(sizeof(SplinePoint));
1845  Transform(&pt->me,&temp,transform);
1846  pt->noprevcp = true; pt->nonextcp = true;
1847  if ( cur!=NULL && cur->first!=NULL && (cur->first!=cur->last || cur->first->next==NULL) ) {
1848  CheckMake(cur->last,pt);
1849  SplineMake3(cur->last,pt);
1850  cur->last = pt;
1851  } else { /* if no current point, then start here */
1852  SplinePointList *spl = chunkalloc(sizeof(SplinePointList));
1853  spl->first = spl->last = pt;
1854  if ( cur!=NULL )
1855  cur->next = spl;
1856  else
1857  head = spl;
1858  cur = spl;
1859  }
1860  }
1862  current.x = cx+r*cos(a2/180 * 3.1415926535897932);
1863  current.y = cy+r*sin(a2/180 * 3.1415926535897932);
1864  } else
1865  sp = 0;
1866  break;
1867  case pt_arct: case pt_arcto:
1868  if ( sp>=5 ) {
1869  real x1, y1, x2, y2, r;
1870  real xt1, xt2, yt1, yt2;
1871  x1 = stack[sp-5].u.val;
1872  y1 = stack[sp-4].u.val;
1873  x2 = stack[sp-3].u.val;
1874  y2 = stack[sp-2].u.val;
1875  r = stack[sp-1].u.val;
1876  sp -= 5;
1877 
1878  xt1 = xt2 = x1; yt1 = yt2 = y1;
1879  if ( cur==NULL || cur->first==NULL || (cur->first==cur->last && cur->first->next!=NULL) )
1880  /* Error */;
1881  else if ( current.x==x1 && current.y==y1 )
1882  /* Error */;
1883  else if (( x1==x2 && y1==y2 ) ||
1884  (current.x-x1)*(y2-y1) == (x2-x1)*(current.y-y1) ) {
1885  /* Degenerate case */
1886  current.x = x1; current.y = y1;
1887  pt = chunkalloc(sizeof(SplinePoint));
1888  Transform(&pt->me,&current,transform);
1889  pt->noprevcp = true; pt->nonextcp = true;
1890  CheckMake(cur->last,pt);
1891  SplineMake3(cur->last,pt);
1892  cur->last = pt;
1893  } else {
1894  real l1 = sqrt((current.x-x1)*(current.x-x1)+(current.y-y1)*(current.y-y1));
1895  real l2 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
1896  real dx = ((current.x-x1)/l1 + (x2-x1)/l2);
1897  real dy = ((current.y-y1)/l1 + (y2-y1)/l2);
1898  /* the line from (x1,y1) to (x1+dx,y1+dy) contains the center*/
1899  real l3 = sqrt(dx*dx+dy*dy);
1900  real cx, cy, t, tmid;
1901  real a1, amid, a2;
1902  int clockwise = true;
1903  dx /= l3; dy /= l3;
1904  a1 = atan2(current.y-y1,current.x-x1);
1905  a2 = atan2(y2-y1,x2-x1);
1906  amid = atan2(dy,dx) - a1;
1907  tmid = r/sin(amid);
1908  t = r/tan(amid);
1909  if ( t<0 ) {
1910  clockwise = false;
1911  t = -t;
1912  tmid = -tmid;
1913  }
1914  cx = x1+ tmid*dx; cy = y1 + tmid*dy;
1915  xt1 = x1 + t*(current.x-x1)/l1; yt1 = y1 + t*(current.y-y1)/l1;
1916  xt2 = x1 + t*(x2-x1)/l2; yt2 = y1 + t*(y2-y1)/l2;
1917  if ( xt1!=current.x || yt1!=current.y ) {
1918  DBasePoint temp;
1919  temp.x = xt1; temp.y = yt1;
1920  pt = chunkalloc(sizeof(SplinePoint));
1921  Transform(&pt->me,&temp,transform);
1922  pt->noprevcp = true; pt->nonextcp = true;
1923  CheckMake(cur->last,pt);
1924  SplineMake3(cur->last,pt);
1925  cur->last = pt;
1926  }
1927  a1 = 3*3.1415926535897932/2+a1;
1928  a2 = 3.1415926535897932/2+a2;
1929  if ( !clockwise ) {
1930  a1 += 3.1415926535897932;
1931  a2 += 3.1415926535897932;
1932  }
1933  circlearcsto(a1*180/3.1415926535897932,a2*180/3.1415926535897932,
1935  }
1936  if ( tok==pt_arcto ) {
1937  stack[sp].type = stack[sp+1].type = stack[sp+2].type = stack[sp+3].type = ps_num;
1938  stack[sp++].u.val = xt1;
1939  stack[sp++].u.val = yt1;
1940  stack[sp++].u.val = xt2;
1941  stack[sp++].u.val = yt2;
1942  }
1943  current.x = xt2; current.y = yt2;
1944  }
1945  break;
1946  case pt_closepath:
1947  if ( cur!=NULL && cur->first!=NULL && cur->first!=cur->last ) {
1948  if ( RealNear(cur->first->me.x,cur->last->me.x) && RealNear(cur->first->me.y,cur->last->me.y) ) {
1949  SplinePoint *oldlast = cur->last;
1950  cur->first->prevcp = oldlast->prevcp;
1951  cur->first->prevcp.x += (cur->first->me.x-oldlast->me.x);
1952  cur->first->prevcp.y += (cur->first->me.y-oldlast->me.y);
1953  cur->first->noprevcp = oldlast->noprevcp;
1954  oldlast->prev->from->next = NULL;
1955  cur->last = oldlast->prev->from;
1956  SplineFree(oldlast->prev);
1957  SplinePointFree(oldlast);
1958  }
1959  CheckMake(cur->last,cur->first);
1960  SplineMake3(cur->last,cur->first);
1961  cur->last = cur->first;
1962  }
1963  break;
1964  case pt_setlinecap:
1965  if ( sp>=1 )
1966  linecap = stack[--sp].u.val;
1967  break;
1968  case pt_setlinejoin:
1969  if ( sp>=1 )
1970  linejoin = stack[--sp].u.val;
1971  break;
1972  case pt_setlinewidth:
1973  if ( sp>=1 )
1974  linewidth = stack[--sp].u.val;
1975  break;
1976  case pt_setdash:
1977  if ( sp>=2 && stack[sp-1].type==ps_num && stack[sp-2].type==ps_array ) {
1978  sp -= 2;
1979  dash_offset = stack[sp+1].u.val;
1980  for ( i=0; i<DASH_MAX && i<stack[sp].u.dict.cnt; ++i )
1981  dashes[i] = stack[sp].u.dict.entries[i].u.val;
1982  dictfree(&stack[sp].u.dict);
1983  }
1984  break;
1986  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1987  stack[sp].type = ps_num;
1989  }
1990  break;
1991  case pt_currentlinewidth:
1992  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1993  stack[sp].type = ps_num;
1994  stack[sp++].u.val = linewidth;
1995  }
1996  break;
1997  case pt_currentdash:
1998  if ( sp+1<(int)(sizeof(stack)/sizeof(stack[0])) ) {
1999  struct pskeydict dict;
2000  dict.is_executable = 0;
2001  for ( i=0; i<DASH_MAX && dashes[i]!=0; ++i );
2002  dict.cnt = dict.max = i;
2003  dict.entries = gcalloc(i,sizeof(struct pskeyval));
2004  for ( j=0; j<i; ++j ) {
2005  dict.entries[j].type = ps_num;
2006  dict.entries[j].u.val = dashes[j];
2007  }
2008  stack[sp].type = ps_array;
2009  stack[sp++].u.dict = dict;
2010  stack[sp].type = ps_num;
2011  stack[sp++].u.val = dash_offset;
2012  }
2013  break;
2014  case pt_currentgray:
2015  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2016  stack[sp].type = ps_num;
2017  stack[sp++].u.val = (3*((fore>>16)&0xff) + 6*((fore>>8)&0xff) + (fore&0xff))/2550.;
2018  }
2019  break;
2020  case pt_setgray:
2021  if ( sp>=1 ) {
2022  fore = stack[--sp].u.val*255;
2023  fore *= 0x010101;
2024  }
2025  break;
2026  case pt_setrgbcolor:
2027  if ( sp>=3 ) {
2028  fore = (((int) (stack[sp-3].u.val*255))<<16) +
2029  (((int) (stack[sp-2].u.val*255))<<8) +
2030  (int) (stack[sp-1].u.val*255);
2031  sp -= 3;
2032  }
2033  break;
2035  if ( sp+2<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2036  stack[sp].type = stack[sp+1].type = stack[sp+2].type = ps_num;
2037  if ( tok==pt_currentrgbcolor ) {
2038  stack[sp++].u.val = ((fore>>16)&0xff)/255.;
2039  stack[sp++].u.val = ((fore>>8)&0xff)/255.;
2040  stack[sp++].u.val = (fore&0xff)/255.;
2041  } else {
2042  int r=fore>>16, g=(fore>>8)&0xff, bl=fore&0xff;
2043  int mx, mn;
2044  real h, s, b;
2045  mx = mn = r;
2046  if ( mx>g ) mn=g; else mx=g;
2047  if ( mx<bl ) mx = bl; if ( mn>bl ) mn = bl;
2048  b = mx/255.;
2049  s = h = 0;
2050  if ( mx>0 )
2051  s = ((real) (mx-mn))/mx;
2052  if ( s!=0 ) {
2053  real rdiff = ((real) (mx-r))/(mx-mn);
2054  real gdiff = ((real) (mx-g))/(mx-mn);
2055  real bdiff = ((real) (mx-bl))/(mx-mn);
2056  if ( rdiff==0 )
2057  h = bdiff-gdiff;
2058  else if ( gdiff==0 )
2059  h = 2 + rdiff-bdiff;
2060  else
2061  h = 4 + gdiff-rdiff;
2062  h /= 6;
2063  if ( h<0 ) h += 1;
2064  }
2065  stack[sp++].u.val = h;
2066  stack[sp++].u.val = s;
2067  stack[sp++].u.val = b;
2068  }
2069  }
2070  break;
2071  case pt_sethsbcolor:
2072  if ( sp>=3 ) {
2073  real h = stack[sp-3].u.val, s = stack[sp-2].u.val, b = stack[sp-1].u.val;
2074  int r=0,g=0,bl=0;
2075  if ( s==0 ) /* it's grey */
2076  fore = ((int) (b*255)) * 0x010101;
2077  else {
2078  real sextant = (h-floor(h))*6;
2079  real mod = sextant-floor(sextant);
2080  real p = b*(1-s), q = b*(1-s*mod), t = b*(1-s*(1-mod));
2081  switch( (int) sextant) {
2082  case 0:
2083  r = b*255.; g = t*255.; bl = p*255.;
2084  break;
2085  case 1:
2086  r = q*255.; g = b*255.; bl = p*255.;
2087  break;
2088  case 2:
2089  r = p*255.; g = b*255.; bl = t*255.;
2090  break;
2091  case 3:
2092  r = p*255.; g = q*255.; bl = b*255.;
2093  break;
2094  case 4:
2095  r = t*255.; g = p*255.; bl = b*255.;
2096  break;
2097  case 5:
2098  r = b*255.; g = p*255.; bl = q*255.;
2099  break;
2100  }
2101  fore = COLOR_CREATE(r,g,bl);
2102  }
2103  sp -= 3;
2104  }
2105  break;
2106  case pt_currentcmykcolor:
2107  if ( sp+3<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2108  real c,m,y,k;
2109  stack[sp].type = stack[sp+1].type = stack[sp+2].type = stack[sp+3].type = ps_num;
2110  y = 1.-(fore&0xff)/255.;
2111  m = 1.-((fore>>8)&0xff)/255.;
2112  c = 1.-((fore>>16)&0xff)/255.;
2113  k = y; if ( k>m ) k=m; if ( k>c ) k=c;
2114  if ( k!=1 ) {
2115  y = (y-k)/(1-k);
2116  m = (m-k)/(1-k);
2117  c = (c-k)/(1-k);
2118  } else
2119  y = m = c = 0;
2120  stack[sp++].u.val = c;
2121  stack[sp++].u.val = m;
2122  stack[sp++].u.val = y;
2123  stack[sp++].u.val = k;
2124  }
2125  break;
2126  case pt_setcmykcolor:
2127  if ( sp>=4 ) {
2128  real c=stack[sp-4].u.val,m=stack[sp-3].u.val,y=stack[sp-2].u.val,k=stack[sp-1].u.val;
2129  sp -= 4;
2130  if ( k==1 )
2131  fore = 0x000000;
2132  else {
2133  if (( y = (1-k)*y+k )<0 ) y=0; else if ( y>1 ) y=1;
2134  if (( m = (1-k)*m+k )<0 ) m=0; else if ( m>1 ) m=1;
2135  if (( c = (1-k)*c+k )<0 ) c=0; else if ( c>1 ) c=1;
2136  fore = ((int) ((1-c)*255.)<<16) |
2137  ((int) ((1-m)*255.)<<8) |
2138  ((int) ((1-y)*255.));
2139  }
2140  }
2141  break;
2142  case pt_currentpoint:
2143  if ( sp+1<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2144  stack[sp].type = ps_num;
2145  stack[sp++].u.val = current.x;
2146  stack[sp].type = ps_num;
2147  stack[sp++].u.val = current.y;
2148  }
2149  break;
2150  case pt_fill: case pt_stroke:
2151  if ( head==NULL && ec->splines!=NULL ) {
2152  /* assume they did a "gsave fill grestore stroke" (or reverse)*/
2153  ent = ec->splines;
2154  if ( tok==pt_stroke ) {
2155  ent->u.splines.cap = linecap; ent->u.splines.join = linejoin;
2156  ent->u.splines.stroke_width = linewidth;
2157  memcpy(ent->u.splines.transform,transform,sizeof(transform));
2158  }
2159  } else {
2160  ent = EntityCreate(head,linecap,linejoin,linewidth,transform,clippath);
2161  ent->next = ec->splines;
2162  ec->splines = ent;
2163  }
2164  if ( tok==pt_fill )
2165  ent->u.splines.fill.col = fore;
2166  else
2167  ent->u.splines.stroke.col = fore;
2168  head = NULL; cur = NULL;
2169  break;
2170  case pt_clip:
2171  /* I really should intersect the old clip path with the new, but */
2172  /* I don't trust my intersect routine, crashes too often */
2173  SplinePointListsFree(clippath);
2174  clippath = SplinePointListCopy(head);
2175  if ( clippath!=NULL && clippath->first!=clippath->last ) {
2176  SplineMake3(clippath->last,clippath->first);
2177  clippath->last = clippath->first;
2178  }
2179  break;
2180  case pt_imagemask:
2181  LogError( _("This version of FontForge does not support the imagemask operator.\nFor support configure --with-multilayer.\n") );
2182  if ( sp>=5 && (stack[sp-1].type==ps_instr || stack[sp-1].type==ps_string))
2183  sp -= 5;
2184  break;
2185 
2186  /* We don't do these right, but at least we'll avoid some errors with this hack */
2187  case pt_save: case pt_currentmatrix:
2188  /* push some junk on the stack */
2189  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2190  stack[sp].type = ps_num;
2191  stack[sp++].u.val = 0;
2192  }
2193  /* Fall through into gsave */;
2194  case pt_gsave:
2195  if ( gsp<30 ) {
2196  memcpy(gsaves[gsp].transform,transform,sizeof(transform));
2197  gsaves[gsp].current = current;
2198  gsaves[gsp].linewidth = linewidth;
2199  gsaves[gsp].linecap = linecap;
2200  gsaves[gsp].linejoin = linejoin;
2201  gsaves[gsp].fore = fore;
2202  gsaves[gsp].clippath = SplinePointListCopy(clippath);
2203  ++gsp;
2204  /* I should be saving the "current path" too, but that's too hard */
2205  }
2206  break;
2207  case pt_restore: case pt_setmatrix:
2208  /* pop some junk off the stack */
2209  if ( sp>=1 )
2210  --sp;
2211  /* Fall through into grestore */;
2212  case pt_grestore:
2213  if ( gsp>0 ) {
2214  --gsp;
2215  memcpy(transform,gsaves[gsp].transform,sizeof(transform));
2216  current = gsaves[gsp].current;
2217  linewidth = gsaves[gsp].linewidth;
2218  linecap = gsaves[gsp].linecap;
2219  linejoin = gsaves[gsp].linejoin;
2220  fore = gsaves[gsp].fore;
2221  SplinePointListsFree(clippath);
2222  clippath = gsaves[gsp].clippath;
2223  }
2224  break;
2225  case pt_null:
2226  /* push a 0. I don't handle pointers properly */
2227  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2228  stack[sp].u.val = 0;
2229  stack[sp++].type = ps_num;
2230  }
2231  break;
2232  case pt_currentoverprint:
2233  /* push false. I don't handle this properly */
2234  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2235  stack[sp].u.val = 0;
2236  stack[sp++].type = ps_bool;
2237  }
2238  break;
2239  case pt_setoverprint:
2240  /* pop one item on stack */
2241  if ( sp>=1 )
2242  --sp;
2243  break;
2244  case pt_currentflat:
2245  /* push 1.0 (default value). I don't handle this properly */
2246  if ( sp<(int)(sizeof(stack)/sizeof(stack[0]) )) {
2247  stack[sp].u.val = 1.0;
2248  stack[sp++].type = ps_num;
2249  }
2250  break;
2251  case pt_setflat:
2252  /* pop one item on stack */
2253  if ( sp>=1 )
2254  --sp;
2255  break;
2256  case pt_currentmiterlimit:
2257  /* push 10.0 (default value). I don't handle this properly */
2258  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2259  stack[sp].u.val = 10.0;
2260  stack[sp++].type = ps_num;
2261  }
2262  break;
2263  case pt_setmiterlimit:
2264  /* pop one item off stack */
2265  if ( sp>=1 )
2266  --sp;
2267  break;
2268  case pt_currentpacking:
2269  /* push false (default value). I don't handle this properly */
2270  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2271  stack[sp].u.val = 0;
2272  stack[sp++].type = ps_bool;
2273  }
2274  break;
2275  case pt_setpacking:
2276  /* pop one item on stack */
2277  if ( sp>=1 )
2278  --sp;
2279  break;
2281  /* push false (default value). I don't handle this properly */
2282  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2283  stack[sp].u.val = 0;
2284  stack[sp++].type = ps_bool;
2285  }
2286  break;
2287  case pt_setstrokeadjust:
2288  /* pop one item on stack */
2289  if ( sp>=1 )
2290  --sp;
2291  break;
2292  case pt_currentsmoothness:
2293  /* default value is installation dependant. I don't handle this properly */
2294  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2295  stack[sp].u.val = 1.0;
2296  stack[sp++].type = ps_num;
2297  }
2298  break;
2299  case pt_setsmoothness:
2300  /* pop one item on stack */
2301  if ( sp>=1 )
2302  --sp;
2303  break;
2305  /* default value is installation dependant. I don't handle this properly */
2306  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2307  stack[sp].u.val = 0.0;
2308  stack[sp++].type = ps_num;
2309  }
2310  break;
2311  case pt_setobjectformat:
2312  /* pop one item on stack */
2313  if ( sp>=1 )
2314  --sp;
2315  break;
2317  /* push false (default value). I don't handle this properly */
2318  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2319  stack[sp].u.val = 0;
2320  stack[sp++].type = ps_bool;
2321  }
2322  break;
2323  case pt_setglobal:
2324  /* pop one item on stack */
2325  if ( sp>=1 )
2326  --sp;
2327  break;
2328 
2329  case pt_openarray: case pt_mark:
2330  if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2331  stack[sp++].type = ps_mark;
2332  }
2333  break;
2334  case pt_counttomark:
2335  for ( i=0; i<sp; ++i )
2336  if ( stack[sp-1-i].type==ps_mark )
2337  break;
2338  if ( i==sp )
2339  LogError( _("No mark in counttomark\n") );
2340  else if ( sp<(int)(sizeof(stack)/sizeof(stack[0])) ) {
2341  stack[sp].type = ps_num;
2342  stack[sp++].u.val = i;
2343  }
2344  break;
2345  case pt_cleartomark:
2346  for ( i=0; i<sp; ++i )
2347  if ( stack[sp-1-i].type==ps_mark )
2348  break;
2349  if ( i==sp )
2350  LogError( _("No mark in cleartomark\n") );
2351  else {
2352  while ( sp>=i ) {
2353  --sp;
2354  if ( stack[sp].type==ps_string || stack[sp].type==ps_instr ||
2355  stack[sp].type==ps_lit )
2356  free(stack[sp].u.str);
2357  else if ( stack[sp].type==ps_array || stack[sp].type==ps_dict )
2358  dictfree(&stack[sp].u.dict);
2359  }
2360  }
2361  break;
2362  case pt_closearray:
2363  for ( i=0; i<sp; ++i )
2364  if ( stack[sp-1-i].type==ps_mark )
2365  break;
2366  if ( i==sp )
2367  LogError( _("No mark in ] (close array)\n") );
2368  else {
2369  struct pskeydict dict;
2370  dict.is_executable = 0;
2371  dict.cnt = dict.max = i;
2372  dict.entries = gcalloc(i,sizeof(struct pskeyval));
2373  for ( j=0; j<i; ++j ) {
2374  dict.entries[j].type = stack[sp-i+j].type;
2375  dict.entries[j].u = stack[sp-i+j].u;
2376  /* don't need to copy because the things on the stack */
2377  /* are being popped (don't need to free either) */
2378  }
2379  collectgarbage(&tofrees,&dict);
2380  sp = sp-i;
2381  stack[sp-1].type = ps_array;
2382  stack[sp-1].u.dict = dict;
2383  }
2384  break;
2385  case pt_array:
2386  if ( sp>=1 && stack[sp-1].type==ps_num ) {
2387  struct pskeydict dict;
2388  dict.is_executable = 0;
2389  dict.cnt = dict.max = stack[sp-1].u.val;
2390  dict.entries = gcalloc(dict.cnt,sizeof(struct pskeyval));
2391  /* all entries are inited to void */
2392  stack[sp-1].type = ps_array;
2393  stack[sp-1].u.dict = dict;
2394  }
2395  break;
2396  case pt_aload:
2397  sp = aload(sp,stack,sizeof(stack)/sizeof(stack[0]),&tofrees);
2398  break;
2399  case pt_astore:
2400  if ( sp>=1 && stack[sp-1].type==ps_array ) {
2401  struct pskeydict dict;
2402  --sp;
2403  dict = stack[sp].u.dict;
2404  if ( sp>=dict.cnt ) {
2405  for ( i=dict.cnt-1; i>=0 ; --i ) {
2406  --sp;
2407  dict.entries[i].type = stack[sp].type;
2408  dict.entries[i].u = stack[sp].u;
2409  }
2410  }
2411  stack[sp].type = ps_array;
2412  stack[sp].u.dict = dict;
2413  ++sp;
2414  }
2415  break;
2416 
2417  case pt_output: case pt_outputd: case pt_print:
2418  if ( sp>=1 ) {
2419  --sp;
2420  switch ( stack[sp].type ) {
2421  case ps_num:
2422  printf( "%g", (double) stack[sp].u.val );
2423  break;
2424  case ps_bool:
2425  printf( "%s", stack[sp].u.tf ? "true" : "false" );
2426  break;
2427  case ps_string: case ps_instr: case ps_lit:
2428  if ( tok==pt_outputd )
2429  printf( stack[sp].type==ps_lit ? "/" :
2430  stack[sp].type==ps_string ? "(" : "{" );
2431  printf( "%s", stack[sp].u.str );
2432  if ( tok==pt_outputd )
2433  printf( stack[sp].type==ps_lit ? "" :
2434  stack[sp].type==ps_string ? ")" : "}" );
2435  free(stack[sp].u.str);
2436  break;
2437  case ps_void:
2438  printf( "-- void --" );
2439  break;
2440  case ps_array:
2441  if ( tok==pt_outputd ) {
2442  printarray(&stack[sp].u.dict);
2443  dictfree(&stack[sp].u.dict);
2444  break;
2445  } /* else fall through */
2446  dictfree(&stack[sp].u.dict);
2447  default:
2448  printf( "-- nostringval --" );
2449  break;
2450  }
2451  if ( tok==pt_output || tok==pt_outputd )
2452  printf( "\n" );
2453  } else
2454  LogError( _("Nothing on stack to print\n") );
2455  break;
2456 
2457  case pt_cvi: case pt_cvr:
2458  /* I shan't distinguish between integers and reals */
2459  if ( sp>=1 && stack[sp-1].type==ps_string ) {
2460  double val = strtod(stack[sp-1].u.str,NULL);
2461  free(stack[sp-1].u.str);
2462  stack[sp-1].u.val = val;
2463  stack[sp-1].type = ps_num;
2464  }
2465  break;
2466  case pt_cvlit:
2467  if ( sp>=1 ) {
2468  if ( stack[sp-1].type==ps_array )
2469  stack[sp-1].u.dict.is_executable = false;
2470  }
2471  case pt_cvn:
2472  if ( sp>=1 ) {
2473  if ( stack[sp-1].type==ps_string )
2474  stack[sp-1].type = ps_lit;
2475  }
2476  case pt_cvx:
2477  if ( sp>=1 ) {
2478  if ( stack[sp-1].type==ps_array )
2479  stack[sp-1].u.dict.is_executable = true;
2480  }
2481  break;
2482  case pt_cvrs:
2483  if ( sp>=3 && stack[sp-1].type==ps_string &&
2484  stack[sp-2].type==ps_num &&
2485  stack[sp-3].type==ps_num ) {
2486  if ( stack[sp-2].u.val==8 )
2487  sprintf( stack[sp-1].u.str, "%o", (int) stack[sp-3].u.val );
2488  else if ( stack[sp-2].u.val==16 )
2489  sprintf( stack[sp-1].u.str, "%X", (int) stack[sp-3].u.val );
2490  else /* default to radix 10 no matter what they asked for */
2491  sprintf( stack[sp-1].u.str, "%g", (double) stack[sp-3].u.val );
2492  stack[sp-3] = stack[sp-1];
2493  sp-=2;
2494  }
2495  break;
2496  case pt_cvs:
2497  if ( sp>=2 && stack[sp-1].type==ps_string ) {
2498  switch ( stack[sp].type ) {
2499  case ps_num:
2500  sprintf( stack[sp-1].u.str, "%g", (double) stack[sp-2].u.val );
2501  break;
2502  case ps_bool:
2503  sprintf( stack[sp-1].u.str, "%s", stack[sp-2].u.tf ? "true" : "false" );
2504  break;
2505  case ps_string: case ps_instr: case ps_lit:
2506  sprintf( stack[sp-1].u.str, "%s", stack[sp-2].u.str );
2507  free(stack[sp].u.str);
2508  break;
2509  case ps_void:
2510  printf( "-- void --" );
2511  break;
2512  case ps_array:
2513  dictfree(&stack[sp].u.dict);
2514  default:
2515  sprintf( stack[sp-1].u.str, "-- nostringval --" );
2516  break;
2517  }
2518  stack[sp-2] = stack[sp-1];
2519  --sp;
2520  }
2521  break;
2522  case pt_stringop: /* the string keyword, not the () thingy */
2523  if ( sp>=1 && stack[sp-1].type==ps_num ) {
2524  stack[sp-1].type = ps_string;
2525  stack[sp-1].u.str = gcalloc(stack[sp-1].u.val+1,1);
2526  }
2527  break;
2528 
2529  case pt_unknown:
2530  if ( !warned ) {
2531  LogError( _("Warning: Unable to parse token %s, some features may be lost\n"), tokbuf );
2532  warned = true;
2533  }
2534  break;
2535 
2536  default:
2537  break;
2538  }}
2539  }
2540  done:
2541  if ( rs!=NULL ) {
2542  int i, cnt, j;
2543  for ( i=sp-1; i>=0; --i )
2544  if ( stack[i].type!=ps_num )
2545  break;
2546  cnt = sp-1-i;
2547  if ( cnt>rs->max ) cnt = rs->max;
2548  rs->cnt = cnt;
2549  for ( j=i+1; j<sp; ++j )
2550  rs->stack[j-i-1] = stack[j].u.val;
2551  }
2552  freestuff(stack,sp,&dict,&gb,&tofrees);
2553  if ( head!=NULL ) {
2554  ent = EntityCreate(head,linecap,linejoin,linewidth,transform,clippath);
2555  ent->next = ec->splines;
2556  ec->splines = ent;
2557  }
2558  while ( gsp>0 ) {
2559  --gsp;
2560  SplinePointListsFree(gsaves[gsp].clippath);
2561  }
2562  SplinePointListsFree(clippath);
2564  if ( ec->width == UNDEFINED_WIDTH )
2565  ec->width = wrapper->advance_width;
2566  setlocale(LC_NUMERIC,oldloc);
2567 }
2568 
2569 static void InterpretPS(FILE *ps, char *psstr, EntityChar *ec, RetStack *rs) {
2570  IO wrapper;
2571 
2572  memset(&wrapper,0,sizeof(wrapper));
2573  wrapper.advance_width = UNDEFINED_WIDTH;
2574  pushio(&wrapper,ps,psstr,0);
2575  _InterpretPS(&wrapper,ec,rs);
2576 }
2577 
2579  SplineSet *spl, *last;
2580  SplinePoint *sp;
2581 
2582  if ( head==NULL ) {
2583  /* Pointless, but legal */
2584  SplinePointListsFree(erase);
2585 return( NULL );
2586  }
2587 
2588  last = NULL;
2589  for ( spl=head; spl!=NULL; spl=spl->next ) {
2590  for ( sp=spl->first; sp!=NULL; ) {
2591  sp->selected = false;
2592  if ( sp->next==NULL )
2593  break;
2594  sp = sp->next->to;
2595  if ( sp==spl->first )
2596  break;
2597  }
2598  last = spl;
2599  }
2600  for ( spl=erase; spl!=NULL; spl=spl->next ) {
2601  for ( sp=spl->first; sp!=NULL; ) {
2602  sp->selected = true;
2603  if ( sp->next==NULL )
2604  break;
2605  sp = sp->next->to;
2606  if ( sp==spl->first )
2607  break;
2608  }
2609  }
2610  last->next = erase;
2612 }
2613 
2614 static Entity *EntityReverse(Entity *ent) {
2615  Entity *next, *last = NULL;
2616 
2617  while ( ent!=NULL ) {
2618  next = ent->next;
2619  ent->next = last;
2620  last = ent;
2621  ent = next;
2622  }
2623 return( last );
2624 }
2625 
2626 void SFSplinesFromLayers(SplineFont *sf, int tostroke) {
2627  (void)sf;
2628  (void)tostroke;
2629 }
2630 
2632  SplineSet *ss;
2633  Entity *ent;
2634  int changed;
2635 
2636  for ( ent=ec->splines; ent!=NULL; ent = ent->next ) {
2637  /* ignore splines which are only stoked, but not filled */
2638  if ( ent->type == et_splines && ent->u.splines.fill.col!=0xffffffff ) {
2639  /* Correct the direction of each stroke or fill with respect to */
2640  /* the splines in it */
2642  if ( ent->u.splines.fill.col==0xffffff ) {
2643  /* If they are filling with white, then assume they mean */
2644  /* an internal area that should be drawn backwards */
2645  for ( ss=ent->u.splines.splines; ss!=NULL; ss=ss->next )
2646  SplineSetReverse(ss);
2647  }
2649  }
2650  }
2651 }
2652 
2653 static void EntityDefaultStrokeFill(Entity *ent) {
2654  while ( ent!=NULL ) {
2655  if ( ent->type == et_splines &&
2656  ent->u.splines.stroke.col==0xffffffff &&
2657  ent->u.splines.fill.col==0xffffffff ) {
2658  SplineSet *spl;
2659  int all=1;
2660  for ( spl=ent->u.splines.splines; spl!=NULL; spl=spl->next )
2661  if ( spl->first->prev!=NULL ) {
2662  all = false;
2663  break;
2664  }
2665  if ( all && ent->u.splines.splines!=NULL &&
2667  ent->u.splines.stroke_width=40; /* random guess */
2669  ent->u.splines.fill.col = COLOR_INHERITED;
2670  else
2672  }
2673  ent = ent->next;
2674  }
2675 }
2676 
2678  Entity *ent, *next;
2679  SplinePointList *head=NULL, *last=NULL, *new, *nlast=NULL, *temp, *each, *transed;
2680  StrokeInfo si;
2681  real inversetrans[6];
2682  /*SplineSet *spl;*/
2683  int handle_eraser = false;
2684  int ask = false;
2685 
2686  EntityDefaultStrokeFill(ec->splines);
2687 
2688  if ( !is_stroked ) {
2689 
2690  if ( *flags==-1 ) {
2691  for ( ent=ec->splines; ent!=NULL; ent = ent->next ) {
2692  if ( ent->type == et_splines &&
2693  (ent->u.splines.fill.col==0xffffff ||
2694  /*ent->u.splines.clippath!=NULL ||*/
2695  (ent->u.splines.stroke_width!=0 && ent->u.splines.stroke.col!=0xffffffff))) {
2696  ask = true;
2697  break;
2698  }
2699  }
2700  if ( ask )
2701  *flags = PsStrokeFlagsDlg();
2702  }
2703 
2704  if ( *flags & sf_correctdir ) /* Will happen if flags still unset (-1) */
2706 
2707  handle_eraser = *flags!=-1 && (*flags & sf_handle_eraser);
2708  if ( handle_eraser )
2709  ec->splines = EntityReverse(ec->splines);
2710  }
2711 
2712  for ( ent=ec->splines; ent!=NULL; ent = next ) {
2713  next = ent->next;
2714  if ( ent->type == et_splines && is_stroked ) {
2715  if ( head==NULL )
2716  head = ent->u.splines.splines;
2717  else
2718  last->next = ent->u.splines.splines;
2719  if ( ent->u.splines.splines!=NULL )
2720  for ( last = ent->u.splines.splines; last->next!=NULL; last=last->next );
2721  ent->u.splines.splines = NULL;
2722  } else if ( ent->type == et_splines ) {
2723  if ( ent->u.splines.stroke.col!=0xffffffff &&
2724  (ent->u.splines.fill.col==0xffffffff || ent->u.splines.stroke_width!=0)) {
2725  /* What does a stroke width of 0 mean? PS Says minimal width line */
2726  /* How do we implement that? Special case: If filled and stroked 0, then */
2727  /* ignore the stroke. This idiom is used by MetaPost sometimes and means */
2728  /* no stroke */
2729  memset(&si,'\0',sizeof(si));
2730  si.toobigwarn = *flags & sf_toobigwarn ? 1 : 0;
2731  si.join = ent->u.splines.join;
2732  si.cap = ent->u.splines.cap;
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);
2745  ent->u.splines.splines),inversetrans,true);
2746  for ( each = transed; each!=NULL; each=each->next ) {
2747  temp = SplineSetStroke(each,&si,ec->sc);
2748  if ( new==NULL )
2749  new=temp;
2750  else
2751  nlast->next = temp;
2752  if ( temp!=NULL )
2753  for ( nlast=temp; nlast->next!=NULL; nlast=nlast->next );
2754  }
2755  new = SplinePointListTransform(new,ent->u.splines.transform,true);
2756  SplinePointListsFree(transed);
2757  if ( handle_eraser && ent->u.splines.stroke.col==0xffffff ) {
2758  head = EraseStroke(ec->sc,head,new);
2759  last = head;
2760  if ( last!=NULL )
2761  for ( ; last->next!=NULL; last=last->next );
2762  } else {
2763  if ( head==NULL )
2764  head = new;
2765  else
2766  last->next = new;
2767  if ( new!=NULL )
2768  for ( last = new; last->next!=NULL; last=last->next );
2769  }
2770  if ( si.toobigwarn )
2771  *flags |= sf_toobigwarn;
2772  }
2773  /* If they have neither a stroke nor a fill, pretend they said fill */
2774  if ( ent->u.splines.fill.col==0xffffffff && ent->u.splines.stroke.col!=0xffffffff )
2776  else if ( handle_eraser && ent->u.splines.fill.col==0xffffff ) {
2777  head = EraseStroke(ec->sc,head,ent->u.splines.splines);
2778  last = head;
2779  if ( last!=NULL )
2780  for ( ; last->next!=NULL; last=last->next );
2781  } else {
2782  new = ent->u.splines.splines;
2783  if ( head==NULL )
2784  head = new;
2785  else
2786  last->next = new;
2787  if ( new!=NULL )
2788  for ( last = new; last->next!=NULL; last=last->next );
2789  }
2790  }
2792  free(ent);
2793  }
2794 return( head );
2795 }
2796 
2797 
2799  RefChar *p, *n;
2800 
2801  if ( cur==NULL )
2802 return( NULL );
2803 
2804  p = NULL;
2805  for ( ; (n=cur->next)!=NULL; cur = n ) {
2806  cur->next = p;
2807  p = cur;
2808  }
2809  cur->next = p;
2810 return( cur );
2811 }
2812 
2813 static void SCInterpretPS(FILE *ps,SplineChar *sc, int *flags) {
2814  EntityChar ec;
2815  real dval;
2816  char tokbuf[10];
2817  IO wrapper;
2818  int ch;
2819 
2820  while ( isspace(ch = getc(ps)) );
2821  ungetc(ch,ps);
2822 
2823  memset(&wrapper,0,sizeof(wrapper));
2824  wrapper.advance_width = UNDEFINED_WIDTH;
2825  if ( ch!='<' ) {
2826  pushio(&wrapper,ps,NULL,0);
2827 
2828  if ( nextpstoken(&wrapper,&dval,tokbuf,sizeof(tokbuf))!=pt_opencurly )
2829  LogError( _("We don't understand this font\n") );
2830  } else {
2831  (void) getc(ps);
2832  pushfogio(&wrapper,ps);
2833  }
2834  memset(&ec,'\0',sizeof(ec));
2835  ec.fromtype3 = true;
2836  ec.sc = sc;
2837  _InterpretPS(&wrapper,&ec,NULL);
2838  sc->width = ec.width;
2839  sc->layers[ly_fore].splines = SplinesFromEntityChar(&ec,flags,false);
2840  sc->layers[ly_fore].refs = revrefs(ec.refs);
2841  free(wrapper.top);
2842 }
2843 
2845  char tokbuf[100];
2846  int tok,i, j;
2847  real dval;
2849  RefChar *p, *ref, *next;
2850  IO wrapper;
2851  int flags = -1;
2852 
2853  wrapper.top = NULL;
2854  wrapper.advance_width = UNDEFINED_WIDTH;
2855  pushio(&wrapper,ps,NULL,0);
2856 
2857  while ( (tok = nextpstoken(&wrapper,&dval,tokbuf,sizeof(tokbuf)))!=pt_eof && tok!=pt_end ) {
2858  if ( tok==pt_namelit ) {
2859  if ( cp->next>=cp->cnt ) {
2860  ++cp->cnt;
2861  cp->keys = grealloc(cp->keys,cp->cnt*sizeof(char *));
2862  cp->values = grealloc(cp->values,cp->cnt*sizeof(char *));
2863  }
2864  if ( cp->next<cp->cnt ) {
2865  sc = SplineCharCreate(2);
2866  cp->keys[cp->next] = copy(tokbuf);
2867  cp->values[cp->next++] = sc;
2868  sc->name = copy(tokbuf);
2870  ff_progress_next();
2871  } else {
2872  memset(&dummy,0,sizeof(dummy));
2873  dummy.fromtype3 = true;
2875  }
2876  }
2877  }
2878  free(wrapper.top);
2879 
2880  /* References were done by name in the postscript. we stored the names in */
2881  /* ref->sc (which is a hack). Now look up all those names and replace */
2882  /* with the appropriate splinechar. If we can't find anything then throw */
2883  /* out the reference */
2884  /* Further fixups come later, where all ps refs are fixedup */
2885  for ( i=0; i<cp->next; ++i ) {
2886  for ( p=NULL, ref=cp->values[i]->layers[ly_fore].refs; ref!=NULL; ref=next ) {
2887  char *refname = (char *) (ref->sc);
2888  next = ref->next;
2889  if ( ref->sc==NULL )
2890  refname=encoding[ref->orig_pos];
2891  for ( j=0; j<cp->next; ++j )
2892  if ( strcmp(cp->keys[j],refname)==0 )
2893  break;
2894  free(ref->sc); /* a string, not a splinechar */
2895  if ( j!=cp->next ) {
2896  ref->sc = cp->values[j];
2897  SCMakeDependent(cp->values[i],ref->sc);
2898  ref->adobe_enc = getAdobeEnc(ref->sc->name);
2899  ref->checked = true;
2900  p = ref;
2901  } else {
2902  if ( p==NULL )
2903  cp->values[i]->layers[ly_fore].refs = next;
2904  else
2905  p->next = next;
2906  ref->next = NULL;
2907  RefCharFree(ref);
2908  }
2909  }
2910  }
2911 }
2912 
2913 static void closepath(SplinePointList *cur, int is_type2) {
2914  if ( cur!=NULL && cur->first==cur->last && cur->first->prev==NULL && is_type2 )
2915 return; /* The "path" is just a single point created by a moveto */
2916  /* Probably we're just doing another moveto */
2917  if ( cur!=NULL && cur->first!=NULL && cur->first!=cur->last ) {
2918 /* I allow for greater errors here than I do in the straight postscript code */
2919 /* because: 1) the rel-rel operators will accumulate more rounding errors */
2920 /* 2) I only output 2 decimal digits after the decimal in type1 output */
2921  if ( RealWithin(cur->first->me.x,cur->last->me.x,.05) && RealWithin(cur->first->me.y,cur->last->me.y,.05) ) {
2922  SplinePoint *oldlast = cur->last;
2923  cur->first->prevcp = oldlast->prevcp;
2924  cur->first->prevcp.x += (cur->first->me.x-oldlast->me.x);
2925  cur->first->prevcp.y += (cur->first->me.y-oldlast->me.y);
2926  cur->first->noprevcp = oldlast->noprevcp;
2927  oldlast->prev->from->next = NULL;
2928  cur->last = oldlast->prev->from;
2929  chunkfree(oldlast->prev,sizeof(*oldlast));
2930  chunkfree(oldlast->hintmask,sizeof(HintMask));
2931  chunkfree(oldlast,sizeof(*oldlast));
2932  }
2933  CheckMake(cur->last,cur->first);
2934  SplineMake3(cur->last,cur->first);
2935  cur->last = cur->first;
2936  }
2937 }
2938 
2939 static void UnblendFree(StemInfo *h ) {
2940  while ( h!=NULL ) {
2941  chunkfree(h->u.unblended,sizeof(real [2][MmMax]));
2942  h->u.unblended = NULL;
2943  h = h->next;
2944  }
2945 }
2946 
2948  StemInfo *h;
2949 
2950  if ( to==NULL )
2951 return( extra );
2952  if ( extra==NULL )
2953 return( to );
2954  for ( h=to; h->next!=NULL; h=h->next );
2955  h->next = extra;
2956 return( to );
2957 }
2958 
2959 static StemInfo *HintNew(double start,double width) {
2960  StemInfo *h;
2961 
2962  h = chunkalloc(sizeof(StemInfo));
2963  h->start = start;
2964  h->width = width;
2965 return( h );
2966 }
2967 
2968 static void RemapHintMask(HintMask *hm,int mapping[96],int max) {
2969  HintMask rpl;
2970  int i, mb;
2971 
2972  if ( hm==NULL )
2973 return;
2974 
2975  if ( max>96 ) max = 96;
2976  mb = (max+7)>>3;
2977 
2978  memset(&rpl,0,mb);
2979  for ( i=0; i<max; ++i ) if ( (*hm)[i>>3]&(0x80>>(i&0x7)) )
2980  rpl[mapping[i]>>3] |= (0x80>>(mapping[i]&0x7));
2981  memcpy(hm,&rpl,mb);
2982 }
2983 
2984 static void HintsRenumber(SplineChar *sc) {
2985  /* In a type1 font the hints may get added to our hint list in a semi- */
2986  /* random order. In an incorrect type2 font the same thing could happen. */
2987  /* Force the order to be correct, and then update all masks */
2988  int mapping[96];
2989  int i, max;
2990  StemInfo *h;
2991  SplineSet *spl;
2992  SplinePoint *sp;
2993 
2994  for ( i=0; i<96; ++i ) mapping[i] = i;
2995 
2996  i = 0;
2997  for ( h=sc->hstem; h!=NULL; h=h->next ) {
2998  if ( h->hintnumber<96 && i<96 ) {
2999  mapping[h->hintnumber] = i;
3000  h->hintnumber = i++;
3001  }
3002  chunkfree(h->u.unblended,sizeof(real [2][MmMax]));
3003  h->u.unblended = NULL;
3004  }
3005  for ( h=sc->vstem; h!=NULL; h=h->next ) {
3006  if ( h->hintnumber<96 && i<96 ) {
3007  mapping[h->hintnumber] = i;
3008  h->hintnumber = i++;
3009  }
3010  chunkfree(h->u.unblended,sizeof(real [2][MmMax]));
3011  h->u.unblended = NULL;
3012  }
3013  max = i;
3014  for ( i=0; i<max; ++i )
3015  if ( mapping[i]!=i )
3016  break;
3017  if ( i==max )
3018 return; /* Didn't change the order */
3019 
3020  for ( i=0; i<sc->countermask_cnt; ++i )
3021  RemapHintMask(&sc->countermasks[i],mapping,max);
3022  for ( spl = sc->layers[ly_fore].splines; spl!=NULL; spl=spl->next ) {
3023  for ( sp = spl->first; ; ) {
3024  RemapHintMask(sp->hintmask,mapping,max);
3025  if ( sp->next==NULL )
3026  break;
3027  sp = sp->next->to;
3028  if ( sp==spl->first )
3029  break;
3030  }
3031  }
3032 }
3033 
3034 int UnblendedCompare(real u1[MmMax], real u2[MmMax], int cnt) {
3035  int i;
3036 
3037  for ( i=0; i<cnt; ++i ) {
3038  if ( u1[i]!=u2[i] )
3039 return( u1[i]>u2[i]?1:-1 );
3040  }
3041 return( 0 );
3042 }
3043 
3045  real unblended[2][MmMax], int instance_count) {
3046  StemInfo *sameh;
3047 
3048  if ( instance_count==0 ) {
3049  for ( sameh=old; sameh!=NULL; sameh=sameh->next )
3050  if ( sameh->start==start && sameh->width==width)
3051  break;
3052  } else { int j;
3053  for ( j=1; j<instance_count; ++j ) {
3054  unblended[0][j] += unblended[0][j-1];
3055  unblended[1][j] += unblended[1][j-1];
3056  }
3057  for ( sameh=old; sameh!=NULL; sameh=sameh->next ) {
3058  if ( (*sameh->u.unblended)[0] == NULL || (*sameh->u.unblended)[1]==NULL )
3059  continue;
3060  if ( UnblendedCompare((*sameh->u.unblended)[0],unblended[0],instance_count)==0 &&
3061  UnblendedCompare((*sameh->u.unblended)[1],unblended[1],instance_count)==0)
3062  break;
3063  }
3064  }
3065 return( sameh );
3066 }
3067 
3068 static real Blend(real u[MmMax],struct pscontext *context) {
3069  real sum = u[0];
3070  int i;
3071 
3072  for ( i=1; i<context->instance_count; ++i )
3073  sum += context->blend_values[i]*u[i];
3074 return( sum );
3075 }
3076 
3077 /* this handles either Type1 or Type2 charstrings. Type2 charstrings have */
3078 /* more operators than Type1s and the old operators have extended meanings */
3079 /* (ie. the rlineto operator can produce more than one line). But pretty */
3080 /* much it's a superset and if we parse for type2 (with a few additions) */
3081 /* we'll get it right */
3082 /* Char width is done differently. Moveto starts a newpath. 0xff starts a 16.16*/
3083 /* number rather than a 32 bit number */
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];
3090  SplinePointList *cur=NULL, *oldcur=NULL;
3091  RefChar *r1, *r2, *rlast=NULL;
3093  real dx, dy, dx2, dy2, dx3, dy3, dx4, dy4, dx5, dy5, dx6=0, dy6;
3094  SplinePoint *pt;
3095  /* subroutines may be nested to a depth of 10 */
3096  struct substate { unsigned char *type1; int len; int subnum; } pcstack[11];
3097  int pcsp=0;
3098  StemInfo *hint, *hp;
3099  real pops[30];
3100  int popsp=0;
3101  int base, polarity;
3102  real coord;
3103  struct pschars *s;
3104  int hint_cnt = 0;
3105  StemInfo *activeh=NULL, *activev=NULL, *sameh;
3106  HintMask *pending_hm = NULL;
3107  HintMask *counters[96];
3108  int cp=0;
3109  real unblended[2][MmMax];
3110  int last_was_b1=false, old_last_was_b1;
3111 
3112  if ( !is_type2 && context->instance_count>1 )
3113  memset(unblended,0,sizeof(unblended));
3114 
3115  ret->name = copy( name );
3116  ret->unicodeenc = -1;
3117  ret->width = (int16) 0x8000;
3118  if ( name==NULL ) name = "unnamed";
3119  ret->manualhints = true;
3120 
3121  current.x = current.y = 0;
3122  while ( len>0 ) {
3123  if ( sp>48 ) {
3124  LogError( _("Stack got too big in %s\n"), name );
3125  sp = 48;
3126  }
3127  base = 0;
3128  --len;
3129  if ( (v = *type1++)>=32 ) {
3130  if ( v<=246) {
3131  stack[sp++] = v - 139;
3132  } else if ( v<=250 ) {
3133  stack[sp++] = (v-247)*256 + *type1++ + 108;
3134  --len;
3135  } else if ( v<=254 ) {
3136  stack[sp++] = -(v-251)*256 - *type1++ - 108;
3137  --len;
3138  } else {
3139  int val = (*type1<<24) | (type1[1]<<16) | (type1[2]<<8) | type1[3];
3140  stack[sp++] = val;
3141  type1 += 4;
3142  len -= 4;
3143  if ( is_type2 ) {
3144 #ifndef PSFixed_Is_TTF /* The type2 spec is contradictory. It says this is a */
3145  /* two's complement number, but it also says it is a */
3146  /* Fixed, which in truetype is not two's complement */
3147  /* (mantisa is always unsigned) */
3148  stack[sp-1] /= 65536.;
3149 #else
3150  int mant = val&0xffff;
3151  stack[sp-1] = (val>>16) + mant/65536.;
3152 #endif
3153  }
3154  }
3155  } else if ( v==28 ) {
3156  stack[sp++] = (short) ((type1[0]<<8) | type1[1]);
3157  type1 += 2;
3158  len -= 2;
3159  /* In the Dict tables of CFF, a 5byte fixed value is prefixed by a */
3160  /* 29 code. In Type2 strings the prefix is 255. */
3161  } else if ( v==12 ) {
3162  old_last_was_b1 = last_was_b1; last_was_b1 = false;
3163  v = *type1++;
3164  --len;
3165  switch ( v ) {
3166  case 0: /* dotsection */
3167  sp = 0;
3168  break;
3169  case 1: /* vstem3 */ /* specifies three v hints zones at once */
3170  if ( sp<6 ) LogError( _("Stack underflow on vstem3 in %s\n"), name );
3171  /* according to the standard, if there is a vstem3 there can't */
3172  /* be any vstems, so there can't be any confusion about hint order */
3173  /* so we don't need to worry about unblended stuff */
3174  sameh = NULL;
3175  if ( !is_type2 )
3176  sameh = SameH(ret->vstem,stack[0] + ret->lsidebearing,stack[1],
3177  unblended,0);
3178  hint = HintNew(stack[0] + ret->lsidebearing,stack[1]);
3179  hint->hintnumber = sameh!=NULL ? sameh->hintnumber : hint_cnt++;
3180  if ( activev==NULL )
3181  activev = hp = hint;
3182  else {
3183  for ( hp=activev; hp->next!=NULL; hp = hp->next );
3184  hp->next = hint;
3185  hp = hint;
3186  }
3187  sameh = NULL;
3188  if ( !is_type2 )
3189  sameh = SameH(ret->vstem,stack[2] + ret->lsidebearing,stack[3],
3190  unblended,0);
3191  hp->next = HintNew(stack[2] + ret->lsidebearing,stack[3]);
3192  hp->next->hintnumber = sameh!=NULL ? sameh->hintnumber : hint_cnt++;
3193  if ( !is_type2 )
3194  sameh = SameH(ret->vstem,stack[4] + ret->lsidebearing,stack[5],
3195  unblended,0);
3196  hp->next->next = HintNew(stack[4] + ret->lsidebearing,stack[5]);
3197  hp->next->next->hintnumber = sameh!=NULL ? sameh->hintnumber : hint_cnt++;
3198  if ( !is_type2 && hp->next->next->hintnumber<96 ) {
3199  if ( pending_hm==NULL )
3200  pending_hm = chunkalloc(sizeof(HintMask));
3201  (*pending_hm)[hint->hintnumber>>3] |= 0x80>>(hint->hintnumber&0x7);
3202  (*pending_hm)[hint->next->hintnumber>>3] |= 0x80>>(hint->next->hintnumber&0x7);
3203  (*pending_hm)[hint->next->next->hintnumber>>3] |= 0x80>>(hint->next->next->hintnumber&0x7);
3204  }
3205  hp = hp->next->next;
3206  sp = 0;
3207  break;
3208  case 2: /* hstem3 */ /* specifies three h hints zones at once */
3209  if ( sp<6 ) LogError( _("Stack underflow on hstem3 in %s\n"), name );
3210  sameh = NULL;
3211  if ( !is_type2 )