1 /* Copyright (C) 2000-2008 by George Williams */
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 # include <ieeefp.h> /* Solaris defines isnan in ieeefp rather than math.h */
38 int THdo_hint_guessing
= 0;
39 int THdo_set_reversing
= 0;
40 int THdo_catagorize
= 0;
46 int backedup
, cnt
, isloop
, isstopped
, fogns
;
53 int advance_width
; /* Can be set from a PS comment by MF2PT1 */
56 typedef struct growbuf
{
62 #define GARBAGE_MAX 64
66 struct pskeyval
*entries
[GARBAGE_MAX
];
67 int16 cnts
[GARBAGE_MAX
];
70 static void GrowBuffer(GrowBuf
*gb
,int len
) {
71 if ( len
<400 ) len
= 400;
72 if ( gb
->base
==NULL
) {
73 gb
->base
= gb
->pt
= galloc(len
);
74 gb
->end
= gb
->base
+ len
;
76 int off
= gb
->pt
-gb
->base
;
77 len
+= (gb
->end
-gb
->base
);
78 gb
->base
= grealloc(gb
->base
,len
);
79 gb
->end
= gb
->base
+ len
;
80 gb
->pt
= gb
->base
+off
;
84 static void AddTok(GrowBuf
*gb
,char *buf
,int islit
) {
85 int len
= islit
+ strlen(buf
) + 1;
87 if ( gb
->pt
+len
+1 >= gb
->end
)
92 gb
->pt
+= strlen(buf
);
96 static struct pskeyval
*lookup(struct pskeydict
*dict
,char *tokbuf
) {
99 for ( i
=0; i
<dict
->cnt
; ++i
)
100 if ( strcmp(dict
->entries
[i
].key
,tokbuf
)==0 )
101 return( &dict
->entries
[i
] );
106 static void dictfree(struct pskeydict
*dict
) {
109 for ( i
=0; i
<dict
->cnt
; ++i
) {
110 if ( dict
->entries
[i
].type
==ps_string
|| dict
->entries
[i
].type
==ps_instr
||
111 dict
->entries
[i
].type
==ps_lit
)
112 free(dict
->entries
[i
].u
.str
);
113 else if ( dict
->entries
[i
].type
==ps_array
|| dict
->entries
[i
].type
==ps_dict
)
114 dictfree(&dict
->entries
[i
].u
.dict
);
118 static void garbagefree(struct garbage
*all
) {
119 struct garbage
*junk
, *next
;
122 for ( junk
= all
; junk
!=NULL
; junk
= next
) {
124 for ( j
=0; j
<junk
->cnt
; ++j
) {
125 for ( i
=0; i
<junk
->cnts
[j
]; ++i
) {
126 if ( junk
->entries
[j
][i
].type
==ps_string
|| junk
->entries
[j
][i
].type
==ps_instr
||
127 junk
->entries
[j
][i
].type
==ps_lit
)
128 free(junk
->entries
[j
][i
].u
.str
);
130 free(junk
->entries
[j
]);
133 chunkfree(junk
,sizeof(struct garbage
));
136 /**************************** Postscript Importer *****************************/
137 /* It's really dumb. It ignores almost everything except linetos and curvetos */
138 /* anything else, function calls, ... is thrown out, if this breaks a lineto */
139 /* or curveto or moveto (if there aren't enough things on the stack) then we */
140 /* ignore that too */
142 enum pstoks
{ pt_eof
=-1, pt_moveto
, pt_rmoveto
, pt_curveto
, pt_rcurveto
,
143 pt_lineto
, pt_rlineto
, pt_arc
, pt_arcn
, pt_arct
, pt_arcto
,
144 pt_newpath
, pt_closepath
, pt_dup
, pt_pop
, pt_index
,
145 pt_exch
, pt_roll
, pt_clear
, pt_copy
, pt_count
,
146 pt_setcachedevice
, pt_setcharwidth
,
147 pt_translate
, pt_scale
, pt_rotate
, pt_concat
, pt_end
, pt_exec
,
148 pt_add
, pt_sub
, pt_mul
, pt_div
, pt_idiv
, pt_mod
, pt_neg
,
149 pt_abs
, pt_round
, pt_ceiling
, pt_floor
, pt_truncate
, pt_max
, pt_min
,
150 pt_ne
, pt_eq
, pt_gt
, pt_ge
, pt_lt
, pt_le
, pt_and
, pt_or
, pt_xor
, pt_not
,
151 pt_exp
, pt_sqrt
, pt_ln
, pt_log
, pt_atan
, pt_sin
, pt_cos
,
153 pt_if
, pt_ifelse
, pt_for
, pt_loop
, pt_repeat
, pt_exit
,
155 pt_def
, pt_bind
, pt_load
,
156 pt_setlinecap
, pt_setlinejoin
, pt_setlinewidth
, pt_setdash
,
157 pt_currentlinecap
, pt_currentlinejoin
, pt_currentlinewidth
, pt_currentdash
,
158 pt_setgray
, pt_currentgray
, pt_sethsbcolor
, pt_currenthsbcolor
,
159 pt_setrgbcolor
, pt_currentrgbcolor
, pt_setcmykcolor
, pt_currentcmykcolor
,
161 pt_fill
, pt_stroke
, pt_clip
,
165 pt_transform
, pt_itransform
, pt_dtransform
, pt_idtransform
,
167 /* things we sort of pretend to do, but actually do something wrong */
168 pt_gsave
, pt_grestore
, pt_save
, pt_restore
, pt_currentmatrix
, pt_setmatrix
,
171 pt_currentflat
, pt_setflat
,
172 pt_currentglobal
, pt_setglobal
,
173 pt_currentmiterlimit
, pt_setmiterlimit
,
174 pt_currentobjectformat
, pt_setobjectformat
,
175 pt_currentoverprint
, pt_setoverprint
,
176 pt_currentpacking
, pt_setpacking
,
178 pt_currentsmoothness
, pt_setsmoothness
,
179 pt_currentstrokeadjust
, pt_setstrokeadjust
,
181 pt_mark
, pt_counttomark
, pt_cleartomark
, pt_array
, pt_aload
, pt_astore
,
182 pt_print
, pt_cvi
, pt_cvlit
, pt_cvn
, pt_cvr
, pt_cvrs
, pt_cvs
, pt_cvx
, pt_stringop
,
184 pt_opencurly
, pt_closecurly
, pt_openarray
, pt_closearray
, pt_string
,
185 pt_number
, pt_unknown
, pt_namelit
, pt_output
, pt_outputd
};
187 static char *toknames
[] = { "moveto", "rmoveto", "curveto", "rcurveto",
188 "lineto", "rlineto", "arc", "arcn", "arct", "arcto",
189 "newpath", "closepath", "dup", "pop", "index",
190 "exch", "roll", "clear", "copy", "count",
191 "setcachedevice", "setcharwidth",
192 "translate", "scale", "rotate", "concat", "end", "exec",
193 "add", "sub", "mul", "div", "idiv", "mod", "neg",
194 "abs", "round", "ceiling", "floor", "truncate", "max", "min",
195 "ne", "eq", "gt", "ge", "lt", "le", "and", "or", "xor", "not",
196 "exp", "sqrt", "ln", "log", "atan", "sin", "cos",
198 "if", "ifelse", "for", "loop", "repeat", "exit",
200 "def", "bind", "load",
201 "setlinecap", "setlinejoin", "setlinewidth", "setdash",
202 "currentlinecap", "currentlinejoin", "currentlinewidth", "currentdash",
203 "setgray", "currentgray", "sethsbcolor", "currenthsbcolor",
204 "setrgbcolor", "currentrgbcolor", "setcmykcolor", "currentcmykcolor",
206 "fill", "stroke", "clip",
210 "transform", "itransform", "dtransform", "idtransform",
212 "gsave", "grestore", "save", "restore", "currentmatrix", "setmatrix",
215 "currentflat", "setflat",
216 "currentglobal", "setglobal",
217 "currentmiterlimit", "setmiterlimit",
218 "currentobjectformat", "setobjectformat",
219 "currentoverprint", "setoverprint",
220 "currentpacking", "setpacking",
222 "currentsmoothness", "setsmoothness",
223 "currentstrokeadjust", "setstrokeadjust",
225 "mark", "counttomark", "cleartomark", "array", "aload", "astore",
226 "print", "cvi", "cvlit", "cvn", "cvr", "cvrs", "cvs", "cvx", "string",
228 "opencurly", "closecurly", "openarray", "closearray", "string",
229 "number", "unknown", "namelit", "=", "==",
233 /* length (of string)
238 static int getfoghex(_IO
*io
) {
241 while ( isspace( ch
= getc(io
->fog
)));
244 else if ( ch
>= 'A' && ch
<= 'F' )
246 else if ( ch
>= 'a' && ch
<= 'f' )
252 while ( isspace( ch
= getc(io
->fog
)));
255 else if ( ch
>= 'A' && ch
<= 'F' )
257 else if ( ch
>= 'a' && ch
<= 'f' )
265 static int nextch(IO
*wrapper
) {
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 " };
276 if ( io
->backedup
!=EOF
) {
280 } else if ( io
->ps
!=NULL
) {
281 if ( (ch
= getc(io
->ps
))!=EOF
)
283 } else if ( io
->fog
!=NULL
) {
284 if ( io
->macro
!=NULL
&& *io
->macro
!='\0' )
285 return( *(io
->macro
++) );
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"
298 io
->macro
=io
->fogbuf
;
299 return( *(io
->macro
++) );
302 if ( (ch
= *(io
->macro
++))!='\0' )
305 io
->macro
= io
->start
;
306 return( nextch(wrapper
));
309 wrapper
->top
= io
->prev
;
311 wrapper
->endedstopped
= true;
319 static void unnextch(int ch
,IO
*wrapper
) {
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
);
329 wrapper
->top
->backedup
= ch
;
332 static void pushio(IO
*wrapper
, FILE *ps
, char *macro
, int cnt
) {
333 _IO
*io
= gcalloc(1,sizeof(_IO
));
335 io
->prev
= wrapper
->top
;
337 io
->macro
= io
->start
= copy(macro
);
341 io
->isstopped
= true;
342 } else if ( cnt
==0 ) {
352 static void pushfogio(IO
*wrapper
, FILE *fog
) {
353 _IO
*io
= gcalloc(1,sizeof(_IO
));
355 io
->prev
= wrapper
->top
;
363 static void ioescapeloop(IO
*wrapper
) {
364 _IO
*io
= wrapper
->top
, *iop
;
367 while ( io
->prev
!=NULL
&& !io
->isstopped
) {
369 wasloop
= io
->isloop
;
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") );
387 static int ioescapestopped(IO
*wrapper
, struct psstack
*stack
, int sp
, const size_t bsize
) {
388 _IO
*io
= wrapper
->top
, *iop
;
391 while ( io
->prev
!=NULL
) {
393 wasstopped
= io
->isstopped
;
398 if ( sp
<(int)bsize
) {
399 stack
[sp
].type
= ps_bool
;
400 stack
[sp
++].u
.tf
= true;
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") );
414 static int endedstopped(IO
*wrapper
) {
415 if ( wrapper
->endedstopped
) {
416 wrapper
->endedstopped
= false;
423 static int nextpstoken(IO
*wrapper
, real
*val
, char *tokbuf
, int tbsize
) {
426 float mf2pt_advance_width
;
431 /* Eat whitespace and comments. Comments last to eol (or formfeed) */
433 while ( isspace(ch
= nextch(wrapper
)) );
436 while ( (ch
=nextch(wrapper
))!=EOF
&& ch
!='\r' && ch
!='\n' && ch
!='\f' )
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
;
453 *pt
++ = ch
; *pt
='\0';
457 while ( (ch
=nextch(wrapper
))!=EOF
) {
458 if ( pt
<end
) *pt
++ = ch
;
463 else if ( ch
==')' ) {
466 } else if ( ch
=='\\' )
471 } else if ( ch
=='<' ) {
472 ch
= nextch(wrapper
);
473 if ( pt
<end
) *pt
++ = ch
;
476 else if ( ch
!='~' ) {
477 while ( (ch
=nextch(wrapper
))!=EOF
&& ch
!='>' )
478 if ( pt
<end
) *pt
++ = ch
;
481 while ( (ch
=nextch(wrapper
))!=EOF
) {
482 if ( pt
<end
) *pt
++ = ch
;
483 if ( ch
=='~' ) twiddle
= 1;
484 else if ( twiddle
&& ch
=='>' )
491 } else if ( ch
==')' || ch
=='>' || ch
=='[' || ch
==']' || ch
=='{' || ch
=='}' ) {
493 return( pt_opencurly
);
495 return( pt_closecurly
);
497 return( pt_openarray
);
499 return( pt_closearray
);
501 return( pt_unknown
); /* single character token */
502 } else if ( ch
=='/' ) {
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 )
510 unnextch(ch
,wrapper
);
511 return( pt_namelit
); /* name literal */
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 )
520 unnextch(ch
,wrapper
);
521 r
= strtol(tokbuf
,&end
,10);
523 if ( *pt
=='\0' ) { /* It's a normal integer */
526 } else if ( *pt
=='#' ) {
527 r
= strtol(pt
+1,&end
,r
);
528 if ( *end
=='\0' ) { /* It's a radix integer */
533 *val
= strtod(tokbuf
,&end
);
534 if ( !finite(*val
) ) {
535 /* GT: NaN is a concept in IEEE floating point which means "Not a Number" */
536 /* GT: it is used to represent errors like 0/0 or sqrt(-1). */
537 LogError( _("Bad number, infinity or nan: %s\n"), tokbuf
);
540 if ( *end
=='\0' ) /* It's a real */
543 /* It's not a number */
544 for ( i
=0; toknames
[i
]!=NULL
; ++i
)
545 if ( strcmp(tokbuf
,toknames
[i
])==0 )
548 return( pt_unknown
);
552 static void Transform(BasePoint
*to
, DBasePoint
*from
, real trans
[6]) {
553 to
->x
= trans
[0]*from
->x
+trans
[2]*from
->y
+trans
[4];
554 to
->y
= trans
[1]*from
->x
+trans
[3]*from
->y
+trans
[5];
557 void MatMultiply(real m1
[6], real m2
[6], real to
[6]) {
560 trans
[0] = m1
[0]*m2
[0] +
562 trans
[1] = m1
[0]*m2
[1] +
564 trans
[2] = m1
[2]*m2
[0] +
566 trans
[3] = m1
[2]*m2
[1] +
568 trans
[4] = m1
[4]*m2
[0] +
571 trans
[5] = m1
[4]*m2
[1] +
574 memcpy(to
,trans
,sizeof(trans
));
577 void MatInverse(real into
[6], real orig
[6]) {
578 real det
= orig
[0]*orig
[3] - orig
[1]*orig
[2];
581 LogError( _("Attempt to invert a singular matrix\n") );
582 memset(into
,0,sizeof(*into
));
584 into
[0] = orig
[3]/det
;
585 into
[1] = -orig
[1]/det
;
586 into
[2] = -orig
[2]/det
;
587 into
[3] = orig
[0]/det
;
588 into
[4] = -orig
[4]*into
[0] - orig
[5]*into
[2];
589 into
[5] = -orig
[4]*into
[1] - orig
[5]*into
[3];
593 static void ECCatagorizePoints( EntityChar
*ec
) {
596 for ( ent
=ec
->splines
; ent
!=NULL
; ent
=ent
->next
) if ( ent
->type
== et_splines
) {
597 SPLCatagorizePoints( ent
->u
.splines
.splines
);
598 SPLCatagorizePoints( ent
->clippath
);
602 static int AddEntry(struct pskeydict
*dict
,struct psstack
*stack
, int sp
) {
605 if ( dict
->cnt
>=dict
->max
) {
606 if ( dict
->cnt
==0 ) {
608 dict
->entries
= galloc(dict
->max
*sizeof(struct pskeyval
));
611 dict
->entries
= grealloc(dict
->entries
,dict
->max
*sizeof(struct pskeyval
));
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") );
622 for ( i
=0; i
<dict
->cnt
; ++i
)
623 if ( strcmp(dict
->entries
[i
].key
,stack
[sp
-2].u
.str
)==0 )
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
);
631 memset(&dict
->entries
[i
],'\0',sizeof(struct pskeyval
));
632 dict
->entries
[i
].key
= stack
[sp
-2].u
.str
;
635 dict
->entries
[i
].type
= stack
[sp
-1].type
;
636 dict
->entries
[i
].u
= stack
[sp
-1].u
;
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 */
645 for ( i
=0; i
<forgets
; ++i
) {
646 if ( stack
[i
].type
==ps_string
|| stack
[i
].type
==ps_instr
||
647 stack
[i
].type
==ps_lit
)
648 free(stack
[i
].u
.str
);
649 else if ( stack
[i
].type
==ps_array
|| stack
[i
].type
==ps_dict
)
650 dictfree(&stack
[i
].u
.dict
);
652 for ( i
=forgets
; i
<sp
; ++i
)
653 stack
[i
-forgets
] = stack
[i
];
654 return( sp
-forgets
);
657 static int rollstack(struct psstack
*stack
, int sp
) {
659 struct psstack
*temp
;
662 n
= stack
[sp
-2].u
.val
;
663 j
= stack
[sp
-1].u
.val
;
665 if ( sp
>=n
&& n
>0 ) {
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
];
679 static void CheckMakeB(BasePoint
*test
, BasePoint
*good
) {
680 if ( !finite(test
->x
) || test
->x
>100000 || test
->x
<-100000 ) {
681 LogError( _("Value out of bounds in spline.\n") );
687 if ( !finite(test
->y
) || test
->y
>100000 || test
->y
<-100000 ) {
688 LogError( _("Value out of bounds in spline.\n") );
696 static void CheckMake(SplinePoint
*from
, SplinePoint
*to
) {
697 CheckMakeB(&from
->me
,NULL
);
698 CheckMakeB(&from
->nextcp
,&from
->me
);
699 CheckMakeB(&to
->prevcp
,&from
->nextcp
);
700 CheckMakeB(&to
->me
,&to
->prevcp
);
703 static void circlearcto(real a1
, real a2
, real cx
, real cy
, real r
,
704 SplineSet
*cur
, real
*transform
) {
706 DBasePoint temp
, base
, cp
;
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
) ) {
725 cp
.x
= temp
.x
+cplen
*s2
; cp
.y
= temp
.y
- cplen
*c2
;
727 Transform(&pt
->prevcp
,&cp
,transform
);
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
);
737 static void circlearcsto(real a1
, real a2
, real cx
, real cy
, real r
,
738 SplineSet
*cur
, real
*transform
, int clockwise
) {
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;
748 for ( a
=((int) (a1
+90)/90)*90; a
<a2
; a
+= 90 ) {
749 circlearcto(last
,a
,cx
,cy
,r
,cur
,transform
);
752 circlearcto(last
,a2
,cx
,cy
,r
,cur
,transform
);
757 for ( a
=((int) (a1
-90)/90)*90+90; a
>a2
; a
-= 90 ) {
758 circlearcto(last
,a
,cx
,cy
,r
,cur
,transform
);
761 circlearcto(last
,a2
,cx
,cy
,r
,cur
,transform
);
765 static void collectgarbage(struct garbage
*tofrees
,struct pskeydict
*to
) {
766 struct garbage
*into
;
768 /* Garbage collection pointers */
770 if ( tofrees
->cnt
>=GARBAGE_MAX
&& tofrees
->next
!=NULL
)
771 into
= tofrees
->next
;
772 if ( into
->cnt
>=GARBAGE_MAX
) {
773 into
= chunkalloc(sizeof(struct garbage
));
774 into
->next
= tofrees
->next
;
775 tofrees
->next
= into
;
777 into
->cnts
[ into
->cnt
] = to
->cnt
;
778 into
->entries
[ into
->cnt
++ ] = to
->entries
;
781 static void copyarray(struct pskeydict
*to
,struct pskeydict
*from
, struct garbage
*tofrees
) {
783 struct pskeyval
*oldent
= from
->entries
;
786 to
->entries
= gcalloc(to
->cnt
,sizeof(struct pskeyval
));
787 for ( i
=0; i
<to
->cnt
; ++i
) {
788 to
->entries
[i
] = oldent
[i
];
789 if ( to
->entries
[i
].type
==ps_string
|| to
->entries
[i
].type
==ps_instr
||
790 to
->entries
[i
].type
==ps_lit
)
791 to
->entries
[i
].u
.str
= copy(to
->entries
[i
].u
.str
);
792 else if ( to
->entries
[i
].type
==ps_array
|| to
->entries
[i
].type
==ps_dict
)
793 copyarray(&to
->entries
[i
].u
.dict
,&oldent
[i
].u
.dict
,tofrees
);
795 collectgarbage(tofrees
,to
);
798 static int aload(int sp
, struct psstack
*stack
,int stacktop
, struct garbage
*tofrees
) {
801 if ( sp
>=1 && stack
[sp
-1].type
==ps_array
) {
802 struct pskeydict dict
;
804 dict
= stack
[sp
].u
.dict
;
805 for ( i
=0; i
<dict
.cnt
; ++i
) {
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
);
819 if ( sp
<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
820 stack
[sp
].type
= ps_array
;
821 stack
[sp
].u
.dict
= dict
;
828 static void printarray(struct pskeydict
*dict
) {
832 for ( i
=0; i
<dict
->cnt
; ++i
) {
833 switch ( dict
->entries
[i
].type
) {
835 printf( "%g", (double) dict
->entries
[i
].u
.val
);
838 printf( "%s", dict
->entries
[i
].u
.tf
? "true" : "false" );
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
? ")" : "}" );
848 printarray(&dict
->entries
[i
].u
.dict
);
851 printf( "-- void --" );
854 printf( "-- nostringval --" );
862 static void freestuff(struct psstack
*stack
, int sp
, struct pskeydict
*dict
,
863 GrowBuf
*gb
, struct garbage
*tofrees
) {
867 for ( i
=0; i
<dict
->cnt
; ++i
) {
868 if ( dict
->entries
[i
].type
==ps_string
|| dict
->entries
[i
].type
==ps_instr
||
869 dict
->entries
[i
].type
==ps_lit
)
870 free(dict
->entries
[i
].u
.str
);
871 free(dict
->entries
[i
].key
);
873 free( dict
->entries
);
874 for ( i
=0; i
<sp
; ++i
) {
875 if ( stack
[i
].type
==ps_string
|| stack
[i
].type
==ps_instr
||
876 stack
[i
].type
==ps_lit
)
877 free(stack
[i
].u
.str
);
878 #if 0 /* Garbage collection should get these */
879 else if ( stack
[i
].type
==ps_array
|| stack
[i
].type
==ps_dict
)
880 dictfree(&stack
[i
].u
.dict
);
883 garbagefree(tofrees
);
886 static void DoMatTransform(int tok
,int sp
,struct psstack
*stack
) {
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
;
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
) {
901 memcpy(t
,invt
,sizeof(t
));
903 stack
[sp
-2].u
.val
= t
[0]*x
+ t
[1]*y
;
904 stack
[sp
-1].u
.val
= t
[2]*x
+ t
[3]*y
;
905 if ( tok
==pt_transform
|| tok
==pt_itransform
) {
906 stack
[sp
-2].u
.val
+= t
[4];
907 stack
[sp
-1].u
.val
+= t
[5];
912 static int DoMatOp(int tok
,int sp
,struct psstack
*stack
) {
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
;
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];
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 */
944 temp
[0] = temp
[3] = cos(stack
[sp
].u
.val
);
945 temp
[1] = sin(stack
[sp
].u
.val
);
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];
959 stack
[nsp
-1] = stack
[sp
-1];
964 static Entity
*EntityCreate(SplinePointList
*head
,int linecap
,int linejoin
,
965 real linewidth
, real
*transform
, SplineSet
*clippath
) {
966 Entity
*ent
= gcalloc(1,sizeof(Entity
));
967 ent
->type
= et_splines
;
968 ent
->u
.splines
.splines
= head
;
969 ent
->u
.splines
.cap
= linecap
;
970 ent
->u
.splines
.join
= linejoin
;
971 ent
->u
.splines
.stroke_width
= linewidth
;
972 ent
->u
.splines
.fill
.col
= 0xffffffff;
973 ent
->u
.splines
.stroke
.col
= 0xffffffff;
974 ent
->u
.splines
.fill
.opacity
= 1.0;
975 ent
->u
.splines
.stroke
.opacity
= 1.0;
976 ent
->clippath
= SplinePointListCopy(clippath
);
977 memcpy(ent
->u
.splines
.transform
,transform
,6*sizeof(real
));
982 static void HandleType3Reference(IO
*wrapper
,EntityChar
*ec
,real transform
[6],
983 char *tokbuf
, int toksize
) {
989 tok
= nextpstoken(wrapper
,&dval
,tokbuf
,toksize
);
990 if ( strcmp(tokbuf
,"get")!=0 )
991 return; /* Hunh. I don't understand it. I give up */
992 tok
= nextpstoken(wrapper
,&dval
,tokbuf
,toksize
);
993 if ( tok
!=pt_namelit
)
994 return; /* Hunh. I don't understand it. I give up */
995 glyphname
= copy(tokbuf
);
996 tok
= nextpstoken(wrapper
,&dval
,tokbuf
,toksize
);
997 if ( strcmp(tokbuf
,"get")!=0 )
998 return; /* Hunh. I don't understand it. I give up */
999 tok
= nextpstoken(wrapper
,&dval
,tokbuf
,toksize
);
1000 if ( strcmp(tokbuf
,"exec")!=0 )
1001 return; /* Hunh. I don't understand it. I give up */
1003 /* Ok, it looks very much like a reference to glyphname */
1004 ref
= RefCharCreate();
1005 memcpy(ref
->transform
,transform
,sizeof(ref
->transform
));
1006 ref
->sc
= (SplineChar
*) glyphname
;
1007 ref
->next
= ec
->refs
;
1011 static void _InterpretPS(IO
*wrapper
, EntityChar
*ec
, RetStack
*rs
) {
1012 SplinePointList
*cur
=NULL
, *head
=NULL
;
1013 DBasePoint current
, temp
;
1015 struct psstack stack
[100];
1019 RefChar
*ref
, *lastref
=NULL
;
1020 real transform
[6], t
[6];
1021 struct graphicsstate
{
1025 int linecap
, linejoin
;
1027 DashType dashes
[DASH_MAX
];
1028 SplineSet
*clippath
;
1033 struct pskeydict dict
;
1034 struct pskeyval
*kv
;
1035 Color fore
=COLOR_INHERITED
;
1036 int linecap
=lc_inherited
, linejoin
=lj_inherited
; real linewidth
=WIDTH_INHERITED
;
1037 DashType dashes
[DASH_MAX
];
1038 int dash_offset
= 0;
1042 struct garbage tofrees
;
1043 SplineSet
*clippath
= NULL
;
1045 const int tokbufsize
= 100;
1047 oldloc
= setlocale(LC_NUMERIC
,"C");
1049 memset(&gb
,'\0',sizeof(GrowBuf
));
1050 memset(&dict
,'\0',sizeof(dict
));
1051 tofrees
.cnt
= 0; tofrees
.next
= NULL
;
1053 transform
[0] = transform
[3] = 1.0;
1054 transform
[1] = transform
[2] = transform
[4] = transform
[5] = 0;
1055 current
.x
= current
.y
= 0;
1056 dashes
[0] = 0; dashes
[1] = DASH_INHERITED
;
1058 if ( ec
->fromtype3
) {
1059 /* My type3 fonts have two things pushed on the stack when they */
1060 /* start. One is a dictionary, the other a flag (number). If the */
1061 /* flag is non-zero then we are a nested call (a reference char) */
1062 /* if 0, we're normal. We don't want to do setcachedevice for */
1063 /* reference chars. We can't represent a dictionary on the stack */
1064 /* so just push two 0s */
1065 stack
[0].type
= stack
[1].type
= ps_num
;
1066 stack
[0].u
.val
= stack
[1].u
.val
= 0;
1070 while ( (tok
= nextpstoken(wrapper
,&dval
,tokbuf
,tokbufsize
))!=pt_eof
) {
1071 if ( endedstopped(wrapper
)) {
1072 if ( sp
<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
1073 stack
[sp
].type
= ps_bool
;
1074 stack
[sp
++].u
.tf
= false;
1077 if ( sp
>(int)(sizeof(stack
)/sizeof(stack
[0])*4/5) ) {
1078 /* We don't interpret all of postscript */
1079 /* Sometimes we leave garbage on the stack that a real PS interp */
1080 /* would have handled. If the stack gets too deep, clean out the */
1081 /* oldest entries */
1082 sp
= forgetstack(stack
,sizeof(stack
)/sizeof(stack
[0])/3,sp
);
1085 if ( tok
==pt_closecurly
)
1087 else if ( tok
==pt_opencurly
)
1090 AddTok(&gb
,tokbuf
,tok
==pt_namelit
);
1092 if ( sp
<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
1093 stack
[sp
].type
= ps_instr
;
1095 stack
[sp
++].u
.str
= copy("");
1097 *gb
.pt
= '\0'; gb
.pt
= gb
.base
;
1098 stack
[sp
++].u
.str
= copy(gb
.base
);
1102 } else if ( tok
==pt_unknown
&& (kv
=lookup(&dict
,tokbuf
))!=NULL
) {
1103 if ( kv
->type
== ps_instr
)
1104 pushio(wrapper
,NULL
,copy(kv
->u
.str
),0);
1105 else if ( sp
<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
1106 stack
[sp
].type
= kv
->type
;
1107 stack
[sp
++].u
= kv
->u
;
1108 if ( kv
->type
==ps_instr
|| kv
->type
==ps_lit
|| kv
->type
==ps_string
)
1109 stack
[sp
-1].u
.str
= copy(stack
[sp
-1].u
.str
);
1110 else if ( kv
->type
==ps_array
|| kv
->type
==ps_dict
) {
1111 copyarray(&stack
[sp
-1].u
.dict
,&stack
[sp
-1].u
.dict
,&tofrees
);
1112 if ( stack
[sp
-1].u
.dict
.is_executable
)
1113 sp
= aload(sp
,stack
,sizeof(stack
)/sizeof(stack
[0]),&tofrees
);
1117 if ( tok
==pt_unknown
) {
1118 if ( strcmp(tokbuf
,"Cache")==0 ) /* Fontographer type3s */
1119 tok
= pt_setcachedevice
;
1120 else if ( strcmp(tokbuf
,"SetWid")==0 ) {
1121 tok
= pt_setcharwidth
;
1122 if ( sp
<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
1123 stack
[sp
].type
= ps_num
;
1124 stack
[sp
++].u
.val
= 0;
1126 } else if ( strcmp(tokbuf
,"rrcurveto")==0 ) {
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
;
1134 } else if ( strcmp(tokbuf
,"FillStroke")==0 ) {
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
;
1147 stack
[sp
-1].u
.val
= (stack
[sp
-1].u
.val
+99)/198.0;
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
) {
1159 t
[0] = stack
[sp
+0].u
.val
;
1160 t
[1] = stack
[sp
+1].u
.val
;
1161 t
[2] = stack
[sp
+2].u
.val
;
1162 t
[3] = stack
[sp
+3].u
.val
;
1163 t
[4] = stack
[sp
+4].u
.val
;
1164 t
[5] = stack
[sp
+5].u
.val
;
1165 MatMultiply(t
,ref
->transform
,ref
->transform
);
1166 wrapper
->top
->fogns
= false;
1168 ref
->orig_pos
= stack
[--sp
].u
.val
;
1169 ref
->next
= ec
->refs
;
1173 } else if ( strcmp(tokbuf
,"togNS_")==0 ) {
1174 wrapper
->top
->fogns
= !wrapper
->top
->fogns
;
1180 if ( sp
<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
1181 stack
[sp
].type
= ps_num
;
1182 stack
[sp
++].u
.val
= dval
;
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);
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
;
1207 if ( sp
<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
1208 stack
[sp
].type
= ps_num
;
1209 stack
[sp
].u
.val
= 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
);
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
);
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
);
1248 int n
= stack
[--sp
].u
.val
;
1249 if ( n
+sp
<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
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
);
1267 struct psstack temp
;
1269 stack
[sp
-1] = stack
[sp
-2];
1274 sp
= rollstack(stack
,sp
);
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
);
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
;
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
;
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
;
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" ));
1315 stack
[sp
-2].u
.val
/= stack
[sp
-1].u
.val
;
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" ));
1324 stack
[sp
-2].u
.val
= ((int) stack
[sp
-2].u
.val
) / ((int) stack
[sp
-1].u
.val
);
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" ));
1333 stack
[sp
-2].u
.val
= ((int) stack
[sp
-2].u
.val
) % ((int) stack
[sp
-1].u
.val
);
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
;
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
;
1353 if ( stack
[sp
-1].type
== ps_num
)
1354 stack
[sp
-1].u
.val
= -stack
[sp
-1].u
.val
;
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
;
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 */
1373 if ( stack
[sp
-1].type
== ps_num
)
1374 stack
[sp
-1].u
.val
= floor(stack
[sp
-1].u
.val
);
1379 if ( stack
[sp
-1].type
== ps_num
)
1380 stack
[sp
-1].u
.val
= ceil(stack
[sp
-1].u
.val
);
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
);
1389 stack
[sp
-1].u
.val
= floor(stack
[sp
-1].u
.val
);
1393 case pt_ne
: case pt_eq
:
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
);
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
;
1408 case pt_gt
: case pt_le
: case pt_lt
: case pt_ge
:
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" ));
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
);
1422 cmp
= strcmp(stack
[sp
-2].u
.str
,stack
[sp
-1].u
.str
);
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;
1430 stack
[sp
-2].u
.tf
= cmp
>=0;
1432 stack
[sp
-2].type
= ps_bool
;
1438 if ( stack
[sp
-1].type
== ps_bool
)
1439 stack
[sp
-1].u
.tf
= !stack
[sp
-1].u
.tf
;
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
;
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
;
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
;
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
);
1476 if ( sp
>=1 && stack
[sp
-1].type
==ps_num
) {
1477 stack
[sp
-1].u
.val
= sqrt(stack
[sp
-1].u
.val
);
1481 if ( sp
>=1 && stack
[sp
-1].type
==ps_num
) {
1482 stack
[sp
-1].u
.val
= log(stack
[sp
-1].u
.val
);
1486 if ( sp
>=1 && stack
[sp
-1].type
==ps_num
) {
1487 stack
[sp
-1].u
.val
= log10(stack
[sp
-1].u
.val
);
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;
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);
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);
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
);
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
);
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);
1533 if ( stack
[sp
-1].type
==ps_instr
)
1534 pushio(wrapper
,NULL
,stack
[sp
-1].u
.str
,0);
1536 if ( stack
[sp
-1].type
==ps_string
|| stack
[sp
-1].type
==ps_instr
|| stack
[sp
-1].type
==ps_lit
)
1537 free(stack
[sp
-1].u
.str
);
1538 if ( stack
[sp
-2].type
==ps_string
|| stack
[sp
-2].type
==ps_instr
|| stack
[sp
-2].type
==ps_lit
)
1539 free(stack
[sp
-2].u
.str
);
1545 real init
, incr
, limit
;
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
;
1558 while ( init
<=limit
) { ++cnt
; init
+= incr
; }
1559 } else if ( incr
<0 ) {
1560 while ( init
>=limit
) { ++cnt
; init
+= incr
; }
1562 pushio(wrapper
,NULL
,func
,cnt
);
1572 if ( stack
[sp
-1].type
==ps_instr
) {
1573 cnt
= 0x7fffffff; /* Loop for ever */
1574 func
= stack
[sp
-1].u
.str
;
1576 pushio(wrapper
,NULL
,func
,cnt
);
1586 if ( stack
[sp
-2].type
==ps_num
&& stack
[sp
-1].type
==ps_instr
) {
1587 cnt
= stack
[sp
-2].u
.val
;
1588 func
= stack
[sp
-1].u
.str
;
1590 pushio(wrapper
,NULL
,func
,cnt
);
1596 ioescapeloop(wrapper
);
1602 if ( stack
[sp
-1].type
==ps_instr
) {
1603 func
= stack
[sp
-1].u
.str
;
1605 pushio(wrapper
,NULL
,func
,-1);
1611 sp
= ioescapestopped(wrapper
,stack
,sp
,sizeof(stack
)/sizeof(stack
[0]));
1614 if ( sp
>=1 && stack
[sp
-1].type
==ps_lit
) {
1615 kv
= lookup(&dict
,stack
[sp
-1].u
.str
);
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
);
1623 stack
[sp
-1].type
= ps_instr
;
1627 sp
= AddEntry(&dict
,stack
,sp
);
1630 /* a noop in this context */
1632 case pt_setcachedevice
:
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 */
1640 case pt_setcharwidth
:
1642 ec
->width
= stack
[sp
-=2].u
.val
;
1645 if ( sp
>=1 && stack
[sp
-1].type
==ps_array
)
1646 sp
= DoMatOp(tok
,sp
,stack
);
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];
1654 if ( sp
>=1 && stack
[sp
-1].type
==ps_array
)
1655 sp
= DoMatOp(tok
,sp
,stack
);
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 */
1666 if ( sp
>=1 && stack
[sp
-1].type
==ps_array
)
1667 sp
= DoMatOp(tok
,sp
,stack
);
1670 t
[0] = t
[3] = cos(stack
[sp
].u
.val
);
1671 t
[1] = sin(stack
[sp
].u
.val
);
1674 MatMultiply(t
,transform
,transform
);
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
) {
1682 t
[5] = stack
[sp
].u
.dict
.entries
[5].u
.val
;
1683 t
[4] = stack
[sp
].u
.dict
.entries
[4].u
.val
;
1684 t
[3] = stack
[sp
].u
.dict
.entries
[3].u
.val
;
1685 t
[2] = stack
[sp
].u
.dict
.entries
[2].u
.val
;
1686 t
[1] = stack
[sp
].u
.dict
.entries
[1].u
.val
;
1687 t
[0] = stack
[sp
].u
.dict
.entries
[0].u
.val
;
1688 dictfree(&stack
[sp
].u
.dict
);
1689 MatMultiply(t
,transform
,transform
);
1695 if ( sp
>=1 && stack
[sp
-1].type
==ps_array
) {
1697 DoMatTransform(tok
,sp
,stack
);
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];
1707 if ( sp
>=1 && stack
[sp
-1].type
==ps_array
) {
1709 DoMatTransform(tok
,sp
,stack
);
1712 } else if ( sp
>=2 ) {
1713 double x
= stack
[sp
-2].u
.val
, y
= stack
[sp
-1].u
.val
;
1714 MatInverse(t
,transform
);
1715 stack
[sp
-2].u
.val
= t
[0]*x
+ t
[1]*y
+ t
[4];
1716 stack
[sp
-1].u
.val
= t
[2]*x
+ t
[3]*y
+ t
[5];
1720 if ( sp
>=1 && stack
[sp
-1].type
==ps_array
) {
1722 DoMatTransform(tok
,sp
,stack
);
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
;
1731 case pt_idtransform
:
1732 if ( sp
>=1 && stack
[sp
-1].type
==ps_array
) {
1734 DoMatTransform(tok
,sp
,stack
);
1737 } else if ( sp
>=2 ) {
1738 double x
= stack
[sp
-2].u
.val
, y
= stack
[sp
-1].u
.val
;
1739 MatInverse(t
,transform
);
1740 stack
[sp
-2].u
.val
= t
[0]*x
+ t
[1]*y
;
1741 stack
[sp
-1].u
.val
= t
[2]*x
+ t
[3]*y
;
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
);
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
)
1760 lastref
->next
= ref
;
1765 SplinePointListsFree(head
);
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
;
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
;
1781 pt
= chunkalloc(sizeof(SplinePoint
));
1782 Transform(&pt
->me
,¤t
,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
;
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
);
1802 case pt_curveto
: case pt_rcurveto
:
1804 if ( tok
==pt_rcurveto
) {
1805 stack
[sp
-1].u
.val
+= current
.y
;
1806 stack
[sp
-3].u
.val
+= current
.y
;
1807 stack
[sp
-5].u
.val
+= current
.y
;
1808 stack
[sp
-2].u
.val
+= current
.x
;
1809 stack
[sp
-4].u
.val
+= current
.x
;
1810 stack
[sp
-6].u
.val
+= current
.x
;
1812 current
.x
= stack
[sp
-2].u
.val
;
1813 current
.y
= stack
[sp
-1].u
.val
;
1814 if ( cur
!=NULL
&& cur
->first
!=NULL
&& (cur
->first
!=cur
->last
|| cur
->first
->next
==NULL
) ) {
1815 temp
.x
= stack
[sp
-6].u
.val
; temp
.y
= stack
[sp
-5].u
.val
;
1816 Transform(&cur
->last
->nextcp
,&temp
,transform
);
1817 cur
->last
->nonextcp
= false;
1818 pt
= chunkalloc(sizeof(SplinePoint
));
1819 temp
.x
= stack
[sp
-4].u
.val
; temp
.y
= stack
[sp
-3].u
.val
;
1820 Transform(&pt
->prevcp
,&temp
,transform
);
1821 Transform(&pt
->me
,¤t
,transform
);
1822 pt
->nonextcp
= true;
1823 CheckMake(cur
->last
,pt
);
1824 SplineMake3(cur
->last
,pt
);
1831 case pt_arc
: case pt_arcn
:
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
;
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
);
1851 } else { /* if no current point, then start here */
1852 SplinePointList
*spl
= chunkalloc(sizeof(SplinePointList
));
1853 spl
->first
= spl
->last
= pt
;
1861 circlearcsto(a1
,a2
,cx
,cy
,r
,cur
,transform
,tok
==pt_arcn
);
1862 current
.x
= cx
+r
*cos(a2
/180 * 3.1415926535897932);
1863 current
.y
= cy
+r
*sin(a2
/180 * 3.1415926535897932);
1867 case pt_arct
: case pt_arcto
:
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
;
1878 xt1
= xt2
= x1
; yt1
= yt2
= y1
;
1879 if ( cur
==NULL
|| cur
->first
==NULL
|| (cur
->first
==cur
->last
&& cur
->first
->next
!=NULL
) )
1881 else if ( current
.x
==x1
&& current
.y
==y1
)
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
,¤t
,transform
);
1889 pt
->noprevcp
= true; pt
->nonextcp
= true;
1890 CheckMake(cur
->last
,pt
);
1891 SplineMake3(cur
->last
,pt
);
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
;
1902 int clockwise
= true;
1904 a1
= atan2(current
.y
-y1
,current
.x
-x1
);
1905 a2
= atan2(y2
-y1
,x2
-x1
);
1906 amid
= atan2(dy
,dx
) - a1
;
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
) {
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
);
1927 a1
= 3*3.1415926535897932/2+a1
;
1928 a2
= 3.1415926535897932/2+a2
;
1930 a1
+= 3.1415926535897932;
1931 a2
+= 3.1415926535897932;
1933 circlearcsto(a1
*180/3.1415926535897932,a2
*180/3.1415926535897932,
1934 cx
,cy
,r
,cur
,transform
,clockwise
);
1936 if ( tok
==pt_arcto
) {
1937 stack
[sp
].type
= stack
[sp
+1].type
= stack
[sp
+2].type
= stack
[sp
+3].type
= ps_num
;
1938 stack
[sp
++].u
.val
= xt1
;
1939 stack
[sp
++].u
.val
= yt1
;
1940 stack
[sp
++].u
.val
= xt2
;
1941 stack
[sp
++].u
.val
= yt2
;
1943 current
.x
= xt2
; current
.y
= yt2
;
1947 if ( cur
!=NULL
&& cur
->first
!=NULL
&& cur
->first
!=cur
->last
) {
1948 if ( RealNear(cur
->first
->me
.x
,cur
->last
->me
.x
) && RealNear(cur
->first
->me
.y
,cur
->last
->me
.y
) ) {
1949 SplinePoint
*oldlast
= cur
->last
;
1950 cur
->first
->prevcp
= oldlast
->prevcp
;
1951 cur
->first
->prevcp
.x
+= (cur
->first
->me
.x
-oldlast
->me
.x
);
1952 cur
->first
->prevcp
.y
+= (cur
->first
->me
.y
-oldlast
->me
.y
);
1953 cur
->first
->noprevcp
= oldlast
->noprevcp
;
1954 oldlast
->prev
->from
->next
= NULL
;
1955 cur
->last
= oldlast
->prev
->from
;
1956 SplineFree(oldlast
->prev
);
1957 SplinePointFree(oldlast
);
1959 CheckMake(cur
->last
,cur
->first
);
1960 SplineMake3(cur
->last
,cur
->first
);
1961 cur
->last
= cur
->first
;
1966 linecap
= stack
[--sp
].u
.val
;
1968 case pt_setlinejoin
:
1970 linejoin
= stack
[--sp
].u
.val
;
1972 case pt_setlinewidth
:
1974 linewidth
= stack
[--sp
].u
.val
;
1977 if ( sp
>=2 && stack
[sp
-1].type
==ps_num
&& stack
[sp
-2].type
==ps_array
) {
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
);
1985 case pt_currentlinecap
: case pt_currentlinejoin
:
1986 if ( sp
<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
1987 stack
[sp
].type
= ps_num
;
1988 stack
[sp
++].u
.val
= tok
==pt_currentlinecap
?linecap
:linejoin
;
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
;
1997 case pt_currentdash
:
1998 if ( sp
+1<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
1999 struct pskeydict dict
;
2000 dict
.is_executable
= 0;
2001 for ( i
=0; i
<DASH_MAX
&& dashes
[i
]!=0; ++i
);
2002 dict
.cnt
= dict
.max
= i
;
2003 dict
.entries
= gcalloc(i
,sizeof(struct pskeyval
));
2004 for ( j
=0; j
<i
; ++j
) {
2005 dict
.entries
[j
].type
= ps_num
;
2006 dict
.entries
[j
].u
.val
= dashes
[j
];
2008 stack
[sp
].type
= ps_array
;
2009 stack
[sp
++].u
.dict
= dict
;
2010 stack
[sp
].type
= ps_num
;
2011 stack
[sp
++].u
.val
= dash_offset
;
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.;
2022 fore
= stack
[--sp
].u
.val
*255;
2026 case pt_setrgbcolor
:
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);
2034 case pt_currenthsbcolor
: case pt_currentrgbcolor
:
2035 if ( sp
+2<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
2036 stack
[sp
].type
= stack
[sp
+1].type
= stack
[sp
+2].type
= ps_num
;
2037 if ( tok
==pt_currentrgbcolor
) {
2038 stack
[sp
++].u
.val
= ((fore
>>16)&0xff)/255.;
2039 stack
[sp
++].u
.val
= ((fore
>>8)&0xff)/255.;
2040 stack
[sp
++].u
.val
= (fore
&0xff)/255.;
2042 int r
=fore
>>16, g
=(fore
>>8)&0xff, bl
=fore
&0xff;
2046 if ( mx
>g
) mn
=g
; else mx
=g
;
2047 if ( mx
<bl
) mx
= bl
; if ( mn
>bl
) mn
= bl
;
2051 s
= ((real
) (mx
-mn
))/mx
;
2053 real rdiff
= ((real
) (mx
-r
))/(mx
-mn
);
2054 real gdiff
= ((real
) (mx
-g
))/(mx
-mn
);
2055 real bdiff
= ((real
) (mx
-bl
))/(mx
-mn
);
2058 else if ( gdiff
==0 )
2059 h
= 2 + rdiff
-bdiff
;
2061 h
= 4 + gdiff
-rdiff
;
2065 stack
[sp
++].u
.val
= h
;
2066 stack
[sp
++].u
.val
= s
;
2067 stack
[sp
++].u
.val
= b
;
2071 case pt_sethsbcolor
:
2073 real h
= stack
[sp
-3].u
.val
, s
= stack
[sp
-2].u
.val
, b
= stack
[sp
-1].u
.val
;
2075 if ( s
==0 ) /* it's grey */
2076 fore
= ((int) (b
*255)) * 0x010101;
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
) {
2083 r
= b
*255.; g
= t
*255.; bl
= p
*255.;
2086 r
= q
*255.; g
= b
*255.; bl
= p
*255.;
2089 r
= p
*255.; g
= b
*255.; bl
= t
*255.;
2092 r
= p
*255.; g
= q
*255.; bl
= b
*255.;
2095 r
= t
*255.; g
= p
*255.; bl
= b
*255.;
2098 r
= b
*255.; g
= p
*255.; bl
= q
*255.;
2101 fore
= COLOR_CREATE(r
,g
,bl
);
2106 case pt_currentcmykcolor
:
2107 if ( sp
+3<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
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
;
2120 stack
[sp
++].u
.val
= c
;
2121 stack
[sp
++].u
.val
= m
;
2122 stack
[sp
++].u
.val
= y
;
2123 stack
[sp
++].u
.val
= k
;
2126 case pt_setcmykcolor
:
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
;
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.));
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
;
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)*/
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
));
2160 ent
= EntityCreate(head
,linecap
,linejoin
,linewidth
,transform
,clippath
);
2161 ent
->next
= ec
->splines
;
2165 ent
->u
.splines
.fill
.col
= fore
;
2167 ent
->u
.splines
.stroke
.col
= fore
;
2168 head
= NULL
; cur
= NULL
;
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
;
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
))
2186 /* We don't do these right, but at least we'll avoid some errors with this hack */
2187 case pt_save
: case pt_currentmatrix
:
2188 /* push some junk on the stack */
2189 if ( sp
<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
2190 stack
[sp
].type
= ps_num
;
2191 stack
[sp
++].u
.val
= 0;
2193 /* Fall through into gsave */;
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
);
2204 /* I should be saving the "current path" too, but that's too hard */
2207 case pt_restore
: case pt_setmatrix
:
2208 /* pop some junk off the stack */
2211 /* Fall through into grestore */;
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
;
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
;
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
;
2239 case pt_setoverprint
:
2240 /* pop one item on stack */
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
;
2252 /* pop one item on stack */
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
;
2263 case pt_setmiterlimit
:
2264 /* pop one item off stack */
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
;
2276 /* pop one item on stack */
2280 case pt_currentstrokeadjust
:
2281 /* push false (default value). I don't handle this properly */
2282 if ( sp
<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
2283 stack
[sp
].u
.val
= 0;
2284 stack
[sp
++].type
= ps_bool
;
2287 case pt_setstrokeadjust
:
2288 /* pop one item on stack */
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
;
2299 case pt_setsmoothness
:
2300 /* pop one item on stack */
2304 case pt_currentobjectformat
:
2305 /* default value is installation dependant. I don't handle this properly */
2306 if ( sp
<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
2307 stack
[sp
].u
.val
= 0.0;
2308 stack
[sp
++].type
= ps_num
;
2311 case pt_setobjectformat
:
2312 /* pop one item on stack */
2316 case pt_currentglobal
: case pt_currentshared
:
2317 /* push false (default value). I don't handle this properly */
2318 if ( sp
<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
2319 stack
[sp
].u
.val
= 0;
2320 stack
[sp
++].type
= ps_bool
;
2324 /* pop one item on stack */
2329 case pt_openarray
: case pt_mark
:
2330 if ( sp
<(int)(sizeof(stack
)/sizeof(stack
[0])) ) {
2331 stack
[sp
++].type
= ps_mark
;
2334 case pt_counttomark
:
2335 for ( i
=0; i
<sp
; ++i
)
2336 if ( stack
[sp
-1-i
].type
==ps_mark
)
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
;
2345 case pt_cleartomark
:
2346 for ( i
=0; i
<sp
; ++i
)
2347 if ( stack
[sp
-1-i
].type
==ps_mark
)
2350 LogError( _("No mark in cleartomark\n") );
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
);
2363 for ( i
=0; i
<sp
; ++i
)
2364 if ( stack
[sp
-1-i
].type
==ps_mark
)
2367 LogError( _("No mark in ] (close array)\n") );
2369 struct pskeydict dict
;
2370 dict
.is_executable
= 0;
2371 dict
.cnt
= dict
.max
= i
;
2372 dict
.entries
= gcalloc(i
,sizeof(struct pskeyval
));
2373 for ( j
=0; j
<i
; ++j
) {
2374 dict
.entries
[j
].type
= stack
[sp
-i
+j
].type
;
2375 dict
.entries
[j
].u
= stack
[sp
-i
+j
].u
;
2376 /* don't need to copy because the things on the stack */
2377 /* are being popped (don't need to free either) */
2379 collectgarbage(&tofrees
,&dict
);
2381 stack
[sp
-1].type
= ps_array
;
2382 stack
[sp
-1].u
.dict
= dict
;
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
;
2397 sp
= aload(sp
,stack
,sizeof(stack
)/sizeof(stack
[0]),&tofrees
);
2400 if ( sp
>=1 && stack
[sp
-1].type
==ps_array
) {
2401 struct pskeydict dict
;
2403 dict
= stack
[sp
].u
.dict
;
2404 if ( sp
>=dict
.cnt
) {
2405 for ( i
=dict
.cnt
-1; i
>=0 ; --i
) {
2407 dict
.entries
[i
].type
= stack
[sp
].type
;
2408 dict
.entries
[i
].u
= stack
[sp
].u
;
2411 stack
[sp
].type
= ps_array
;
2412 stack
[sp
].u
.dict
= dict
;
2417 case pt_output
: case pt_outputd
: case pt_print
:
2420 switch ( stack
[sp
].type
) {
2422 printf( "%g", (double) stack
[sp
].u
.val
);
2425 printf( "%s", stack
[sp
].u
.tf
? "true" : "false" );
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
);
2438 printf( "-- void --" );
2441 if ( tok
==pt_outputd
) {
2442 printarray(&stack
[sp
].u
.dict
);
2443 dictfree(&stack
[sp
].u
.dict
);
2445 } /* else fall through */
2446 dictfree(&stack
[sp
].u
.dict
);
2448 printf( "-- nostringval --" );
2451 if ( tok
==pt_output
|| tok
==pt_outputd
)
2454 LogError( _("Nothing on stack to print\n") );
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
;
2468 if ( stack
[sp
-1].type
==ps_array
)
2469 stack
[sp
-1].u
.dict
.is_executable
= false;
2473 if ( stack
[sp
-1].type
==ps_string
)
2474 stack
[sp
-1].type
= ps_lit
;
2478 if ( stack
[sp
-1].type
==ps_array
)
2479 stack
[sp
-1].u
.dict
.is_executable
= true;
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];
2497 if ( sp
>=2 && stack
[sp
-1].type
==ps_string
) {
2498 switch ( stack
[sp
].type
) {
2500 sprintf( stack
[sp
-1].u
.str
, "%g", (double) stack
[sp
-2].u
.val
);
2503 sprintf( stack
[sp
-1].u
.str
, "%s", stack
[sp
-2].u
.tf
? "true" : "false" );
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
);
2510 printf( "-- void --" );
2513 dictfree(&stack
[sp
].u
.dict
);
2515 sprintf( stack
[sp
-1].u
.str
, "-- nostringval --" );
2518 stack
[sp
-2] = stack
[sp
-1];
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);
2531 LogError( _("Warning: Unable to parse token %s, some features may be lost\n"), tokbuf
);
2543 for ( i
=sp
-1; i
>=0; --i
)
2544 if ( stack
[i
].type
!=ps_num
)
2547 if ( cnt
>rs
->max
) cnt
= rs
->max
;
2549 for ( j
=i
+1; j
<sp
; ++j
)
2550 rs
->stack
[j
-i
-1] = stack
[j
].u
.val
;
2552 freestuff(stack
,sp
,&dict
,&gb
,&tofrees
);
2554 ent
= EntityCreate(head
,linecap
,linejoin
,linewidth
,transform
,clippath
);
2555 ent
->next
= ec
->splines
;
2560 SplinePointListsFree(gsaves
[gsp
].clippath
);
2562 SplinePointListsFree(clippath
);
2563 ECCatagorizePoints(ec
);
2564 if ( ec
->width
== UNDEFINED_WIDTH
)
2565 ec
->width
= wrapper
->advance_width
;
2566 setlocale(LC_NUMERIC
,oldloc
);
2569 static void InterpretPS(FILE *ps
, char *psstr
, EntityChar
*ec
, RetStack
*rs
) {
2572 memset(&wrapper
,0,sizeof(wrapper
));
2573 wrapper
.advance_width
= UNDEFINED_WIDTH
;
2574 pushio(&wrapper
,ps
,psstr
,0);
2575 _InterpretPS(&wrapper
,ec
,rs
);
2578 static SplinePointList
*EraseStroke(SplineChar
*sc
,SplinePointList
*head
,SplinePointList
*erase
) {
2579 SplineSet
*spl
, *last
;
2583 /* Pointless, but legal */
2584 SplinePointListsFree(erase
);
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
)
2595 if ( sp
==spl
->first
)
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
)
2606 if ( sp
==spl
->first
)
2611 return( SplineSetRemoveOverlap(sc
,head
,over_exclude
) );
2614 static Entity
*EntityReverse(Entity
*ent
) {
2615 Entity
*next
, *last
= NULL
;
2617 while ( ent
!=NULL
) {
2626 void SFSplinesFromLayers(SplineFont
*sf
, int tostroke
) {
2631 static void EntityCharCorrectDir(EntityChar
*ec
) {
2636 for ( ent
=ec
->splines
; ent
!=NULL
; ent
= ent
->next
) {
2637 /* ignore splines which are only stoked, but not filled */
2638 if ( ent
->type
== et_splines
&& ent
->u
.splines
.fill
.col
!=0xffffffff ) {
2639 /* Correct the direction of each stroke or fill with respect to */
2640 /* the splines in it */
2641 SplineSetsCorrect(ent
->u
.splines
.splines
,&changed
);
2642 if ( ent
->u
.splines
.fill
.col
==0xffffff ) {
2643 /* If they are filling with white, then assume they mean */
2644 /* an internal area that should be drawn backwards */
2645 for ( ss
=ent
->u
.splines
.splines
; ss
!=NULL
; ss
=ss
->next
)
2646 SplineSetReverse(ss
);
2648 SplineSetsCorrect(ent
->clippath
,&changed
);
2653 static void EntityDefaultStrokeFill(Entity
*ent
) {
2654 while ( ent
!=NULL
) {
2655 if ( ent
->type
== et_splines
&&
2656 ent
->u
.splines
.stroke
.col
==0xffffffff &&
2657 ent
->u
.splines
.fill
.col
==0xffffffff ) {
2660 for ( spl
=ent
->u
.splines
.splines
; spl
!=NULL
; spl
=spl
->next
)
2661 if ( spl
->first
->prev
!=NULL
) {
2665 if ( all
&& ent
->u
.splines
.splines
!=NULL
&&
2666 (ent
->u
.splines
.stroke_width
==0 || ent
->u
.splines
.stroke_width
==WIDTH_INHERITED
))
2667 ent
->u
.splines
.stroke_width
=40; /* random guess */
2668 if (ent
->u
.splines
.stroke_width
==0 || ent
->u
.splines
.stroke_width
==WIDTH_INHERITED
)
2669 ent
->u
.splines
.fill
.col
= COLOR_INHERITED
;
2671 ent
->u
.splines
.stroke
.col
= COLOR_INHERITED
;
2677 static SplinePointList
*SplinesFromEntityChar(EntityChar
*ec
,int *flags
,int is_stroked
) {
2679 SplinePointList
*head
=NULL
, *last
=NULL
, *new, *nlast
=NULL
, *temp
, *each
, *transed
;
2681 real inversetrans
[6];
2683 int handle_eraser
= false;
2686 EntityDefaultStrokeFill(ec
->splines
);
2688 if ( !is_stroked
) {
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))) {
2701 *flags
= PsStrokeFlagsDlg();
2704 if ( *flags
& sf_correctdir
) /* Will happen if flags still unset (-1) */
2705 EntityCharCorrectDir(ec
);
2707 handle_eraser
= *flags
!=-1 && (*flags
& sf_handle_eraser
);
2708 if ( handle_eraser
)
2709 ec
->splines
= EntityReverse(ec
->splines
);
2712 for ( ent
=ec
->splines
; ent
!=NULL
; ent
= next
) {
2714 if ( ent
->type
== et_splines
&& is_stroked
) {
2716 head
= ent
->u
.splines
.splines
;
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 */
2729 memset(&si
,'\0',sizeof(si
));
2730 si
.toobigwarn
= *flags
& sf_toobigwarn
? 1 : 0;
2731 si
.join
= ent
->u
.splines
.join
;
2732 si
.cap
= ent
->u
.splines
.cap
;
2733 si
.removeoverlapifneeded
= *flags
& sf_removeoverlap
? 1 : 0;
2734 si
.radius
= ent
->u
.splines
.stroke_width
/2;
2735 if ( ent
->u
.splines
.stroke_width
==WIDTH_INHERITED
)
2737 if ( si
.cap
== lc_inherited
) si
.cap
= lc_butt
;
2738 if ( si
.join
== lc_inherited
) si
.join
= lj_miter
;
2741 SSBisectTurners(ent
->u
.splines
.splines
);
2743 MatInverse(inversetrans
,ent
->u
.splines
.transform
);
2744 transed
= SplinePointListTransform(SplinePointListCopy(
2745 ent
->u
.splines
.splines
),inversetrans
,true);
2746 for ( each
= transed
; each
!=NULL
; each
=each
->next
) {
2747 temp
= SplineSetStroke(each
,&si
,ec
->sc
);
2753 for ( nlast
=temp
; nlast
->next
!=NULL
; nlast
=nlast
->next
);
2755 new = SplinePointListTransform(new,ent
->u
.splines
.transform
,true);
2756 SplinePointListsFree(transed
);
2757 if ( handle_eraser
&& ent
->u
.splines
.stroke
.col
==0xffffff ) {
2758 head
= EraseStroke(ec
->sc
,head
,new);
2761 for ( ; last
->next
!=NULL
; last
=last
->next
);
2768 for ( last
= new; last
->next
!=NULL
; last
=last
->next
);
2770 if ( si
.toobigwarn
)
2771 *flags
|= sf_toobigwarn
;
2773 /* If they have neither a stroke nor a fill, pretend they said fill */
2774 if ( ent
->u
.splines
.fill
.col
==0xffffffff && ent
->u
.splines
.stroke
.col
!=0xffffffff )
2775 SplinePointListsFree(ent
->u
.splines
.splines
);
2776 else if ( handle_eraser
&& ent
->u
.splines
.fill
.col
==0xffffff ) {
2777 head
= EraseStroke(ec
->sc
,head
,ent
->u
.splines
.splines
);
2780 for ( ; last
->next
!=NULL
; last
=last
->next
);
2782 new = ent
->u
.splines
.splines
;
2788 for ( last
= new; last
->next
!=NULL
; last
=last
->next
);
2791 SplinePointListsFree(ent
->clippath
);
2798 static RefChar
*revrefs(RefChar
*cur
) {
2805 for ( ; (n
=cur
->next
)!=NULL
; cur
= n
) {
2813 static void SCInterpretPS(FILE *ps
,SplineChar
*sc
, int *flags
) {
2820 while ( isspace(ch
= getc(ps
)) );
2823 memset(&wrapper
,0,sizeof(wrapper
));
2824 wrapper
.advance_width
= UNDEFINED_WIDTH
;
2826 pushio(&wrapper
,ps
,NULL
,0);
2828 if ( nextpstoken(&wrapper
,&dval
,tokbuf
,sizeof(tokbuf
))!=pt_opencurly
)
2829 LogError( _("We don't understand this font\n") );
2832 pushfogio(&wrapper
,ps
);
2834 memset(&ec
,'\0',sizeof(ec
));
2835 ec
.fromtype3
= true;
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
);
2844 void PSFontInterpretPS(FILE *ps
,struct charprocs
*cp
,char **encoding
) {
2848 SplineChar
*sc
; EntityChar dummy
;
2849 RefChar
*p
, *ref
, *next
;
2854 wrapper
.advance_width
= UNDEFINED_WIDTH
;
2855 pushio(&wrapper
,ps
,NULL
,0);
2857 while ( (tok
= nextpstoken(&wrapper
,&dval
,tokbuf
,sizeof(tokbuf
)))!=pt_eof
&& tok
!=pt_end
) {
2858 if ( tok
==pt_namelit
) {
2859 if ( cp
->next
>=cp
->cnt
) {
2861 cp
->keys
= grealloc(cp
->keys
,cp
->cnt
*sizeof(char *));
2862 cp
->values
= grealloc(cp
->values
,cp
->cnt
*sizeof(char *));
2864 if ( cp
->next
<cp
->cnt
) {
2865 sc
= SplineCharCreate(2);
2866 cp
->keys
[cp
->next
] = copy(tokbuf
);
2867 cp
->values
[cp
->next
++] = sc
;
2868 sc
->name
= copy(tokbuf
);
2869 SCInterpretPS(ps
,sc
,&flags
);
2872 memset(&dummy
,0,sizeof(dummy
));
2873 dummy
.fromtype3
= true;
2874 InterpretPS(ps
,NULL
,&dummy
,NULL
);
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
);
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 )
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;
2903 cp
->values
[i
]->layers
[ly_fore
].refs
= next
;
2913 static void closepath(SplinePointList
*cur
, int is_type2
) {
2914 if ( cur
!=NULL
&& cur
->first
==cur
->last
&& cur
->first
->prev
==NULL
&& is_type2
)
2915 return; /* The "path" is just a single point created by a moveto */
2916 /* Probably we're just doing another moveto */
2917 if ( cur
!=NULL
&& cur
->first
!=NULL
&& cur
->first
!=cur
->last
) {
2918 /* I allow for greater errors here than I do in the straight postscript code */
2919 /* because: 1) the rel-rel operators will accumulate more rounding errors */
2920 /* 2) I only output 2 decimal digits after the decimal in type1 output */
2921 if ( RealWithin(cur
->first
->me
.x
,cur
->last
->me
.x
,.05) && RealWithin(cur
->first
->me
.y
,cur
->last
->me
.y
,.05) ) {
2922 SplinePoint
*oldlast
= cur
->last
;
2923 cur
->first
->prevcp
= oldlast
->prevcp
;
2924 cur
->first
->prevcp
.x
+= (cur
->first
->me
.x
-oldlast
->me
.x
);
2925 cur
->first
->prevcp
.y
+= (cur
->first
->me
.y
-oldlast
->me
.y
);
2926 cur
->first
->noprevcp
= oldlast
->noprevcp
;
2927 oldlast
->prev
->from
->next
= NULL
;
2928 cur
->last
= oldlast
->prev
->from
;
2929 chunkfree(oldlast
->prev
,sizeof(*oldlast
));
2930 chunkfree(oldlast
->hintmask
,sizeof(HintMask
));
2931 chunkfree(oldlast
,sizeof(*oldlast
));
2933 CheckMake(cur
->last
,cur
->first
);
2934 SplineMake3(cur
->last
,cur
->first
);
2935 cur
->last
= cur
->first
;
2939 static void UnblendFree(StemInfo
*h
) {
2941 chunkfree(h
->u
.unblended
,sizeof(real
[2][MmMax
]));
2942 h
->u
.unblended
= NULL
;
2947 static StemInfo
*HintsAppend(StemInfo
*to
,StemInfo
*extra
) {
2954 for ( h
=to
; h
->next
!=NULL
; h
=h
->next
);
2959 static StemInfo
*HintNew(double start
,double width
) {
2962 h
= chunkalloc(sizeof(StemInfo
));
2968 static void RemapHintMask(HintMask
*hm
,int mapping
[96],int max
) {
2975 if ( max
>96 ) max
= 96;
2979 for ( i
=0; i
<max
; ++i
) if ( (*hm
)[i
>>3]&(0x80>>(i
&0x7)) )
2980 rpl
[mapping
[i
]>>3] |= (0x80>>(mapping
[i
]&0x7));
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 */
2994 for ( i
=0; i
<96; ++i
) mapping
[i
] = i
;
2997 for ( h
=sc
->hstem
; h
!=NULL
; h
=h
->next
) {
2998 if ( h
->hintnumber
<96 && i
<96 ) {
2999 mapping
[h
->hintnumber
] = i
;
3000 h
->hintnumber
= i
++;
3002 chunkfree(h
->u
.unblended
,sizeof(real
[2][MmMax
]));
3003 h
->u
.unblended
= NULL
;
3005 for ( h
=sc
->vstem
; h
!=NULL
; h
=h
->next
) {
3006 if ( h
->hintnumber
<96 && i
<96 ) {
3007 mapping
[h
->hintnumber
] = i
;
3008 h
->hintnumber
= i
++;
3010 chunkfree(h
->u
.unblended
,sizeof(real
[2][MmMax
]));
3011 h
->u
.unblended
= NULL
;
3014 for ( i
=0; i
<max
; ++i
)
3015 if ( mapping
[i
]!=i
)
3018 return; /* Didn't change the order */
3020 for ( i
=0; i
<sc
->countermask_cnt
; ++i
)
3021 RemapHintMask(&sc
->countermasks
[i
],mapping
,max
);
3022 for ( spl
= sc
->layers
[ly_fore
].splines
; spl
!=NULL
; spl
=spl
->next
) {
3023 for ( sp
= spl
->first
; ; ) {
3024 RemapHintMask(sp
->hintmask
,mapping
,max
);
3025 if ( sp
->next
==NULL
)
3028 if ( sp
==spl
->first
)
3034 int UnblendedCompare(real u1
[MmMax
], real u2
[MmMax
], int cnt
) {
3037 for ( i
=0; i
<cnt
; ++i
) {
3039 return( u1
[i
]>u2
[i
]?1:-1 );
3044 static StemInfo
*SameH(StemInfo
*old
,real start
, real width
,
3045 real unblended
[2][MmMax
], int instance_count
) {
3048 if ( instance_count
==0 ) {
3049 for ( sameh
=old
; sameh
!=NULL
; sameh
=sameh
->next
)
3050 if ( sameh
->start
==start
&& sameh
->width
==width
)
3053 for ( j
=1; j
<instance_count
; ++j
) {
3054 unblended
[0][j
] += unblended
[0][j
-1];
3055 unblended
[1][j
] += unblended
[1][j
-1];
3057 for ( sameh
=old
; sameh
!=NULL
; sameh
=sameh
->next
) {
3058 if ( (*sameh
->u
.unblended
)[0] == NULL
|| (*sameh
->u
.unblended
)[1]==NULL
)
3060 if ( UnblendedCompare((*sameh
->u
.unblended
)[0],unblended
[0],instance_count
)==0 &&
3061 UnblendedCompare((*sameh
->u
.unblended
)[1],unblended
[1],instance_count
)==0)
3068 static real
Blend(real u
[MmMax
],struct pscontext
*context
) {
3072 for ( i
=1; i
<context
->instance_count
; ++i
)
3073 sum
+= context
->blend_values
[i
]*u
[i
];
3077 /* this handles either Type1 or Type2 charstrings. Type2 charstrings have */
3078 /* more operators than Type1s and the old operators have extended meanings */
3079 /* (ie. the rlineto operator can produce more than one line). But pretty */
3080 /* much it's a superset and if we parse for type2 (with a few additions) */
3081 /* we'll get it right */
3082 /* Char width is done differently. Moveto starts a newpath. 0xff starts a 16.16*/
3083 /* number rather than a 32 bit number */
3084 SplineChar
*PSCharStringToSplines(uint8
*type1
, int len
, struct pscontext
*context
,
3085 struct pschars
*subrs
, struct pschars
*gsubrs
, const char *name
) {
3086 int is_type2
= context
->is_type2
;
3087 real stack
[50]; int sp
=0, v
; /* Type1 stack is about 25 long, Type2 stack is 48 */
3089 SplineChar
*ret
= SplineCharCreate(2);
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
;
3095 /* subroutines may be nested to a depth of 10 */
3096 struct substate
{ unsigned char *type1
; int len
; int subnum
; } pcstack
[11];
3098 StemInfo
*hint
, *hp
;
3105 StemInfo
*activeh
=NULL
, *activev
=NULL
, *sameh
;
3106 HintMask
*pending_hm
= NULL
;
3107 HintMask
*counters
[96];
3109 real unblended
[2][MmMax
];
3110 int last_was_b1
=false, old_last_was_b1
;
3112 if ( !is_type2
&& context
->instance_count
>1 )
3113 memset(unblended
,0,sizeof(unblended
));
3115 ret
->name
= copy( name
);
3116 ret
->unicodeenc
= -1;
3117 ret
->width
= (int16
) 0x8000;
3118 if ( name
==NULL
) name
= "unnamed";
3119 ret
->manualhints
= true;
3121 current
.x
= current
.y
= 0;
3124 LogError( _("Stack got too big in %s\n"), name
);
3129 if ( (v
= *type1
++)>=32 ) {
3131 stack
[sp
++] = v
- 139;
3132 } else if ( v
<=250 ) {
3133 stack
[sp
++] = (v
-247)*256 + *type1
++ + 108;
3135 } else if ( v
<=254 ) {
3136 stack
[sp
++] = -(v
-251)*256 - *type1
++ - 108;
3139 int val
= (*type1
<<24) | (type1
[1]<<16) | (type1
[2]<<8) | type1
[3];
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.;
3150 int mant
= val
&0xffff;
3151 stack
[sp
-1] = (val
>>16) + mant
/65536.;
3155 } else if ( v
==28 ) {
3156 stack
[sp
++] = (short) ((type1
[0]<<8) | type1
[1]);
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;
3166 case 0: /* dotsection */
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 */
3176 sameh
= SameH(ret
->vstem
,stack
[0] + ret
->lsidebearing
,stack
[1],
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
;
3183 for ( hp
=activev
; hp
->next
!=NULL
; hp
= hp
->next
);
3189 sameh
= SameH(ret
->vstem
,stack
[2] + ret
->lsidebearing
,stack
[3],
3191 hp
->next
= HintNew(stack
[2] + ret
->lsidebearing
,stack
[3]);
3192 hp
->next
->hintnumber
= sameh
!=NULL
? sameh
->hintnumber
: hint_cnt
++;
3194 sameh
= SameH(ret
->vstem
,stack
[4] + ret
->lsidebearing
,stack
[5],
3196 hp
->next
->next
= HintNew(stack
[4] + ret
->lsidebearing
,stack
[5]);
3197 hp
->next
->next
->hintnumber
= sameh
!=NULL
? sameh
->hintnumber
: hint_cnt
++;
3198 if ( !is_type2
&& hp
->next
->next
->hintnumber
<96 ) {
3199 if ( pending_hm
==NULL
)
3200 pending_hm
= chunkalloc(sizeof(HintMask
));
3201 (*pending_hm
)[hint
->hintnumber
>>3] |= 0x80>>(hint
->hintnumber
&0x7);
3202 (*pending_hm
)[hint
->next
->hintnumber
>>3] |= 0x80>>(hint
->next
->hintnumber
&0x7);
3203 (*pending_hm
)[hint
->next
->next
->hintnumber
>>3] |= 0x80>>(hint
->next
->next
->hintnumber
&0x7);
3205 hp
= hp
->next
->next
;
3208 case 2: /* hstem3 */ /* specifies three h hints zones at once */
3209 if ( sp
<6 ) LogError( _("Stack underflow on hstem3 in %s\n"), name
);
3212 sameh
= SameH(ret
->hstem
,stack
[0],stack
[1], unblended
,0);
3213 hint
= HintNew(stack
[0],stack
[1]);
3214 hint
->hintnumber
= sameh
!=NULL
? sameh
->hintnumber
: hint_cnt
++;
3215 if ( activeh
==NULL
)
3216 activeh
= hp
= hint
;
3218 for ( hp
=activeh
; hp
->next
!=NULL
; hp
= hp
->next
);
3224 sameh
= SameH(ret
->hstem
,stack
[2],stack
[3], unblended
,0);
3225 hp
->next
= HintNew(stack
[2],stack
[3]);
3226 hp
->next
->hintnumber
= sameh
!=NULL
? sameh
->hintnumber
: hint_cnt
++;
3229 sameh
= SameH(ret
->hstem
,stack
[4],stack
[5], unblended
,0);
3230 hp
->next
->next
= HintNew(stack
[4],stack
[5]);
3231 hp
->next
->next
->hintnumber
= sameh
!=NULL
? sameh
->hintnumber
: hint_cnt
++;
3232 if ( !is_type2
&& hp
->next
->next
->hintnumber
<96 ) {
3233 if ( pending_hm
==NULL
)
3234 pending_hm
= chunkalloc(sizeof(HintMask
));
3235 (*pending_hm
)[hint
->hintnumber
>>3] |= 0x80>>(hint
->hintnumber
&0x7);
3236 (*pending_hm
)[hint
->next
->hintnumber
>>3] |= 0x80>>(hint
->next
->hintnumber
&0x7);
3237 (*pending_hm
)[hint
->next
->next
->hintnumber
>>3] |= 0x80>>(hint
->next
->next
->hintnumber
&0x7);
3239 hp
= hp
->next
->next
;
3242 case 6: /* seac */ /* build accented characters */
3244 if ( sp
<5 ) LogError( _("Stack underflow on seac in %s\n"), name
);
3245 /* stack[0] must be the lsidebearing of the accent. I'm not sure why */
3246 r1
= RefCharCreate();
3247 r2
= RefCharCreate();
3248 r2
->transform
[0] = 1; r2
->transform
[3]=1;
3249 r2
->transform
[4] = stack
[1] - (stack
[0]-ret
->lsidebearing
);
3250 r2
->transform
[5] = stack
[2];
3251 /* the translation of the accent here is said to be relative */
3252 /* to the origins of the base character. I think they place */
3253 /* the origin at the left bearing. And they don't mean the */
3254 /* base char at all, they mean the current char's lbearing */
3255 /* (which is normally the same as the base char's, except */
3256 /* when I has a big accent (like diaerisis) */
3257 r1
->transform
[0] = 1; r1
->transform
[3]=1;
3258 r1
->adobe_enc
= stack
[3];
3259 r2
->adobe_enc
= stack
[4];
3260 if ( stack
[3]<0 || stack
[3]>=256 || stack
[4]<0 || stack
[4]>=256 ) {
3261 LogError( _("Reference encoding out of bounds in %s\n"), name
);
3266 if ( rlast
!=NULL
) rlast
->next
= r1
;
3267 else ret
->layers
[ly_fore
].refs
= r1
;
3268 ret
->changedsincelasthinted
= true; /* seac glyphs contain no hints */
3272 case 7: /* sbw */ /* generalized width/sidebearing command */
3273 if ( sp
<4 ) LogError( _("Stack underflow on sbw in %s\n"), name
);
3274 ret
->lsidebearing
= stack
[0];
3275 /* stack[1] is lsidebearing y (only for vertical writing styles, CJK) */
3276 ret
->width
= stack
[2];
3277 /* stack[3] is height (for vertical writing styles, CJK) */
3280 case 5: case 9: case 14: case 26:
3281 if ( sp
<1 ) LogError( _("Stack underflow on unary operator in %s\n"), name
);
3283 case 5: stack
[sp
-1] = (stack
[sp
-1]==0); break; /* not */
3284 case 9: if ( stack
[sp
-1]<0 ) stack
[sp
-1]= -stack
[sp
-1]; break; /* abs */
3285 case 14: stack
[sp
-1] = -stack
[sp
-1]; break; /* neg */
3286 case 26: stack
[sp
-1] = sqrt(stack
[sp
-1]); break; /* sqrt */
3289 case 3: case 4: case 10: case 11: case 12: case 15: case 24:
3290 if ( sp
<2 ) LogError( _("Stack underflow on binary operator in %s\n"), name
);
3293 stack
[sp
-2] = (stack
[sp
-1]!=0 && stack
[sp
-2]!=0);
3296 stack
[sp
-2] = (stack
[sp
-1]!=0 || stack
[sp
-2]!=0);
3299 stack
[sp
-2] += stack
[sp
-1];
3302 stack
[sp
-2] -= stack
[sp
-1];
3305 stack
[sp
-2] /= stack
[sp
-1];
3308 stack
[sp
-2] *= stack
[sp
-1];
3311 stack
[sp
-2] = (stack
[sp
-1]==stack
[sp
-2]);
3316 case 22: /* ifelse */
3317 if ( sp
<4 ) LogError( _("Stack underflow on ifelse in %s\n"), name
);
3319 if ( stack
[sp
-2]>stack
[sp
-1] )
3320 stack
[sp
-4] = stack
[sp
-3];
3324 case 23: /* random */
3325 /* This function returns something (0,1]. It's not clear to me*/
3326 /* if rand includes 0 and RAND_MAX or not, but this approach */
3327 /* should work no matter what */
3329 stack
[sp
] = (rand()/(RAND_MAX
-1));
3330 } while ( stack
[sp
]==0 || stack
[sp
]>1 );
3333 case 16: /* callothersubr */
3334 /* stack[sp-1] is the number of the thing to call in the othersubr array */
3335 /* stack[sp-2] is the number of args to grab off our stack and put on the */
3336 /* real postscript stack */
3338 LogError( _("Type2 fonts do not support the Type1 callothersubrs operator") );
3339 if ( sp
<2 || sp
< 2+stack
[sp
-2] ) {
3340 LogError( _("Stack underflow on callothersubr in %s\n"), name
);
3343 int tot
= stack
[sp
-2], i
, k
, j
;
3345 for ( k
=sp
-3; k
>=sp
-2-tot
; --k
)
3346 pops
[popsp
++] = stack
[k
];
3347 /* othersubrs 0-3 must be interpretted. 0-2 are Flex, 3 is Hint Replacement */
3348 /* othersubrs 12,13 are for counter hints. We don't need to */
3349 /* do anything to ignore them */
3350 /* Subroutines 14-18 are multiple master blenders. We need */
3351 /* to pay attention to them too */
3352 switch ( (int) stack
[sp
-1] ) {
3354 /* when we weren't capabable of hint replacement we */
3355 /* punted by putting 3 on the stack (T1 spec page 70) */
3356 /* subroutine 3 is a noop */
3357 /*pops[popsp-1] = 3;*/
3358 ret
->manualhints
= false;
3359 /* We can manage hint substitution from hintmask though*/
3360 /* well enough that we needn't clear the manualhints bit */
3361 ret
->hstem
= HintsAppend(ret
->hstem
,activeh
); activeh
=NULL
;
3362 ret
->vstem
= HintsAppend(ret
->vstem
,activev
); activev
=NULL
;
3365 /* Essentially what we want to do is draw a line from */
3366 /* where we are at the beginning to where we are at */
3367 /* the end. So we save the beginning here (this starts*/
3368 /* the flex sequence), we ignore all calls to othersub*/
3369 /* 2, and when we get to othersub 0 we put everything*/
3370 /* back to where it should be and free up whatever */
3371 /* extranious junk we created along the way and draw */
3373 /* Let's punt a little less, and actually figure out */
3374 /* the appropriate rrcurveto commands and put in a */
3376 /* We should never get here in a type2 font. But we did*/
3377 /* this code won't work if we follow type2 conventions*/
3378 /* so turn off type2 until we get 0 callothersubrs */
3379 /* which marks the end of the flex sequence */
3385 LogError( _("Bad flex subroutine in %s\n"), name
);
3390 case 0: if ( oldcur
!=NULL
) {
3391 SplinePointList
*spl
= oldcur
->next
;
3392 if ( spl
!=NULL
&& spl
->next
!=NULL
&&
3393 spl
->next
->next
!=NULL
&&
3394 spl
->next
->next
->next
!=NULL
&&
3395 spl
->next
->next
->next
->next
!=NULL
&&
3396 spl
->next
->next
->next
->next
->next
!=NULL
&&
3397 spl
->next
->next
->next
->next
->next
->next
!=NULL
) {
3398 BasePoint old_nextcp
, mid_prevcp
, mid
, mid_nextcp
,
3400 old_nextcp
= spl
->next
->first
->me
;
3401 mid_prevcp
= spl
->next
->next
->first
->me
;
3402 mid
= spl
->next
->next
->next
->first
->me
;
3403 mid_nextcp
= spl
->next
->next
->next
->next
->first
->me
;
3404 end_prevcp
= spl
->next
->next
->next
->next
->next
->first
->me
;
3405 end
= spl
->next
->next
->next
->next
->next
->next
->first
->me
;
3407 if ( cur
!=NULL
&& cur
->first
!=NULL
&& (cur
->first
!=cur
->last
|| cur
->first
->next
==NULL
) ) {
3408 cur
->last
->nextcp
= old_nextcp
;
3409 cur
->last
->nonextcp
= false;
3410 pt
= chunkalloc(sizeof(SplinePoint
));
3411 pt
->hintmask
= pending_hm
; pending_hm
= NULL
;
3412 pt
->prevcp
= mid_prevcp
;
3414 pt
->nextcp
= mid_nextcp
;
3415 /*pt->flex = pops[2];*/
3416 CheckMake(cur
->last
,pt
);
3417 SplineMake3(cur
->last
,pt
);
3419 pt
= chunkalloc(sizeof(SplinePoint
));
3420 pt
->prevcp
= end_prevcp
;
3422 pt
->nonextcp
= true;
3423 CheckMake(cur
->last
,pt
);
3424 SplineMake3(cur
->last
,pt
);
3427 LogError( _("No previous point on path in curveto from flex 0 in %s\n"), name
);
3429 /* Um, something's wrong. Let's just draw a line */
3430 /* do the simple method, which consists of creating */
3431 /* the appropriate line */
3432 pt
= chunkalloc(sizeof(SplinePoint
));
3433 pt
->me
.x
= pops
[1]; pt
->me
.y
= pops
[0];
3434 pt
->noprevcp
= true; pt
->nonextcp
= true;
3435 SplinePointListFree(oldcur
->next
); oldcur
->next
= NULL
; spl
= NULL
;
3437 if ( cur
!=NULL
&& cur
->first
!=NULL
&& (cur
->first
!=cur
->last
|| cur
->first
->next
==NULL
) ) {
3438 CheckMake(cur
->last
,pt
);
3439 SplineMake3(cur
->last
,pt
);
3442 LogError( _("No previous point on path in lineto from flex 0 in %s\n"), name
);
3446 SplinePointListsFree(spl
);
3449 LogError( _("Bad flex subroutine in %s\n"), name
);
3451 is_type2
= context
->is_type2
;
3452 /* If we found a type2 font with a type1 flex sequence */
3453 /* (an illegal idea, but never mind, someone gave us one)*/
3454 /* then we had to turn off type2 untill the end of the */
3455 /* flex sequence. Which is here */
3457 case 14: /* results in 1 blended value */
3458 case 15: /* results in 2 blended values */
3459 case 16: /* results in 3 blended values */
3460 case 17: /* results in 4 blended values */
3461 case 18: { /* results in 6 blended values */
3462 int cnt
= stack
[sp
-1]-13;
3463 if ( cnt
==5 ) cnt
=6;
3464 if ( context
->instance_count
==0 )
3465 LogError( _("Attempt to use a multiple master subroutine in a non-mm font in %s.\n"), name
);
3466 else if ( tot
!=cnt
*context
->instance_count
)
3467 LogError( _("Multiple master subroutine called with the wrong number of arguments in %s.\n"), name
);
3469 /* Hints need to keep track of the original blends */
3470 if ( cnt
==1 && !is_type2
) {
3471 if ( sp
-2-tot
>=1 && (!old_last_was_b1
|| stack
[0]!=Blend(unblended
[1],context
))) {
3472 unblended
[0][0] = stack
[0];
3473 for ( i
=1; i
<context
->instance_count
; ++i
)
3474 unblended
[0][i
] = 0;
3476 memcpy(unblended
,unblended
+1,context
->instance_count
*sizeof(real
));
3477 for ( j
=0; j
<context
->instance_count
; ++j
)
3478 unblended
[1][j
] = stack
[sp
-2-tot
+j
];
3479 } else if ( cnt
==2 && !is_type2
) {
3480 unblended
[0][0] = stack
[sp
-2-tot
];
3481 unblended
[1][0] = stack
[sp
-2-tot
+1];
3482 for ( i
=0; i
<2; ++i
)
3483 for ( j
=1; j
<context
->instance_count
; ++j
)
3484 unblended
[i
][j
] = stack
[sp
-2-tot
+2+i
*(context
->instance_count
-1)+(j
-1)];
3487 for ( i
=0; i
<cnt
; ++i
) {
3488 double sum
= stack
[sp
-2-tot
+ i
];
3489 for ( j
=1; j
<context
->instance_count
; ++j
)
3490 sum
+= context
->blend_values
[j
]*
3491 stack
[sp
-2-tot
+ cnt
+i
*(context
->instance_count
-1)+ j
-1];
3492 pops
[cnt
-1-popsp
++] = sum
;
3501 if ( sp
<2 ) LogError( _("Too few items on stack for put in %s\n"), name
);
3502 else if ( stack
[sp
-1]<0 || stack
[sp
-1]>=32 ) LogError( _("Reference to transient memory out of bounds in put in %s\n"), name
);
3504 transient
[(int)stack
[sp
-1]] = stack
[sp
-2];
3509 if ( sp
<1 ) LogError( _("Too few items on stack for get in %s\n"), name
);
3510 else if ( stack
[sp
-1]<0 || stack
[sp
-1]>=32 ) LogError( _("Reference to transient memory out of bounds in put in %s\n"), name
);
3512 stack
[sp
-1] = transient
[(int)stack
[sp
-1]];
3515 /* pops something from the postscript stack and pushes it on ours */
3516 /* used to get a return value from an othersubr call */
3517 /* Bleah. Adobe wants the pops to return the arguments if we */
3518 /* don't understand the call. What use is the subroutine then?*/
3520 LogError( _("Pop stack underflow on pop in %s\n"), name
);
3522 stack
[sp
++] = pops
[--popsp
];
3529 stack
[sp
] = stack
[sp
-1];
3535 real temp
= stack
[sp
-1];
3536 stack
[sp
-1] = stack
[sp
-2]; stack
[sp
-2] = temp
;
3539 case 29: /* index */
3541 int index
= stack
[--sp
];
3542 if ( index
<0 || sp
<index
+1 )
3543 LogError( _("Index out of range in %s\n"), name
);
3545 stack
[sp
] = stack
[sp
-index
-1];
3552 int j
= stack
[sp
-1], N
=stack
[sp
-2];
3553 if ( N
>sp
|| j
>=N
|| j
<0 || N
<0 )
3554 LogError( _("roll out of range in %s\n"), name
);
3555 else if ( j
==0 || N
==0 )
3558 real
*temp
= galloc(N
*sizeof(real
));
3560 for ( i
=0; i
<N
; ++i
)
3561 temp
[i
] = stack
[sp
-N
+i
];
3562 for ( i
=0; i
<N
; ++i
)
3563 stack
[sp
-N
+i
] = temp
[(i
+j
)%N
];
3568 case 33: /* setcurrentpoint */
3569 if ( sp
<2 ) LogError( _("Stack underflow on setcurrentpoint in %s\n"), name
);
3571 current
.x
= stack
[0];
3572 current
.y
= stack
[1];
3576 case 34: /* hflex */
3578 case 36: /* hflex1 */
3579 case 37: /* flex1 */
3580 dy
= dy3
= dy4
= dy5
= dy6
= 0;
3584 dx2
= stack
[base
++];
3585 dy2
= stack
[base
++];
3586 dx3
= stack
[base
++];
3587 if ( v
!=34 && v
!=36 )
3588 dy3
= stack
[base
++];
3589 dx4
= stack
[base
++];
3590 if ( v
!=34 && v
!=36 )
3591 dy4
= stack
[base
++];
3592 dx5
= stack
[base
++];
3596 dy5
= stack
[base
++];
3600 dx6
= stack
[base
++];
3601 dy6
= stack
[base
++];
3603 case 34: /* hflex */
3604 dx6
= stack
[base
++];
3606 case 36: /* hflex1 */
3607 dx6
= stack
[base
++];
3610 case 37: /* flex1 */
3611 xt
= dx
+dx2
+dx3
+dx4
+dx5
;
3612 yt
= dy
+dy2
+dy3
+dy4
+dy5
;
3613 if ( xt
<0 ) xt
= -xt
;
3614 if ( yt
<0 ) yt
= -yt
;
3616 dx6
= stack
[base
++];
3617 dy6
= -dy
-dy2
-dy3
-dy4
-dy5
;
3619 dy6
= stack
[base
++];
3620 dx6
= -dx
-dx2
-dx3
-dx4
-dx5
;
3624 if ( cur
!=NULL
&& cur
->first
!=NULL
&& (cur
->first
!=cur
->last
|| cur
->first
->next
==NULL
) ) {
3625 current
.x
= rint((current
.x
+dx
)*1024)/1024; current
.y
= rint((current
.y
+dy
)*1024)/1024;
3626 cur
->last
->nextcp
.x
= current
.x
; cur
->last
->nextcp
.y
= current
.y
;
3627 cur
->last
->nonextcp
= false;
3628 current
.x
= rint((current
.x
+dx2
)*1024)/1024; current
.y
= rint((current
.y
+dy2
)*1024)/1024;
3629 pt
= chunkalloc(sizeof(SplinePoint
));
3630 pt
->hintmask
= pending_hm
; pending_hm
= NULL
;
3631 pt
->prevcp
.x
= current
.x
; pt
->prevcp
.y
= current
.y
;
3632 current
.x
= rint((current
.x
+dx3
)*1024)/1024; current
.y
= rint((current
.y
+dy3
)*1024)/1024;
3633 pt
->me
.x
= current
.x
; pt
->me
.y
= current
.y
;
3634 pt
->nonextcp
= true;
3635 CheckMake(cur
->last
,pt
);
3636 SplineMake3(cur
->last
,pt
);
3639 current
.x
= rint((current
.x
+dx4
)*1024)/1024; current
.y
= rint((current
.y
+dy4
)*1024)/1024;
3640 cur
->last
->nextcp
.x
= current
.x
; cur
->last
->nextcp
.y
= current
.y
;
3641 cur
->last
->nonextcp
= false;
3642 current
.x
= rint((current
.x
+dx5
)*1024)/1024; current
.y
= rint((current
.y
+dy5
)*1024)/1024;
3643 pt
= chunkalloc(sizeof(SplinePoint
));
3644 pt
->prevcp
.x
= current
.x
; pt
->prevcp
.y
= current
.y
;
3645 current
.x
= rint((current
.x
+dx6
)*1024)/1024; current
.y
= rint((current
.y
+dy6
)*1024)/1024;
3646 pt
->me
.x
= current
.x
; pt
->me
.y
= current
.y
;
3647 pt
->nonextcp
= true;
3648 CheckMake(cur
->last
,pt
);
3649 SplineMake3(cur
->last
,pt
);
3652 LogError( _("No previous point on path in flex operator in %s\n"), name
);
3656 LogError( _("Uninterpreted opcode 12,%d in %s\n"), v
, name
);
3659 } else { last_was_b1
= false; switch ( v
) {
3661 case 18: /* hstemhm */
3663 if ( (sp
&1) && ret
->width
== (int16
) 0x8000 )
3664 ret
->width
= stack
[0];
3668 LogError( _("Stack underflow on hstem in %s\n"), name
);
3669 /* stack[0] is absolute y for start of horizontal hint */
3670 /* (actually relative to the y specified as lsidebearing y in sbw*/
3671 /* stack[1] is relative y for height of hint zone */
3674 if ( activeh
!=NULL
)
3675 for ( hp
=activeh
; hp
->next
!=NULL
; hp
= hp
->next
);
3676 while ( sp
-base
>=2 ) {
3679 sameh
= SameH(ret
->hstem
,stack
[base
]+coord
,stack
[base
+1],
3680 unblended
,context
->instance_count
);
3681 hint
= HintNew(stack
[base
]+coord
,stack
[base
+1]);
3682 hint
->hintnumber
= sameh
!=NULL
? sameh
->hintnumber
: hint_cnt
++;
3683 if ( !is_type2
&& context
->instance_count
!=0 ) {
3684 hint
->u
.unblended
= chunkalloc(sizeof(real
[2][MmMax
]));
3685 memcpy(hint
->u
.unblended
,unblended
,sizeof(real
[2][MmMax
]));
3687 if ( activeh
==NULL
)
3692 if ( !is_type2
&& hint
->hintnumber
<96 ) {
3693 if ( pending_hm
==NULL
)
3694 pending_hm
= chunkalloc(sizeof(HintMask
));
3695 (*pending_hm
)[hint
->hintnumber
>>3] |= 0x80>>(hint
->hintnumber
&0x7);
3698 coord
= hint
->start
+hint
->width
;
3702 case 19: /* hintmask */
3703 case 20: /* cntrmask */
3704 /* If there's anything on the stack treat it as a vstem hint */
3706 case 23: /* vstemhm */
3708 if ( cur
==NULL
|| v
==3 || v
==23 ) {
3709 if ( (sp
&1) && is_type2
&& ret
->width
== (int16
) 0x8000 ) {
3710 ret
->width
= stack
[0];
3714 /* I've seen a vstemhm with no arguments. I've no idea what that */
3715 /* means. It came right after a hintmask */
3716 /* I'm confused about v/hstemhm because the manual says it needs */
3717 /* to be used if one uses a hintmask, but that's not what the */
3718 /* examples show. Or I'm not understanding. */
3719 if ( sp
-base
<2 && v
!=19 && v
!=20 )
3720 LogError( _("Stack underflow on vstem in %s\n"), name
);
3721 /* stack[0] is absolute x for start of vertical hint */
3722 /* (actually relative to the x specified as lsidebearing in h/sbw*/
3723 /* stack[1] is relative x for height of hint zone */
3724 coord
= ret
->lsidebearing
;
3726 if ( activev
!=NULL
)
3727 for ( hp
=activev
; hp
->next
!=NULL
; hp
= hp
->next
);
3728 while ( sp
-base
>=2 ) {
3731 sameh
= SameH(ret
->vstem
,stack
[base
]+coord
,stack
[base
+1],
3732 unblended
,context
->instance_count
);
3733 hint
= HintNew(stack
[base
]+coord
,stack
[base
+1]);
3734 hint
->hintnumber
= sameh
!=NULL
? sameh
->hintnumber
: hint_cnt
++;
3735 if ( !is_type2
&& context
->instance_count
!=0 ) {
3736 hint
->u
.unblended
= chunkalloc(sizeof(real
[2][MmMax
]));
3737 memcpy(hint
->u
.unblended
,unblended
,sizeof(real
[2][MmMax
]));
3739 if ( !is_type2
&& hint
->hintnumber
<96 ) {
3740 if ( pending_hm
==NULL
)
3741 pending_hm
= chunkalloc(sizeof(HintMask
));
3742 (*pending_hm
)[hint
->hintnumber
>>3] |= 0x80>>(hint
->hintnumber
&0x7);
3744 if ( activev
==NULL
)
3750 coord
= hint
->start
+hint
->width
;
3754 if ( v
==19 || v
==20 ) { /* hintmask, cntrmask */
3755 unsigned bytes
= (hint_cnt
+7)/8;
3756 if ( bytes
>sizeof(HintMask
) ) bytes
= sizeof(HintMask
);
3758 ret
->hstem
= HintsAppend(ret
->hstem
,activeh
); activeh
=NULL
;
3759 ret
->vstem
= HintsAppend(ret
->vstem
,activev
); activev
=NULL
;
3760 if ( pending_hm
==NULL
)
3761 pending_hm
= chunkalloc(sizeof(HintMask
));
3762 memcpy(pending_hm
,type1
,bytes
);
3763 } else if ( cp
<(int)(sizeof(counters
)/sizeof(counters
[0])) ) {
3764 counters
[cp
] = chunkalloc(sizeof(HintMask
));
3765 memcpy(counters
[cp
],type1
,bytes
);
3768 if ( bytes
!=(unsigned)hint_cnt
/8 ) {
3769 int mask
= 0xff>>(hint_cnt
&7);
3770 if ( type1
[bytes
-1]&mask
)
3771 LogError( _("Hint mask (or counter mask) with too many hints in %s\n"), name
);
3777 case 14: /* endchar */
3778 /* endchar is allowed to terminate processing even within a subroutine */
3779 if ( (sp
&1) && is_type2
&& ret
->width
== (int16
) 0x8000 )
3780 ret
->width
= stack
[0];
3781 if ( context
->painttype
!=2 )
3782 closepath(cur
,is_type2
);
3785 /* In Type2 strings endchar has a depreciated function of doing */
3786 /* a seac (which doesn't exist at all). Except enchar takes */
3787 /* 4 args and seac takes 5. Bleah */
3788 stack
[4] = stack
[3]; stack
[3] = stack
[2]; stack
[2] = stack
[1]; stack
[1] = stack
[0];
3792 } else if ( sp
==5 ) {
3793 /* same as above except also specified a width */
3797 /* the docs say that endchar must be the last command in a char */
3798 /* (or the last command in a subroutine which is the last in the */
3799 /* char) So in theory if there's anything left we should complain*/
3800 /* In practice though, the EuroFont has a return statement after */
3801 /* the endchar in a subroutine. So we won't try to catch that err*/
3802 /* and just stop. */
3803 /* Adobe says it's not an error, but I can't understand their */
3807 case 13: /* hsbw (set left sidebearing and width) */
3808 if ( sp
<2 ) LogError( _("Stack underflow on hsbw in %s\n"), name
);
3809 ret
->lsidebearing
= stack
[0];
3810 current
.x
= stack
[0]; /* sets the current point too */
3811 ret
->width
= stack
[1];
3814 case 9: /* closepath */
3816 closepath(cur
,is_type2
);
3818 case 21: /* rmoveto */
3819 case 22: /* hmoveto */
3820 case 4: /* vmoveto */
3822 if (( (v
==21 && sp
==3) || (v
!=21 && sp
==2)) && ret
->width
== (int16
) 0x8000 )
3823 /* Character's width may be specified on the first moveto */
3824 ret
->width
= stack
[0];
3825 if ( v
==21 && sp
>2 ) {
3826 stack
[0] = stack
[sp
-2]; stack
[1] = stack
[sp
-1];
3828 } else if ( v
!=21 && sp
>1 ) {
3829 stack
[0] = stack
[sp
-1];
3832 if ( context
->painttype
!=2 )
3833 closepath(cur
,true);
3835 case 5: /* rlineto */
3836 case 6: /* hlineto */
3837 case 7: /* vlineto */
3842 if ( v
==5 || v
==21 ) {
3844 LogError( _("Stack underflow on rlineto/rmoveto in %s\n"), name
);
3849 } else if ( (v
==6 && !(polarity
&1)) || (v
==7 && (polarity
&1)) || v
==22 ) {
3851 LogError( _("Stack underflow on hlineto/hmoveto in %s\n"), name
);
3855 } else /*if ( (v==7 && !(parity&1)) || (v==6 && (parity&1) || v==4 )*/ {
3857 LogError( _("Stack underflow on vlineto/vmoveto in %s\n"), name
);
3863 current
.x
= rint((current
.x
+dx
)*1024)/1024; current
.y
= rint((current
.y
+dy
)*1024)/1024;
3864 pt
= chunkalloc(sizeof(SplinePoint
));
3865 pt
->hintmask
= pending_hm
; pending_hm
= NULL
;
3866 pt
->me
.x
= current
.x
; pt
->me
.y
= current
.y
;
3867 pt
->noprevcp
= true; pt
->nonextcp
= true;
3868 if ( v
==4 || v
==21 || v
==22 ) {
3869 if ( cur
!=NULL
&& cur
->first
==cur
->last
&& cur
->first
->prev
==NULL
&& is_type2
) {
3870 /* Two adjacent movetos should not create single point paths */
3871 cur
->first
->me
.x
= current
.x
; cur
->first
->me
.y
= current
.y
;
3872 SplinePointFree(pt
);
3874 SplinePointList
*spl
= chunkalloc(sizeof(SplinePointList
));
3875 spl
->first
= spl
->last
= pt
;
3879 ret
->layers
[ly_fore
].splines
= spl
;
3884 if ( cur
!=NULL
&& cur
->first
!=NULL
&& (cur
->first
!=cur
->last
|| cur
->first
->next
==NULL
) ) {
3885 CheckMake(cur
->last
,pt
);
3886 SplineMake3(cur
->last
,pt
);
3889 LogError( _("No previous point on path in lineto in %s\n"), name
);
3896 case 25: /* rlinecurve */
3898 while ( sp
>base
+6 ) {
3899 current
.x
= rint((current
.x
+stack
[base
++])*1024)/1024; current
.y
= rint((current
.y
+stack
[base
++])*1024)/1024;
3901 pt
= chunkalloc(sizeof(SplinePoint
));
3902 pt
->hintmask
= pending_hm
; pending_hm
= NULL
;
3903 pt
->me
.x
= current
.x
; pt
->me
.y
= current
.y
;
3904 pt
->noprevcp
= true; pt
->nonextcp
= true;
3905 CheckMake(cur
->last
,pt
);
3906 SplineMake3(cur
->last
,pt
);
3910 case 24: /* rcurveline */
3911 case 8: /* rrcurveto */
3912 case 31: /* hvcurveto */
3913 case 30: /* vhcurveto */
3914 case 27: /* hhcurveto */
3915 case 26: /* vvcurveto */
3917 while ( sp
>base
+2 ) {
3918 dx
= dy
= dx2
= dy2
= dx3
= dy3
= 0;
3919 if ( v
==8 || v
==25 || v
==24 ) {
3921 LogError( _("Stack underflow on rrcurveto in %s\n"), name
);
3926 dx2
= stack
[base
++];
3927 dy2
= stack
[base
++];
3928 dx3
= stack
[base
++];
3929 dy3
= stack
[base
++];
3931 } else if ( v
==27 ) { /* hhcurveto */
3933 LogError( _("Stack underflow on hhcurveto in %s\n"), name
);
3936 if ( (sp
-base
)&1 ) dy
= stack
[base
++];
3938 dx2
= stack
[base
++];
3939 dy2
= stack
[base
++];
3940 dx3
= stack
[base
++];
3942 } else if ( v
==26 ) { /* vvcurveto */
3944 LogError( _("Stack underflow on hhcurveto in %s\n"), name
);
3947 if ( (sp
-base
)&1 ) dx
= stack
[base
++];
3949 dx2
= stack
[base
++];
3950 dy2
= stack
[base
++];
3951 dy3
= stack
[base
++];
3953 } else if ( (v
==31 && !(polarity
&1)) || (v
==30 && (polarity
&1)) ) {
3955 LogError( _("Stack underflow on hvcurveto in %s\n"), name
);
3959 dx2
= stack
[base
++];
3960 dy2
= stack
[base
++];
3961 dy3
= stack
[base
++];
3963 dx3
= stack
[base
++];
3965 } else /*if ( (v==30 && !(polarity&1)) || (v==31 && (polarity&1)) )*/ {
3967 LogError( _("Stack underflow on vhcurveto in %s\n"), name
);
3971 dx2
= stack
[base
++];
3972 dy2
= stack
[base
++];
3973 dx3
= stack
[base
++];
3975 dy3
= stack
[base
++];
3979 if ( cur
!=NULL
&& cur
->first
!=NULL
&& (cur
->first
!=cur
->last
|| cur
->first
->next
==NULL
) ) {
3980 current
.x
= rint((current
.x
+dx
)*1024)/1024; current
.y
= rint((current
.y
+dy
)*1024)/1024;
3981 cur
->last
->nextcp
.x
= current
.x
; cur
->last
->nextcp
.y
= current
.y
;
3982 cur
->last
->nonextcp
= false;
3983 current
.x
= rint((current
.x
+dx2
)*1024)/1024; current
.y
= rint((current
.y
+dy2
)*1024)/1024;
3984 pt
= chunkalloc(sizeof(SplinePoint
));
3985 pt
->hintmask
= pending_hm
; pending_hm
= NULL
;
3986 pt
->prevcp
.x
= current
.x
; pt
->prevcp
.y
= current
.y
;
3987 current
.x
= rint((current
.x
+dx3
)*1024)/1024; current
.y
= rint((current
.y
+dy3
)*1024)/1024;
3988 pt
->me
.x
= current
.x
; pt
->me
.y
= current
.y
;
3989 pt
->nonextcp
= true;
3990 CheckMake(cur
->last
,pt
);
3991 SplineMake3(cur
->last
,pt
);
3994 LogError( _("No previous point on path in curveto in %s\n"), name
);
3997 current
.x
= rint((current
.x
+stack
[base
++])*1024)/1024; current
.y
= rint((current
.y
+stack
[base
++])*1024)/1024;
3998 if ( cur
!=NULL
) { /* In legal code, cur can't be null here, but I got something illegal... */
3999 pt
= chunkalloc(sizeof(SplinePoint
));
4000 pt
->hintmask
= pending_hm
; pending_hm
= NULL
;
4001 pt
->me
.x
= current
.x
; pt
->me
.y
= current
.y
;
4002 pt
->noprevcp
= true; pt
->nonextcp
= true;
4003 CheckMake(cur
->last
,pt
);
4004 SplineMake3(cur
->last
,pt
);
4010 case 29: /* callgsubr */
4011 case 10: /* callsubr */
4012 /* stack[sp-1] contains the number of the subroutine to call */
4014 LogError( _("Stack underflow on callsubr in %s\n"), name
);
4016 } else if ( pcsp
>10 ) {
4017 LogError( _("Too many subroutine calls in %s\n"), name
);
4020 s
=subrs
; if ( v
==29 ) s
= gsubrs
;
4021 if ( s
!=NULL
) stack
[sp
-1] += s
->bias
;
4022 /* Type2 subrs have a bias that must be added to the subr-number */
4023 /* Type1 subrs do not. We set the bias on them to 0 */
4024 if ( s
==NULL
|| stack
[sp
-1]>=s
->cnt
|| stack
[sp
-1]<0 ||
4025 s
->values
[(int) stack
[sp
-1]]==NULL
)
4026 LogError( _("Subroutine number out of bounds in %s\n"), name
);
4028 pcstack
[pcsp
].type1
= type1
;
4029 pcstack
[pcsp
].len
= len
;
4030 pcstack
[pcsp
].subnum
= stack
[sp
-1];
4032 type1
= s
->values
[(int) stack
[sp
-1]];
4033 len
= s
->lens
[(int) stack
[sp
-1]];
4035 if ( --sp
<0 ) sp
= 0;
4037 case 11: /* return */
4038 /* return from a subr outine */
4039 if ( pcsp
<1 ) LogError( _("return when not in subroutine in %s\n"), name
);
4042 type1
= pcstack
[pcsp
].type1
;
4043 len
= pcstack
[pcsp
].len
;
4046 case 16: { /* blend -- obsolete type 2 multiple master operator */
4048 if ( context
->instance_count
==0 )
4049 LogError( _("Attempt to use a multiple master subroutine in a non-mm font.\n") );
4050 else if ( sp
<1 || sp
<context
->instance_count
*stack
[sp
-1]+1 )
4051 LogError( _("Too few items on stack for blend in %s\n"), name
);
4053 if ( !context
->blend_warn
) {
4054 LogError( _("Use of obsolete blend operator.\n") );
4055 context
->blend_warn
= true;
4058 sp
-= context
->instance_count
*stack
[sp
-1]+1;
4059 for ( i
=0; i
<cnt
; ++i
) {
4060 for ( j
=1; j
<context
->instance_count
; ++j
)
4061 stack
[sp
+i
] += context
->blend_values
[j
]*stack
[sp
+
4062 cnt
+ i
*(context
->instance_count
-1)+ j
-1];
4064 /* there will always be fewer pushes than there were pops */
4065 /* so I don't bother to check the stack */
4071 LogError( _("Uninterpreted opcode %d in %s\n"), v
, name
);
4077 LogError( _("end of subroutine reached with no return in %s\n"), name
);
4078 if (THdo_catagorize
)
4079 SCCatagorizePoints(ret
);
4081 ret
->hstem
= HintsAppend(ret
->hstem
,activeh
); activeh
=NULL
;
4082 ret
->vstem
= HintsAppend(ret
->vstem
,activev
); activev
=NULL
;
4084 if ( cp
!=0 ) { int i
;
4085 ret
->countermasks
= galloc(cp
*sizeof(HintMask
));
4086 ret
->countermask_cnt
= cp
;
4087 for ( i
=0; i
<cp
; ++i
) {
4088 memcpy(&ret
->countermasks
[i
],counters
[i
],sizeof(HintMask
));
4089 chunkfree(counters
[i
],sizeof(HintMask
));
4093 /* Even in type1 fonts all paths should be closed. But if we close them at*/
4094 /* the obvious moveto, that breaks flex hints. So we have a hack here at */
4095 /* the end which closes any open paths. */
4096 /* If we do have a PaintType 2 font, then presumably the difference between*/
4097 /* open and closed paths matters */
4098 if ( !is_type2
&& !context
->painttype
)
4099 for ( cur
= ret
->layers
[ly_fore
].splines
; cur
!=NULL
; cur
= cur
->next
) if ( cur
->first
->prev
==NULL
) {
4100 CheckMake(cur
->last
,cur
->first
);
4101 SplineMake3(cur
->last
,cur
->first
);
4102 cur
->last
= cur
->first
;
4104 /* Oh, I see. PS and TT disagree on which direction to use, so Fontographer*/
4105 /* chose the TT direction and we must reverse postscript */
4106 if (THdo_set_reversing
) {
4107 for ( cur
= ret
->layers
[ly_fore
].splines
; cur
!=NULL
; cur
= cur
->next
)
4108 SplineSetReverse(cur
);
4110 if ( ret
->hstem
==NULL
&& ret
->vstem
==NULL
)
4111 ret
->manualhints
= false;
4112 if ( !is_type2
&& context
->instance_count
!=0 ) {
4113 UnblendFree(ret
->hstem
);
4114 UnblendFree(ret
->vstem
);
4116 if (THdo_hint_guessing
) {
4117 ret
->hstem
= HintCleanup(ret
->hstem
,true,context
->instance_count
);
4118 ret
->vstem
= HintCleanup(ret
->vstem
,true,context
->instance_count
);
4119 SCGuessHHintInstancesList(ret
,ly_fore
);
4120 SCGuessVHintInstancesList(ret
,ly_fore
);
4121 ret
->hconflicts
= StemListAnyConflicts(ret
->hstem
);
4122 ret
->vconflicts
= StemListAnyConflicts(ret
->vstem
);
4123 if ( context
->instance_count
==1 && !ret
->hconflicts
&& !ret
->vconflicts
)
4124 SCClearHintMasks(ret
,ly_fore
,false);
4127 if ( name
!=NULL
&& strcmp(name
,".notdef")!=0 )
4128 ret
->widthset
= true;
4133 /* This finds the 'connect-the-dots' boundingbox of a Type2 charstring */
4134 /* It is a simplified version of PSCharStringToSplines, above */
4136 SplineChar
*PSCharStringToBB(uint8
*type1
, int len
, struct pscontext
*context
,
4137 struct pschars
*subrs
, struct pschars
*gsubrs
, const char *name
) {
4138 real stack
[50]; int sp
=0, v
; /* Type1 stack is about 25 long, Type2 stack is 48 */
4140 SplineChar
*ret
= SplineCharCreate(2);
4142 DBasePoint current
, ll
, ur
;
4143 real dx
, dy
, dx2
, dy2
, dx3
, dy3
, dx4
, dy4
, dx5
, dy5
, dx6
=0, dy6
;
4145 int first
= 1; /* to flag extra set width */
4146 /* subroutines may be nested to a depth of 10 */
4147 struct substate
{ unsigned char *type1
; int len
; int subnum
; } pcstack
[11];
4157 int last_was_b1
=false, old_last_was_b1
;
4159 ret
->name
= copy( name
);
4160 ret
->unicodeenc
= -1;
4161 ret
->width
= (int16
) 0x8000;
4162 if ( name
==NULL
) name
= "unnamed";
4163 ret
->manualhints
= true;
4164 if ( !context
->is_type2
) {
4165 LogError( _("Quick boundingbox mode only does CFF charstrings, not Type1 (font %s)\n"), name
);
4169 current
.x
= current
.y
= 0;
4170 ll
.x
= ll
.y
= (int16
) 0x7FFF;
4171 ur
.x
= ur
.y
= (int16
) -0x7FFF;
4175 LogError( _("Stack got too big in %s\n"), name
);
4180 if ( (v
= *type1
++)>=32 ) {
4182 stack
[sp
++] = v
- 139;
4183 } else if ( v
<=250 ) {
4184 stack
[sp
++] = (v
-247)*256 + *type1
++ + 108;
4186 } else if ( v
<=254 ) {
4187 stack
[sp
++] = -(v
-251)*256 - *type1
++ - 108;
4190 int val
= (*type1
<<24) | (type1
[1]<<16) | (type1
[2]<<8) | type1
[3];
4194 stack
[sp
-1] /= 65536.;
4196 } else if ( v
==28 ) {
4197 stack
[sp
++] = (short) ((type1
[0]<<8) | type1
[1]);
4200 /* In the Dict tables of CFF, a 5byte fixed value is prefixed by a */
4201 /* 29 code. In Type2 strings the prefix is 255. */
4202 } else if ( v
==12 ) {
4203 old_last_was_b1
= last_was_b1
; last_was_b1
= false;
4207 case 0: /* dotsection */
4210 case 1: /* vstem3 */ /* specifies three v hints zones at once */
4211 if ( sp
<6 ) LogError( _("Stack underflow on vstem3 in %s\n"), name
);
4212 /* according to the standard, if there is a vstem3 there can't */
4213 /* be any vstems, so there can't be any confusion about hint order */
4214 /* so we don't need to worry about unblended stuff */
4218 case 2: /* hstem3 */ /* specifies three h hints zones at once */
4219 if ( sp
<6 ) LogError( _("Stack underflow on hstem3 in %s\n"), name
);
4223 case 6: /* seac */ /* build accented characters */
4225 if ( sp
<5 ) LogError( _("Stack underflow on seac in %s\n"), name
);
4226 /* stack[0] must be the lsidebearing of the accent. I'm not sure why */
4229 case 7: /* sbw */ /* generalized width/sidebearing command */
4230 if ( sp
<4 ) LogError( _("Stack underflow on sbw in %s\n"), name
);
4231 ret
->lsidebearing
= stack
[0];
4232 /* stack[1] is lsidebearing y (only for vertical writing styles, CJK) */
4233 ret
->width
= stack
[2];
4234 /* stack[3] is height (for vertical writing styles, CJK) */
4237 case 5: case 9: case 14: case 26:
4238 if ( sp
<1 ) LogError( _("Stack underflow on unary operator in %s\n"), name
);
4240 case 5: stack
[sp
-1] = (stack
[sp
-1]==0); break; /* not */
4241 case 9: if ( stack
[sp
-1]<0 ) stack
[sp
-1]= -stack
[sp
-1]; break; /* abs */
4242 case 14: stack
[sp
-1] = -stack
[sp
-1]; break; /* neg */
4243 case 26: stack
[sp
-1] = sqrt(stack
[sp
-1]); break; /* sqrt */
4246 case 3: case 4: case 10: case 11: case 12: case 15: case 24:
4247 if ( sp
<2 ) LogError( _("Stack underflow on binary operator in %s\n"), name
);
4250 stack
[sp
-2] = (stack
[sp
-1]!=0 && stack
[sp
-2]!=0);
4253 stack
[sp
-2] = (stack
[sp
-1]!=0 || stack
[sp
-2]!=0);
4256 stack
[sp
-2] += stack
[sp
-1];
4259 stack
[sp
-2] -= stack
[sp
-1];
4262 stack
[sp
-2] /= stack
[sp
-1];
4265 stack
[sp
-2] *= stack
[sp
-1];
4268 stack
[sp
-2] = (stack
[sp
-1]==stack
[sp
-2]);
4273 case 22: /* ifelse */
4274 if ( sp
<4 ) LogError( _("Stack underflow on ifelse in %s\n"), name
);
4276 if ( stack
[sp
-2]>stack
[sp
-1] )
4277 stack
[sp
-4] = stack
[sp
-3];
4281 case 23: /* random */
4282 /* This function returns something (0,1]. It's not clear to me*/
4283 /* if rand includes 0 and RAND_MAX or not, but this approach */
4284 /* should work no matter what */
4286 stack
[sp
] = (rand()/(RAND_MAX
-1));
4287 } while ( stack
[sp
]==0 || stack
[sp
]>1 );
4291 if ( sp
<2 ) LogError( _("Too few items on stack for put in %s\n"), name
);
4292 else if ( stack
[sp
-1]<0 || stack
[sp
-1]>=32 ) LogError( _("Reference to transient memory out of bounds in put in %s\n"), name
);
4294 transient
[(int)stack
[sp
-1]] = stack
[sp
-2];
4299 if ( sp
<1 ) LogError( _("Too few items on stack for get in %s\n"), name
);
4300 else if ( stack
[sp
-1]<0 || stack
[sp
-1]>=32 ) LogError( _("Reference to transient memory out of bounds in put in %s\n"), name
);
4302 stack
[sp
-1] = transient
[(int)stack
[sp
-1]];
4305 /* pops something from the postscript stack and pushes it on ours */
4306 /* used to get a return value from an othersubr call */
4307 /* Bleah. Adobe wants the pops to return the arguments if we */
4308 /* don't understand the call. What use is the subroutine then?*/
4310 LogError( _("Pop stack underflow on pop in %s\n"), name
);
4312 stack
[sp
++] = pops
[--popsp
];
4319 stack
[sp
] = stack
[sp
-1];
4325 real temp
= stack
[sp
-1];
4326 stack
[sp
-1] = stack
[sp
-2]; stack
[sp
-2] = temp
;
4329 case 29: /* index */
4331 int index
= stack
[--sp
];
4332 if ( index
<0 || sp
<index
+1 )
4333 LogError( _("Index out of range in %s\n"), name
);
4335 stack
[sp
] = stack
[sp
-index
-1];
4342 int j
= stack
[sp
-1], N
=stack
[sp
-2];
4343 if ( N
>sp
|| j
>=N
|| j
<0 || N
<0 )
4344 LogError( _("roll out of range in %s\n"), name
);
4345 else if ( j
==0 || N
==0 )
4348 real
*temp
= galloc(N
*sizeof(real
));
4350 for ( i
=0; i
<N
; ++i
)
4351 temp
[i
] = stack
[sp
-N
+i
];
4352 for ( i
=0; i
<N
; ++i
)
4353 stack
[sp
-N
+i
] = temp
[(i
+j
)%N
];
4358 case 33: /* setcurrentpoint */
4359 if ( sp
<2 ) LogError( _("Stack underflow on setcurrentpoint in %s\n"), name
);
4361 current
.x
= stack
[0];
4362 current
.y
= stack
[1];
4363 if (ll
.y
>current
.y
) ll
.y
= current
.y
;
4364 if (ur
.y
<current
.y
) ur
.y
= current
.y
;
4365 if (ll
.x
>current
.x
) ll
.x
= current
.x
;
4366 if (ur
.x
<current
.x
) ur
.x
= current
.x
;
4370 case 34: /* hflex */
4372 case 36: /* hflex1 */
4373 case 37: /* flex1 */
4374 dy
= dy3
= dy4
= dy5
= dy6
= 0;
4378 dx2
= stack
[base
++];
4379 dy2
= stack
[base
++];
4380 dx3
= stack
[base
++];
4381 if ( v
!=34 && v
!=36 )
4382 dy3
= stack
[base
++];
4383 dx4
= stack
[base
++];
4384 if ( v
!=34 && v
!=36 )
4385 dy4
= stack
[base
++];
4386 dx5
= stack
[base
++];
4390 dy5
= stack
[base
++];
4394 dx6
= stack
[base
++];
4395 dy6
= stack
[base
++];
4397 case 34: /* hflex */
4398 dx6
= stack
[base
++];
4400 case 36: /* hflex1 */
4401 dx6
= stack
[base
++];
4404 case 37: /* flex1 */
4405 xt
= dx
+dx2
+dx3
+dx4
+dx5
;
4406 yt
= dy
+dy2
+dy3
+dy4
+dy5
;
4407 if ( xt
<0 ) xt
= -xt
;
4408 if ( yt
<0 ) yt
= -yt
;
4410 dx6
= stack
[base
++];
4411 dy6
= -dy
-dy2
-dy3
-dy4
-dy5
;
4413 dy6
= stack
[base
++];
4414 dx6
= -dx
-dx2
-dx3
-dx4
-dx5
;
4418 current
.x
= current
.x
+dx
; current
.y
= current
.y
+dy
;
4419 if (ll
.y
>current
.y
) ll
.y
= current
.y
;
4420 if (ur
.y
<current
.y
) ur
.y
= current
.y
;
4421 if (ll
.x
>current
.x
) ll
.x
= current
.x
;
4422 if (ur
.x
<current
.x
) ur
.x
= current
.x
;
4423 current
.x
= current
.x
+dx2
; current
.y
= current
.y
+dy2
;
4424 if (ll
.y
>current
.y
) ll
.y
= current
.y
;
4425 if (ur
.y
<current
.y
) ur
.y
= current
.y
;
4426 if (ll
.x
>current
.x
) ll
.x
= current
.x
;
4427 if (ur
.x
<current
.x
) ur
.x
= current
.x
;
4428 current
.x
= current
.x
+dx3
; current
.y
= current
.y
+dy3
;
4429 if (ll
.y
>current
.y
) ll
.y
= current
.y
;
4430 if (ur
.y
<current
.y
) ur
.y
= current
.y
;
4431 if (ll
.x
>current
.x
) ll
.x
= current
.x
;
4432 if (ur
.x
<current
.x
) ur
.x
= current
.x
;
4434 current
.x
= current
.x
+dx4
; current
.y
= current
.y
+dy4
;
4435 if (ll
.y
>current
.y
) ll
.y
= current
.y
;
4436 if (ur
.y
<current
.y
) ur
.y
= current
.y
;
4437 if (ll
.x
>current
.x
) ll
.x
= current
.x
;
4438 if (ur
.x
<current
.x
) ur
.x
= current
.x
;
4439 current
.x
= current
.x
+dx5
; current
.y
= current
.y
+dy5
;
4440 if (ll
.y
>current
.y
) ll
.y
= current
.y
;
4441 if (ur
.y
<current
.y
) ur
.y
= current
.y
;
4442 if (ll
.x
>current
.x
) ll
.x
= current
.x
;
4443 if (ur
.x
<current
.x
) ur
.x
= current
.x
;
4444 current
.x
= current
.x
+dx6
; current
.y
= current
.y
+dy6
;
4445 if (ll
.y
>current
.y
) ll
.y
= current
.y
;
4446 if (ur
.y
<current
.y
) ur
.y
= current
.y
;
4447 if (ll
.x
>current
.x
) ll
.x
= current
.x
;
4448 if (ur
.x
<current
.x
) ur
.x
= current
.x
;
4452 LogError( _("Uninterpreted opcode 12,%d in %s\n"), v
, name
);
4455 } else { last_was_b1
= false; switch ( v
) {
4457 case 18: /* hstemhm */
4459 if ( (sp
&1) && ret
->width
== (int16
) 0x8000 )
4460 ret
->width
= stack
[0];
4464 LogError( _("Stack underflow on hstem in %s\n"), name
);
4465 /* stack[0] is absolute y for start of horizontal hint */
4466 /* (actually relative to the y specified as lsidebearing y in sbw*/
4467 /* stack[1] is relative y for height of hint zone */
4470 while ( sp
-base
>=2 ) {
4476 case 19: /* hintmask */
4477 case 20: /* cntrmask */
4478 /* If there's anything on the stack treat it as a vstem hint */
4480 case 23: /* vstemhm */
4482 if ( first
|| v
==3 || v
==23 ) {
4483 if ( (sp
&1) && ret
->width
== (int16
) 0x8000 ) {
4484 ret
->width
= stack
[0];
4488 if ( sp
-base
<2 && v
!=19 && v
!=20 )
4489 LogError( _("Stack underflow on vstem in %s\n"), name
);
4490 /* stack[0] is absolute x for start of vertical hint */
4491 /* (actually relative to the x specified as lsidebearing in h/sbw*/
4492 /* stack[1] is relative x for height of hint zone */
4495 while ( sp
-base
>=2 ) {
4501 if ( v
==19 || v
==20 ) { /* hintmask, cntrmask */
4502 unsigned bytes
= (hint_cnt
+7)/8;
4503 if ( bytes
>sizeof(HintMask
) ) bytes
= sizeof(HintMask
);
4504 if ( bytes
!=(unsigned)hint_cnt
/8 ) {
4505 int mask
= 0xff>>(hint_cnt
&7);
4506 if ( type1
[bytes
-1]&mask
)
4507 LogError( _("Hint mask (or counter mask) with too many hints in %s\n"), name
);
4513 case 14: /* endchar */
4514 /* endchar is allowed to terminate processing even within a subroutine */
4515 if ( (sp
&1) && ret
->width
== (int16
) 0x8000 )
4516 ret
->width
= stack
[0];
4519 /* In Type2 strings endchar has a depreciated function of doing */
4520 /* a seac (which doesn't exist at all). Except enchar takes */
4521 /* 4 args and seac takes 5. Bleah */
4522 stack
[4] = stack
[3]; stack
[3] = stack
[2]; stack
[2] = stack
[1]; stack
[1] = stack
[0];
4526 } else if ( sp
==5 ) {
4527 /* same as above except also specified a width */
4531 /* the docs say that endchar must be the last command in a char */
4534 case 13: /* hsbw (set left sidebearing and width) */
4535 if ( sp
<2 ) LogError( _("Stack underflow on hsbw in %s\n"), name
);
4536 ret
->lsidebearing
= stack
[0];
4537 current
.x
= stack
[0]; /* sets the current point too */
4538 if (ll
.x
>current
.x
) ll
.x
= current
.x
;
4539 if (ur
.x
<current
.x
) ur
.x
= current
.x
;
4540 ret
->width
= stack
[1];
4543 case 9: /* closepath */
4546 case 21: /* rmoveto */
4547 case 22: /* hmoveto */
4548 case 4: /* vmoveto */
4549 if (( (v
==21 && sp
==3) || (v
!=21 && sp
==2)) && ret
->width
== (int16
) 0x8000 )
4550 /* Character's width may be specified on the first moveto */
4551 ret
->width
= stack
[0];
4552 if ( v
==21 && sp
>2 ) {
4553 stack
[0] = stack
[sp
-2]; stack
[1] = stack
[sp
-1];
4555 } else if ( v
!=21 && sp
>1 ) {
4556 stack
[0] = stack
[sp
-1];
4560 case 5: /* rlineto */
4561 case 6: /* hlineto */
4562 case 7: /* vlineto */
4567 if ( v
==5 || v
==21 ) {
4569 LogError( _("Stack underflow on rlineto/rmoveto in %s\n"), name
);
4574 } else if ( (v
==6 && !(polarity
&1)) || (v
==7 && (polarity
&1)) || v
==22 ) {
4576 LogError( _("Stack underflow on hlineto/hmoveto in %s\n"), name
);
4580 } else /*if ( (v==7 && !(parity&1)) || (v==6 && (parity&1) || v==4 )*/ {
4582 LogError( _("Stack underflow on vlineto/vmoveto in %s\n"), name
);
4588 current
.x
= current
.x
+dx
; current
.y
= current
.y
+dy
;
4589 if (ll
.y
>current
.y
) ll
.y
= current
.y
;
4590 if (ur
.y
<current
.y
) ur
.y
= current
.y
;
4591 if (ll
.x
>current
.x
) ll
.x
= current
.x
;
4592 if (ur
.x
<current
.x
) ur
.x
= current
.x
;
4593 if ( v
==4 || v
==21 || v
==22 ) {
4602 case 25: /* rlinecurve */
4604 while ( sp
>base
+6 ) {
4605 current
.x
= current
.x
+stack
[base
++]; current
.y
= current
.y
+stack
[base
++];
4606 if (ll
.y
>current
.y
) ll
.y
= current
.y
;
4607 if (ur
.y
<current
.y
) ur
.y
= current
.y
;
4608 if (ll
.x
>current
.x
) ll
.x
= current
.x
;
4609 if (ur
.x
<current
.x
) ur
.x
= current
.x
;
4612 case 24: /* rcurveline */
4613 case 8: /* rrcurveto */
4614 case 31: /* hvcurveto */
4615 case 30: /* vhcurveto */
4616 case 27: /* hhcurveto */
4617 case 26: /* vvcurveto */
4619 while ( sp
>base
+2 ) {
4620 dx
= dy
= dx2
= dy2
= dx3
= dy3
= 0;
4621 if ( v
==8 || v
==25 || v
==24 ) {
4623 LogError( _("Stack underflow on rrcurveto in %s\n"), name
);
4628 dx2
= stack
[base
++];
4629 dy2
= stack
[base
++];
4630 dx3
= stack
[base
++];
4631 dy3
= stack
[base
++];
4633 } else if ( v
==27 ) { /* hhcurveto */
4635 LogError( _("Stack underflow on hhcurveto in %s\n"), name
);
4638 if ( (sp
-base
)&1 ) dy
= stack
[base
++];
4640 dx2
= stack
[base
++];
4641 dy2
= stack
[base
++];
4642 dx3
= stack
[base
++];
4644 } else if ( v
==26 ) { /* vvcurveto */
4646 LogError( _("Stack underflow on hhcurveto in %s\n"), name
);
4649 if ( (sp
-base
)&1 ) dx
= stack
[base
++];
4651 dx2
= stack
[base
++];
4652 dy2
= stack
[base
++];
4653 dy3
= stack
[base
++];
4655 } else if ( (v
==31 && !(polarity
&1)) || (v
==30 && (polarity
&1)) ) {
4657 LogError( _("Stack underflow on hvcurveto in %s\n"), name
);
4661 dx2
= stack
[base
++];
4662 dy2
= stack
[base
++];
4663 dy3
= stack
[base
++];
4665 dx3
= stack
[base
++];
4667 } else /*if ( (v==30 && !(polarity&1)) || (v==31 && (polarity&1)) )*/ {
4669 LogError( _("Stack underflow on vhcurveto in %s\n"), name
);
4673 dx2
= stack
[base
++];
4674 dy2
= stack
[base
++];
4675 dx3
= stack
[base
++];
4677 dy3
= stack
[base
++];
4681 current
.x
= current
.x
+dx
; current
.y
= current
.y
+dy
;
4682 if (ll
.y
>current
.y
) ll
.y
= current
.y
;
4683 if (ur
.y
<current
.y
) ur
.y
= current
.y
;
4684 if (ll
.x
>current
.x
) ll
.x
= current
.x
;
4685 if (ur
.x
<current
.x
) ur
.x
= current
.x
;
4686 current
.x
= current
.x
+dx2
; current
.y
= current
.y
+dy2
;
4687 if (ll
.y
>current
.y
) ll
.y
= current
.y
;
4688 if (ur
.y
<current
.y
) ur
.y
= current
.y
;
4689 if (ll
.x
>current
.x
) ll
.x
= current
.x
;
4690 if (ur
.x
<current
.x
) ur
.x
= current
.x
;
4691 current
.x
= current
.x
+dx3
; current
.y
= current
.y
+dy3
;
4692 if (ll
.y
>current
.y
) ll
.y
= current
.y
;
4693 if (ur
.y
<current
.y
) ur
.y
= current
.y
;
4694 if (ll
.x
>current
.x
) ll
.x
= current
.x
;
4695 if (ur
.x
<current
.x
) ur
.x
= current
.x
;
4698 current
.x
= current
.x
+stack
[base
++]; current
.y
= current
.y
+stack
[base
++];
4699 if (ll
.y
>current
.y
) ll
.y
= current
.y
;
4700 if (ur
.y
<current
.y
) ur
.y
= current
.y
;
4701 if (ll
.x
>current
.x
) ll
.x
= current
.x
;
4702 if (ur
.x
<current
.x
) ur
.x
= current
.x
;
4706 case 29: /* callgsubr */
4707 case 10: /* callsubr */
4708 /* stack[sp-1] contains the number of the subroutine to call */
4710 LogError( _("Stack underflow on callsubr in %s\n"), name
);
4712 } else if ( pcsp
>10 ) {
4713 LogError( _("Too many subroutine calls in %s\n"), name
);
4716 s
=subrs
; if ( v
==29 ) s
= gsubrs
;
4717 if ( s
!=NULL
) stack
[sp
-1] += s
->bias
;
4718 /* Type2 subrs have a bias that must be added to the subr-number */
4719 /* Type1 subrs do not. We set the bias on them to 0 */
4720 if ( s
==NULL
|| stack
[sp
-1]>=s
->cnt
|| stack
[sp
-1]<0 ||
4721 s
->values
[(int) stack
[sp
-1]]==NULL
)
4722 LogError( _("Subroutine number out of bounds in %s\n"), name
);
4724 pcstack
[pcsp
].type1
= type1
;
4725 pcstack
[pcsp
].len
= len
;
4726 pcstack
[pcsp
].subnum
= stack
[sp
-1];
4728 type1
= s
->values
[(int) stack
[sp
-1]];
4729 len
= s
->lens
[(int) stack
[sp
-1]];
4731 if ( --sp
<0 ) sp
= 0;
4733 case 11: /* return */
4734 /* return from a subr outine */
4735 if ( pcsp
<1 ) LogError( _("return when not in subroutine in %s\n"), name
);
4738 type1
= pcstack
[pcsp
].type1
;
4739 len
= pcstack
[pcsp
].len
;
4742 case 16: { /* blend -- obsolete type 2 multiple master operator */
4744 if ( context
->instance_count
==0 )
4745 LogError( _("Attempt to use a multiple master subroutine in a non-mm font.\n") );
4746 else if ( sp
<1 || sp
<context
->instance_count
*stack
[sp
-1]+1 )
4747 LogError( _("Too few items on stack for blend in %s\n"), name
);
4749 if ( !context
->blend_warn
) {
4750 LogError( _("Use of obsolete blend operator.\n") );
4751 context
->blend_warn
= true;
4754 sp
-= context
->instance_count
*stack
[sp
-1]+1;
4755 for ( i
=0; i
<cnt
; ++i
) {
4756 for ( j
=1; j
<context
->instance_count
; ++j
)
4757 stack
[sp
+i
] += context
->blend_values
[j
]*stack
[sp
+
4758 cnt
+ i
*(context
->instance_count
-1)+ j
-1];
4760 /* there will always be fewer pushes than there were pops */
4761 /* so I don't bother to check the stack */
4767 LogError( _("Uninterpreted opcode %d in %s\n"), v
, name
);
4773 LogError( _("end of subroutine reached with no return in %s\n"), name
);
4775 if ( name
!=NULL
&& strcmp(name
,".notdef")!=0 )
4776 ret
->widthset
= true;
4777 if (ur
.x
== -0x7FFF) ur
.x
= 0;
4778 if (ur
.y
== -0x7FFF) ur
.y
= 0;
4779 if (ll
.x
== 0x7FFF) ll
.x
= 0;
4780 if (ll
.y
== 0x7FFF) ll
.y
= 0;
4781 if (ll
.x
>ur
.x
) ll
.x
= ur
.x
;
4782 if (ll
.y
>ur
.y
) ll
.y
= ur
.y
;
4785 ret
->xmin
= rint(ll
.x
);
4786 ret
->ymin
= rint(ll
.y
);
4787 ret
->xmax
= rint(ur
.x
);
4788 ret
->ymax
= rint(ur
.y
);
4789 /* free the curves */
4790 if (ret
->layers
!=NULL
&& ret
->layers
[ly_fore
].splines
!= NULL
) {
4791 SplinePointListsFree(ret
->layers
[ly_fore
].splines
);
4792 ret
->layers
[ly_fore
].splines
=NULL
;
4794 if (ret
->layers
[ly_fore
].refs
!=NULL
) {
4795 RefCharsFree(ret
->layers
[ly_fore
].refs
);
4796 ret
->layers
[ly_fore
].refs
= NULL
;