/* * $Id: T2Interpreter.java,v 1.2 2007-07-26 11:10:18 davidsch Exp $ * * Typecast - The Font Development Environment * * Copyright (c) 2004-2007 David Schweinsberg * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jogamp.graph.font.typecast.t2; import java.util.ArrayList; import jogamp.graph.font.typecast.ot.Point; import jogamp.graph.font.typecast.ot.table.CharstringType2; /** * Type 2 Charstring Interpreter. Operator descriptions are quoted from * Adobe's Type 2 Charstring Format document -- 5117.Type2.pdf. * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a> * @version $Id: T2Interpreter.java,v 1.2 2007-07-26 11:10:18 davidsch Exp $ */ public class T2Interpreter { private static final int ARGUMENT_STACK_LIMIT = 48; private static final int SUBR_STACK_LIMIT = 10; private static final int TRANSIENT_ARRAY_ELEMENT_COUNT = 32; private final Number[] _argStack = new Number[ARGUMENT_STACK_LIMIT]; private int _argStackIndex = 0; private final int[] _subrStack = new int[SUBR_STACK_LIMIT]; private int _subrStackIndex = 0; private final Number[] _transientArray = new Number[TRANSIENT_ARRAY_ELEMENT_COUNT]; private ArrayList<Point> _points; /** Creates a new instance of T2Interpreter */ public T2Interpreter() { } /** * Moves the current point to a position at the relative coordinates * (dx1, dy1). */ private void _rmoveto() { final int dy1 = popArg().intValue(); final int dx1 = popArg().intValue(); clearArg(); final Point lastPoint = getLastPoint(); moveTo(lastPoint.x + dx1, lastPoint.y + dy1); } /** * Moves the current point dx1 units in the horizontal direction. */ private void _hmoveto() { final int dx1 = popArg().intValue(); clearArg(); final Point lastPoint = getLastPoint(); moveTo(lastPoint.x + dx1, lastPoint.y); } /** * Moves the current point dy1 units in the vertical direction. */ private void _vmoveto() { final int dy1 = popArg().intValue(); clearArg(); final Point lastPoint = getLastPoint(); moveTo(lastPoint.x, lastPoint.y + dy1); } /** * Appends a line from the current point to a position at the * relative coordinates dxa, dya. Additional rlineto operations are * performed for all subsequent argument pairs. The number of * lines is determined from the number of arguments on the stack. */ private void _rlineto() { final int count = getArgCount() / 2; final int[] dx = new int[count]; final int[] dy = new int[count]; for (int i = 0; i < count; ++i) { dy[count - i - 1] = popArg().intValue(); dx[count - i - 1] = popArg().intValue(); } for (int i = 0; i < count; ++i) { final Point lastPoint = getLastPoint(); lineTo(lastPoint.x + dx[i], lastPoint.y + dy[i]); } clearArg(); } /** * Appends a horizontal line of length dx1 to the current point. * With an odd number of arguments, subsequent argument pairs * are interpreted as alternating values of dy and dx, for which * additional lineto operators draw alternating vertical and * horizontal lines. With an even number of arguments, the * arguments are interpreted as alternating horizontal and * vertical lines. The number of lines is determined from the * number of arguments on the stack. */ private void _hlineto() { final int count = getArgCount(); final Number[] nums = new Number[count]; for (int i = 0; i < count; ++i) { nums[count - i - 1] = popArg(); } for (int i = 0; i < count; ++i) { final Point lastPoint = getLastPoint(); if (i % 2 == 0) { lineTo(lastPoint.x + nums[i].intValue(), lastPoint.y); } else { lineTo(lastPoint.x, lastPoint.y + nums[i].intValue()); } } clearArg(); } /** * Appends a vertical line of length dy1 to the current point. With * an odd number of arguments, subsequent argument pairs are * interpreted as alternating values of dx and dy, for which * additional lineto operators draw alternating horizontal and * vertical lines. With an even number of arguments, the * arguments are interpreted as alternating vertical and * horizontal lines. The number of lines is determined from the * number of arguments on the stack. */ private void _vlineto() { final int count = getArgCount(); final Number[] nums = new Number[count]; for (int i = 0; i < count; ++i) { nums[count - i - 1] = popArg(); } for (int i = 0; i < count; ++i) { final Point lastPoint = getLastPoint(); if (i % 2 == 0) { lineTo(lastPoint.x, lastPoint.y + nums[i].intValue()); } else { lineTo(lastPoint.x + nums[i].intValue(), lastPoint.y); } } clearArg(); } /** * Appends a Bezier curve, defined by dxa...dyc, to the current * point. For each subsequent set of six arguments, an additional * curve is appended to the current point. The number of curve * segments is determined from the number of arguments on the * number stack and is limited only by the size of the number * stack. */ private void _rrcurveto() { final int count = getArgCount() / 6; final int[] dxa = new int[count]; final int[] dya = new int[count]; final int[] dxb = new int[count]; final int[] dyb = new int[count]; final int[] dxc = new int[count]; final int[] dyc = new int[count]; for (int i = 0; i < count; ++i) { dyc[count - i - 1] = popArg().intValue(); dxc[count - i - 1] = popArg().intValue(); dyb[count - i - 1] = popArg().intValue(); dxb[count - i - 1] = popArg().intValue(); dya[count - i - 1] = popArg().intValue(); dxa[count - i - 1] = popArg().intValue(); } for (int i = 0; i < count; ++i) { final Point lastPoint = getLastPoint(); final int xa = lastPoint.x + dxa[i]; final int ya = lastPoint.y + dya[i]; final int xb = xa + dxb[i]; final int yb = ya + dyb[i]; final int xc = xb + dxc[i]; final int yc = yb + dyc[i]; curveTo(xa, ya, xb, yb, xc, yc); } clearArg(); } /** * Appends one or more Bezier curves, as described by the * dxa...dxc set of arguments, to the current point. For each curve, * if there are 4 arguments, the curve starts and ends horizontal. * The first curve need not start horizontal (the odd argument * case). Note the argument order for the odd argument case. */ private void _hhcurveto() { final int count = getArgCount() / 4; int dy1 = 0; final int[] dxa = new int[count]; final int[] dxb = new int[count]; final int[] dyb = new int[count]; final int[] dxc = new int[count]; for (int i = 0; i < count; ++i) { dxc[count - i - 1] = popArg().intValue(); dyb[count - i - 1] = popArg().intValue(); dxb[count - i - 1] = popArg().intValue(); dxa[count - i - 1] = popArg().intValue(); } if (getArgCount() == 1) { dy1 = popArg().intValue(); } for (int i = 0; i < count; ++i) { final Point lastPoint = getLastPoint(); final int xa = lastPoint.x + dxa[i]; final int ya = lastPoint.y + (i == 0 ? dy1 : 0); final int xb = xa + dxb[i]; final int yb = ya + dyb[i]; final int xc = xb + dxc[i]; final int yc = yb; curveTo(xa, ya, xb, yb, xc, yc); } clearArg(); } /** * Appends one or more Bezier curves to the current point. The * tangent for the first Bezier must be horizontal, and the second * must be vertical (except as noted below). * If there is a multiple of four arguments, the curve starts * horizontal and ends vertical. Note that the curves alternate * between start horizontal, end vertical, and start vertical, and * end horizontal. The last curve (the odd argument case) need not * end horizontal/vertical. */ private void _hvcurveto() { if (getArgCount() % 8 <= 1) { final int count = getArgCount() / 8; final int[] dxa = new int[count]; final int[] dxb = new int[count]; final int[] dyb = new int[count]; final int[] dyc = new int[count]; final int[] dyd = new int[count]; final int[] dxe = new int[count]; final int[] dye = new int[count]; final int[] dxf = new int[count]; int dyf = 0; if (getArgCount() % 8 == 1) { dyf = popArg().intValue(); } for (int i = 0; i < count; ++i) { dxf[count - i - 1] = popArg().intValue(); dye[count - i - 1] = popArg().intValue(); dxe[count - i - 1] = popArg().intValue(); dyd[count - i - 1] = popArg().intValue(); dyc[count - i - 1] = popArg().intValue(); dyb[count - i - 1] = popArg().intValue(); dxb[count - i - 1] = popArg().intValue(); dxa[count - i - 1] = popArg().intValue(); } for (int i = 0; i < count; ++i) { final Point lastPoint = getLastPoint(); final int xa = lastPoint.x + dxa[i]; final int ya = lastPoint.y; final int xb = xa + dxb[i]; final int yb = ya + dyb[i]; final int xc = xb; final int yc = yb + dyc[i]; final int xd = xc; final int yd = yc + dyd[i]; final int xe = xd + dxe[i]; final int ye = yd + dye[i]; final int xf = xe + dxf[i]; final int yf = ye + dyf; curveTo(xa, ya, xb, yb, xc, yc); curveTo(xd, yd, xe, ye, xf, yf); } } else { final int count = getArgCount() / 8; final int[] dya = new int[count]; final int[] dxb = new int[count]; final int[] dyb = new int[count]; final int[] dxc = new int[count]; final int[] dxd = new int[count]; final int[] dxe = new int[count]; final int[] dye = new int[count]; final int[] dyf = new int[count]; int dxf = 0; if (getArgCount() % 8 == 1) { dxf = popArg().intValue(); } for (int i = 0; i < count; ++i) { dyf[count - i - 1] = popArg().intValue(); dye[count - i - 1] = popArg().intValue(); dxe[count - i - 1] = popArg().intValue(); dxd[count - i - 1] = popArg().intValue(); dxc[count - i - 1] = popArg().intValue(); dyb[count - i - 1] = popArg().intValue(); dxb[count - i - 1] = popArg().intValue(); dya[count - i - 1] = popArg().intValue(); } /** * Not using the 'popped' arguments, * hence simply pop them from stack! * final int dy3 = popArg().intValue(); final int dy2 = popArg().intValue(); final int dx2 = popArg().intValue(); final int dx1 = popArg().intValue(); */ popArg(); popArg(); popArg(); popArg(); for (int i = 0; i < count; ++i) { final Point lastPoint = getLastPoint(); final int xa = lastPoint.x; final int ya = lastPoint.y + dya[i]; final int xb = xa + dxb[i]; final int yb = ya + dyb[i]; final int xc = xb + dxc[i]; final int yc = yb; final int xd = xc + dxd[i]; final int yd = yc; final int xe = xd + dxe[i]; final int ye = yd + dye[i]; final int xf = xe + dxf; final int yf = ye + dyf[i]; curveTo(xa, ya, xb, yb, xc, yc); curveTo(xd, yd, xe, ye, xf, yf); // What on earth do we do with dx1, dx2, dy2 and dy3? } } clearArg(); } /** * Is equivalent to one rrcurveto for each set of six arguments * dxa...dyc, followed by exactly one rlineto using the dxd, dyd * arguments. The number of curves is determined from the count * on the argument stack. */ private void _rcurveline() { final int count = (getArgCount() - 2) / 6; final int[] dxa = new int[count]; final int[] dya = new int[count]; final int[] dxb = new int[count]; final int[] dyb = new int[count]; final int[] dxc = new int[count]; final int[] dyc = new int[count]; final int dyd = popArg().intValue(); final int dxd = popArg().intValue(); for (int i = 0; i < count; ++i) { dyc[count - i - 1] = popArg().intValue(); dxc[count - i - 1] = popArg().intValue(); dyb[count - i - 1] = popArg().intValue(); dxb[count - i - 1] = popArg().intValue(); dya[count - i - 1] = popArg().intValue(); dxa[count - i - 1] = popArg().intValue(); } int xc = 0; int yc = 0; for (int i = 0; i < count; ++i) { final Point lastPoint = getLastPoint(); final int xa = lastPoint.x + dxa[i]; final int ya = lastPoint.y + dya[i]; final int xb = xa + dxb[i]; final int yb = ya + dyb[i]; xc = xb + dxc[i]; yc = yb + dyc[i]; curveTo(xa, ya, xb, yb, xc, yc); } lineTo(xc + dxd, yc + dyd); clearArg(); } /** * Is equivalent to one rlineto for each pair of arguments beyond * the six arguments dxb...dyd needed for the one rrcurveto * command. The number of lines is determined from the count of * items on the argument stack. */ private void _rlinecurve() { final int count = (getArgCount() - 6) / 2; final int[] dxa = new int[count]; final int[] dya = new int[count]; final int dyd = popArg().intValue(); final int dxd = popArg().intValue(); final int dyc = popArg().intValue(); final int dxc = popArg().intValue(); final int dyb = popArg().intValue(); final int dxb = popArg().intValue(); for (int i = 0; i < count; ++i) { dya[count - i - 1] = popArg().intValue(); dxa[count - i - 1] = popArg().intValue(); } int xa = 0; int ya = 0; for (int i = 0; i < count; ++i) { final Point lastPoint = getLastPoint(); xa = lastPoint.x + dxa[i]; ya = lastPoint.y + dya[i]; lineTo(xa, ya); } final int xb = xa + dxb; final int yb = ya + dyb; final int xc = xb + dxc; final int yc = yb + dyc; final int xd = xc + dxd; final int yd = yc + dyd; curveTo(xb, yb, xc, yc, xd, yd); clearArg(); } /** * Appends one or more Bezier curves to the current point, where * the first tangent is vertical and the second tangent is horizontal. * This command is the complement of hvcurveto; see the * description of hvcurveto for more information. */ private void _vhcurveto() { if (getArgCount() % 8 <= 1) { final int count = getArgCount() / 8; final int[] dya = new int[count]; final int[] dxb = new int[count]; final int[] dyb = new int[count]; final int[] dxc = new int[count]; final int[] dxd = new int[count]; final int[] dxe = new int[count]; final int[] dye = new int[count]; final int[] dyf = new int[count]; int dxf = 0; if (getArgCount() % 8 == 1) { dxf = popArg().intValue(); } for (int i = 0; i < count; ++i) { dyf[count - i - 1] = popArg().intValue(); dye[count - i - 1] = popArg().intValue(); dxe[count - i - 1] = popArg().intValue(); dxd[count - i - 1] = popArg().intValue(); dxc[count - i - 1] = popArg().intValue(); dyb[count - i - 1] = popArg().intValue(); dxb[count - i - 1] = popArg().intValue(); dya[count - i - 1] = popArg().intValue(); } for (int i = 0; i < count; ++i) { final Point lastPoint = getLastPoint(); final int xa = lastPoint.x; final int ya = lastPoint.y + dya[i]; final int xb = xa + dxb[i]; final int yb = ya + dyb[i]; final int xc = xb + dxc[i]; final int yc = yb; final int xd = xc + dxd[i]; final int yd = yc; final int xe = xd + dxe[i]; final int ye = yd + dye[i]; final int xf = xe + dxf; final int yf = ye + dyf[i]; curveTo(xa, ya, xb, yb, xc, yc); curveTo(xd, yd, xe, ye, xf, yf); } } else { final int foo = 0; } clearArg(); } /** * Appends one or more curves to the current point. If the argument * count is a multiple of four, the curve starts and ends vertical. If * the argument count is odd, the first curve does not begin with a * vertical tangent. */ private void _vvcurveto() { clearArg(); } /** * Causes two Bezier curves, as described by the arguments (as * shown in Figure 2 below), to be rendered as a straight line when * the flex depth is less than fd /100 device pixels, and as curved lines * when the flex depth is greater than or equal to fd/100 device * pixels. */ private void _flex() { clearArg(); } /** * Causes the two curves described by the arguments dx1...dx6 to * be rendered as a straight line when the flex depth is less than * 0.5 (that is, fd is 50) device pixels, and as curved lines when the * flex depth is greater than or equal to 0.5 device pixels. */ private void _hflex() { clearArg(); } /** * Causes the two curves described by the arguments to be * rendered as a straight line when the flex depth is less than 0.5 * device pixels, and as curved lines when the flex depth is greater * than or equal to 0.5 device pixels. */ private void _hflex1() { clearArg(); } /** * Causes the two curves described by the arguments to be * rendered as a straight line when the flex depth is less than 0.5 * device pixels, and as curved lines when the flex depth is greater * than or equal to 0.5 device pixels. */ private void _flex1() { clearArg(); } /** * Finishes a charstring outline definition, and must be the * last operator in a character's outline. */ private void _endchar() { endContour(); clearArg(); } private void _hstem() { clearArg(); } private void _vstem() { clearArg(); } private void _hstemhm() { clearArg(); } private void _vstemhm() { clearArg(); } private void _hintmask() { clearArg(); } private void _cntrmask() { clearArg(); } /** * Returns the absolute value of num. */ private void _abs() { final double num = popArg().doubleValue(); pushArg(Math.abs(num)); } /** * Returns the sum of the two numbers num1 and num2. */ private void _add() { final double num2 = popArg().doubleValue(); final double num1 = popArg().doubleValue(); pushArg(num1 + num2); } /** * Returns the result of subtracting num2 from num1. */ private void _sub() { final double num2 = popArg().doubleValue(); final double num1 = popArg().doubleValue(); pushArg(num1 - num2); } /** * Returns the quotient of num1 divided by num2. The result is * undefined if overflow occurs and is zero for underflow. */ private void _div() { final double num2 = popArg().doubleValue(); final double num1 = popArg().doubleValue(); pushArg(num1 / num2); } /** * Returns the negative of num. */ private void _neg() { final double num = popArg().doubleValue(); pushArg(-num); } /** * Returns a pseudo random number num2 in the range (0,1], that * is, greater than zero and less than or equal to one. */ private void _random() { pushArg(1.0 - Math.random()); } /** * Returns the product of num1 and num2. If overflow occurs, the * result is undefined, and zero is returned for underflow. */ private void _mul() { final double num2 = popArg().doubleValue(); final double num1 = popArg().doubleValue(); pushArg(num1 * num2); } /** * Returns the square root of num. If num is negative, the result is * undefined. */ private void _sqrt() { final double num = popArg().doubleValue(); pushArg(Math.sqrt(num)); } /** * Removes the top element num from the Type 2 argument stack. */ private void _drop() { popArg(); } /** * Exchanges the top two elements on the argument stack. */ private void _exch() { final Number num2 = popArg(); final Number num1 = popArg(); pushArg(num2); pushArg(num1); } /** * Retrieves the element i from the top of the argument stack and * pushes a copy of that element onto that stack. If i is negative, * the top element is copied. If i is greater than X, the operation is * undefined. */ private void _index() { final int i = popArg().intValue(); final Number[] nums = new Number[i]; for (int j = 0; j < i; ++j) { nums[j] = popArg(); } for (int j = i - 1; j >= 0; --j) { pushArg(nums[j]); } pushArg(nums[i]); } /** * Performs a circular shift of the elements num(Nx1) ... num0 on * the argument stack by the amount J. Positive J indicates upward * motion of the stack; negative J indicates downward motion. * The value N must be a non-negative integer, otherwise the * operation is undefined. */ private void _roll() { final int j = popArg().intValue(); final int n = popArg().intValue(); final Number[] nums = new Number[n]; for (int i = 0; i < n; ++i) { nums[i] = popArg(); } for (int i = n - 1; i >= 0; --i) { pushArg(nums[(n + i + j) % n]); } } /** * Duplicates the top element on the argument stack. */ private void _dup() { final Number any = popArg(); pushArg(any); pushArg(any); } /** * Stores val into the transient array at the location given by i. */ private void _put() { final int i = popArg().intValue(); final Number val = popArg(); _transientArray[i] = val; } /** * Retrieves the value stored in the transient array at the location * given by i and pushes the value onto the argument stack. If get * is executed prior to put for i during execution of the current * charstring, the value returned is undefined. */ private void _get() { final int i = popArg().intValue(); pushArg(_transientArray[i]); } /** * Puts a 1 on the stack if num1 and num2 are both non-zero, and * puts a 0 on the stack if either argument is zero. */ private void _and() { final double num2 = popArg().doubleValue(); final double num1 = popArg().doubleValue(); pushArg((num1!=0.0) && (num2!=0.0) ? 1 : 0); } /** * Puts a 1 on the stack if either num1 or num2 are non-zero, and * puts a 0 on the stack if both arguments are zero. */ private void _or() { final double num2 = popArg().doubleValue(); final double num1 = popArg().doubleValue(); pushArg((num1!=0.0) || (num2!=0.0) ? 1 : 0); } /** * Returns a 0 if num1 is non-zero; returns a 1 if num1 is zero. */ private void _not() { final double num1 = popArg().doubleValue(); pushArg((num1!=0.0) ? 0 : 1); } /** * Puts a 1 on the stack if num1 equals num2, otherwise a 0 (zero) * is put on the stack. */ private void _eq() { final double num2 = popArg().doubleValue(); final double num1 = popArg().doubleValue(); pushArg(num1 == num2 ? 1 : 0); } /** * Leaves the value s1 on the stack if v1 ? v2, or leaves s2 on the * stack if v1 > v2. The value of s1 and s2 is usually the biased * number of a subroutine. */ private void _ifelse() { final double v2 = popArg().doubleValue(); final double v1 = popArg().doubleValue(); final Number s2 = popArg(); final Number s1 = popArg(); pushArg(v1 <= v2 ? s1 : s2); } /** * Calls a charstring subroutine with index subr# (actually the subr * number plus the subroutine bias number, as described in section * 2.3) in the Subrs array. Each element of the Subrs array is a * charstring encoded like any other charstring. Arguments * pushed on the Type 2 argument stack prior to calling the * subroutine, and results pushed on this stack by the subroutine, * act according to the manner in which the subroutine is coded. * Calling an undefined subr (gsubr) has undefined results. */ private void _callsubr() { } /** * Operates in the same manner as callsubr except that it calls a * global subroutine. */ private void _callgsubr() { } /** * Returns from either a local or global charstring subroutine, and * continues execution after the corresponding call(g)subr. */ private void _return() { } public Point[] execute(final CharstringType2 cs) { _points = new ArrayList<Point>(); cs.resetIP(); while (cs.moreBytes()) { while (cs.isOperandAtIndex()) { pushArg(cs.nextOperand()); } int operator = cs.nextByte(); if (operator == 12) { operator = cs.nextByte(); // Two-byte operators switch (operator) { case T2Mnemonic.AND: _and(); break; case T2Mnemonic.OR: _or(); break; case T2Mnemonic.NOT: _not(); break; case T2Mnemonic.ABS: _abs(); break; case T2Mnemonic.ADD: _add(); break; case T2Mnemonic.SUB: _sub(); break; case T2Mnemonic.DIV: _div(); break; case T2Mnemonic.NEG: _neg(); break; case T2Mnemonic.EQ: _eq(); break; case T2Mnemonic.DROP: _drop(); break; case T2Mnemonic.PUT: _put(); break; case T2Mnemonic.GET: _get(); break; case T2Mnemonic.IFELSE: _ifelse(); break; case T2Mnemonic.RANDOM: _random(); break; case T2Mnemonic.MUL: _mul(); break; case T2Mnemonic.SQRT: _sqrt(); break; case T2Mnemonic.DUP: _dup(); break; case T2Mnemonic.EXCH: _exch(); break; case T2Mnemonic.INDEX: _index(); break; case T2Mnemonic.ROLL: _roll(); break; case T2Mnemonic.HFLEX: _hflex(); break; case T2Mnemonic.FLEX: _flex(); break; case T2Mnemonic.HFLEX1: _hflex1(); break; case T2Mnemonic.FLEX1: _flex1(); break; default: //throw new Exception(); return null; } } else { // One-byte operators switch (operator) { case T2Mnemonic.HSTEM: _hstem(); break; case T2Mnemonic.VSTEM: _vstem(); break; case T2Mnemonic.VMOVETO: _vmoveto(); break; case T2Mnemonic.RLINETO: _rlineto(); break; case T2Mnemonic.HLINETO: _hlineto(); break; case T2Mnemonic.VLINETO: _vlineto(); break; case T2Mnemonic.RRCURVETO: _rrcurveto(); break; case T2Mnemonic.CALLSUBR: _callsubr(); break; case T2Mnemonic.RETURN: _return(); break; case T2Mnemonic.ENDCHAR: _endchar(); break; case T2Mnemonic.HSTEMHM: _hstemhm(); break; case T2Mnemonic.HINTMASK: _hintmask(); break; case T2Mnemonic.CNTRMASK: _cntrmask(); break; case T2Mnemonic.RMOVETO: _rmoveto(); break; case T2Mnemonic.HMOVETO: _hmoveto(); break; case T2Mnemonic.VSTEMHM: _vstemhm(); break; case T2Mnemonic.RCURVELINE: _rcurveline(); break; case T2Mnemonic.RLINECURVE: _rlinecurve(); break; case T2Mnemonic.VVCURVETO: _vvcurveto(); break; case T2Mnemonic.HHCURVETO: _hhcurveto(); break; case T2Mnemonic.CALLGSUBR: _callgsubr(); break; case T2Mnemonic.VHCURVETO: _vhcurveto(); break; case T2Mnemonic.HVCURVETO: _hvcurveto(); break; default: //throw new Exception(); return null; } } } final Point[] pointArray = new Point[_points.size()]; _points.toArray(pointArray); return pointArray; } /** * The number of arguments on the argument stack */ private int getArgCount() { return _argStackIndex; } /** * Pop a value off the argument stack */ private Number popArg() { return _argStack[--_argStackIndex]; } /** * Push a value on to the argument stack */ private void pushArg(final Number n) { _argStack[_argStackIndex++] = n; } /** * Pop a value off the subroutine stack */ private int popSubr() { return _subrStack[--_subrStackIndex]; } /** * Push a value on to the subroutine stack */ private void pushSubr(final int n) { _subrStack[_subrStackIndex++] = n; } /** * Clear the argument stack */ private void clearArg() { _argStackIndex = 0; } private Point getLastPoint() { final int size = _points.size(); if (size > 0) { return _points.get(size - 1); } else { return new Point(0, 0, true, false); } } private void moveTo(final int x, final int y) { endContour(); _points.add(new Point(x, y, true, false)); } private void lineTo(final int x, final int y) { _points.add(new Point(x, y, true, false)); } private void curveTo(final int cx1, final int cy1, final int cx2, final int cy2, final int x, final int y) { _points.add(new Point(cx1, cy1, false, false)); _points.add(new Point(cx2, cy2, false, false)); _points.add(new Point(x, y, true, false)); } private void endContour() { final Point lastPoint = getLastPoint(); if (lastPoint != null) { lastPoint.endOfContour = true; } } }