int kind = 0; Iterator<Integer> it = Curve.breakPtsAtTs(middle, 8, subdivTs, nSplits); while(it.hasNext()) { int curCurveOff = it.next(); kind = computeOffsetCubic(middle, curCurveOff, lp, rp); emitLineTo(lp[0], lp[1]); switch(kind) { case 8: emitCurveTo(lp[0], lp[1], lp[2], lp[3], lp[4], lp[5], lp[6], lp[7], false); emitCurveTo(rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7], true); break; case 4: emitLineTo(lp[2], lp[3]); emitLineTo(rp[0], rp[1], true); break; } emitLineTo(rp[kind - 2], rp[kind - 1], true); } this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2; this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2; this.cdx = dxf; this.cdy = dyf; this.cx0 = xf; this.cy0 = yf; this.prev = DRAWING_OP_TO; } @Override public void quadTo(float x1, float y1, float x2, float y2) { middle[0] = cx0; middle[1] = cy0; middle[2] = x1; middle[3] = y1; middle[4] = x2; middle[5] = y2; // inlined version of somethingTo(8); // See the TODO on somethingTo // need these so we can update the state at the end of this method final float xf = middle[4], yf = middle[5]; float dxs = middle[2] - middle[0]; float dys = middle[3] - middle[1]; float dxf = middle[4] - middle[2]; float dyf = middle[5] - middle[3]; if ((dxs == 0f && dys == 0f) || (dxf == 0f && dyf == 0f)) { dxs = dxf = middle[4] - middle[0]; dys = dyf = middle[5] - middle[1]; } if (dxs == 0f && dys == 0f) { // this happens iff the "curve" is just a point lineTo(middle[0], middle[1]); return; } // if these vectors are too small, normalize them, to avoid future // precision problems. if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) { float len = (float) sqrt(dxs*dxs + dys*dys); dxs /= len; dys /= len; } if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) { float len = (float) sqrt(dxf*dxf + dyf*dyf); dxf /= len; dyf /= len; } computeOffset(dxs, dys, lineWidth2, offset[0]); final float mx = offset[0][0]; final float my = offset[0][1]; drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, mx, my); int nSplits = findSubdivPoints(middle, subdivTs, 6, lineWidth2); int kind = 0; Iterator<Integer> it = Curve.breakPtsAtTs(middle, 6, subdivTs, nSplits); while(it.hasNext()) { int curCurveOff = it.next(); kind = computeOffsetQuad(middle, curCurveOff, lp, rp); emitLineTo(lp[0], lp[1]); switch(kind) { case 6: emitQuadTo(lp[0], lp[1], lp[2], lp[3], lp[4], lp[5], false); emitQuadTo(rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], true); break; case 4: emitLineTo(lp[2], lp[3]); emitLineTo(rp[0], rp[1], true); break; } emitLineTo(rp[kind - 2], rp[kind - 1], true); } this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2; this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2; this.cdx = dxf; this.cdy = dyf; this.cx0 = xf; this.cy0 = yf; this.prev = DRAWING_OP_TO; } @Override public long getNativeConsumer() { throw new InternalError("Stroker doesn't use a native consumer"); } // a stack of polynomial curves where each curve shares endpoints with // adjacent ones. private static final class PolyStack { float[] curves; int end; int[] curveTypes; int numCurves; private static final int INIT_SIZE = 50; PolyStack() { curves = new float[8 * INIT_SIZE]; curveTypes = new int[INIT_SIZE]; end = 0; numCurves = 0; } public boolean isEmpty() { return numCurves == 0; } private void ensureSpace(int n) { if (end + n >= curves.length) { int newSize = (end + n) * 2; curves = Arrays.copyOf(curves, newSize); } if (numCurves >= curveTypes.length) { int newSize = numCurves * 2; curveTypes = Arrays.copyOf(curveTypes, newSize); } } public void pushCubic(float x0, float y0, float x1, float y1, float x2, float y2) { ensureSpace(6); curveTypes[numCurves++] = 8; // assert(x0 == lastX && y0 == lastY) // we reverse the coordinate order to make popping easier curves[end++] = x2; curves[end++] = y2; curves[end++] = x1; curves[end++] = y1; curves[end++] = x0; curves[end++] = y0; } public void pushQuad(float x0, float y0, float x1, float y1) { ensureSpace(4); curveTypes[numCurves++] = 6; // assert(x0 == lastX && y0 == lastY) curves[end++] = x1; curves[end++] = y1; curves[end++] = x0; curves[end++] = y0; } public void pushLine(float x, float y) { ensureSpace(2); curveTypes[numCurves++] = 4; // assert(x0 == lastX && y0 == lastY) curves[end++] = x; curves[end++] = y; } @SuppressWarnings("unused") public int pop(float[] pts) { int ret = curveTypes[numCurves - 1]; numCurves--; end -= (ret - 2); System.arraycopy(curves, end, pts, 0, ret - 2); return ret; } public void pop(PathConsumer2D io) { numCurves--; int type = curveTypes[numCurves]; end -= (type - 2); switch(type) { case 8: io.curveTo(curves[end+0], curves[end+1], curves[end+2], curves[end+3], curves[end+4], curves[end+5]); break; case 6: io.quadTo(curves[end+0], curves[end+1], curves[end+2], curves[end+3]); break; case 4: io.lineTo(curves[end], curves[end+1]); } } @Override public String toString() { String ret = ""; int nc = numCurves; int end = this.end; while (nc > 0) { nc--; int type = curveTypes[numCurves]; end -= (type - 2); switch(type) { case 8: ret += "cubic: "; break; case 6: ret += "quad: "; break; case 4: ret += "line: "; break; } ret += Arrays.toString(Arrays.copyOfRange(curves, end, end+type-2)) + "\n"; } return ret; } }}Lines 1001–1223 of 1223. Previous lines
int kind = 0; Iterator<Integer> it = Curve.breakPtsAtTs(middle, 8, subdivTs, nSplits); while(it.hasNext()) { int curCurveOff = it.next(); kind = computeOffsetCubic(middle, curCurveOff, lp, rp); emitLineTo(lp[0], lp[1]); switch(kind) { case 8: emitCurveTo(lp[0], lp[1], lp[2], lp[3], lp[4], lp[5], lp[6], lp[7], false); emitCurveTo(rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7], true); break; case 4: emitLineTo(lp[2], lp[3]); emitLineTo(rp[0], rp[1], true); break; } emitLineTo(rp[kind - 2], rp[kind - 1], true); } this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2; this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2; this.cdx = dxf; this.cdy = dyf; this.cx0 = xf; this.cy0 = yf; this.prev = DRAWING_OP_TO; } @Override public void quadTo(float x1, float y1, float x2, float y2) { middle[0] = cx0; middle[1] = cy0; middle[2] = x1; middle[3] = y1; middle[4] = x2; middle[5] = y2; // inlined version of somethingTo(8); // See the TODO on somethingTo // need these so we can update the state at the end of this method final float xf = middle[4], yf = middle[5]; float dxs = middle[2] - middle[0]; float dys = middle[3] - middle[1]; float dxf = middle[4] - middle[2]; float dyf = middle[5] - middle[3]; if ((dxs == 0f && dys == 0f) || (dxf == 0f && dyf == 0f)) { dxs = dxf = middle[4] - middle[0]; dys = dyf = middle[5] - middle[1]; } if (dxs == 0f && dys == 0f) { // this happens iff the "curve" is just a point lineTo(middle[0], middle[1]); return; } // if these vectors are too small, normalize them, to avoid future // precision problems. if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) { float len = (float) sqrt(dxs*dxs + dys*dys); dxs /= len; dys /= len; } if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) { float len = (float) sqrt(dxf*dxf + dyf*dyf); dxf /= len; dyf /= len; } computeOffset(dxs, dys, lineWidth2, offset[0]); final float mx = offset[0][0]; final float my = offset[0][1]; drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, mx, my); int nSplits = findSubdivPoints(middle, subdivTs, 6, lineWidth2); int kind = 0; Iterator<Integer> it = Curve.breakPtsAtTs(middle, 6, subdivTs, nSplits); while(it.hasNext()) { int curCurveOff = it.next(); kind = computeOffsetQuad(middle, curCurveOff, lp, rp); emitLineTo(lp[0], lp[1]); switch(kind) { case 6: emitQuadTo(lp[0], lp[1], lp[2], lp[3], lp[4], lp[5], false); emitQuadTo(rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], true); break; case 4: emitLineTo(lp[2], lp[3]); emitLineTo(rp[0], rp[1], true); break; } emitLineTo(rp[kind - 2], rp[kind - 1], true); } this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2; this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2; this.cdx = dxf; this.cdy = dyf; this.cx0 = xf; this.cy0 = yf; this.prev = DRAWING_OP_TO; } @Override public long getNativeConsumer() { throw new InternalError("Stroker doesn't use a native consumer"); } // a stack of polynomial curves where each curve shares endpoints with // adjacent ones. private static final class PolyStack { float[] curves; int end; int[] curveTypes; int numCurves; private static final int INIT_SIZE = 50; PolyStack() { curves = new float[8 * INIT_SIZE]; curveTypes = new int[INIT_SIZE]; end = 0; numCurves = 0; } public boolean isEmpty() { return numCurves == 0; } private void ensureSpace(int n) { if (end + n >= curves.length) { int newSize = (end + n) * 2; curves = Arrays.copyOf(curves, newSize); } if (numCurves >= curveTypes.length) { int newSize = numCurves * 2; curveTypes = Arrays.copyOf(curveTypes, newSize); } } public void pushCubic(float x0, float y0, float x1, float y1, float x2, float y2) { ensureSpace(6); curveTypes[numCurves++] = 8; // assert(x0 == lastX && y0 == lastY) // we reverse the coordinate order to make popping easier curves[end++] = x2; curves[end++] = y2; curves[end++] = x1; curves[end++] = y1; curves[end++] = x0; curves[end++] = y0; } public void pushQuad(float x0, float y0, float x1, float y1) { ensureSpace(4); curveTypes[numCurves++] = 6; // assert(x0 == lastX && y0 == lastY) curves[end++] = x1; curves[end++] = y1; curves[end++] = x0; curves[end++] = y0; } public void pushLine(float x, float y) { ensureSpace(2); curveTypes[numCurves++] = 4; // assert(x0 == lastX && y0 == lastY) curves[end++] = x; curves[end++] = y; } @SuppressWarnings("unused") public int pop(float[] pts) { int ret = curveTypes[numCurves - 1]; numCurves--; end -= (ret - 2); System.arraycopy(curves, end, pts, 0, ret - 2); return ret; } public void pop(PathConsumer2D io) { numCurves--; int type = curveTypes[numCurves]; end -= (type - 2); switch(type) { case 8: io.curveTo(curves[end+0], curves[end+1], curves[end+2], curves[end+3], curves[end+4], curves[end+5]); break; case 6: io.quadTo(curves[end+0], curves[end+1], curves[end+2], curves[end+3]); break; case 4: io.lineTo(curves[end], curves[end+1]); } } @Override public String toString() { String ret = ""; int nc = numCurves; int end = this.end; while (nc > 0) { nc--; int type = curveTypes[numCurves]; end -= (type - 2); switch(type) { case 8: ret += "cubic: "; break; case 6: ret += "quad: "; break; case 4: ret += "line: "; break; } ret += Arrays.toString(Arrays.copyOfRange(curves, end, end+type-2)) + "\n"; } return ret; } } }