1 /*
2  * $Id: T2Interpreter.java,v 1.2 2007-07-26 11:10:18 davidsch Exp $
3  *
4  * Typecast - The Font Development Environment
5  *
6  * Copyright (c) 2004-2007 David Schweinsberg
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 package jogamp.graph.font.typecast.t2;
22 
23 import java.util.ArrayList;
24 
25 import jogamp.graph.font.typecast.ot.Point;
26 import jogamp.graph.font.typecast.ot.table.CharstringType2;
27 
28 
29 
30 /**
31  * Type 2 Charstring Interpreter.  Operator descriptions are quoted from
32  * Adobe's Type 2 Charstring Format document -- 5117.Type2.pdf.
33  * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
34  * @version $Id: T2Interpreter.java,v 1.2 2007-07-26 11:10:18 davidsch Exp $
35  */
36 public class T2Interpreter {
37 
38     private static final int ARGUMENT_STACK_LIMIT = 48;
39     private static final int SUBR_STACK_LIMIT = 10;
40     private static final int TRANSIENT_ARRAY_ELEMENT_COUNT = 32;
41 
42     private final Number[] _argStack = new Number[ARGUMENT_STACK_LIMIT];
43     private int _argStackIndex = 0;
44     private final int[] _subrStack = new int[SUBR_STACK_LIMIT];
45     private int _subrStackIndex = 0;
46     private final Number[] _transientArray = new Number[TRANSIENT_ARRAY_ELEMENT_COUNT];
47 
48     private ArrayList<Point> _points;
49 
50     /** Creates a new instance of T2Interpreter */
T2Interpreter()51     public T2Interpreter() {
52     }
53 
54     /**
55      * Moves the current point to a position at the relative coordinates
56      * (dx1, dy1).
57      */
_rmoveto()58     private void _rmoveto() {
59         final int dy1 = popArg().intValue();
60         final int dx1 = popArg().intValue();
61         clearArg();
62         final Point lastPoint = getLastPoint();
63         moveTo(lastPoint.x + dx1, lastPoint.y + dy1);
64     }
65 
66     /**
67      * Moves the current point dx1 units in the horizontal direction.
68      */
_hmoveto()69     private void _hmoveto() {
70         final int dx1 = popArg().intValue();
71         clearArg();
72         final Point lastPoint = getLastPoint();
73         moveTo(lastPoint.x + dx1, lastPoint.y);
74     }
75 
76     /**
77      * Moves the current point dy1 units in the vertical direction.
78      */
_vmoveto()79     private void _vmoveto() {
80         final int dy1 = popArg().intValue();
81         clearArg();
82         final Point lastPoint = getLastPoint();
83         moveTo(lastPoint.x, lastPoint.y + dy1);
84     }
85 
86     /**
87      * Appends a line from the current point to a position at the
88      * relative coordinates dxa, dya. Additional rlineto operations are
89      * performed for all subsequent argument pairs. The number of
90      * lines is determined from the number of arguments on the stack.
91      */
_rlineto()92     private void _rlineto() {
93         final int count = getArgCount() / 2;
94         final int[] dx = new int[count];
95         final int[] dy = new int[count];
96         for (int i = 0; i < count; ++i) {
97             dy[count - i - 1] = popArg().intValue();
98             dx[count - i - 1] = popArg().intValue();
99         }
100         for (int i = 0; i < count; ++i) {
101             final Point lastPoint = getLastPoint();
102             lineTo(lastPoint.x + dx[i], lastPoint.y + dy[i]);
103         }
104         clearArg();
105     }
106 
107     /**
108      * Appends a horizontal line of length dx1 to the current point.
109      * With an odd number of arguments, subsequent argument pairs
110      * are interpreted as alternating values of dy and dx, for which
111      * additional lineto operators draw alternating vertical and
112      * horizontal lines. With an even number of arguments, the
113      * arguments are interpreted as alternating horizontal and
114      * vertical lines. The number of lines is determined from the
115      * number of arguments on the stack.
116      */
_hlineto()117     private void _hlineto() {
118         final int count = getArgCount();
119         final Number[] nums = new Number[count];
120         for (int i = 0; i < count; ++i) {
121             nums[count - i - 1] = popArg();
122         }
123         for (int i = 0; i < count; ++i) {
124             final Point lastPoint = getLastPoint();
125             if (i % 2 == 0) {
126                 lineTo(lastPoint.x + nums[i].intValue(), lastPoint.y);
127             } else {
128                 lineTo(lastPoint.x, lastPoint.y + nums[i].intValue());
129             }
130         }
131         clearArg();
132     }
133 
134     /**
135      * Appends a vertical line of length dy1 to the current point. With
136      * an odd number of arguments, subsequent argument pairs are
137      * interpreted as alternating values of dx and dy, for which
138      * additional lineto operators draw alternating horizontal and
139      * vertical lines. With an even number of arguments, the
140      * arguments are interpreted as alternating vertical and
141      * horizontal lines. The number of lines is determined from the
142      * number of arguments on the stack.
143      */
_vlineto()144     private void _vlineto() {
145         final int count = getArgCount();
146         final Number[] nums = new Number[count];
147         for (int i = 0; i < count; ++i) {
148             nums[count - i - 1] = popArg();
149         }
150         for (int i = 0; i < count; ++i) {
151             final Point lastPoint = getLastPoint();
152             if (i % 2 == 0) {
153                 lineTo(lastPoint.x, lastPoint.y + nums[i].intValue());
154             } else {
155                 lineTo(lastPoint.x + nums[i].intValue(), lastPoint.y);
156             }
157         }
158         clearArg();
159     }
160 
161     /**
162      * Appends a Bezier curve, defined by dxa...dyc, to the current
163      * point. For each subsequent set of six arguments, an additional
164      * curve is appended to the current point. The number of curve
165      * segments is determined from the number of arguments on the
166      * number stack and is limited only by the size of the number
167      * stack.
168      */
_rrcurveto()169     private void _rrcurveto() {
170         final int count = getArgCount() / 6;
171         final int[] dxa = new int[count];
172         final int[] dya = new int[count];
173         final int[] dxb = new int[count];
174         final int[] dyb = new int[count];
175         final int[] dxc = new int[count];
176         final int[] dyc = new int[count];
177         for (int i = 0; i < count; ++i) {
178             dyc[count - i - 1] = popArg().intValue();
179             dxc[count - i - 1] = popArg().intValue();
180             dyb[count - i - 1] = popArg().intValue();
181             dxb[count - i - 1] = popArg().intValue();
182             dya[count - i - 1] = popArg().intValue();
183             dxa[count - i - 1] = popArg().intValue();
184         }
185         for (int i = 0; i < count; ++i) {
186             final Point lastPoint = getLastPoint();
187             final int xa = lastPoint.x + dxa[i];
188             final int ya = lastPoint.y + dya[i];
189             final int xb = xa + dxb[i];
190             final int yb = ya + dyb[i];
191             final int xc = xb + dxc[i];
192             final int yc = yb + dyc[i];
193             curveTo(xa, ya, xb, yb, xc, yc);
194         }
195         clearArg();
196     }
197 
198     /**
199      * Appends one or more Bezier curves, as described by the
200      * dxa...dxc set of arguments, to the current point. For each curve,
201      * if there are 4 arguments, the curve starts and ends horizontal.
202      * The first curve need not start horizontal (the odd argument
203      * case). Note the argument order for the odd argument case.
204      */
_hhcurveto()205     private void _hhcurveto() {
206         final int count = getArgCount() / 4;
207         int dy1 = 0;
208         final int[] dxa = new int[count];
209         final int[] dxb = new int[count];
210         final int[] dyb = new int[count];
211         final int[] dxc = new int[count];
212         for (int i = 0; i < count; ++i) {
213             dxc[count - i - 1] = popArg().intValue();
214             dyb[count - i - 1] = popArg().intValue();
215             dxb[count - i - 1] = popArg().intValue();
216             dxa[count - i - 1] = popArg().intValue();
217         }
218         if (getArgCount() == 1) {
219             dy1 = popArg().intValue();
220         }
221         for (int i = 0; i < count; ++i) {
222             final Point lastPoint = getLastPoint();
223             final int xa = lastPoint.x + dxa[i];
224             final int ya = lastPoint.y + (i == 0 ? dy1 : 0);
225             final int xb = xa + dxb[i];
226             final int yb = ya + dyb[i];
227             final int xc = xb + dxc[i];
228             final int yc = yb;
229             curveTo(xa, ya, xb, yb, xc, yc);
230         }
231         clearArg();
232     }
233 
234     /**
235      * Appends one or more Bezier curves to the current point. The
236      * tangent for the first Bezier must be horizontal, and the second
237      * must be vertical (except as noted below).
238      * If there is a multiple of four arguments, the curve starts
239      * horizontal and ends vertical. Note that the curves alternate
240      * between start horizontal, end vertical, and start vertical, and
241      * end horizontal. The last curve (the odd argument case) need not
242      * end horizontal/vertical.
243      */
_hvcurveto()244     private void _hvcurveto() {
245         if (getArgCount() % 8 <= 1) {
246             final int count = getArgCount() / 8;
247             final int[] dxa = new int[count];
248             final int[] dxb = new int[count];
249             final int[] dyb = new int[count];
250             final int[] dyc = new int[count];
251             final int[] dyd = new int[count];
252             final int[] dxe = new int[count];
253             final int[] dye = new int[count];
254             final int[] dxf = new int[count];
255             int dyf = 0;
256             if (getArgCount() % 8 == 1) {
257                 dyf = popArg().intValue();
258             }
259             for (int i = 0; i < count; ++i) {
260                 dxf[count - i - 1] = popArg().intValue();
261                 dye[count - i - 1] = popArg().intValue();
262                 dxe[count - i - 1] = popArg().intValue();
263                 dyd[count - i - 1] = popArg().intValue();
264                 dyc[count - i - 1] = popArg().intValue();
265                 dyb[count - i - 1] = popArg().intValue();
266                 dxb[count - i - 1] = popArg().intValue();
267                 dxa[count - i - 1] = popArg().intValue();
268             }
269             for (int i = 0; i < count; ++i) {
270                 final Point lastPoint = getLastPoint();
271                 final int xa = lastPoint.x + dxa[i];
272                 final int ya = lastPoint.y;
273                 final int xb = xa + dxb[i];
274                 final int yb = ya + dyb[i];
275                 final int xc = xb;
276                 final int yc = yb + dyc[i];
277                 final int xd = xc;
278                 final int yd = yc + dyd[i];
279                 final int xe = xd + dxe[i];
280                 final int ye = yd + dye[i];
281                 final int xf = xe + dxf[i];
282                 final int yf = ye + dyf;
283                 curveTo(xa, ya, xb, yb, xc, yc);
284                 curveTo(xd, yd, xe, ye, xf, yf);
285             }
286         } else {
287             final int count = getArgCount() / 8;
288             final int[] dya = new int[count];
289             final int[] dxb = new int[count];
290             final int[] dyb = new int[count];
291             final int[] dxc = new int[count];
292             final int[] dxd = new int[count];
293             final int[] dxe = new int[count];
294             final int[] dye = new int[count];
295             final int[] dyf = new int[count];
296             int dxf = 0;
297             if (getArgCount() % 8 == 1) {
298                 dxf = popArg().intValue();
299             }
300             for (int i = 0; i < count; ++i) {
301                 dyf[count - i - 1] = popArg().intValue();
302                 dye[count - i - 1] = popArg().intValue();
303                 dxe[count - i - 1] = popArg().intValue();
304                 dxd[count - i - 1] = popArg().intValue();
305                 dxc[count - i - 1] = popArg().intValue();
306                 dyb[count - i - 1] = popArg().intValue();
307                 dxb[count - i - 1] = popArg().intValue();
308                 dya[count - i - 1] = popArg().intValue();
309             }
310             /**
311              * Not using the 'popped' arguments,
312              * hence simply pop them from stack!
313              *
314             final int dy3 = popArg().intValue();
315             final int dy2 = popArg().intValue();
316             final int dx2 = popArg().intValue();
317             final int dx1 = popArg().intValue();
318             */
319             popArg();
320             popArg();
321             popArg();
322             popArg();
323 
324             for (int i = 0; i < count; ++i) {
325                 final Point lastPoint = getLastPoint();
326                 final int xa = lastPoint.x;
327                 final int ya = lastPoint.y + dya[i];
328                 final int xb = xa + dxb[i];
329                 final int yb = ya + dyb[i];
330                 final int xc = xb + dxc[i];
331                 final int yc = yb;
332                 final int xd = xc + dxd[i];
333                 final int yd = yc;
334                 final int xe = xd + dxe[i];
335                 final int ye = yd + dye[i];
336                 final int xf = xe + dxf;
337                 final int yf = ye + dyf[i];
338                 curveTo(xa, ya, xb, yb, xc, yc);
339                 curveTo(xd, yd, xe, ye, xf, yf);
340 
341                 // What on earth do we do with dx1, dx2, dy2 and dy3?
342             }
343         }
344         clearArg();
345     }
346 
347     /**
348      * Is equivalent to one rrcurveto for each set of six arguments
349      * dxa...dyc, followed by exactly one rlineto using the dxd, dyd
350      * arguments. The number of curves is determined from the count
351      * on the argument stack.
352      */
_rcurveline()353     private void _rcurveline() {
354         final int count = (getArgCount() - 2) / 6;
355         final int[] dxa = new int[count];
356         final int[] dya = new int[count];
357         final int[] dxb = new int[count];
358         final int[] dyb = new int[count];
359         final int[] dxc = new int[count];
360         final int[] dyc = new int[count];
361         final int dyd = popArg().intValue();
362         final int dxd = popArg().intValue();
363         for (int i = 0; i < count; ++i) {
364             dyc[count - i - 1] = popArg().intValue();
365             dxc[count - i - 1] = popArg().intValue();
366             dyb[count - i - 1] = popArg().intValue();
367             dxb[count - i - 1] = popArg().intValue();
368             dya[count - i - 1] = popArg().intValue();
369             dxa[count - i - 1] = popArg().intValue();
370         }
371         int xc = 0;
372         int yc = 0;
373         for (int i = 0; i < count; ++i) {
374             final Point lastPoint = getLastPoint();
375             final int xa = lastPoint.x + dxa[i];
376             final int ya = lastPoint.y + dya[i];
377             final int xb = xa + dxb[i];
378             final int yb = ya + dyb[i];
379             xc = xb + dxc[i];
380             yc = yb + dyc[i];
381             curveTo(xa, ya, xb, yb, xc, yc);
382         }
383         lineTo(xc + dxd, yc + dyd);
384         clearArg();
385     }
386 
387     /**
388      * Is equivalent to one rlineto for each pair of arguments beyond
389      * the six arguments dxb...dyd needed for the one rrcurveto
390      * command. The number of lines is determined from the count of
391      * items on the argument stack.
392      */
_rlinecurve()393     private void _rlinecurve() {
394         final int count = (getArgCount() - 6) / 2;
395         final int[] dxa = new int[count];
396         final int[] dya = new int[count];
397         final int dyd = popArg().intValue();
398         final int dxd = popArg().intValue();
399         final int dyc = popArg().intValue();
400         final int dxc = popArg().intValue();
401         final int dyb = popArg().intValue();
402         final int dxb = popArg().intValue();
403         for (int i = 0; i < count; ++i) {
404             dya[count - i - 1] = popArg().intValue();
405             dxa[count - i - 1] = popArg().intValue();
406         }
407         int xa = 0;
408         int ya = 0;
409         for (int i = 0; i < count; ++i) {
410             final Point lastPoint = getLastPoint();
411             xa = lastPoint.x + dxa[i];
412             ya = lastPoint.y + dya[i];
413             lineTo(xa, ya);
414         }
415         final int xb = xa + dxb;
416         final int yb = ya + dyb;
417         final int xc = xb + dxc;
418         final int yc = yb + dyc;
419         final int xd = xc + dxd;
420         final int yd = yc + dyd;
421         curveTo(xb, yb, xc, yc, xd, yd);
422         clearArg();
423     }
424 
425     /**
426      * Appends one or more Bezier curves to the current point, where
427      * the first tangent is vertical and the second tangent is horizontal.
428      * This command is the complement of hvcurveto; see the
429      * description of hvcurveto for more information.
430      */
_vhcurveto()431     private void _vhcurveto() {
432         if (getArgCount() % 8 <= 1) {
433             final int count = getArgCount() / 8;
434             final int[] dya = new int[count];
435             final int[] dxb = new int[count];
436             final int[] dyb = new int[count];
437             final int[] dxc = new int[count];
438             final int[] dxd = new int[count];
439             final int[] dxe = new int[count];
440             final int[] dye = new int[count];
441             final int[] dyf = new int[count];
442             int dxf = 0;
443             if (getArgCount() % 8 == 1) {
444                 dxf = popArg().intValue();
445             }
446             for (int i = 0; i < count; ++i) {
447                 dyf[count - i - 1] = popArg().intValue();
448                 dye[count - i - 1] = popArg().intValue();
449                 dxe[count - i - 1] = popArg().intValue();
450                 dxd[count - i - 1] = popArg().intValue();
451                 dxc[count - i - 1] = popArg().intValue();
452                 dyb[count - i - 1] = popArg().intValue();
453                 dxb[count - i - 1] = popArg().intValue();
454                 dya[count - i - 1] = popArg().intValue();
455             }
456             for (int i = 0; i < count; ++i) {
457                 final Point lastPoint = getLastPoint();
458                 final int xa = lastPoint.x;
459                 final int ya = lastPoint.y + dya[i];
460                 final int xb = xa + dxb[i];
461                 final int yb = ya + dyb[i];
462                 final int xc = xb + dxc[i];
463                 final int yc = yb;
464                 final int xd = xc + dxd[i];
465                 final int yd = yc;
466                 final int xe = xd + dxe[i];
467                 final int ye = yd + dye[i];
468                 final int xf = xe + dxf;
469                 final int yf = ye + dyf[i];
470                 curveTo(xa, ya, xb, yb, xc, yc);
471                 curveTo(xd, yd, xe, ye, xf, yf);
472             }
473         } else {
474             final int foo = 0;
475         }
476         clearArg();
477     }
478 
479     /**
480      * Appends one or more curves to the current point. If the argument
481      * count is a multiple of four, the curve starts and ends vertical. If
482      * the argument count is odd, the first curve does not begin with a
483      * vertical tangent.
484      */
_vvcurveto()485     private void _vvcurveto() {
486 
487         clearArg();
488     }
489 
490     /**
491      * Causes two Bezier curves, as described by the arguments (as
492      * shown in Figure 2 below), to be rendered as a straight line when
493      * the flex depth is less than fd /100 device pixels, and as curved lines
494      * when the flex depth is greater than or equal to fd/100 device
495      * pixels.
496      */
_flex()497     private void _flex() {
498 
499         clearArg();
500     }
501 
502     /**
503      * Causes the two curves described by the arguments dx1...dx6 to
504      * be rendered as a straight line when the flex depth is less than
505      * 0.5 (that is, fd is 50) device pixels, and as curved lines when the
506      * flex depth is greater than or equal to 0.5 device pixels.
507      */
_hflex()508     private void _hflex() {
509 
510         clearArg();
511     }
512 
513     /**
514      * Causes the two curves described by the arguments to be
515      * rendered as a straight line when the flex depth is less than 0.5
516      * device pixels, and as curved lines when the flex depth is greater
517      * than or equal to 0.5 device pixels.
518      */
_hflex1()519     private void _hflex1() {
520 
521         clearArg();
522     }
523 
524     /**
525      * Causes the two curves described by the arguments to be
526      * rendered as a straight line when the flex depth is less than 0.5
527      * device pixels, and as curved lines when the flex depth is greater
528      * than or equal to 0.5 device pixels.
529      */
_flex1()530     private void _flex1() {
531 
532         clearArg();
533     }
534 
535     /**
536      * Finishes a charstring outline definition, and must be the
537      * last operator in a character's outline.
538      */
_endchar()539     private void _endchar() {
540         endContour();
541         clearArg();
542     }
543 
_hstem()544     private void _hstem() {
545 
546         clearArg();
547     }
548 
_vstem()549     private void _vstem() {
550 
551         clearArg();
552     }
553 
_hstemhm()554     private void _hstemhm() {
555 
556         clearArg();
557     }
558 
_vstemhm()559     private void _vstemhm() {
560 
561         clearArg();
562     }
563 
_hintmask()564     private void _hintmask() {
565 
566         clearArg();
567     }
568 
_cntrmask()569     private void _cntrmask() {
570 
571         clearArg();
572     }
573 
574     /**
575      * Returns the absolute value of num.
576      */
_abs()577     private void _abs() {
578         final double num = popArg().doubleValue();
579         pushArg(Math.abs(num));
580     }
581 
582     /**
583      * Returns the sum of the two numbers num1 and num2.
584      */
_add()585     private void _add() {
586         final double num2 = popArg().doubleValue();
587         final double num1 = popArg().doubleValue();
588         pushArg(num1 + num2);
589     }
590 
591     /**
592      * Returns the result of subtracting num2 from num1.
593      */
_sub()594     private void _sub() {
595         final double num2 = popArg().doubleValue();
596         final double num1 = popArg().doubleValue();
597         pushArg(num1 - num2);
598     }
599 
600     /**
601      * Returns the quotient of num1 divided by num2. The result is
602      * undefined if overflow occurs and is zero for underflow.
603      */
_div()604     private void _div() {
605         final double num2 = popArg().doubleValue();
606         final double num1 = popArg().doubleValue();
607         pushArg(num1 / num2);
608     }
609 
610     /**
611      * Returns the negative of num.
612      */
_neg()613     private void _neg() {
614         final double num = popArg().doubleValue();
615         pushArg(-num);
616     }
617 
618     /**
619      * Returns a pseudo random number num2 in the range (0,1], that
620      * is, greater than zero and less than or equal to one.
621      */
_random()622     private void _random() {
623         pushArg(1.0 - Math.random());
624     }
625 
626     /**
627      * Returns the product of num1 and num2. If overflow occurs, the
628      * result is undefined, and zero is returned for underflow.
629      */
_mul()630     private void _mul() {
631         final double num2 = popArg().doubleValue();
632         final double num1 = popArg().doubleValue();
633         pushArg(num1 * num2);
634     }
635 
636     /**
637      * Returns the square root of num. If num is negative, the result is
638      * undefined.
639      */
_sqrt()640     private void _sqrt() {
641         final double num = popArg().doubleValue();
642         pushArg(Math.sqrt(num));
643     }
644 
645     /**
646      * Removes the top element num from the Type 2 argument stack.
647      */
_drop()648     private void _drop() {
649         popArg();
650     }
651 
652     /**
653      * Exchanges the top two elements on the argument stack.
654      */
_exch()655     private void _exch() {
656         final Number num2 = popArg();
657         final Number num1 = popArg();
658         pushArg(num2);
659         pushArg(num1);
660     }
661 
662     /**
663      * Retrieves the element i from the top of the argument stack and
664      * pushes a copy of that element onto that stack. If i is negative,
665      * the top element is copied. If i is greater than X, the operation is
666      * undefined.
667      */
_index()668     private void _index() {
669         final int i = popArg().intValue();
670         final Number[] nums = new Number[i];
671         for (int j = 0; j < i; ++j) {
672             nums[j] = popArg();
673         }
674         for (int j = i - 1; j >= 0; --j) {
675             pushArg(nums[j]);
676         }
677         pushArg(nums[i]);
678     }
679 
680     /**
681      * Performs a circular shift of the elements num(Nx1) ... num0 on
682      * the argument stack by the amount J. Positive J indicates upward
683      * motion of the stack; negative J indicates downward motion.
684      * The value N must be a non-negative integer, otherwise the
685      * operation is undefined.
686      */
_roll()687     private void _roll() {
688         final int j = popArg().intValue();
689         final int n = popArg().intValue();
690         final Number[] nums = new Number[n];
691         for (int i = 0; i < n; ++i) {
692             nums[i] = popArg();
693         }
694         for (int i = n - 1; i >= 0; --i) {
695             pushArg(nums[(n + i + j) % n]);
696         }
697     }
698 
699     /**
700      * Duplicates the top element on the argument stack.
701      */
_dup()702     private void _dup() {
703         final Number any = popArg();
704         pushArg(any);
705         pushArg(any);
706     }
707 
708     /**
709      * Stores val into the transient array at the location given by i.
710      */
_put()711     private void _put() {
712         final int i = popArg().intValue();
713         final Number val = popArg();
714         _transientArray[i] = val;
715     }
716 
717     /**
718      * Retrieves the value stored in the transient array at the location
719      * given by i and pushes the value onto the argument stack. If get
720      * is executed prior to put for i during execution of the current
721      * charstring, the value returned is undefined.
722      */
_get()723     private void _get() {
724         final int i = popArg().intValue();
725         pushArg(_transientArray[i]);
726     }
727 
728     /**
729      * Puts a 1 on the stack if num1 and num2 are both non-zero, and
730      * puts a 0 on the stack if either argument is zero.
731      */
_and()732     private void _and() {
733         final double num2 = popArg().doubleValue();
734         final double num1 = popArg().doubleValue();
735         pushArg((num1!=0.0) && (num2!=0.0) ? 1 : 0);
736     }
737 
738     /**
739      * Puts a 1 on the stack if either num1 or num2 are non-zero, and
740      * puts a 0 on the stack if both arguments are zero.
741      */
_or()742     private void _or() {
743         final double num2 = popArg().doubleValue();
744         final double num1 = popArg().doubleValue();
745         pushArg((num1!=0.0) || (num2!=0.0) ? 1 : 0);
746     }
747 
748     /**
749      * Returns a 0 if num1 is non-zero; returns a 1 if num1 is zero.
750      */
_not()751     private void _not() {
752         final double num1 = popArg().doubleValue();
753         pushArg((num1!=0.0) ? 0 : 1);
754     }
755 
756     /**
757      * Puts a 1 on the stack if num1 equals num2, otherwise a 0 (zero)
758      * is put on the stack.
759      */
_eq()760     private void _eq() {
761         final double num2 = popArg().doubleValue();
762         final double num1 = popArg().doubleValue();
763         pushArg(num1 == num2 ? 1 : 0);
764     }
765 
766     /**
767      * Leaves the value s1 on the stack if v1 ? v2, or leaves s2 on the
768      * stack if v1 > v2. The value of s1 and s2 is usually the biased
769      * number of a subroutine.
770      */
_ifelse()771     private void _ifelse() {
772         final double v2 = popArg().doubleValue();
773         final double v1 = popArg().doubleValue();
774         final Number s2 = popArg();
775         final Number s1 = popArg();
776         pushArg(v1 <= v2 ? s1 : s2);
777     }
778 
779     /**
780      * Calls a charstring subroutine with index subr# (actually the subr
781      * number plus the subroutine bias number, as described in section
782      * 2.3) in the Subrs array. Each element of the Subrs array is a
783      * charstring encoded like any other charstring. Arguments
784      * pushed on the Type 2 argument stack prior to calling the
785      * subroutine, and results pushed on this stack by the subroutine,
786      * act according to the manner in which the subroutine is coded.
787      * Calling an undefined subr (gsubr) has undefined results.
788      */
_callsubr()789     private void _callsubr() {
790 
791     }
792 
793     /**
794      * Operates in the same manner as callsubr except that it calls a
795      * global subroutine.
796      */
_callgsubr()797     private void _callgsubr() {
798 
799     }
800 
801     /**
802      * Returns from either a local or global charstring subroutine, and
803      * continues execution after the corresponding call(g)subr.
804      */
_return()805     private void _return() {
806 
807     }
808 
execute(final CharstringType2 cs)809     public Point[] execute(final CharstringType2 cs) {
810         _points = new ArrayList<Point>();
811         cs.resetIP();
812         while (cs.moreBytes()) {
813             while (cs.isOperandAtIndex()) {
814                 pushArg(cs.nextOperand());
815             }
816             int operator = cs.nextByte();
817             if (operator == 12) {
818                 operator = cs.nextByte();
819 
820                 // Two-byte operators
821                 switch (operator) {
822                 case T2Mnemonic.AND:
823                     _and();
824                     break;
825                 case T2Mnemonic.OR:
826                     _or();
827                     break;
828                 case T2Mnemonic.NOT:
829                     _not();
830                     break;
831                 case T2Mnemonic.ABS:
832                     _abs();
833                     break;
834                 case T2Mnemonic.ADD:
835                     _add();
836                     break;
837                 case T2Mnemonic.SUB:
838                     _sub();
839                     break;
840                 case T2Mnemonic.DIV:
841                     _div();
842                     break;
843                 case T2Mnemonic.NEG:
844                     _neg();
845                     break;
846                 case T2Mnemonic.EQ:
847                     _eq();
848                     break;
849                 case T2Mnemonic.DROP:
850                     _drop();
851                     break;
852                 case T2Mnemonic.PUT:
853                     _put();
854                     break;
855                 case T2Mnemonic.GET:
856                     _get();
857                     break;
858                 case T2Mnemonic.IFELSE:
859                     _ifelse();
860                     break;
861                 case T2Mnemonic.RANDOM:
862                     _random();
863                     break;
864                 case T2Mnemonic.MUL:
865                     _mul();
866                     break;
867                 case T2Mnemonic.SQRT:
868                     _sqrt();
869                     break;
870                 case T2Mnemonic.DUP:
871                     _dup();
872                     break;
873                 case T2Mnemonic.EXCH:
874                     _exch();
875                     break;
876                 case T2Mnemonic.INDEX:
877                     _index();
878                     break;
879                 case T2Mnemonic.ROLL:
880                     _roll();
881                     break;
882                 case T2Mnemonic.HFLEX:
883                     _hflex();
884                     break;
885                 case T2Mnemonic.FLEX:
886                     _flex();
887                     break;
888                 case T2Mnemonic.HFLEX1:
889                     _hflex1();
890                     break;
891                 case T2Mnemonic.FLEX1:
892                     _flex1();
893                     break;
894                 default:
895                     //throw new Exception();
896                     return null;
897                 }
898             } else {
899 
900                 // One-byte operators
901                 switch (operator) {
902                 case T2Mnemonic.HSTEM:
903                     _hstem();
904                     break;
905                 case T2Mnemonic.VSTEM:
906                     _vstem();
907                     break;
908                 case T2Mnemonic.VMOVETO:
909                     _vmoveto();
910                     break;
911                 case T2Mnemonic.RLINETO:
912                     _rlineto();
913                     break;
914                 case T2Mnemonic.HLINETO:
915                     _hlineto();
916                     break;
917                 case T2Mnemonic.VLINETO:
918                     _vlineto();
919                     break;
920                 case T2Mnemonic.RRCURVETO:
921                     _rrcurveto();
922                     break;
923                 case T2Mnemonic.CALLSUBR:
924                     _callsubr();
925                     break;
926                 case T2Mnemonic.RETURN:
927                     _return();
928                     break;
929                 case T2Mnemonic.ENDCHAR:
930                     _endchar();
931                     break;
932                 case T2Mnemonic.HSTEMHM:
933                     _hstemhm();
934                     break;
935                 case T2Mnemonic.HINTMASK:
936                     _hintmask();
937                     break;
938                 case T2Mnemonic.CNTRMASK:
939                     _cntrmask();
940                     break;
941                 case T2Mnemonic.RMOVETO:
942                     _rmoveto();
943                     break;
944                 case T2Mnemonic.HMOVETO:
945                     _hmoveto();
946                     break;
947                 case T2Mnemonic.VSTEMHM:
948                     _vstemhm();
949                     break;
950                 case T2Mnemonic.RCURVELINE:
951                     _rcurveline();
952                     break;
953                 case T2Mnemonic.RLINECURVE:
954                     _rlinecurve();
955                     break;
956                 case T2Mnemonic.VVCURVETO:
957                     _vvcurveto();
958                     break;
959                 case T2Mnemonic.HHCURVETO:
960                     _hhcurveto();
961                     break;
962                 case T2Mnemonic.CALLGSUBR:
963                     _callgsubr();
964                     break;
965                 case T2Mnemonic.VHCURVETO:
966                     _vhcurveto();
967                     break;
968                 case T2Mnemonic.HVCURVETO:
969                     _hvcurveto();
970                     break;
971                 default:
972                     //throw new Exception();
973                     return null;
974                 }
975             }
976         }
977         final Point[] pointArray = new Point[_points.size()];
978         _points.toArray(pointArray);
979         return pointArray;
980     }
981 
982     /**
983      * The number of arguments on the argument stack
984      */
getArgCount()985     private int getArgCount() {
986         return _argStackIndex;
987     }
988 
989     /**
990      * Pop a value off the argument stack
991      */
popArg()992     private Number popArg() {
993         return _argStack[--_argStackIndex];
994     }
995 
996     /**
997      * Push a value on to the argument stack
998      */
pushArg(final Number n)999     private void pushArg(final Number n) {
1000         _argStack[_argStackIndex++] = n;
1001     }
1002 
1003     /**
1004      * Pop a value off the subroutine stack
1005      */
popSubr()1006     private int popSubr() {
1007         return _subrStack[--_subrStackIndex];
1008     }
1009 
1010     /**
1011      * Push a value on to the subroutine stack
1012      */
pushSubr(final int n)1013     private void pushSubr(final int n) {
1014         _subrStack[_subrStackIndex++] = n;
1015     }
1016 
1017     /**
1018      * Clear the argument stack
1019      */
clearArg()1020     private void clearArg() {
1021         _argStackIndex = 0;
1022     }
1023 
getLastPoint()1024     private Point getLastPoint() {
1025         final int size = _points.size();
1026         if (size > 0) {
1027             return _points.get(size - 1);
1028         } else {
1029             return new Point(0, 0, true, false);
1030         }
1031     }
1032 
moveTo(final int x, final int y)1033     private void moveTo(final int x, final int y) {
1034         endContour();
1035         _points.add(new Point(x, y, true, false));
1036     }
1037 
lineTo(final int x, final int y)1038     private void lineTo(final int x, final int y) {
1039         _points.add(new Point(x, y, true, false));
1040     }
1041 
curveTo(final int cx1, final int cy1, final int cx2, final int cy2, final int x, final int y)1042     private void curveTo(final int cx1, final int cy1, final int cx2, final int cy2, final int x, final int y) {
1043         _points.add(new Point(cx1, cy1, false, false));
1044         _points.add(new Point(cx2, cy2, false, false));
1045         _points.add(new Point(x, y, true, false));
1046     }
1047 
endContour()1048     private void endContour() {
1049         final Point lastPoint = getLastPoint();
1050         if (lastPoint != null) {
1051             lastPoint.endOfContour = true;
1052         }
1053     }
1054 }
1055