com.jiahuan.svgmapview.core.helper.map.SVGParser.java Source code

Java tutorial

Introduction

Here is the source code for com.jiahuan.svgmapview.core.helper.map.SVGParser.java

Source

package com.jiahuan.svgmapview.core.helper.map;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.StringTokenizer;
import java.util.regex.Pattern;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Picture;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
import android.util.FloatMath;
import android.util.Log;

import android.app.Application;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
 * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
 * to You 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.
 */

/**
 * @author Larva Labs, LLC
 */
public class SVGParser {

    static final String TAG = "SVGAndroid";

    private static boolean DISALLOW_DOCTYPE_DECL = true;

    /**
     * Parses a single SVG path and returns it as a
     * <code>android.graphics.Path</code> object. An example path is
     * <code>M250,150L150,350L350,350Z</code>, which draws a triangle.
     * 
     * @param pathString
     *            the SVG path, see the specification <a
     *            href="http://www.w3.org/TR/SVG/paths.html">here</a>.
     */
    public static Path parsePath(String pathString) {
        return doPath(pathString);
    }

    static SVG parse(InputSource data, SVGHandler handler) throws SVGParseException {
        try {
            final Picture picture = new Picture();
            handler.setPicture(picture);

            SAXParserFactory spf = SAXParserFactory.newInstance();
            SAXParser sp = spf.newSAXParser();
            XMLReader xr = sp.getXMLReader();
            xr.setContentHandler(handler);
            xr.setFeature("http://xml.org/sax/features/validation", false);
            if (DISALLOW_DOCTYPE_DECL) {
                try {
                    xr.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
                } catch (SAXNotRecognizedException e) {
                    DISALLOW_DOCTYPE_DECL = false;
                }
            }
            xr.parse(data);

            SVG result = new SVG(picture, handler.bounds);
            // Skip bounds if it was an empty pic
            if (!Float.isInfinite(handler.limits.top)) {
                result.setLimits(handler.limits);
            }
            return result;
        } catch (Exception e) {
            Log.e(TAG, "Failed to parse SVG.", e);
            throw new SVGParseException(e);
        }
    }

    private static NumberParse parseNumbers(String s) {
        // Util.debug("Parsing numbers from: '" + s + "'");
        int n = s.length();
        int p = 0;
        ArrayList<Float> numbers = new ArrayList<Float>();
        boolean skipChar = false;
        boolean prevWasE = false;
        for (int i = 1; i < n; i++) {
            if (skipChar) {
                skipChar = false;
                continue;
            }
            char c = s.charAt(i);
            switch (c) {
            // This ends the parsing, as we are on the next element
            case 'M':
            case 'm':
            case 'Z':
            case 'z':
            case 'L':
            case 'l':
            case 'H':
            case 'h':
            case 'V':
            case 'v':
            case 'C':
            case 'c':
            case 'S':
            case 's':
            case 'Q':
            case 'q':
            case 'T':
            case 't':
            case 'a':
            case 'A':
            case ')': {
                String str = s.substring(p, i);
                if (str.trim().length() > 0) {
                    // Util.debug("  Last: " + str);
                    Float f = Float.parseFloat(str);
                    numbers.add(f);
                }
                p = i;
                return new NumberParse(numbers, p);
            }
            case '-':
                // Allow numbers with negative exp such as 7.23e-4
                if (prevWasE) {
                    prevWasE = false;
                    break;
                }
                // fall-through
            case '\n':
            case '\t':
            case ' ':
            case ',': {
                String str = s.substring(p, i);
                // Just keep moving if multiple whitespace
                if (str.trim().length() > 0) {
                    // Util.debug("  Next: " + str);
                    Float f = Float.parseFloat(str);
                    numbers.add(f);
                    if (c == '-') {
                        p = i;
                    } else {
                        p = i + 1;
                        skipChar = true;
                    }
                } else {
                    p++;
                }
                prevWasE = false;
                break;
            }
            case 'e':
                prevWasE = true;
                break;
            default:
                prevWasE = false;
            }
        }

        String last = s.substring(p);
        if (last.length() > 0) {
            // Util.debug("  Last: " + last);
            try {
                numbers.add(Float.parseFloat(last));
            } catch (NumberFormatException nfe) {
                // Just white-space, forget it
            }
            p = s.length();
        }
        return new NumberParse(numbers, p);
    }

    private static final Pattern TRANSFORM_SEP = Pattern.compile("[\\s,]*");

    /**
     * Parse a list of transforms such as: foo(n,n,n...) bar(n,n,n..._ ...)
     * Delimiters are whitespaces or commas
     */
    private static Matrix parseTransform(String s) {
        Matrix matrix = new Matrix();
        while (true) {
            parseTransformItem(s, matrix);
            // Log.i(TAG, "Transformed: (" + s + ") " + matrix);
            final int rparen = s.indexOf(")");
            if (rparen > 0 && s.length() > rparen + 1) {
                s = TRANSFORM_SEP.matcher(s.substring(rparen + 1)).replaceFirst("");
            } else {
                break;
            }
        }
        return matrix;
    }

    private static Matrix parseTransformItem(String s, Matrix matrix) {
        if (s.startsWith("matrix(")) {
            NumberParse np = parseNumbers(s.substring("matrix(".length()));
            if (np.numbers.size() == 6) {
                Matrix mat = new Matrix();
                mat.setValues(new float[] {
                        // Row 1
                        np.numbers.get(0), np.numbers.get(2), np.numbers.get(4),
                        // Row 2
                        np.numbers.get(1), np.numbers.get(3), np.numbers.get(5),
                        // Row 3
                        0, 0, 1, });
                matrix.preConcat(mat);
            }
        } else if (s.startsWith("translate(")) {
            NumberParse np = parseNumbers(s.substring("translate(".length()));
            if (np.numbers.size() > 0) {
                float tx = np.numbers.get(0);
                float ty = 0;
                if (np.numbers.size() > 1) {
                    ty = np.numbers.get(1);
                }
                matrix.preTranslate(tx, ty);
            }
        } else if (s.startsWith("scale(")) {
            NumberParse np = parseNumbers(s.substring("scale(".length()));
            if (np.numbers.size() > 0) {
                float sx = np.numbers.get(0);
                float sy = sx;
                if (np.numbers.size() > 1) {
                    sy = np.numbers.get(1);
                }
                matrix.preScale(sx, sy);
            }
        } else if (s.startsWith("skewX(")) {
            NumberParse np = parseNumbers(s.substring("skewX(".length()));
            if (np.numbers.size() > 0) {
                float angle = np.numbers.get(0);
                matrix.preSkew((float) Math.tan(angle), 0);
            }
        } else if (s.startsWith("skewY(")) {
            NumberParse np = parseNumbers(s.substring("skewY(".length()));
            if (np.numbers.size() > 0) {
                float angle = np.numbers.get(0);
                matrix.preSkew(0, (float) Math.tan(angle));
            }
        } else if (s.startsWith("rotate(")) {
            NumberParse np = parseNumbers(s.substring("rotate(".length()));
            if (np.numbers.size() > 0) {
                float angle = np.numbers.get(0);
                float cx = 0;
                float cy = 0;
                if (np.numbers.size() > 2) {
                    cx = np.numbers.get(1);
                    cy = np.numbers.get(2);
                }
                matrix.preTranslate(-cx, -cy);
                matrix.preRotate(angle);
                matrix.preTranslate(cx, cy);
            }
        } else {
            Log.w(TAG, "Invalid transform (" + s + ")");
        }
        return matrix;
    }

    /**
     * This is where the hard-to-parse paths are handled. Uppercase rules are
     * absolute positions, lowercase are relative. Types of path rules:
     * <p/>
     * <ol>
     * <li>M/m - (x y)+ - Move to (without drawing)
     * <li>Z/z - (no params) - Close path (back to starting point)
     * <li>L/l - (x y)+ - Line to
     * <li>H/h - x+ - Horizontal ine to
     * <li>V/v - y+ - Vertical line to
     * <li>C/c - (x1 y1 x2 y2 x y)+ - Cubic bezier to
     * <li>S/s - (x2 y2 x y)+ - Smooth cubic bezier to (shorthand that assumes
     * the x2, y2 from previous C/S is the x1, y1 of this bezier)
     * <li>Q/q - (x1 y1 x y)+ - Quadratic bezier to
     * <li>T/t - (x y)+ - Smooth quadratic bezier to (assumes previous control
     * point is "reflection" of last one w.r.t. to current point)
     * </ol>
     * <p/>
     * Numbers are separate by whitespace, comma or nothing at all (!) if they
     * are self-delimiting, (ie. begin with a - sign)
     * 
     * @param s
     *            the path string from the XML
     */
    private static Path doPath(String s) {
        int n = s.length();
        ParserHelper ph = new ParserHelper(s, 0);
        ph.skipWhitespace();
        Path p = new Path();
        float lastX = 0;
        float lastY = 0;
        float lastX1 = 0;
        float lastY1 = 0;
        float subPathStartX = 0;
        float subPathStartY = 0;
        char prevCmd = 0;
        while (ph.pos < n) {
            char cmd = s.charAt(ph.pos);
            switch (cmd) {
            case '-':
            case '+':
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                if (prevCmd == 'm' || prevCmd == 'M') {
                    cmd = (char) ((prevCmd) - 1);
                    break;
                } else if (("lhvcsqta").indexOf(Character.toLowerCase(prevCmd)) >= 0) {
                    cmd = prevCmd;
                    break;
                }
            default: {
                ph.advance();
                prevCmd = cmd;
            }
            }

            boolean wasCurve = false;
            switch (cmd) {
            case 'M':
            case 'm': {
                float x = ph.nextFloat();
                float y = ph.nextFloat();
                if (cmd == 'm') {
                    subPathStartX += x;
                    subPathStartY += y;
                    p.rMoveTo(x, y);
                    lastX += x;
                    lastY += y;
                } else {
                    subPathStartX = x;
                    subPathStartY = y;
                    p.moveTo(x, y);
                    lastX = x;
                    lastY = y;
                }
                break;
            }
            case 'Z':
            case 'z': {
                p.close();
                p.moveTo(subPathStartX, subPathStartY);
                lastX = subPathStartX;
                lastY = subPathStartY;
                lastX1 = subPathStartX;
                lastY1 = subPathStartY;
                wasCurve = true;
                break;
            }
            case 'T':
            case 't':
                // todo - smooth quadratic Bezier (two parameters)
            case 'L':
            case 'l': {
                float x = ph.nextFloat();
                float y = ph.nextFloat();
                if (cmd == 'l') {
                    p.rLineTo(x, y);
                    lastX += x;
                    lastY += y;
                } else {
                    p.lineTo(x, y);
                    lastX = x;
                    lastY = y;
                }
                break;
            }
            case 'H':
            case 'h': {
                float x = ph.nextFloat();
                if (cmd == 'h') {
                    p.rLineTo(x, 0);
                    lastX += x;
                } else {
                    p.lineTo(x, lastY);
                    lastX = x;
                }
                break;
            }
            case 'V':
            case 'v': {
                float y = ph.nextFloat();
                if (cmd == 'v') {
                    p.rLineTo(0, y);
                    lastY += y;
                } else {
                    p.lineTo(lastX, y);
                    lastY = y;
                }
                break;
            }
            case 'C':
            case 'c': {
                wasCurve = true;
                float x1 = ph.nextFloat();
                float y1 = ph.nextFloat();
                float x2 = ph.nextFloat();
                float y2 = ph.nextFloat();
                float x = ph.nextFloat();
                float y = ph.nextFloat();
                if (cmd == 'c') {
                    x1 += lastX;
                    x2 += lastX;
                    x += lastX;
                    y1 += lastY;
                    y2 += lastY;
                    y += lastY;
                }
                p.cubicTo(x1, y1, x2, y2, x, y);
                lastX1 = x2;
                lastY1 = y2;
                lastX = x;
                lastY = y;
                break;
            }
            case 'Q':
            case 'q':
                // todo - quadratic Bezier (four parameters)
            case 'S':
            case 's': {
                wasCurve = true;
                float x2 = ph.nextFloat();
                float y2 = ph.nextFloat();
                float x = ph.nextFloat();
                float y = ph.nextFloat();
                if (Character.isLowerCase(cmd)) {
                    x2 += lastX;
                    x += lastX;
                    y2 += lastY;
                    y += lastY;
                }
                float x1 = 2 * lastX - lastX1;
                float y1 = 2 * lastY - lastY1;
                p.cubicTo(x1, y1, x2, y2, x, y);
                lastX1 = x2;
                lastY1 = y2;
                lastX = x;
                lastY = y;
                break;
            }
            case 'A':
            case 'a': {
                float rx = ph.nextFloat();
                float ry = ph.nextFloat();
                float theta = ph.nextFloat();
                int largeArc = ph.nextFlag();
                int sweepArc = ph.nextFlag();
                float x = ph.nextFloat();
                float y = ph.nextFloat();
                if (cmd == 'a') {
                    x += lastX;
                    y += lastY;
                }
                drawArc(p, lastX, lastY, x, y, rx, ry, theta, largeArc, sweepArc);
                lastX = x;
                lastY = y;
                break;
            }
            default:
                Log.w(TAG, "Invalid path command: " + cmd);
                ph.advance();
            }
            if (!wasCurve) {
                lastX1 = lastX;
                lastY1 = lastY;
            }
            ph.skipWhitespace();
        }
        return p;
    }

    private static float angle(float x1, float y1, float x2, float y2) {

        return (float) Math.toDegrees(Math.atan2(x1, y1) - Math.atan2(x2, y2)) % 360;
    }

    private static final RectF arcRectf = new RectF();
    private static final Matrix arcMatrix = new Matrix();
    private static final Matrix arcMatrix2 = new Matrix();

    private static void drawArc(Path p, float lastX, float lastY, float x, float y, float rx, float ry, float theta,
            int largeArc, int sweepArc) {
        // Log.d("drawArc", "from (" + lastX + "," + lastY + ") to (" + x + ","+
        // y + ") r=(" + rx + "," + ry +
        // ") theta=" + theta + " flags="+ largeArc + "," + sweepArc);

        // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes

        if (rx == 0 || ry == 0) {
            p.lineTo(x, y);
            return;
        }

        if (x == lastX && y == lastY) {
            return; // nothing to draw
        }

        rx = Math.abs(rx);
        ry = Math.abs(ry);

        final float thrad = theta * (float) Math.PI / 180;
        final float st = FloatMath.sin(thrad);
        final float ct = FloatMath.cos(thrad);

        final float xc = (lastX - x) / 2;
        final float yc = (lastY - y) / 2;
        final float x1t = ct * xc + st * yc;
        final float y1t = -st * xc + ct * yc;

        final float x1ts = x1t * x1t;
        final float y1ts = y1t * y1t;
        float rxs = rx * rx;
        float rys = ry * ry;

        float lambda = (x1ts / rxs + y1ts / rys) * 1.001f; // add 0.1% to be
        // sure that no out
        // of range occurs
        // due to
        // limited precision
        if (lambda > 1) {
            float lambdasr = FloatMath.sqrt(lambda);
            rx *= lambdasr;
            ry *= lambdasr;
            rxs = rx * rx;
            rys = ry * ry;
        }

        final float R = FloatMath.sqrt((rxs * rys - rxs * y1ts - rys * x1ts) / (rxs * y1ts + rys * x1ts))
                * ((largeArc == sweepArc) ? -1 : 1);
        final float cxt = R * rx * y1t / ry;
        final float cyt = -R * ry * x1t / rx;
        final float cx = ct * cxt - st * cyt + (lastX + x) / 2;
        final float cy = st * cxt + ct * cyt + (lastY + y) / 2;

        final float th1 = angle(1, 0, (x1t - cxt) / rx, (y1t - cyt) / ry);
        float dth = angle((x1t - cxt) / rx, (y1t - cyt) / ry, (-x1t - cxt) / rx, (-y1t - cyt) / ry);

        if (sweepArc == 0 && dth > 0) {
            dth -= 360;
        } else if (sweepArc != 0 && dth < 0) {
            dth += 360;
        }

        // draw
        if ((theta % 360) == 0) {
            // no rotate and translate need
            arcRectf.set(cx - rx, cy - ry, cx + rx, cy + ry);
            p.arcTo(arcRectf, th1, dth);
        } else {
            // this is the hard and slow part :-)
            arcRectf.set(-rx, -ry, rx, ry);

            arcMatrix.reset();
            arcMatrix.postRotate(theta);
            arcMatrix.postTranslate(cx, cy);
            arcMatrix.invert(arcMatrix2);

            p.transform(arcMatrix2);
            p.arcTo(arcRectf, th1, dth);
            p.transform(arcMatrix);
        }
    }

    private static NumberParse getNumberParseAttr(String name, Attributes attributes) {
        int n = attributes.getLength();
        for (int i = 0; i < n; i++) {
            if (attributes.getLocalName(i).equals(name)) {
                return parseNumbers(attributes.getValue(i));
            }
        }
        return null;
    }

    private static String getStringAttr(String name, Attributes attributes) {
        int n = attributes.getLength();
        for (int i = 0; i < n; i++) {
            if (attributes.getLocalName(i).equals(name)) {
                return attributes.getValue(i);
            }
        }
        return null;
    }

    private static Float getFloatAttr(String name, Attributes attributes) {
        return getFloatAttr(name, attributes, null);
    }

    private static Float getFloatAttr(String name, Attributes attributes, Float defaultValue) {
        String v = getStringAttr(name, attributes);
        return parseFloatValue(v, defaultValue);
    }

    private static float getFloatAttr(String name, Attributes attributes, float defaultValue) {
        String v = getStringAttr(name, attributes);
        return parseFloatValue(v, defaultValue);
    }

    private static Float parseFloatValue(String str, Float defaultValue) {
        if (str == null) {
            return defaultValue;
        } else if (str.endsWith("px")) {
            str = str.substring(0, str.length() - 2);
        } else if (str.endsWith("%")) {
            str = str.substring(0, str.length() - 1);
            return Float.parseFloat(str) / 100;
        }
        // Log.d(TAG, "Float parsing '" + name + "=" + v + "'");
        return Float.parseFloat(str);
    }

    private static class NumberParse {
        private ArrayList<Float> numbers;
        private int nextCmd;

        public NumberParse(ArrayList<Float> numbers, int nextCmd) {
            this.numbers = numbers;
            this.nextCmd = nextCmd;
        }

        public int getNextCmd() {
            return nextCmd;
        }

        public float getNumber(int index) {
            return numbers.get(index);
        }

    }

    private static class Gradient {
        String id;
        String xlink;
        boolean isLinear;
        float x1, y1, x2, y2;
        float x, y, radius;
        ArrayList<Float> positions = new ArrayList<Float>();
        ArrayList<Integer> colors = new ArrayList<Integer>();
        Matrix matrix = null;
        public Shader shader = null;
        public boolean boundingBox = false;
        public TileMode tilemode;

        public Gradient createChild(Gradient g) {
            Gradient child = new Gradient();
            child.id = g.id;
            child.xlink = id;
            child.isLinear = g.isLinear;
            child.x1 = g.x1;
            child.x2 = g.x2;
            child.y1 = g.y1;
            child.y2 = g.y2;
            child.x = g.x;
            child.y = g.y;
            child.radius = g.radius;
            child.positions = positions;
            child.colors = colors;
            child.matrix = matrix;
            if (g.matrix != null) {
                if (matrix == null) {
                    child.matrix = g.matrix;
                } else {
                    Matrix m = new Matrix(matrix);
                    m.preConcat(g.matrix);
                    child.matrix = m;
                }
            }
            child.boundingBox = g.boundingBox;
            child.shader = g.shader;
            child.tilemode = g.tilemode;
            return child;
        }
    }

    private static class StyleSet {
        HashMap<String, String> styleMap = new HashMap<String, String>();

        private StyleSet(String string) {
            String[] styles = string.split(";");
            for (String s : styles) {
                String[] style = s.split(":");
                if (style.length == 2) {
                    styleMap.put(style[0], style[1]);
                }
            }
        }

        public String getStyle(String name) {
            return styleMap.get(name);
        }
    }

    private static class Properties {
        StyleSet styles = null;
        Attributes atts;

        private Properties(Attributes atts) {
            this.atts = atts;
            String styleAttr = getStringAttr("style", atts);
            if (styleAttr != null) {
                styles = new StyleSet(styleAttr);
            }
        }

        public String getAttr(String name) {
            String v = null;
            if (styles != null) {
                v = styles.getStyle(name);
            }
            if (v == null) {
                v = getStringAttr(name, atts);
            }
            return v;
        }

        public String getString(String name) {
            return getAttr(name);
        }

        private Integer rgb(int r, int g, int b) {
            return ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff);
        }

        private int parseNum(String v) throws NumberFormatException {
            if (v.endsWith("%")) {
                v = v.substring(0, v.length() - 1);
                return Math.round(Float.parseFloat(v) / 100 * 255);
            }
            return Integer.parseInt(v);
        }

        public Integer getColor(String name) {
            String v = getAttr(name);
            if (v == null) {
                return null;
            } else if (v.startsWith("#")) {
                try {
                    int c = Integer.parseInt(v.substring(1), 16);
                    return v.length() == 4 ? hex3Tohex6(c) : c;
                } catch (NumberFormatException nfe) {
                    return null;
                }
            } else if (v.startsWith("rgb(") && v.endsWith(")")) {
                String values[] = v.substring(4, v.length() - 1).split(",");
                try {
                    return rgb(parseNum(values[0]), parseNum(values[1]), parseNum(values[2]));
                } catch (NumberFormatException nfe) {
                    return null;
                } catch (ArrayIndexOutOfBoundsException e) {
                    return null;
                }
            } else {
                return SVGColors.mapColour(v);
            }
        }

        // convert 0xRGB into 0xRRGGBB
        private int hex3Tohex6(int x) {
            return (x & 0xF00) << 8 | (x & 0xF00) << 12 | (x & 0xF0) << 4 | (x & 0xF0) << 8 | (x & 0xF) << 4
                    | (x & 0xF);
        }

        public float getFloat(String name, float defaultValue) {
            String v = getAttr(name);
            if (v == null) {
                return defaultValue;
            } else {
                try {
                    return Float.parseFloat(v);
                } catch (NumberFormatException nfe) {
                    return defaultValue;
                }
            }
        }

        public Float getFloat(String name, Float defaultValue) {
            String v = getAttr(name);
            if (v == null) {
                return defaultValue;
            } else {
                try {
                    return Float.parseFloat(v);
                } catch (NumberFormatException nfe) {
                    return defaultValue;
                }
            }
        }

        public Float getFloat(String name) {
            return getFloat(name, null);
        }
    }

    private static class LayerAttributes {
        public final float opacity;

        public LayerAttributes(float opacity) {
            this.opacity = opacity;
        }
    }

    private static class Poidata {
        public String poi_id;
        public String poi_name;
        public float poi_location_x;
        public float poi_location_y;
        public float poi_next_x;
        public float poi_next_y;

        public Poidata() {

        }

        public Poidata(String id, String name, float lx, float ly, float nx, float ny) {
            poi_id = id;
            poi_name = name;
            poi_location_x = lx;
            poi_location_y = ly;
            poi_next_x = nx;
            poi_next_y = ny;
        }

    }

    static class SVGHandler extends DefaultHandler {

        private Picture picture;
        private Canvas canvas;
        private Float limitsAdjustmentX, limitsAdjustmentY;

        final LinkedList<LayerAttributes> layerAttributeStack = new LinkedList<LayerAttributes>();

        Paint strokePaint;
        boolean strokeSet = false;
        final LinkedList<Paint> strokePaintStack = new LinkedList<Paint>();
        final LinkedList<Boolean> strokeSetStack = new LinkedList<Boolean>();

        Paint textPaint;

        Paint fillPaint;
        boolean fillSet = false;
        final LinkedList<Paint> fillPaintStack = new LinkedList<Paint>();
        final LinkedList<Boolean> fillSetStack = new LinkedList<Boolean>();

        // Scratch rect (so we aren't constantly making new ones)
        final RectF rect = new RectF();
        RectF bounds = null;
        final RectF limits = new RectF(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY,
                Float.NEGATIVE_INFINITY);

        Integer searchColor = null;
        Integer replaceColor = null;
        Float opacityMultiplier = null;

        boolean whiteMode = false;

        Integer canvasRestoreCount;

        final LinkedList<Boolean> transformStack = new LinkedList<Boolean>();
        final LinkedList<Matrix> matrixStack = new LinkedList<Matrix>();

        final HashMap<String, Gradient> gradientMap = new HashMap<String, Gradient>();
        Gradient gradient = null;

        boolean documentDesc = false;
        boolean rectElement = false;
        boolean rectDesc = false;
        boolean titleDesc = false;

        Context context;
        String RectID = "";
        String RectName = "";
        Float RectWidth;
        Float RectHeight;
        Float RectCenterX;
        Float RectCenterY;
        Float RectNextX = 0.0f;
        Float RectNextY = 0.0f;
        ArrayList<Poidata> poi = new ArrayList<Poidata>();

        final private int louti = 1;
        final private int dianti = 2;
        final private int futi = 3;
        final private int churukou = 4;
        final private int weishengjian = 5;
        final private int atm = 6;

        public static final String rectElement_ACTION = "android.intent.action.rectElement.data";
        public static final String DOCUMENTDESC_ACTION = "android.intent.action.documentdesc.data";
        public static final String SCALE_ACTION = "android.intent.action.scale.data";
        public static final String mPerfName = "svgdata";

        public SVGHandler(Context context) {
            strokePaint = new Paint();
            strokePaint.setAntiAlias(true);
            strokePaint.setStyle(Paint.Style.STROKE);
            fillPaint = new Paint();
            fillPaint.setAntiAlias(true);
            fillPaint.setStyle(Paint.Style.FILL);
            textPaint = new Paint();
            textPaint.setColor(Color.BLACK);
            textPaint.setTextSize(10);
            textPaint.setAntiAlias(true);
            matrixStack.addFirst(new Matrix());
            layerAttributeStack.addFirst(new LayerAttributes(1f));
            this.context = context;

            //application = new Application();  
            //this.context = application.getApplicationContext();  
        }

        void setPicture(Picture picture) {
            this.picture = picture;
        }

        public void setColorSwap(Integer searchColor, Integer replaceColor, boolean overideOpacity) {
            this.searchColor = searchColor;
            this.replaceColor = replaceColor;
            if (replaceColor != null && overideOpacity) {
                opacityMultiplier = ((replaceColor >> 24) & 0x000000FF) / 255f;
            } else {
                opacityMultiplier = null;
            }
        }

        public void setWhiteMode(boolean whiteMode) {
            this.whiteMode = whiteMode;
        }

        @Override
        public void startDocument() throws SAXException {
            // Set up prior to parsing a doc
        }

        @Override
        public void endDocument() throws SAXException {
            // Clean up after parsing a doc
            for (Poidata data : poi) {
                Intent intent = new Intent();
                intent.setAction(rectElement_ACTION);
                intent.putExtra("poiElementId", data.poi_id);
                intent.putExtra("poiName", data.poi_name);
                intent.putExtra("centerX", data.poi_location_x);
                intent.putExtra("centerY", data.poi_location_y);
                intent.putExtra("nextX", data.poi_next_x);
                intent.putExtra("nextY", data.poi_next_y);
                context.sendBroadcast(intent);
                Log.d(TAG, data.poi_name);

            }
            Log.d(TAG, "the end of document");
        }

        private final Matrix gradMatrix = new Matrix();

        private boolean doFill(Properties atts, RectF bounding_box) {
            if ("none".equals(atts.getString("display"))) {
                return false;
            }
            if (whiteMode) {
                fillPaint.setShader(null);
                fillPaint.setColor(Color.WHITE);
                return true;
            }
            String fillString = atts.getString("fill");
            if (fillString != null) {
                if (fillString.startsWith("url(#")) {

                    // It's a gradient fill, look it up in our map
                    String id = fillString.substring("url(#".length(), fillString.length() - 1);
                    Gradient g = gradientMap.get(id);
                    Shader shader = null;
                    if (g != null) {
                        shader = g.shader;
                    }
                    if (shader != null) {
                        // Util.debug("Found shader!");
                        fillPaint.setShader(shader);
                        gradMatrix.set(g.matrix);
                        if (g.boundingBox && bounding_box != null) {
                            // Log.d("svg", "gradient is bounding box");
                            gradMatrix.preTranslate(bounding_box.left, bounding_box.top);
                            gradMatrix.preScale(bounding_box.width(), bounding_box.height());
                        }
                        shader.setLocalMatrix(gradMatrix);
                        return true;
                    } else {
                        Log.w(TAG, "Didn't find shader, using black: " + id);
                        fillPaint.setShader(null);
                        doColor(atts, Color.BLACK, true, fillPaint);
                        return true;
                    }
                } else if (fillString.equalsIgnoreCase("none")) {
                    fillPaint.setShader(null);
                    fillPaint.setColor(Color.TRANSPARENT);
                    return true;
                } else {
                    fillPaint.setShader(null);
                    Integer color = atts.getColor("fill");
                    if (color != null) {
                        doColor(atts, color, true, fillPaint);
                        return true;
                    } else {
                        Log.w(TAG, "Unrecognized fill color, using black: " + fillString);
                        doColor(atts, Color.BLACK, true, fillPaint);
                        return true;
                    }
                }
            } else {
                if (fillSet) {
                    // If fill is set, inherit from parent
                    return fillPaint.getColor() != Color.TRANSPARENT; // optimization
                } else {
                    // Default is black fill
                    fillPaint.setShader(null);
                    fillPaint.setColor(Color.BLACK);
                    return true;
                }
            }
        }

        private boolean doStroke(Properties atts) {
            if (whiteMode) {
                // Never stroke in white mode
                return false;
            }
            if ("none".equals(atts.getString("display"))) {
                return false;
            }

            // Check for other stroke attributes
            Float width = atts.getFloat("stroke-width");
            if (width != null) {
                strokePaint.setStrokeWidth(width);
            }

            String linecap = atts.getString("stroke-linecap");
            if ("round".equals(linecap)) {
                strokePaint.setStrokeCap(Paint.Cap.ROUND);
            } else if ("square".equals(linecap)) {
                strokePaint.setStrokeCap(Paint.Cap.SQUARE);
            } else if ("butt".equals(linecap)) {
                strokePaint.setStrokeCap(Paint.Cap.BUTT);
            }

            String linejoin = atts.getString("stroke-linejoin");
            if ("miter".equals(linejoin)) {
                strokePaint.setStrokeJoin(Paint.Join.MITER);
            } else if ("round".equals(linejoin)) {
                strokePaint.setStrokeJoin(Paint.Join.ROUND);
            } else if ("bevel".equals(linejoin)) {
                strokePaint.setStrokeJoin(Paint.Join.BEVEL);
            }

            pathStyleHelper(atts.getString("stroke-dasharray"), atts.getString("stroke-dashoffset"));

            String strokeString = atts.getAttr("stroke");
            if (strokeString != null) {
                if (strokeString.equalsIgnoreCase("none")) {
                    strokePaint.setColor(Color.TRANSPARENT);
                    return false;
                } else {
                    Integer color = atts.getColor("stroke");
                    if (color != null) {
                        doColor(atts, color, false, strokePaint);
                        return true;
                    } else {
                        Log.w(TAG, "Unrecognized stroke color, using none: " + strokeString);
                        strokePaint.setColor(Color.TRANSPARENT);
                        return false;
                    }
                }
            } else {
                if (strokeSet) {
                    // Inherit from parent
                    return strokePaint.getColor() != Color.TRANSPARENT; // optimization
                } else {
                    // Default is none
                    strokePaint.setColor(Color.TRANSPARENT);
                    return false;
                }
            }
        }

        private Gradient doGradient(boolean isLinear, Attributes atts) {
            Gradient gradient = new Gradient();
            gradient.id = getStringAttr("id", atts);
            gradient.isLinear = isLinear;
            if (isLinear) {
                gradient.x1 = getFloatAttr("x1", atts, 0f);
                gradient.x2 = getFloatAttr("x2", atts, 1f);
                gradient.y1 = getFloatAttr("y1", atts, 0f);
                gradient.y2 = getFloatAttr("y2", atts, 0f);
            } else {
                gradient.x = getFloatAttr("cx", atts, 0f);
                gradient.y = getFloatAttr("cy", atts, 0f);
                gradient.radius = getFloatAttr("r", atts, 0f);
            }
            String transform = getStringAttr("gradientTransform", atts);
            if (transform != null) {
                gradient.matrix = parseTransform(transform);
            }
            String spreadMethod = getStringAttr("spreadMethod", atts);
            if (spreadMethod == null) {
                spreadMethod = "pad";
            }

            gradient.tilemode = (spreadMethod.equals("reflect")) ? TileMode.MIRROR
                    : (spreadMethod.equals("repeat")) ? TileMode.REPEAT : TileMode.CLAMP;

            String unit = getStringAttr("gradientUnits", atts);
            if (unit == null) {
                unit = "objectBoundingBox";
            }
            gradient.boundingBox = !unit.equals("userSpaceOnUse");

            String xlink = getStringAttr("href", atts);
            if (xlink != null) {
                if (xlink.startsWith("#")) {
                    xlink = xlink.substring(1);
                }
                gradient.xlink = xlink;
            }
            return gradient;
        }

        private void doColor(Properties atts, Integer color, boolean fillMode, Paint paint) {
            int c = (0xFFFFFF & color) | 0xFF000000;
            if (searchColor != null && searchColor.intValue() == c) {
                c = replaceColor;
            }
            paint.setShader(null);
            paint.setColor(c);
            Float opacityAttr = atts.getFloat("opacity");
            if (opacityAttr == null) {
                opacityAttr = atts.getFloat(fillMode ? "fill-opacity" : "stroke-opacity");
            }

            float opacity = opacityAttr != null ? opacityAttr : 1f;
            opacity *= currentLayerAttributes().opacity;
            if (opacityMultiplier != null) {
                opacity *= opacityMultiplier;
            }
            paint.setAlpha((int) (255f * opacity));
        }

        /**
         * set the path style (if any) stroke-dasharray="n1,n2,..."
         * stroke-dashoffset=n
         */
        private void pathStyleHelper(String style, String offset) {
            if (style == null) {
                return;
            }

            if (style.equals("none")) {
                strokePaint.setPathEffect(null);
                return;
            }

            StringTokenizer st = new StringTokenizer(style, " ,");
            int count = st.countTokens();
            float[] intervals = new float[(count & 1) == 1 ? count * 2 : count];
            float max = 0;
            float current = 1f;
            int i = 0;
            while (st.hasMoreTokens()) {
                intervals[i++] = current = toFloat(st.nextToken(), current);
                max += current;
            }

            // in svg speak, we double the intervals on an odd count
            for (int start = 0; i < intervals.length; i++, start++) {
                max += intervals[i] = intervals[start];
            }

            float off = 0f;
            if (offset != null) {
                try {
                    off = Float.parseFloat(offset) % max;
                } catch (NumberFormatException e) {
                    // ignore
                }
            }

            strokePaint.setPathEffect(new DashPathEffect(intervals, off));
        }

        private static float toFloat(String s, float dflt) {
            float result = dflt;
            try {
                result = Float.parseFloat(s);
            } catch (NumberFormatException e) {
                // ignore
            }
            return result;
        }

        private boolean hidden = false;
        private int hiddenLevel = 0;
        private boolean boundsMode = false;

        private void doLimits2(float x, float y) {
            if (x < limits.left) {
                limits.left = x;
            }
            if (x > limits.right) {
                limits.right = x;
            }
            if (y < limits.top) {
                limits.top = y;
            }
            if (y > limits.bottom) {
                limits.bottom = y;
            }
        }

        private final RectF tmpLimitRect = new RectF();

        private void doLimits(RectF box, Paint paint) {
            Matrix m = matrixStack.getLast();
            m.mapRect(tmpLimitRect, box);
            float width2 = (paint == null) ? 0 : paint.getStrokeWidth() / 2;
            doLimits2(tmpLimitRect.left - width2, tmpLimitRect.top - width2);
            doLimits2(tmpLimitRect.right + width2, tmpLimitRect.bottom + width2);
        }

        private void doLimits(RectF box) {
            doLimits(box, null);
        }

        private void pushTransform(Attributes atts) {
            final String transform = getStringAttr("transform", atts);
            boolean pushed = transform != null;
            transformStack.addLast(pushed);
            if (pushed) {
                final Matrix matrix = parseTransform(transform);
                canvas.save();
                canvas.concat(matrix);
                matrix.postConcat(matrixStack.getLast());
                matrixStack.addLast(matrix);
            }

        }

        private void popTransform() {
            if (transformStack.removeLast()) {
                canvas.restore();
                matrixStack.removeLast();
            }
        }

        @Override
        public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
                throws SAXException {
            // Reset paint opacity
            strokePaint.setAlpha(255);
            fillPaint.setAlpha(255);
            // Ignore everything but rectangles in bounds mode
            if (boundsMode) {
                if (localName.equals("rect")) {
                    Float x = getFloatAttr("x", atts);
                    if (x == null) {
                        x = 0f;
                    }
                    Float y = getFloatAttr("y", atts);
                    if (y == null) {
                        y = 0f;
                    }
                    Float width = getFloatAttr("width", atts);
                    Float height = getFloatAttr("height", atts);
                    bounds = new RectF(x, y, x + width, y + height);
                }
                return;
            }
            if (localName.equals("svg")) {
                canvas = null;
                String viewboxStr = getStringAttr("viewBox", atts);
                if (viewboxStr != null) {
                    String[] dims = viewboxStr.replace(',', ' ').split("\\s+");
                    if (dims.length == 4) {
                        Float x1 = parseFloatValue(dims[0], null);
                        Float y1 = parseFloatValue(dims[1], null);
                        Float x2 = parseFloatValue(dims[2], null);
                        Float y2 = parseFloatValue(dims[3], null);
                        if (x1 != null && x2 != null && y1 != null && y2 != null) {
                            float width = FloatMath.ceil(x2 - x1);
                            float height = FloatMath.ceil(y2 - y1);

                            canvas = picture.beginRecording((int) width, (int) height);
                            canvasRestoreCount = canvas.save();
                            canvas.clipRect(0f, 0f, width, height);
                            limitsAdjustmentX = -x1;
                            limitsAdjustmentY = -y1;
                            canvas.translate(limitsAdjustmentX, limitsAdjustmentY);

                            SharedPreferences.Editor prefs = context.getSharedPreferences(mPerfName, 0).edit();
                            prefs.putFloat("svgWidth", width);
                            prefs.commit();
                        }
                    }
                }
                String scale = getStringAttr("scale", atts);
                if (scale != null) {
                    float scaleValue = Float.valueOf(scale);
                    SharedPreferences.Editor prefs = context.getSharedPreferences(mPerfName, 0).edit();
                    prefs.putFloat("svgScale", scaleValue);
                    prefs.commit();
                }
                // No viewbox
                if (canvas == null) {
                    int width = (int) FloatMath.ceil(getFloatAttr("width", atts));
                    int height = (int) FloatMath.ceil(getFloatAttr("height", atts));
                    canvas = picture.beginRecording(width, height);
                    canvasRestoreCount = null;
                }

            } else if (localName.equals("defs")) {
                // Ignore
            } else if (localName.equals("linearGradient")) {
                gradient = doGradient(true, atts);
            } else if (localName.equals("radialGradient")) {
                gradient = doGradient(false, atts);
            } else if (localName.equals("stop")) {
                if (gradient != null) {
                    final Properties props = new Properties(atts);

                    final int colour;
                    final Integer stopColour = props.getColor("stop-color");
                    if (stopColour == null) {
                        colour = 0;
                    } else {
                        float alpha = props.getFloat("stop-opacity", 1) * currentLayerAttributes().opacity;
                        int alphaInt = Math.round(255 * alpha);
                        colour = stopColour.intValue() | (alphaInt << 24);
                    }
                    gradient.colors.add(colour);

                    float offset = props.getFloat("offset", 0);
                    gradient.positions.add(offset);
                }
            } else if (localName.equals("g")) {
                final Properties props = new Properties(atts);

                // Check to see if this is the "bounds" layer
                if ("bounds".equalsIgnoreCase(getStringAttr("id", atts))) {
                    boundsMode = true;
                }
                if (hidden) {
                    hiddenLevel++;
                    // Util.debug("Hidden up: " + hiddenLevel);
                }
                // Go in to hidden mode if display is "none"
                if ("none".equals(getStringAttr("display", atts)) || "none".equals(props.getString("display"))) {
                    if (!hidden) {
                        hidden = true;
                        hiddenLevel = 1;
                        // Util.debug("Hidden up: " + hiddenLevel);
                    }
                }

                // Create layer attributes
                final float opacity = props.getFloat("opacity", 1f);
                LayerAttributes curLayerAttr = currentLayerAttributes();
                LayerAttributes newLayerAttr = new LayerAttributes(curLayerAttr.opacity * opacity);
                layerAttributeStack.addLast(newLayerAttr);

                pushTransform(atts);
                fillPaintStack.addLast(new Paint(fillPaint));
                strokePaintStack.addLast(new Paint(strokePaint));
                fillSetStack.addLast(fillSet);
                strokeSetStack.addLast(strokeSet);

                doFill(props, null); // Added by mrn but a boundingBox is now
                                     // required by josef.
                doStroke(props);

                fillSet |= (props.getString("fill") != null);
                strokeSet |= (props.getString("stroke") != null);

            } else if (!hidden && localName.equals("title")) {
                if (rectElement) {
                    titleDesc = true;
                }
            } else if (!hidden && localName.equals("rect")) {
                rectElement = true;

                Float x = getFloatAttr("x", atts);
                RectID = getStringAttr("id", atts);
                if (x == null) {
                    x = 0f;
                }
                Float y = getFloatAttr("y", atts);
                if (y == null) {
                    y = 0f;
                }
                RectWidth = getFloatAttr("width", atts);
                RectHeight = getFloatAttr("height", atts);
                Float rx = getFloatAttr("rx", atts, 0f);
                Float ry = getFloatAttr("ry", atts, 0f);

                pushTransform(atts);
                Properties props = new Properties(atts);
                rect.set(x, y, x + RectWidth, y + RectHeight);
                RectCenterX = rect.centerX();
                RectCenterY = rect.centerY();
                if (doFill(props, rect)) {
                    rect.set(x, y, x + RectWidth, y + RectHeight);
                    if (rx <= 0f && ry <= 0f) {
                        canvas.drawRect(rect, fillPaint);
                    } else {
                        canvas.drawRoundRect(rect, rx, ry, fillPaint);
                    }
                    doLimits(rect);
                }
                if (doStroke(props)) {
                    rect.set(x, y, x + RectWidth, y + RectHeight);
                    if (rx <= 0f && ry <= 0f) {
                        canvas.drawRect(rect, strokePaint);
                    } else {
                        canvas.drawRoundRect(rect, rx, ry, strokePaint);
                    }
                    doLimits(rect, strokePaint);
                }

            } else if (!hidden && localName.equals("line")) {
                Float x1 = getFloatAttr("x1", atts);
                Float x2 = getFloatAttr("x2", atts);
                Float y1 = getFloatAttr("y1", atts);
                Float y2 = getFloatAttr("y2", atts);
                Properties props = new Properties(atts);
                if (doStroke(props)) {
                    pushTransform(atts);
                    rect.set(x1, y1, x2, y2);
                    canvas.drawLine(x1, y1, x2, y2, strokePaint);
                    doLimits(rect, strokePaint);
                    popTransform();
                }
            } else if (!hidden && (localName.equals("circle") || localName.equals("ellipse"))) {
                Float centerX, centerY, radiusX, radiusY;

                centerX = getFloatAttr("cx", atts);
                centerY = getFloatAttr("cy", atts);
                if (localName.equals("ellipse")) {
                    radiusX = getFloatAttr("rx", atts);
                    radiusY = getFloatAttr("ry", atts);

                } else {
                    radiusX = radiusY = getFloatAttr("r", atts);
                }
                if (centerX != null && centerY != null && radiusX != null && radiusY != null) {
                    pushTransform(atts);
                    Properties props = new Properties(atts);
                    rect.set(centerX - radiusX, centerY - radiusY, centerX + radiusX, centerY + radiusY);
                    if (doFill(props, rect)) {
                        canvas.drawOval(rect, fillPaint);
                        doLimits(rect);
                    }
                    if (doStroke(props)) {
                        canvas.drawOval(rect, strokePaint);
                        doLimits(rect, strokePaint);
                    }
                    popTransform();
                }
            } else if (!hidden && (localName.equals("polygon") || localName.equals("polyline"))) {
                NumberParse numbers = getNumberParseAttr("points", atts);
                if (numbers != null) {
                    Path p = new Path();
                    ArrayList<Float> points = numbers.numbers;
                    if (points.size() > 1) {
                        pushTransform(atts);
                        Properties props = new Properties(atts);
                        p.moveTo(points.get(0), points.get(1));
                        for (int i = 2; i < points.size(); i += 2) {
                            float x = points.get(i);
                            float y = points.get(i + 1);
                            p.lineTo(x, y);
                        }
                        // Don't close a polyline
                        if (localName.equals("polygon")) {
                            p.close();
                        }
                        p.computeBounds(rect, false);
                        if (doFill(props, rect)) {
                            canvas.drawPath(p, fillPaint);
                            doLimits(rect);
                        }
                        if (doStroke(props)) {
                            canvas.drawPath(p, strokePaint);
                            doLimits(rect, strokePaint);
                        }
                        popTransform();
                    }
                }
            } else if (!hidden && localName.equals("path")) {
                Path p = doPath(getStringAttr("d", atts));
                pushTransform(atts);
                Properties props = new Properties(atts);
                p.computeBounds(rect, false);
                if (doFill(props, rect)) {
                    canvas.drawPath(p, fillPaint);
                    doLimits(rect);
                }
                if (doStroke(props)) {
                    canvas.drawPath(p, strokePaint);
                    doLimits(rect, strokePaint);
                }
                popTransform();
            } else if (!hidden && localName.equals("desc")) {
                /*??description
                 * rectsvg
                 * ?rectsvg*/
                if (!rectElement)
                    documentDesc = true;
                else
                    rectDesc = true;
            }

            else if (!hidden) {
                Log.w(TAG, "UNRECOGNIZED SVG COMMAND: " + localName);
            }
        }

        public LayerAttributes currentLayerAttributes() {
            return layerAttributeStack.getLast();
        }

        @Override
        public void characters(char ch[], int start, int length) {
            // no-op

            if (rectDesc) {
                if (!RectID.equals("")) {
                    String[] desc = (new String(ch, start, length)).split(",");
                    RectNextX = Float.parseFloat(desc[0]);
                    RectNextY = Float.parseFloat(desc[1]);

                    //LocalBroadcastManager.getInstance(getInstance()).sendBroadcast(intent);
                }
            } else if (documentDesc) {
                String desc = new String(ch, start, length);
                if (desc.startsWith("p")) {
                    Intent intent = new Intent();
                    intent.setAction(DOCUMENTDESC_ACTION);
                    intent.putExtra("naviInfo", desc);
                    context.sendBroadcast(intent);
                } else {
                    String[] pois = desc.split(";");
                    String poiName = null;
                    String poiElementId = null;
                    float center_x;
                    float center_y;
                    float next_x;
                    float next_y;
                    for (String poi : pois) {
                        String[] tmp = poi.split(":");
                        switch (Integer.parseInt(tmp[0])) {
                        case louti:
                            poiName = "";
                            poiElementId = "louti";
                            break;
                        case dianti:
                            poiName = "";
                            poiElementId = "dianti";
                            break;
                        case futi:
                            poiName = "";
                            poiElementId = "futi";
                            break;
                        case churukou:
                            poiName = "?";
                            poiElementId = "churukou";
                            break;
                        case weishengjian:
                            poiName = "?";
                            poiElementId = "weishengjian";
                            break;
                        case atm:
                            poiName = "ATM";
                            poiElementId = "atm";
                            break;
                        }
                        center_x = Float.parseFloat(tmp[1].split(",")[0]);
                        center_y = Float.parseFloat(tmp[1].split(",")[1]);
                        next_x = Float.parseFloat(tmp[2].split(",")[0]);
                        next_y = Float.parseFloat(tmp[2].split(",")[1]);

                        Intent intent = new Intent();
                        intent.setAction(rectElement_ACTION);
                        intent.putExtra("poiElementId", poiElementId);
                        intent.putExtra("poiName", poiName);
                        intent.putExtra("centerX", center_x);
                        intent.putExtra("centerY", center_y);
                        intent.putExtra("nextX", next_x);
                        intent.putExtra("nextY", next_y);
                        context.sendBroadcast(intent);
                        Log.i(TAG, "center = (" + RectCenterX + ", " + RectCenterY + ")");

                    }
                }

            } else if (titleDesc) {

                RectName = new String(ch, start, length);
                Log.d(TAG, "titleDesc RectName = " + RectName);
                Float textLen = textPaint.measureText(RectName);
                if (RectWidth >= RectHeight) {
                    Float extraSpace = RectWidth - textLen;
                    canvas.drawText(RectName, rect.centerX() + (extraSpace / 2), rect.centerY(), textPaint);
                } else {
                    Float extraSpace = RectHeight - textLen;
                    canvas.save();
                    canvas.rotate(-90, rect.centerX(), rect.centerY());
                    canvas.drawText(RectName, rect.centerX() - (RectHeight / 2) + extraSpace, rect.centerY(),
                            textPaint);
                    canvas.restore();
                }

            }
        }

        @Override
        public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
            if (localName.equals("svg")) {
                if (canvasRestoreCount != null) {
                    canvas.restoreToCount(canvasRestoreCount);
                }
                if (limitsAdjustmentX != null) {
                    limits.left += limitsAdjustmentX;
                    limits.right += limitsAdjustmentX;
                }
                if (limitsAdjustmentY != null) {
                    limits.top += limitsAdjustmentY;
                    limits.bottom += limitsAdjustmentY;
                }
                picture.endRecording();

            } else if (localName.equals("linearGradient") || localName.equals("radialGradient")) {
                if (gradient.id != null) {
                    if (gradient.xlink != null) {
                        Gradient parent = gradientMap.get(gradient.xlink);
                        if (parent != null) {
                            gradient = parent.createChild(gradient);
                        }
                    }
                    int[] colors = new int[gradient.colors.size()];
                    for (int i = 0; i < colors.length; i++) {
                        colors[i] = gradient.colors.get(i);
                    }
                    float[] positions = new float[gradient.positions.size()];
                    for (int i = 0; i < positions.length; i++) {
                        positions[i] = gradient.positions.get(i);
                    }
                    if (colors.length == 0) {
                        Log.d("BAD", "BAD");
                    }
                    if (localName.equals("linearGradient")) {
                        gradient.shader = new LinearGradient(gradient.x1, gradient.y1, gradient.x2, gradient.y2,
                                colors, positions, gradient.tilemode);
                    } else {
                        gradient.shader = new RadialGradient(gradient.x, gradient.y, gradient.radius, colors,
                                positions, gradient.tilemode);
                    }
                    gradientMap.put(gradient.id, gradient);
                }
            } else if (localName.equals("g")) {
                if (boundsMode) {
                    boundsMode = false;
                }
                // Break out of hidden mode
                if (hidden) {
                    hiddenLevel--;
                    // Util.debug("Hidden down: " + hiddenLevel);
                    if (hiddenLevel == 0) {
                        hidden = false;
                    }
                }
                // // Clear gradient map
                // gradientRefMap.clear();
                popTransform();
                fillPaint = fillPaintStack.removeLast();
                fillSet = fillSetStack.removeLast();
                strokePaint = strokePaintStack.removeLast();
                strokeSet = strokeSetStack.removeLast();
                if (!layerAttributeStack.isEmpty()) {
                    layerAttributeStack.removeLast();
                }
            } else if (localName.equals("desc")) {
                rectDesc = false;
                documentDesc = false;

            } else if (localName.equals("rect")) {
                popTransform();
                rectElement = false;
                Poidata poidata = new Poidata(RectID, RectName, RectCenterX, RectCenterY, RectNextX, RectNextY);
                poi.add(poidata);
            } else if (localName.equals("title")) {
                titleDesc = false;
            }

        }
    }
}