Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.lang.ref.WeakReference;
- import java.util.Random;
- import java.util.Stack;
- import org.xml.sax.Attributes;
- import org.xml.sax.SAXException;
- import org.xml.sax.helpers.DefaultHandler;
- import com.kikijiki.ryukisenga.Uti;
- import com.kikijiki.ryukisenga.content.SVGUti.SvgTag;
- import com.kikijiki.ryukisenga.drawing.Sen;
- import com.kikijiki.ryukisenga.drawing.Sequence.Settings;
- import com.kikijiki.ryukisenga.drawing.vec;
- import android.annotation.SuppressLint;
- import android.graphics.Matrix;
- public class SvgContentHandler extends DefaultHandler
- {
- private final int CIRCLE_ELLIPSE_SEGMENTS_MIN = 4;
- private final static float PI2 = (float) (Math.PI * 2);
- private WeakReference<ParserInterface> _thread;
- private Stack<Matrix> _transform = new Stack<Matrix>();
- private boolean _abort = false;
- private Random _rnd = new Random();
- private Settings _settings;
- private CubicBezierFlattener _flattener;
- private ParserData _data = new ParserData();
- private class ParserData
- {
- String s;
- int cur = 0;
- int len = 0;
- float prev_x = .0f;
- float prev_y = .0f;
- float prev_cx = .0f;
- float prev_cy = .0f;
- float start_x = .0f;
- float start_y = .0f;
- char prev_curve;
- char next_curve = 0;
- public void setData(String data)
- {
- s = data;
- len = s.length();
- cur = 0;
- prev_x = 0;
- prev_y = 0;
- prev_cx = .0f;
- prev_cy = .0f;
- start_x = .0f;
- start_y = .0f;
- prev_curve = 0;
- next_curve = 0;
- }
- public boolean hasNext()
- {
- return cur < len;
- }
- public char getNext()
- {
- return s.charAt(cur++);
- }
- public char peekNext()
- {
- return s.charAt(cur);
- }
- public void skipSpaces()
- {
- while(hasNext())
- {
- char c = s.charAt(cur);
- switch(c)
- {
- case ' ':
- case ',':
- case '\n':
- case '\t':
- case '\r':
- break;
- default:
- return;
- }
- cur++;
- }
- }
- private float parseFloat()
- {
- boolean exp = false;
- skipSpaces();
- int j = cur;
- if(s.charAt(j) == '-')
- {
- getNext();
- }
- while(hasNext())
- {
- char c = getNext();
- switch(c)
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '+':
- case '.':
- exp = false;
- break;
- case '-':
- if(exp)
- {
- exp = false;
- }
- else
- {
- cur--;
- return Uti.safeParseFloat(s.substring(j, cur));
- }
- break;
- case 'e':
- case 'E':
- exp = true;
- break;
- default:
- cur--;
- return Uti.safeParseFloat(s.substring(j, cur));
- }
- }
- return Uti.safeParseFloat(s.substring(j, cur));
- }
- }
- public SvgContentHandler(ParserInterface thread, Settings settings)
- {
- _thread = new WeakReference<ParserInterface>(thread);
- Matrix root = new Matrix();
- if(!(settings.viewbox.x < 0 || settings.viewbox.y < 0))
- {
- root.setTranslate(-settings.viewbox.x, -settings.viewbox.y);
- }
- _transform.push(root);
- _settings = settings;
- _flattener = new CubicBezierConverterFloat(_settings.invScale);
- }
- private Matrix getCurrentTransform(Attributes attributes, boolean push)
- {
- String mat = SVGUti.getTransform(attributes);
- if(mat == null)
- {
- if(push)
- {
- _transform.push(_transform.peek());
- }
- return _transform.peek();
- }
- else
- {
- Matrix cur = parseTransform(mat);
- cur.preConcat(_transform.peek());
- if(push)
- {
- _transform.push(cur);
- }
- return cur;
- }
- }
- @SuppressLint("DefaultLocale")
- @Override
- public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
- {
- checkAbort();
- SvgTag tag = SvgTag.ignore;
- try
- {
- tag = SvgTag.valueOf(qName.toLowerCase());
- }
- catch(Exception e)
- {
- //e.printStackTrace();
- }
- switch(tag)
- {
- case svg:
- break;
- case g:
- getCurrentTransform(attributes, true);
- break;
- case path:
- {
- _data.setData(SVGUti.getPathData(attributes));
- PointData ptbuf = new PointData();
- Matrix m = getCurrentTransform(attributes, false);
- while(true)
- {
- _data.skipSpaces();
- if(_data.hasNext())
- {
- char c = _data.peekNext();
- if(c >= 'A' && c <= 'z')
- {
- _data.next_curve = _data.getNext();
- }
- ptbuf = parseCurve(_data, ptbuf, m);
- }
- else
- {
- break;
- }
- }
- if(!ptbuf.isEmpty())
- appendElement(ptbuf);
- }
- break;
- case rect:
- {
- float x = SVGUti.getRectX(attributes);
- float y = SVGUti.getRectY(attributes);
- float w = SVGUti.getRectWidth(attributes);
- float h = SVGUti.getRectHeight(attributes);
- float xx = x + w;
- float yy = y + h;
- Matrix m = getCurrentTransform(attributes, false);
- float[] pt = {
- x, y,
- xx, y,
- xx, yy,
- x, yy,
- x, y};
- m.mapPoints(pt);
- PointData buf = new PointData();
- buf.append(pt[0], pt[1]);
- buf.append(pt[2], pt[3]);
- buf.append(pt[4], pt[5]);
- buf.append(pt[6], pt[7]);
- appendElement(buf);
- }
- break;
- case line:
- {
- float x1 = SVGUti.getLineX1(attributes);
- float y1 = SVGUti.getLineY1(attributes);
- float x2 = SVGUti.getLineX2(attributes);
- float y2 = SVGUti.getLineY2(attributes);
- Matrix m = getCurrentTransform(attributes, false);
- float[] pt = {x1, y1, x2, y2};
- m.mapPoints(pt);
- PointData buf = new PointData();
- buf.append(pt[0], pt[1]);
- buf.append(pt[2], pt[3]);
- appendElement(buf);
- }
- break;
- case polyline:
- {
- appendElement(computePolyline(SVGUti.getPolylinePoints(attributes), false, getCurrentTransform(attributes, false)));
- }
- break;
- case polygon:
- {
- appendElement(computePolyline(SVGUti.getPolygonPoints(attributes), true, getCurrentTransform(attributes, false)));
- }
- break;
- case circle:
- {
- vec cnt = SVGUti.getCircleCnt(attributes);
- float r = SVGUti.getCircleRadius(attributes);
- appendElement(computeEllipse(r, r, cnt.x, cnt.y, getCurrentTransform(attributes, false)));
- }
- break;
- case ellipse:
- {
- vec cnt = SVGUti.getEllipseCnt(attributes);
- vec r = SVGUti.getEllipseRadius(attributes);
- appendElement(computeEllipse(r.x, r.y, cnt.x, cnt.y, getCurrentTransform(attributes, false)));
- }
- break;
- case ignore:
- break;
- }
- }
- @SuppressWarnings("unused")
- private PointData parseCurve(ParserData data, PointData ptbuf, Matrix m) throws SAXException
- {
- data.prev_curve = data.next_curve;
- switch(data.next_curve)
- {
- case 'm':
- {
- if(!ptbuf.isEmpty())
- appendElement(ptbuf);
- ptbuf = new PointData();
- data.start_x = data.prev_x + data.parseFloat();
- data.start_y = data.prev_y + data.parseFloat();
- data.prev_x = data.start_x;
- data.prev_y = data.start_y;
- ptbuf.append(data.start_x, data.start_y, m);
- data.next_curve = 'l';
- }
- break;
- case 'M':
- {
- if(!ptbuf.isEmpty())
- appendElement(ptbuf);
- ptbuf = new PointData();
- data.start_x = data.parseFloat();
- data.start_y = data.parseFloat();
- data.prev_x = data.start_x;
- data.prev_y = data.start_y;
- ptbuf.append(data.start_x, data.start_y, m);
- data.next_curve = 'L';
- }
- break;
- case 'z':
- case 'Z':
- {
- data.prev_x = data.start_x;
- data.prev_y = data.start_y;
- ptbuf.append(data.start_x, data.start_y, m);
- }
- break;
- case 'h':
- {
- float x = data.prev_x + data.parseFloat();
- data.prev_x = x;
- ptbuf.append(x, data.prev_y, m);
- }
- break;
- case 'H':
- {
- float x = data.parseFloat();
- data.prev_x = x;
- ptbuf.append(x, data.prev_y, m);
- }
- break;
- case 'v':
- {
- float y = data.prev_y + data.parseFloat();
- data.prev_y = y;
- ptbuf.append(data.prev_x, y, m);
- }
- break;
- case 'V':
- {
- float y = data.parseFloat();
- data.prev_y = y;
- ptbuf.append(data.prev_x, y, m);
- }
- break;
- case 'l':
- {
- float x = data.prev_x + data.parseFloat();
- float y = data.prev_y + data.parseFloat();
- data.prev_x = x;
- data.prev_y = y;
- ptbuf.append(x, y, m);
- }
- break;
- case 'L':
- {
- float x = data.parseFloat();
- float y = data.parseFloat();
- data.prev_x = x;
- data.prev_y = y;
- ptbuf.append(x, y, m);
- }
- break;
- case 'q':
- {
- float[] ctp = {.0f, .0f, .0f, .0f, .0f, .0f, .0f, .0f};
- ctp[0] = data.prev_x;
- ctp[1] = data.prev_y;
- ctp[2] = ctp[0] + data.parseFloat();
- ctp[3] = ctp[1] + data.parseFloat();
- ctp[4] = ctp[0] + data.parseFloat();
- ctp[5] = ctp[1] + data.parseFloat();
- data.prev_x = ctp[4];
- data.prev_y = ctp[5];
- computeQuadratic(ctp, ptbuf);
- }
- break;
- case 'Q':
- {
- float[] ctp = {.0f, .0f, .0f, .0f, .0f, .0f, .0f, .0f};
- ctp[0] = data.prev_x;
- ctp[1] = data.prev_y;
- ctp[2] = data.parseFloat();
- ctp[3] = data.parseFloat();
- ctp[4] = data.parseFloat();
- ctp[5] = data.parseFloat();
- data.prev_x = ctp[4];
- data.prev_y = ctp[5];
- computeQuadratic(ctp, ptbuf);
- }
- break;
- case 't':
- break;
- case 'T':
- break;
- case 'c':
- {
- float[] ctp = {.0f, .0f, .0f, .0f, .0f, .0f, .0f, .0f};
- ctp[0] = data.prev_x;
- ctp[1] = data.prev_y;
- ctp[2] = ctp[0] + data.parseFloat();
- ctp[3] = ctp[1] + data.parseFloat();
- ctp[4] = ctp[0] + data.parseFloat();
- ctp[5] = ctp[1] + data.parseFloat();
- ctp[6] = ctp[0] + data.parseFloat();
- ctp[7] = ctp[1] + data.parseFloat();
- data.prev_x = ctp[6];
- data.prev_y = ctp[7];
- data.prev_cx = ctp[4];
- data.prev_cy = ctp[5];
- computeCubic(ctp, ptbuf);
- }
- break;
- case 'C':
- {
- float[] ctp = {.0f, .0f, .0f, .0f, .0f, .0f, .0f, .0f};
- ctp[0] = data.prev_x;
- ctp[1] = data.prev_y;
- ctp[2] = data.parseFloat();
- ctp[3] = data.parseFloat();
- ctp[4] = data.parseFloat();
- ctp[5] = data.parseFloat();
- ctp[6] = data.parseFloat();
- ctp[7] = data.parseFloat();
- data.prev_x = ctp[6];
- data.prev_y = ctp[7];
- data.prev_cx = ctp[4];
- data.prev_cy = ctp[5];
- computeCubic(ctp, ptbuf);
- }
- break;
- case 's':
- {
- float[] ctp = {.0f, .0f, .0f, .0f, .0f, .0f, .0f, .0f};
- ctp[0] = data.prev_x;
- ctp[1] = data.prev_y;
- if( data.prev_curve == 's' || data.prev_curve == 'S' || data.prev_curve == 'c' || data.prev_curve == 'C')
- {
- ctp[2] = data.prev_cx;
- ctp[3] = data.prev_cy;
- }
- else
- {
- ctp[2] = ctp[0];
- ctp[3] = ctp[1];
- }
- ctp[4] = ctp[0] + data.parseFloat();
- ctp[5] = ctp[1] + data.parseFloat();
- ctp[6] = ctp[0] + data.parseFloat();
- ctp[7] = ctp[1] + data.parseFloat();
- data.prev_x = ctp[6];
- data.prev_y = ctp[7];
- data.prev_cx = ctp[4];
- data.prev_cy = ctp[5];
- computeCubic(ctp, ptbuf);
- }
- break;
- case 'S':
- {
- float[] ctp = {.0f, .0f, .0f, .0f, .0f, .0f, .0f, .0f};
- ctp[0] = data.prev_x;
- ctp[1] = data.prev_y;
- if( data.prev_curve == 's' || data.prev_curve == 'S' || data.prev_curve == 'c' || data.prev_curve == 'C')
- {
- ctp[2] = data.prev_cx;
- ctp[3] = data.prev_cy;
- }
- else
- {
- ctp[2] = ctp[0];
- ctp[3] = ctp[1];
- }
- ctp[4] = data.parseFloat();
- ctp[5] = data.parseFloat();
- ctp[6] = data.parseFloat();
- ctp[7] = data.parseFloat();
- data.prev_x = ctp[6];
- data.prev_y = ctp[7];
- data.prev_cx = ctp[4];
- data.prev_cy = ctp[5];
- computeCubic(ctp, ptbuf);
- }
- break;
- case 'a':
- {
- float x0 = data.prev_x;
- float y0 = data.prev_y;
- float rx = data.parseFloat();
- float ry = data.parseFloat();
- float angle = data.parseFloat();
- boolean largeArcFlag = (int)data.parseFloat() == 1;
- boolean sweepFlag = (int)data.parseFloat() == 1;
- float x = x0 + data.parseFloat();
- float y = y0 + data.parseFloat();
- data.prev_x = x;
- data.prev_y = y;
- ptbuf.append(x, y); //Arcs not implemented
- }
- break;
- case 'A':
- {
- float x0 = data.prev_x;
- float y0 = data.prev_y;
- float rx = data.parseFloat();
- float ry = data.parseFloat();
- float angle = data.parseFloat();
- boolean largeArcFlag = (int)data.parseFloat() == 1;
- boolean sweepFlag = (int)data.parseFloat() == 1;
- float x = data.parseFloat();
- float y = data.parseFloat();
- data.prev_x = x;
- data.prev_y = y;
- ptbuf.append(x, y); //Arcs not implemented
- }
- break;
- default:
- data.getNext();
- break;
- }
- return ptbuf;
- }
- private void computeQuadratic(float[] ctp, PointData ptbuf)
- {
- final float c = 2.0f / 3.0f;
- ctp[6] = ctp[4];
- ctp[7] = ctp[5];
- ctp[4] = ctp[4] + c * (ctp[2] - ctp[4]);
- ctp[5] = ctp[5] + c * (ctp[3] - ctp[5]);
- ctp[2] = ctp[0] + c * (ctp[2] - ctp[0]);
- ctp[3] = ctp[1] + c * (ctp[3] - ctp[1]);
- computeCubic(ctp, ptbuf);
- }
- private void computeCubic(float[] ctp, PointData ptbuf)
- {
- _transform.peek().mapPoints(ctp);
- _flattener.convert(false, ctp, ptbuf);
- }
- PointData computePolyline(String points, boolean close, Matrix m)
- {
- PointData buf = new PointData();
- _data.setData(points);
- while(_data.hasNext())
- {
- char c = _data.peekNext();
- switch(c)
- {
- case ' ':
- case ',':
- _data.cur++;
- break;
- default:
- buf.append(_data.parseFloat(), _data.parseFloat(), m);
- break;
- }
- }
- if(close)
- {
- buf.close();
- }
- return buf;
- }
- private PointData computeEllipse(float rx, float ry, float cntx, float cnty, Matrix m)
- {
- PointData buf = new PointData();
- int div = (int) Math.max(CIRCLE_ELLIPSE_SEGMENTS_MIN, (rx + rx + ry + ry) * _settings.scale * .25f);
- float da = PI2 / (float)div;
- float a = da * _rnd.nextInt(div);
- for(int i = 0; i < div; i++)
- {
- float x = (float) (cntx + rx * Math.cos(a));
- float y = (float) (cnty + ry * Math.sin(a));
- buf.append(x, y, m);
- a += da;
- }
- buf.close();
- return buf;
- }
- private void appendElement(PointData data) throws SAXException
- {
- checkAbort();
- if(data == null || data.pt.size() == 0 || data.len <= Float.MIN_VALUE)
- return;
- ParserInterface p = _thread.get();
- if(p != null)
- {
- p.append(new Sen(data, _settings));
- }
- else
- {
- _abort = true;
- _thread.clear();
- throw new SAXException("Thread expired.");
- }
- }
- private Matrix parseTransform(String mat)
- {
- int index_first = mat.indexOf(SVGUti.SVG_TRANSFORM_MATRIX_START_BRACKET) + 1;
- int index_last = mat.lastIndexOf(SVGUti.SVG_TRANSFORM_MATRIX_END_BRACKET);
- String[] coeff = mat.substring(index_first, index_last).split(SVGUti.SVG_TRANSFORM_MATRIX_COEFF_REGEX);
- Matrix ret = new Matrix();
- if(mat.startsWith(SVGUti.SVG_TRANSFORM_MATRIX_TYPE_MATRIX))
- {
- float[] fcoeff = new float[]{
- 1.0f, .0f, .0f,
- .0f, 1.0f, .0f,
- .0f, .0f, 1.0f};
- //ref: http://www.w3.org/TR/SVG/coords.html#TransformMatrixDefined
- SVGUti.SafeParse(coeff, 0, fcoeff, 0); //a
- SVGUti.SafeParse(coeff, 1, fcoeff, 3); //c
- SVGUti.SafeParse(coeff, 2, fcoeff, 1); //e
- SVGUti.SafeParse(coeff, 3, fcoeff, 4); //b
- SVGUti.SafeParse(coeff, 4, fcoeff, 2); //d
- SVGUti.SafeParse(coeff, 5, fcoeff, 5); //f
- ret.setValues(fcoeff);
- }
- else if(mat.startsWith(SVGUti.SVG_TRANSFORM_MATRIX_TYPE_TRANSLATE))
- {
- float tx = SVGUti.SafeParse(coeff, 0);
- float ty = SVGUti.SafeParse(coeff, 1);
- ret.setTranslate(tx, ty);
- }
- else if(mat.startsWith(SVGUti.SVG_TRANSFORM_MATRIX_TYPE_SCALE))
- {
- float sx = SVGUti.SafeParse(coeff, 0);
- float sy = SVGUti.SafeParse(coeff, 1);
- ret.setScale(sx, sy);
- }
- else if(mat.startsWith(SVGUti.SVG_TRANSFORM_MATRIX_TYPE_ROTATE))
- {
- float a = SVGUti.SafeParse(coeff, 0);
- float cx = SVGUti.SafeParse(coeff, 1);
- float cy = SVGUti.SafeParse(coeff, 2);
- ret.setRotate(a, cx, cy);
- }
- else if(mat.startsWith(SVGUti.SVG_TRANSFORM_MATRIX_TYPE_SKEWX))
- {
- float sk = SVGUti.SafeParse(coeff, 0);
- ret.setSkew(sk, .0f);
- }
- else if(mat.startsWith(SVGUti.SVG_TRANSFORM_MATRIX_TYPE_SKEWY))
- {
- float sk = SVGUti.SafeParse(coeff, 0);
- ret.setSkew(.0f, sk);
- }
- return ret;
- }
- @Override
- public void endElement(String uri, String localName, String qName) throws SAXException
- {
- if(qName.equalsIgnoreCase("g"))
- {
- _transform.pop();
- }
- }
- public void abort()
- {
- _abort = true;
- }
- private void checkAbort() throws SAXException
- {
- if(_abort || Thread.interrupted())
- throw new SAXException("Aborted by the loading thread.");
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement