VectorDrawable.java revision 63cfd85bcce488a3f3952bd1db523a727d30ca39
1abb7d134c02ac60091108c491dafb00877093170John Hoford/*
2abb7d134c02ac60091108c491dafb00877093170John Hoford * Copyright (C) 2014 The Android Open Source Project
3abb7d134c02ac60091108c491dafb00877093170John Hoford *
4abb7d134c02ac60091108c491dafb00877093170John Hoford * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5abb7d134c02ac60091108c491dafb00877093170John Hoford * in compliance with the License. You may obtain a copy of the License at
6abb7d134c02ac60091108c491dafb00877093170John Hoford *
7abb7d134c02ac60091108c491dafb00877093170John Hoford * http://www.apache.org/licenses/LICENSE-2.0
8abb7d134c02ac60091108c491dafb00877093170John Hoford *
9abb7d134c02ac60091108c491dafb00877093170John Hoford * Unless required by applicable law or agreed to in writing, software distributed under the License
10abb7d134c02ac60091108c491dafb00877093170John Hoford * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11abb7d134c02ac60091108c491dafb00877093170John Hoford * or implied. See the License for the specific language governing permissions and limitations under
12abb7d134c02ac60091108c491dafb00877093170John Hoford * the License.
13abb7d134c02ac60091108c491dafb00877093170John Hoford */
14abb7d134c02ac60091108c491dafb00877093170John Hoford
15abb7d134c02ac60091108c491dafb00877093170John Hofordpackage android.graphics.drawable;
16abb7d134c02ac60091108c491dafb00877093170John Hoford
17abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.Resources;
18abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.Resources.Theme;
194b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viveretteimport android.content.res.TypedArray;
20abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Canvas;
21abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.ColorFilter;
22abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Matrix;
23abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Paint;
24abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Path;
25abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.PathMeasure;
26abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.PixelFormat;
27abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Rect;
28abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Region;
29abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.AttributeSet;
30abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.Log;
314b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viveretteimport android.util.Xml;
32abb7d134c02ac60091108c491dafb00877093170John Hoford
33abb7d134c02ac60091108c491dafb00877093170John Hofordimport com.android.internal.R;
34abb7d134c02ac60091108c491dafb00877093170John Hoford
35abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParser;
36abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParserException;
374b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viveretteimport org.xmlpull.v1.XmlPullParserFactory;
38abb7d134c02ac60091108c491dafb00877093170John Hoford
39abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.io.IOException;
40abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.ArrayList;
41abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.Arrays;
42abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.HashMap;
434b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
44abb7d134c02ac60091108c491dafb00877093170John Hoford/**
45d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * This lets you create a drawable based on an XML vector graphic It can be
46d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * defined in an XML file with the <code>&lt;vector></code> element.
47abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
4846e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * The vector drawable has the following elements:
49abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
50abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
51177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui * <dt><code>&lt;vector></code></dt>
52e3c45e7a6b2a7d2176aa46ee482e299b54feeb9fztenghui * <dd>Used to defined a vector drawable</dd>
53abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;size></code></dt>
54abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the intrinsic Width Height size of the drawable using
55d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <code>android:width</code> and <code>android:height</code></dd>
56abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;viewport></code></dt>
57abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the size of the virtual canvas the paths are drawn on.
58d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * The size is defined using the attributes <code>android:viewportHeight</code>
59d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <code>android:viewportWidth</code></dd>
606d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui * <dt><code>&lt;group></code></dt>
616d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui * <dd>Defines a group of paths or subgroups, plus transformation information.</dd>
62abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;path></code></dt>
636d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui * <dd>Defines paths to be drawn.
64abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
65abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:name</code>
66abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the name of the path.</dd></dt>
67abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pathData</code>
6846e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * <dd>Defines path string. This is using exactly same format as "d" attribute
6946e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * in the SVG's path data</dd></dt>
70abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fill</code>
71abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the color to fill the path (none if not present).</dd></dt>
72abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:stroke</code>
73d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <dd>Defines the color to draw the path outline (none if not present).</dd>
74d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * </dt>
75abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeWidth</code>
76abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The width a path stroke</dd></dt>
77abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeOpacity</code>
78abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity of a path stroke</dd></dt>
79abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:rotation</code>
80abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The amount to rotation the path stroke.</dd></dt>
81abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotX</code>
82abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The X coordinate of the center of rotation of a path</dd></dt>
83abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotY</code>
84abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The Y coordinate of the center of rotation of a path</dd></dt>
85abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fillOpacity</code>
86abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity to fill the path with</dd></dt>
87abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathStart</code>
88abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the start from 0 to 1</dd></dt>
89abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathEnd</code>
90abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the end from 0 to 1</dd></dt>
91abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathOffset</code>
92d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <dd>Shift trim region (allows showed region to include the start and end)
93d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * from 0 to 1</dd></dt>
94abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:clipToPath</code>
95abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Path will set the clip path</dd></dt>
96abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineCap</code>
97abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the linecap for a stroked path: butt, round, square</dd></dt>
98abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineJoin</code>
99abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt>
100abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeMiterLimit</code>
101abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the Miter limit for a stroked path</dd></dt>
102abb7d134c02ac60091108c491dafb00877093170John Hoford * </dl>
103abb7d134c02ac60091108c491dafb00877093170John Hoford * </dd>
104abb7d134c02ac60091108c491dafb00877093170John Hoford */
105abb7d134c02ac60091108c491dafb00877093170John Hofordpublic class VectorDrawable extends Drawable {
1069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private static final String LOGTAG = VectorDrawable.class.getSimpleName();
1079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
108abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_SIZE = "size";
109abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VIEWPORT = "viewport";
1106d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui    private static final String SHAPE_GROUP = "group";
111abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_PATH = "path";
112abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VECTOR = "vector";
113abb7d134c02ac60091108c491dafb00877093170John Hoford
114abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_BUTT = 0;
115abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_ROUND = 1;
116abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_SQUARE = 2;
1179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
118abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_MITER = 0;
119abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_ROUND = 1;
120abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_BEVEL = 2;
1219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1224b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette    private final VectorDrawableState mVectorState;
1234b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
124abb7d134c02ac60091108c491dafb00877093170John Hoford    private int mAlpha = 0xFF;
125abb7d134c02ac60091108c491dafb00877093170John Hoford
126abb7d134c02ac60091108c491dafb00877093170John Hoford    public VectorDrawable() {
1279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        mVectorState = new VectorDrawableState(null);
128abb7d134c02ac60091108c491dafb00877093170John Hoford    }
129abb7d134c02ac60091108c491dafb00877093170John Hoford
1309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
131abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState = new VectorDrawableState(state);
1329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (theme != null && canApplyTheme()) {
1349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            applyTheme(theme);
1359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
136abb7d134c02ac60091108c491dafb00877093170John Hoford    }
137abb7d134c02ac60091108c491dafb00877093170John Hoford
138abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
139abb7d134c02ac60091108c491dafb00877093170John Hoford    public ConstantState getConstantState() {
140abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState;
141abb7d134c02ac60091108c491dafb00877093170John Hoford    }
142abb7d134c02ac60091108c491dafb00877093170John Hoford
1434554a6a5137d8e9bdfb623ad84ff344a48b7eb9dAlan Viverette    @Override
144abb7d134c02ac60091108c491dafb00877093170John Hoford    public void draw(Canvas canvas) {
1454b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final int saveCount = canvas.save();
1464b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final Rect bounds = getBounds();
1474b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.translate(bounds.left, bounds.top);
148ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
1494b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.restoreToCount(saveCount);
150abb7d134c02ac60091108c491dafb00877093170John Hoford    }
151abb7d134c02ac60091108c491dafb00877093170John Hoford
152abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
153abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setAlpha(int alpha) {
154abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO correct handling of transparent
155abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mAlpha != alpha) {
156abb7d134c02ac60091108c491dafb00877093170John Hoford            mAlpha = alpha;
157abb7d134c02ac60091108c491dafb00877093170John Hoford            invalidateSelf();
158abb7d134c02ac60091108c491dafb00877093170John Hoford        }
159abb7d134c02ac60091108c491dafb00877093170John Hoford    }
160abb7d134c02ac60091108c491dafb00877093170John Hoford
161abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
162abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setColorFilter(ColorFilter colorFilter) {
163fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        mVectorState.mVPathRenderer.setColorFilter(colorFilter);
164fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        invalidateSelf();
165abb7d134c02ac60091108c491dafb00877093170John Hoford    }
166abb7d134c02ac60091108c491dafb00877093170John Hoford
167abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
168abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getOpacity() {
169abb7d134c02ac60091108c491dafb00877093170John Hoford        return PixelFormat.TRANSLUCENT;
170abb7d134c02ac60091108c491dafb00877093170John Hoford    }
171abb7d134c02ac60091108c491dafb00877093170John Hoford
172abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
173d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette     * Sets padding for this shape, defined by a Rect object. Define the padding
174d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette     * in the Rect object as: left, top, right, bottom.
175abb7d134c02ac60091108c491dafb00877093170John Hoford     */
176abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(Rect padding) {
177abb7d134c02ac60091108c491dafb00877093170John Hoford        setPadding(padding.left, padding.top, padding.right, padding.bottom);
178abb7d134c02ac60091108c491dafb00877093170John Hoford    }
179abb7d134c02ac60091108c491dafb00877093170John Hoford
180abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
181abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets padding for the shape.
182abb7d134c02ac60091108c491dafb00877093170John Hoford     *
183abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param left padding for the left side (in pixels)
184abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param top padding for the top (in pixels)
185abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param right padding for the right side (in pixels)
186abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param bottom padding for the bottom (in pixels)
187abb7d134c02ac60091108c491dafb00877093170John Hoford     */
188abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(int left, int top, int right, int bottom) {
189abb7d134c02ac60091108c491dafb00877093170John Hoford        if ((left | top | right | bottom) == 0) {
190abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding = null;
191abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
192abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mVectorState.mPadding == null) {
193abb7d134c02ac60091108c491dafb00877093170John Hoford                mVectorState.mPadding = new Rect();
194abb7d134c02ac60091108c491dafb00877093170John Hoford            }
195abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding.set(left, top, right, bottom);
196abb7d134c02ac60091108c491dafb00877093170John Hoford        }
197abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
198abb7d134c02ac60091108c491dafb00877093170John Hoford    }
199abb7d134c02ac60091108c491dafb00877093170John Hoford
200abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
201abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicWidth() {
202ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return (int) mVectorState.mVPathRenderer.mBaseWidth;
203abb7d134c02ac60091108c491dafb00877093170John Hoford    }
204abb7d134c02ac60091108c491dafb00877093170John Hoford
205abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
206abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicHeight() {
207ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return (int) mVectorState.mVPathRenderer.mBaseHeight;
208abb7d134c02ac60091108c491dafb00877093170John Hoford    }
209abb7d134c02ac60091108c491dafb00877093170John Hoford
210abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
211abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean getPadding(Rect padding) {
212abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mVectorState.mPadding != null) {
213abb7d134c02ac60091108c491dafb00877093170John Hoford            padding.set(mVectorState.mPadding);
214abb7d134c02ac60091108c491dafb00877093170John Hoford            return true;
215abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
216abb7d134c02ac60091108c491dafb00877093170John Hoford            return super.getPadding(padding);
217abb7d134c02ac60091108c491dafb00877093170John Hoford        }
218abb7d134c02ac60091108c491dafb00877093170John Hoford    }
219abb7d134c02ac60091108c491dafb00877093170John Hoford
220abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
221abb7d134c02ac60091108c491dafb00877093170John Hoford    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
222abb7d134c02ac60091108c491dafb00877093170John Hoford            throws XmlPullParserException, IOException {
223ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer p = inflateInternal(res, parser, attrs, theme);
224ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        setPathRenderer(p);
225abb7d134c02ac60091108c491dafb00877093170John Hoford    }
226abb7d134c02ac60091108c491dafb00877093170John Hoford
2279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
2289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public boolean canApplyTheme() {
2299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme();
2309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
2319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
2329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
2339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public void applyTheme(Theme t) {
2349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        super.applyTheme(t);
2359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
2369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VectorDrawableState state = mVectorState;
237ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer path = state.mVPathRenderer;
2389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (path != null && path.canApplyTheme()) {
2399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            path.applyTheme(t);
2409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
2419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
2429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
2434b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    /** @hide */
2444b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    public static VectorDrawable create(Resources resources, int rid) {
2454b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        try {
2464b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final XmlPullParser xpp = resources.getXml(rid);
2474b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final AttributeSet attrs = Xml.asAttributeSet(xpp);
2484b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
2494b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            factory.setNamespaceAware(true);
2504b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
2514b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final VectorDrawable drawable = new VectorDrawable();
2524b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            drawable.inflate(resources, xpp, attrs);
2534b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
2544b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            return drawable;
2554b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        } catch (XmlPullParserException e) {
2564b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            Log.e(LOGTAG, "parser error", e);
2574b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        } catch (IOException e) {
2584b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            Log.e(LOGTAG, "parser error", e);
2594b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        }
2604b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        return null;
2614b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    }
2624b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
263ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
2649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            Theme theme) throws XmlPullParserException, IOException {
265ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer pathRenderer = new VPathRenderer();
2669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
267abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noSizeTag = true;
268abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noViewportTag = true;
2696d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui        boolean noGroupTag = true;
270abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noPathTag = true;
2719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
27246e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui        VGroup currentGroup = new VGroup();
273abb7d134c02ac60091108c491dafb00877093170John Hoford
274abb7d134c02ac60091108c491dafb00877093170John Hoford        int eventType = parser.getEventType();
275abb7d134c02ac60091108c491dafb00877093170John Hoford        while (eventType != XmlPullParser.END_DOCUMENT) {
276abb7d134c02ac60091108c491dafb00877093170John Hoford            if (eventType == XmlPullParser.START_TAG) {
2779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final String tagName = parser.getName();
278abb7d134c02ac60091108c491dafb00877093170John Hoford                if (SHAPE_PATH.equals(tagName)) {
2799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = new VPath();
2809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    path.inflate(res, attrs, theme);
2819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    currentGroup.add(path);
282abb7d134c02ac60091108c491dafb00877093170John Hoford                    noPathTag = false;
283abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_SIZE.equals(tagName)) {
284ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                    pathRenderer.parseSize(res, attrs);
285abb7d134c02ac60091108c491dafb00877093170John Hoford                    noSizeTag = false;
286abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_VIEWPORT.equals(tagName)) {
287ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                    pathRenderer.parseViewport(res, attrs);
288abb7d134c02ac60091108c491dafb00877093170John Hoford                    noViewportTag = false;
2896d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                } else if (SHAPE_GROUP.equals(tagName)) {
2906d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    currentGroup = new VGroup();
29163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    currentGroup.inflate(res, attrs, theme);
2926d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    pathRenderer.mGroupList.add(currentGroup);
2936d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    noGroupTag = false;
294abb7d134c02ac60091108c491dafb00877093170John Hoford                }
295abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
297abb7d134c02ac60091108c491dafb00877093170John Hoford            eventType = parser.next();
298abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
3006d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui        if (noGroupTag && !noPathTag) {
3016d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui            pathRenderer.mGroupList.add(currentGroup);
3026d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui        }
3036d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui
30446e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui        if (noSizeTag || noViewportTag || noPathTag) {
3059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final StringBuffer tag = new StringBuffer();
3069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
307abb7d134c02ac60091108c491dafb00877093170John Hoford            if (noSizeTag) {
3089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
309abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
311d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette            if (noViewportTag) {
312d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                if (tag.length() > 0) {
313abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
314abb7d134c02ac60091108c491dafb00877093170John Hoford                }
3159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
316abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
318d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette            if (noPathTag) {
319d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                if (tag.length() > 0) {
320abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" or ");
321abb7d134c02ac60091108c491dafb00877093170John Hoford                }
3229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_PATH);
323abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
3259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            throw new XmlPullParserException("no " + tag + " defined");
326abb7d134c02ac60091108c491dafb00877093170John Hoford        }
3279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
328ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return pathRenderer;
329abb7d134c02ac60091108c491dafb00877093170John Hoford    }
330abb7d134c02ac60091108c491dafb00877093170John Hoford
331ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private void setPathRenderer(VPathRenderer pathRenderer) {
332ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        mVectorState.mVPathRenderer = pathRenderer;
333abb7d134c02ac60091108c491dafb00877093170John Hoford    }
334abb7d134c02ac60091108c491dafb00877093170John Hoford
3355c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    private static class VectorDrawableState extends ConstantState {
3365c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        int mChangingConfigurations;
337ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        VPathRenderer mVPathRenderer;
3385c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        Rect mPadding;
3395c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3405c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public VectorDrawableState(VectorDrawableState copy) {
3415c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            if (copy != null) {
3425c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mChangingConfigurations = copy.mChangingConfigurations;
343ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
3445c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mPadding = new Rect(copy.mPadding);
3455c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            }
3465c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3475c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3485c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3495c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable() {
3505c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, null, null);
3515c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3525c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res) {
3555c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, null);
3565c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3575c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3585c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3595c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res, Theme theme) {
3605c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, theme);
3615c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3625c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3635c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3645c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public int getChangingConfigurations() {
3655c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return mChangingConfigurations;
3665c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3675c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    }
3685c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
369ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private static class VPathRenderer {
3704b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mPath = new Path();
3714b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mRenderPath = new Path();
3724b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Matrix mMatrix = new Matrix();
3734b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
3744b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mStrokePaint;
3754b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mFillPaint;
376fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        private ColorFilter mColorFilter;
377abb7d134c02ac60091108c491dafb00877093170John Hoford        private PathMeasure mPathMeasure;
3784b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
3796d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui        final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
3809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
381fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        float mBaseWidth = 0;
382fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        float mBaseHeight = 0;
383fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        float mViewportWidth = 0;
384fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        float mViewportHeight = 0;
385abb7d134c02ac60091108c491dafb00877093170John Hoford
386ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        public VPathRenderer() {
387abb7d134c02ac60091108c491dafb00877093170John Hoford        }
3889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
389ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        public VPathRenderer(VPathRenderer copy) {
3906d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui            mGroupList.addAll(copy.mGroupList);
391abb7d134c02ac60091108c491dafb00877093170John Hoford
392abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = copy.mBaseWidth;
393abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = copy.mBaseHeight;
394abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = copy.mViewportHeight;
395abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = copy.mViewportHeight;
396abb7d134c02ac60091108c491dafb00877093170John Hoford        }
397abb7d134c02ac60091108c491dafb00877093170John Hoford
3989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
3996d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui            final ArrayList<VGroup> groups = mGroupList;
4006d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui            for (int i = groups.size() - 1; i >= 0; i--) {
4016d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                final ArrayList<VPath> paths = groups.get(i).mVGList;
4026d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                for (int j = paths.size() - 1; j >= 0; j--) {
4036d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    final VPath path = paths.get(j);
4046d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    if (path.canApplyTheme()) {
4056d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                        return true;
4066d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    }
4079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
4089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
4096d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui
4109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return false;
4119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
4129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
4146d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui            final ArrayList<VGroup> groups = mGroupList;
4156d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui            for (int i = groups.size() - 1; i >= 0; i--) {
41663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                VGroup currentGroup = groups.get(i);
41763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                currentGroup.applyTheme(t);
41863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                final ArrayList<VPath> paths = currentGroup.mVGList;
4196d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                for (int j = paths.size() - 1; j >= 0; j--) {
4206d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    final VPath path = paths.get(j);
4216d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    if (path.canApplyTheme()) {
4226d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                        path.applyTheme(t);
4236d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    }
4249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
4259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
426abb7d134c02ac60091108c491dafb00877093170John Hoford        }
427abb7d134c02ac60091108c491dafb00877093170John Hoford
428fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        public void setColorFilter(ColorFilter colorFilter) {
429fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mColorFilter = colorFilter;
430fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
431fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            if (mFillPaint != null) {
432fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                mFillPaint.setColorFilter(colorFilter);
433fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            }
434fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
435fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            if (mStrokePaint != null) {
436fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                mStrokePaint.setColorFilter(colorFilter);
437fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            }
4386d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui
439fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        }
440fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
4414b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        public void draw(Canvas canvas, int w, int h) {
44263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            if (mGroupList == null || mGroupList.size() == 0) {
44363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                Log.e(LOGTAG,"There is no group to draw");
444abb7d134c02ac60091108c491dafb00877093170John Hoford                return;
445abb7d134c02ac60091108c491dafb00877093170John Hoford            }
446abb7d134c02ac60091108c491dafb00877093170John Hoford
44763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            for (int i = 0; i < mGroupList.size(); i++) {
44863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                VGroup currentGroup = mGroupList.get(i);
44963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                if (currentGroup != null) {
45063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    drawPath(currentGroup, canvas, w, h);
451abb7d134c02ac60091108c491dafb00877093170John Hoford                }
452abb7d134c02ac60091108c491dafb00877093170John Hoford            }
453abb7d134c02ac60091108c491dafb00877093170John Hoford        }
454abb7d134c02ac60091108c491dafb00877093170John Hoford
45563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        private void drawPath(VGroup vGroup, Canvas canvas, int w, int h) {
4569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
457abb7d134c02ac60091108c491dafb00877093170John Hoford
458abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.reset();
459abb7d134c02ac60091108c491dafb00877093170John Hoford
46063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            mMatrix.postRotate(vGroup.mRotate, vGroup.mPivotX, vGroup.mPivotY);
461abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
462abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
463abb7d134c02ac60091108c491dafb00877093170John Hoford
46463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            ArrayList<VPath> paths = vGroup.getPaths();
46563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            for (int i = 0; i < paths.size(); i++) {
46663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                VPath vPath = paths.get(i);
46763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                vPath.toPath(mPath);
46863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                final Path path = mPath;
469abb7d134c02ac60091108c491dafb00877093170John Hoford
47063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
47163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
47263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f;
4739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
47463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    if (mPathMeasure == null) {
47563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mPathMeasure = new PathMeasure();
47663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    }
47763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    mPathMeasure.setPath(mPath, false);
47863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
47963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    float len = mPathMeasure.getLength();
48063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    start = start * len;
48163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    end = end * len;
48263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    path.reset();
48363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    if (start > end) {
48463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mPathMeasure.getSegment(start, len, path, true);
48563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mPathMeasure.getSegment(0f, end, path, true);
48663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    } else {
48763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mPathMeasure.getSegment(start, end, path, true);
48863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    }
48963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    path.rLineTo(0, 0); // fix bug in measure
4904b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                }
4914b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
49263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                mRenderPath.reset();
4939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
49463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                mRenderPath.addPath(path, mMatrix);
4954b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
49663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                if (vPath.mClip) {
49763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    canvas.clipPath(mRenderPath, Region.Op.REPLACE);
498abb7d134c02ac60091108c491dafb00877093170John Hoford                }
4994b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
50063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                if (vPath.mFillColor != 0) {
50163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    if (mFillPaint == null) {
50263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mFillPaint = new Paint();
50363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mFillPaint.setColorFilter(mColorFilter);
50463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mFillPaint.setStyle(Paint.Style.FILL);
50563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mFillPaint.setAntiAlias(true);
50663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    }
50763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
50863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    mFillPaint.setColor(vPath.mFillColor);
50963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    canvas.drawPath(mRenderPath, mFillPaint);
510abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5114b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
51263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                if (vPath.mStrokeColor != 0) {
51363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    if (mStrokePaint == null) {
51463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mStrokePaint = new Paint();
51563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mStrokePaint.setColorFilter(mColorFilter);
51663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mStrokePaint.setStyle(Paint.Style.STROKE);
51763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mStrokePaint.setAntiAlias(true);
51863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    }
519abb7d134c02ac60091108c491dafb00877093170John Hoford
52063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    final Paint strokePaint = mStrokePaint;
52163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    if (vPath.mStrokeLineJoin != null) {
52263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
52363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    }
52463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
52563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    if (vPath.mStrokeLineCap != null) {
52663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        strokePaint.setStrokeCap(vPath.mStrokeLineCap);
52763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    }
52863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
52963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
53063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    strokePaint.setColor(vPath.mStrokeColor);
53163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
53263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    canvas.drawPath(mRenderPath, strokePaint);
53363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                }
534abb7d134c02ac60091108c491dafb00877093170John Hoford            }
535abb7d134c02ac60091108c491dafb00877093170John Hoford        }
536abb7d134c02ac60091108c491dafb00877093170John Hoford
537abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseViewport(Resources r, AttributeSet attrs)
538abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException {
5394b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
540fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, mViewportWidth);
541fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, mViewportHeight);
542fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
543fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            if (mViewportWidth <= 0) {
544fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                throw new XmlPullParserException(a.getPositionDescription() +
545fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                        "<viewport> tag requires viewportWidth > 0");
546fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            } else if (mViewportHeight <= 0) {
547fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                throw new XmlPullParserException(a.getPositionDescription() +
548fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                        "<viewport> tag requires viewportHeight > 0");
549abb7d134c02ac60091108c491dafb00877093170John Hoford            }
550fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
551abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
552abb7d134c02ac60091108c491dafb00877093170John Hoford        }
553abb7d134c02ac60091108c491dafb00877093170John Hoford
554abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseSize(Resources r, AttributeSet attrs)
555abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException  {
5564b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
557fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, mBaseWidth);
558fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, mBaseHeight);
559fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
560fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            if (mBaseWidth <= 0) {
561fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                throw new XmlPullParserException(a.getPositionDescription() +
562fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                        "<size> tag requires width > 0");
563fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            } else if (mBaseHeight <= 0) {
564fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                throw new XmlPullParserException(a.getPositionDescription() +
565fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                        "<size> tag requires height > 0");
566abb7d134c02ac60091108c491dafb00877093170John Hoford            }
567fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
568abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
569abb7d134c02ac60091108c491dafb00877093170John Hoford        }
5704b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
571abb7d134c02ac60091108c491dafb00877093170John Hoford    }
572abb7d134c02ac60091108c491dafb00877093170John Hoford
573abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VGroup {
5749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
5759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final ArrayList<VPath> mVGList = new ArrayList<VPath>();
576abb7d134c02ac60091108c491dafb00877093170John Hoford
57763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        private float mRotate = 0;
57863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        private float mPivotX = 0;
57963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        private float mPivotY = 0;
58063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
58163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        private int[] mThemeAttrs;
58263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
583abb7d134c02ac60091108c491dafb00877093170John Hoford        public void add(VPath path) {
584abb7d134c02ac60091108c491dafb00877093170John Hoford            String id = path.getID();
585abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGPathMap.put(id, path);
586abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGList.add(path);
587abb7d134c02ac60091108c491dafb00877093170John Hoford         }
588abb7d134c02ac60091108c491dafb00877093170John Hoford
58963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        public void applyTheme(Theme t) {
59063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            if (mThemeAttrs == null) {
59163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                return;
59263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            }
59363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
59463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            final TypedArray a = t.resolveAttributes(
59563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    mThemeAttrs, R.styleable.VectorDrawablePath);
59663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
59763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
59863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
59963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
60063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            a.recycle();
60163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        }
60263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
60363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        public void inflate(Resources res, AttributeSet attrs, Theme theme) {
60463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawableGroup);
60563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            final int[] themeAttrs = a.extractThemeAttrs();
60663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
60763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            mThemeAttrs = themeAttrs;
60863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            // NOTE: The set of attributes loaded here MUST match the
60963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            // set of attributes loaded in applyTheme.
61063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
61163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_rotation] == 0) {
61263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
61363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            }
61463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
61563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotX] == 0) {
61663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
61763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            }
61863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
61963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotY] == 0) {
62063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
62163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            }
62263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
62363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            a.recycle();
62463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        }
62563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
626abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
627abb7d134c02ac60091108c491dafb00877093170John Hoford         * Must return in order of adding
628abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return ordered list of paths
629abb7d134c02ac60091108c491dafb00877093170John Hoford         */
63063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        public ArrayList<VPath> getPaths() {
631abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGList;
632abb7d134c02ac60091108c491dafb00877093170John Hoford        }
633abb7d134c02ac60091108c491dafb00877093170John Hoford
634abb7d134c02ac60091108c491dafb00877093170John Hoford    }
635abb7d134c02ac60091108c491dafb00877093170John Hoford
636abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VPath {
637abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int MAX_STATES = 10;
6389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int[] mThemeAttrs;
6409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
641abb7d134c02ac60091108c491dafb00877093170John Hoford        int mStrokeColor = 0;
642abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeWidth = 0;
643abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeOpacity = Float.NaN;
6449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
645abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillColor = 0;
646abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillRule;
647abb7d134c02ac60091108c491dafb00877093170John Hoford        float mFillOpacity = Float.NaN;
6489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
649abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathStart = 0;
650abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathEnd = 1;
651abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathOffset = 0;
6529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
653abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean mClip = false;
6544b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
6554b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Join mStrokeLineJoin = Paint.Join.MITER;
656abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeMiterlimit = 4;
6579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private VNode[] mNode = null;
6599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private String mId;
660abb7d134c02ac60091108c491dafb00877093170John Hoford
6619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath() {
6629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // Empty constructor.
6639453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
6649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
665abb7d134c02ac60091108c491dafb00877093170John Hoford        public void toPath(Path path) {
666abb7d134c02ac60091108c491dafb00877093170John Hoford            path.reset();
667abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mNode != null) {
668abb7d134c02ac60091108c491dafb00877093170John Hoford                VNode.createPath(mNode, path);
669abb7d134c02ac60091108c491dafb00877093170John Hoford            }
670abb7d134c02ac60091108c491dafb00877093170John Hoford        }
671abb7d134c02ac60091108c491dafb00877093170John Hoford
6727f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        public String getID() {
673abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
674abb7d134c02ac60091108c491dafb00877093170John Hoford        }
675abb7d134c02ac60091108c491dafb00877093170John Hoford
6767f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
6777f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
6787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_BUTT:
6797f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.BUTT;
6807f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_ROUND:
6817f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.ROUND;
6827f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_SQUARE:
6837f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.SQUARE;
6847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
6857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
6867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6877f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
6887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
6907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
6917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_MITER:
6927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.MITER;
6937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_ROUND:
6947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.ROUND;
6957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_BEVEL:
6967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.BEVEL;
6977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
6987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
6997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
7017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
7039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
7049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int[] themeAttrs = a.extractThemeAttrs();
7059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mThemeAttrs = themeAttrs;
7069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // NOTE: The set of attributes loaded here MUST match the
7087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // set of attributes loaded in applyTheme.
7097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_clipToPath] == 0) {
7107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
7117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) {
7147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mId = a.getString(R.styleable.VectorDrawablePath_name);
7157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) {
7187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
7197f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
720abb7d134c02ac60091108c491dafb00877093170John Hoford
7219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) {
7227f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
7239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7257f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) {
7267f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
727abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7297f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7307f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) {
7317f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineCap = getStrokeLineCap(
7327f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
7337f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7347f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7357f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7367f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineJoin] == 0) {
7377f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineJoin = getStrokeLineJoin(
7387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
739abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7417f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeMiterLimit] == 0) {
7437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeMiterlimit = a.getFloat(
7447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
7457f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7479453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) {
7489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
749abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7509453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7519453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null
7529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) {
7539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeOpacity = a.getFloat(
7547f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
7559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7577f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeWidth] == 0) {
7587f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
7597f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7617f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_trimPathEnd] == 0) {
7627f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
7637f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7657f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7667f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathOffset] == 0) {
7677f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathOffset = a.getFloat(
7687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
7697f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7707f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7717f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7727f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathStart] == 0) {
7737f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathStart = a.getFloat(
7747f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
7757f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7767f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
7789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
779abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
780abb7d134c02ac60091108c491dafb00877093170John Hoford        }
781abb7d134c02ac60091108c491dafb00877093170John Hoford
7829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
7839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mThemeAttrs != null;
7849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
7859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
7879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (mThemeAttrs == null) {
7889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                return;
7899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = t.resolveAttributes(
7920cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette                    mThemeAttrs, R.styleable.VectorDrawablePath);
7939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
7959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_name)) {
7977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mId = a.getString(R.styleable.VectorDrawablePath_name);
7989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
8007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) {
8017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
8029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
8039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
8047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
8057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
8067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
8077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = getStrokeLineCap(a.getInt(
8087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
8097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
8107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
8117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeMiterlimit = a.getFloat(
8127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
8137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
8147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeOpacity = a.getFloat(
8157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
8167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
8177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
8187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
8197f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathOffset = a.getFloat(
8207f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
8217f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathStart = a.getFloat(
8227f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
8239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
8249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
82563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            a.recycle();
8269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
8279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
8289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private void updateColorAlphas() {
8299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mFillOpacity)) {
8309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor &= 0x00FFFFFF;
8319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor |= ((int) (0xFF * mFillOpacity)) << 24;
8329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
8339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
8349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mStrokeOpacity)) {
8359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor &= 0x00FFFFFF;
8369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor |= ((int) (0xFF * mStrokeOpacity)) << 24;
8379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
8389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
8399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
840abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int nextStart(String s, int end) {
841abb7d134c02ac60091108c491dafb00877093170John Hoford            char c;
842abb7d134c02ac60091108c491dafb00877093170John Hoford
843abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < s.length()) {
844abb7d134c02ac60091108c491dafb00877093170John Hoford                c = s.charAt(end);
845abb7d134c02ac60091108c491dafb00877093170John Hoford                if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) {
846abb7d134c02ac60091108c491dafb00877093170John Hoford                    return end;
847abb7d134c02ac60091108c491dafb00877093170John Hoford                }
848abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
849abb7d134c02ac60091108c491dafb00877093170John Hoford            }
850abb7d134c02ac60091108c491dafb00877093170John Hoford            return end;
851abb7d134c02ac60091108c491dafb00877093170John Hoford        }
852abb7d134c02ac60091108c491dafb00877093170John Hoford
853abb7d134c02ac60091108c491dafb00877093170John Hoford        private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) {
854abb7d134c02ac60091108c491dafb00877093170John Hoford            list.add(new VectorDrawable.VNode(cmd, val));
855abb7d134c02ac60091108c491dafb00877093170John Hoford        }
856abb7d134c02ac60091108c491dafb00877093170John Hoford
857abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
858abb7d134c02ac60091108c491dafb00877093170John Hoford         * parse the floats in the string
859abb7d134c02ac60091108c491dafb00877093170John Hoford         * this is an optimized version of
860abb7d134c02ac60091108c491dafb00877093170John Hoford         * parseFloat(s.split(",|\\s"));
861abb7d134c02ac60091108c491dafb00877093170John Hoford         *
862abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string containing a command and list of floats
863abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return array of floats
864abb7d134c02ac60091108c491dafb00877093170John Hoford         */
865abb7d134c02ac60091108c491dafb00877093170John Hoford        private static float[] getFloats(String s) {
866abb7d134c02ac60091108c491dafb00877093170John Hoford            if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') {
867abb7d134c02ac60091108c491dafb00877093170John Hoford                return new float[0];
868abb7d134c02ac60091108c491dafb00877093170John Hoford            }
869abb7d134c02ac60091108c491dafb00877093170John Hoford            try {
870abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] tmp = new float[s.length()];
871abb7d134c02ac60091108c491dafb00877093170John Hoford                int count = 0;
872abb7d134c02ac60091108c491dafb00877093170John Hoford                int pos = 1, end;
873abb7d134c02ac60091108c491dafb00877093170John Hoford                while ((end = extract(s, pos)) >= 0) {
874abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (pos < end) {
875abb7d134c02ac60091108c491dafb00877093170John Hoford                        tmp[count++] = Float.parseFloat(s.substring(pos, end));
876abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
877abb7d134c02ac60091108c491dafb00877093170John Hoford                    pos = end + 1;
878abb7d134c02ac60091108c491dafb00877093170John Hoford                }
879abb7d134c02ac60091108c491dafb00877093170John Hoford                // handle the final float if there is one
880abb7d134c02ac60091108c491dafb00877093170John Hoford                if (pos < s.length()) {
881abb7d134c02ac60091108c491dafb00877093170John Hoford                    tmp[count++] = Float.parseFloat(s.substring(pos, s.length()));
882abb7d134c02ac60091108c491dafb00877093170John Hoford                }
883abb7d134c02ac60091108c491dafb00877093170John Hoford                return Arrays.copyOf(tmp, count);
884abb7d134c02ac60091108c491dafb00877093170John Hoford            } catch (NumberFormatException e){
885abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"error in parsing \""+s+"\"");
886abb7d134c02ac60091108c491dafb00877093170John Hoford                throw e;
887abb7d134c02ac60091108c491dafb00877093170John Hoford            }
888abb7d134c02ac60091108c491dafb00877093170John Hoford        }
889abb7d134c02ac60091108c491dafb00877093170John Hoford
890abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
891abb7d134c02ac60091108c491dafb00877093170John Hoford         * calculate the position of the next comma or space
892abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string to search
893abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start the position to start searching
894abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the position of the next comma or space or -1 if none found
895abb7d134c02ac60091108c491dafb00877093170John Hoford         */
896abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int extract(String s, int start) {
897abb7d134c02ac60091108c491dafb00877093170John Hoford            int space = s.indexOf(' ', start);
898abb7d134c02ac60091108c491dafb00877093170John Hoford            int comma = s.indexOf(',', start);
899abb7d134c02ac60091108c491dafb00877093170John Hoford            if (space == -1) {
900abb7d134c02ac60091108c491dafb00877093170John Hoford                return comma;
901abb7d134c02ac60091108c491dafb00877093170John Hoford            }
902abb7d134c02ac60091108c491dafb00877093170John Hoford            if (comma == -1) {
903abb7d134c02ac60091108c491dafb00877093170John Hoford                return space;
904abb7d134c02ac60091108c491dafb00877093170John Hoford            }
905abb7d134c02ac60091108c491dafb00877093170John Hoford            return (comma > space) ? space : comma;
906abb7d134c02ac60091108c491dafb00877093170John Hoford        }
907abb7d134c02ac60091108c491dafb00877093170John Hoford
908abb7d134c02ac60091108c491dafb00877093170John Hoford        private VectorDrawable.VNode[] parsePath(String value) {
909abb7d134c02ac60091108c491dafb00877093170John Hoford            int start = 0;
910abb7d134c02ac60091108c491dafb00877093170John Hoford            int end = 1;
911abb7d134c02ac60091108c491dafb00877093170John Hoford
912abb7d134c02ac60091108c491dafb00877093170John Hoford            ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>();
913abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < value.length()) {
914abb7d134c02ac60091108c491dafb00877093170John Hoford                end = nextStart(value, end);
915abb7d134c02ac60091108c491dafb00877093170John Hoford                String s = value.substring(start, end);
916abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] val = getFloats(s);
917abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, s.charAt(0), val);
918abb7d134c02ac60091108c491dafb00877093170John Hoford
919abb7d134c02ac60091108c491dafb00877093170John Hoford                start = end;
920abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
921abb7d134c02ac60091108c491dafb00877093170John Hoford            }
922abb7d134c02ac60091108c491dafb00877093170John Hoford            if ((end - start) == 1 && start < value.length()) {
923abb7d134c02ac60091108c491dafb00877093170John Hoford
924abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, value.charAt(start), new float[0]);
925abb7d134c02ac60091108c491dafb00877093170John Hoford            }
926abb7d134c02ac60091108c491dafb00877093170John Hoford            return list.toArray(new VectorDrawable.VNode[list.size()]);
927abb7d134c02ac60091108c491dafb00877093170John Hoford        }
928abb7d134c02ac60091108c491dafb00877093170John Hoford    }
929abb7d134c02ac60091108c491dafb00877093170John Hoford
930abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VNode {
9315c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private char mType;
9325c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private float[] mParams;
9339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
934abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(char type, float[] params) {
9355c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = type;
9365c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = params;
937abb7d134c02ac60091108c491dafb00877093170John Hoford        }
938abb7d134c02ac60091108c491dafb00877093170John Hoford
939abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(VNode n) {
9405c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = n.mType;
9415c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = Arrays.copyOf(n.mParams, n.mParams.length);
942abb7d134c02ac60091108c491dafb00877093170John Hoford        }
943abb7d134c02ac60091108c491dafb00877093170John Hoford
944abb7d134c02ac60091108c491dafb00877093170John Hoford        public static void createPath(VNode[] node, Path path) {
9455c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            float[] current = new float[4];
94633ed52eff4b41f88858874e1af7723277a041b56ztenghui            char previousCommand = 'm';
947abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < node.length; i++) {
94833ed52eff4b41f88858874e1af7723277a041b56ztenghui                addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
94933ed52eff4b41f88858874e1af7723277a041b56ztenghui                previousCommand = node[i].mType;
950abb7d134c02ac60091108c491dafb00877093170John Hoford            }
951abb7d134c02ac60091108c491dafb00877093170John Hoford        }
952abb7d134c02ac60091108c491dafb00877093170John Hoford
95333ed52eff4b41f88858874e1af7723277a041b56ztenghui        private static void addCommand(Path path, float[] current,
95433ed52eff4b41f88858874e1af7723277a041b56ztenghui                char previousCmd, char cmd, float[] val) {
955abb7d134c02ac60091108c491dafb00877093170John Hoford
956abb7d134c02ac60091108c491dafb00877093170John Hoford            int incr = 2;
957abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentX = current[0];
958abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentY = current[1];
959abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointX = current[2];
960abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointY = current[3];
96133ed52eff4b41f88858874e1af7723277a041b56ztenghui            float reflectiveCtrlPointX;
96233ed52eff4b41f88858874e1af7723277a041b56ztenghui            float reflectiveCtrlPointY;
963abb7d134c02ac60091108c491dafb00877093170John Hoford
964abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (cmd) {
965abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'z':
966abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Z':
967abb7d134c02ac60091108c491dafb00877093170John Hoford                    path.close();
968abb7d134c02ac60091108c491dafb00877093170John Hoford                    return;
969abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'm':
970abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'M':
971abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'l':
972abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'L':
973abb7d134c02ac60091108c491dafb00877093170John Hoford                case 't':
974abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'T':
975abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 2;
976abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
977abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'h':
978abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'H':
979abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'v':
980abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'V':
981abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 1;
982abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
983abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'c':
984abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'C':
985abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 6;
986abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
987abb7d134c02ac60091108c491dafb00877093170John Hoford                case 's':
988abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'S':
989abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'q':
990abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Q':
991abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 4;
992abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
993abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'a':
994abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'A':
995abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 7;
996abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
997abb7d134c02ac60091108c491dafb00877093170John Hoford            }
998abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int k = 0; k < val.length; k += incr) {
999abb7d134c02ac60091108c491dafb00877093170John Hoford                switch (cmd) {
1000abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'm': // moveto - Start a new sub-path (relative)
1001abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rMoveTo(val[k + 0], val[k + 1]);
1002abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1003abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1004abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1005abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'M': // moveto - Start a new sub-path
1006abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.moveTo(val[k + 0], val[k + 1]);
1007abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1008abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1009abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1010abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'l': // lineto - Draw a line from the current point (relative)
1011abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], val[k + 1]);
1012abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1013abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1014abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1015abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'L': // lineto - Draw a line from the current point
1016abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], val[k + 1]);
1017abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1018abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1019abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1020abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'z': // closepath - Close the current subpath
1021abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Z': // closepath - Close the current subpath
1022abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.close();
1023abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1024abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'h': // horizontal lineto - Draws a horizontal line (relative)
1025abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], 0);
1026abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1027abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1028abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'H': // horizontal lineto - Draws a horizontal line
1029abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], currentY);
1030abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1031abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1032abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'v': // vertical lineto - Draws a vertical line from the current point (r)
1033abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(0, val[k + 0]);
1034abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 0];
1035abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1036abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'V': // vertical lineto - Draws a vertical line from the current point
1037abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(currentX, val[k + 0]);
1038abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 0];
1039abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1040abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'c': // curveto - Draws a cubic Bézier curve (relative)
104133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
104233ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 4], val[k + 5]);
1043abb7d134c02ac60091108c491dafb00877093170John Hoford
1044abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 2];
1045abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 3];
1046abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 4];
1047abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 5];
1048abb7d134c02ac60091108c491dafb00877093170John Hoford
1049abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1050abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'C': // curveto - Draws a cubic Bézier curve
105133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
105233ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 4], val[k + 5]);
1053abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 4];
1054abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 5];
1055abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 2];
1056abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 3];
1057abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1058abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
105933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = 0;
106033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = 0;
106133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'c' || previousCmd == 's'
106233ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'C' || previousCmd == 'S') {
106333ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = currentX - ctrlPointX;
106433ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = currentY - ctrlPointY;
106533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
106633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1067abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1],
1068abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2], val[k + 3]);
1069abb7d134c02ac60091108c491dafb00877093170John Hoford
1070abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 0];
1071abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 1];
1072abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1073abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1074abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1075abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
107633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = currentX;
107733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = currentY;
107833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'c' || previousCmd == 's'
107933ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'C' || previousCmd == 'S') {
108033ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
108133ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
108233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
108333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
108433ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1085abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1086abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
108733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentX = val[k + 2];
108833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 3];
1089abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1090abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'q': // Draws a quadratic Bézier (relative)
1091abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
109233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointX = currentX + val[k + 0];
109333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointY = currentY + val[k + 1];
1094abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1095abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1096abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1097abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Q': // Draws a quadratic Bézier
1098abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1099abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1100abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
110133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentX = val[k + 2];
110233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 3];
1103abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1104abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
110533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = 0;
110633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = 0;
110733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'q' || previousCmd == 't'
110833ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'Q' || previousCmd == 'T') {
110933ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = currentX - ctrlPointX;
111033ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = currentY - ctrlPointY;
111133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
111233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1113abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
1114175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui                        ctrlPointX = currentX + reflectiveCtrlPointX;
1115175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui                        ctrlPointY = currentY + reflectiveCtrlPointY;
1116abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1117abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1118abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1119abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'T': // Draws a quadratic Bézier curve (reflective control point)
112033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = currentX;
112133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = currentY;
112233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'q' || previousCmd == 't'
112333ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'Q' || previousCmd == 'T') {
112433ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
112533ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
112633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
112733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1128abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
112933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointX = reflectiveCtrlPointX;
113033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointY = reflectiveCtrlPointY;
1131abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
113233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 1];
1133abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1134abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'a': // Draws an elliptical arc
1135abb7d134c02ac60091108c491dafb00877093170John Hoford                        // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
1136abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1137abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1138abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1139abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5] + currentX,
1140abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6] + currentY,
1141abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1142abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1143abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1144abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1145abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1146abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 5];
1147abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 6];
1148abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
1149abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
1150abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1151abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'A': // Draws an elliptical arc
1152abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1153abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1154abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1155abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5],
1156abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6],
1157abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1158abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1159abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1160abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1161abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1162abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 5];
1163abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 6];
1164abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
1165abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
1166abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1167abb7d134c02ac60091108c491dafb00877093170John Hoford                }
116833ed52eff4b41f88858874e1af7723277a041b56ztenghui                previousCmd = cmd;
1169abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1170abb7d134c02ac60091108c491dafb00877093170John Hoford            current[0] = currentX;
1171abb7d134c02ac60091108c491dafb00877093170John Hoford            current[1] = currentY;
1172abb7d134c02ac60091108c491dafb00877093170John Hoford            current[2] = ctrlPointX;
1173abb7d134c02ac60091108c491dafb00877093170John Hoford            current[3] = ctrlPointY;
1174abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1175abb7d134c02ac60091108c491dafb00877093170John Hoford
1176abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void drawArc(Path p,
1177abb7d134c02ac60091108c491dafb00877093170John Hoford                float x0,
1178abb7d134c02ac60091108c491dafb00877093170John Hoford                float y0,
1179abb7d134c02ac60091108c491dafb00877093170John Hoford                float x1,
1180abb7d134c02ac60091108c491dafb00877093170John Hoford                float y1,
1181abb7d134c02ac60091108c491dafb00877093170John Hoford                float a,
1182abb7d134c02ac60091108c491dafb00877093170John Hoford                float b,
1183abb7d134c02ac60091108c491dafb00877093170John Hoford                float theta,
1184abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isMoreThanHalf,
1185abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isPositiveArc) {
1186abb7d134c02ac60091108c491dafb00877093170John Hoford
1187abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Convert rotation angle from degrees to radians */
1188abb7d134c02ac60091108c491dafb00877093170John Hoford            double thetaD = Math.toRadians(theta);
1189abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Pre-compute rotation matrix entries */
1190abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(thetaD);
1191abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(thetaD);
1192abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Transform (x0, y0) and (x1, y1) into unit space */
1193abb7d134c02ac60091108c491dafb00877093170John Hoford            /* using (inverse) rotation, followed by (inverse) scale */
1194abb7d134c02ac60091108c491dafb00877093170John Hoford            double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
1195abb7d134c02ac60091108c491dafb00877093170John Hoford            double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
1196abb7d134c02ac60091108c491dafb00877093170John Hoford            double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
1197abb7d134c02ac60091108c491dafb00877093170John Hoford            double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
1198abb7d134c02ac60091108c491dafb00877093170John Hoford
1199abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Compute differences and averages */
1200abb7d134c02ac60091108c491dafb00877093170John Hoford            double dx = x0p - x1p;
1201abb7d134c02ac60091108c491dafb00877093170John Hoford            double dy = y0p - y1p;
1202abb7d134c02ac60091108c491dafb00877093170John Hoford            double xm = (x0p + x1p) / 2;
1203abb7d134c02ac60091108c491dafb00877093170John Hoford            double ym = (y0p + y1p) / 2;
1204abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Solve for intersecting unit circles */
1205abb7d134c02ac60091108c491dafb00877093170John Hoford            double dsq = dx * dx + dy * dy;
1206abb7d134c02ac60091108c491dafb00877093170John Hoford            if (dsq == 0.0) {
1207abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, " Points are coincident");
1208abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are coincident */
1209abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1210abb7d134c02ac60091108c491dafb00877093170John Hoford            double disc = 1.0 / dsq - 1.0 / 4.0;
1211abb7d134c02ac60091108c491dafb00877093170John Hoford            if (disc < 0.0) {
1212abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, "Points are too far apart " + dsq);
1213abb7d134c02ac60091108c491dafb00877093170John Hoford                float adjust = (float) (Math.sqrt(dsq) / 1.99999);
1214abb7d134c02ac60091108c491dafb00877093170John Hoford                drawArc(p, x0, y0, x1, y1, a * adjust,
1215abb7d134c02ac60091108c491dafb00877093170John Hoford                        b * adjust, theta, isMoreThanHalf, isPositiveArc);
1216abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are too far apart */
1217abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1218abb7d134c02ac60091108c491dafb00877093170John Hoford            double s = Math.sqrt(disc);
1219abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdx = s * dx;
1220abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdy = s * dy;
1221abb7d134c02ac60091108c491dafb00877093170John Hoford            double cx;
1222abb7d134c02ac60091108c491dafb00877093170John Hoford            double cy;
1223abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isMoreThanHalf == isPositiveArc) {
1224abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm - sdy;
1225abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym + sdx;
1226abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
1227abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm + sdy;
1228abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym - sdx;
1229abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1230abb7d134c02ac60091108c491dafb00877093170John Hoford
1231abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta0 = Math.atan2((y0p - cy), (x0p - cx));
1232abb7d134c02ac60091108c491dafb00877093170John Hoford
1233abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = Math.atan2((y1p - cy), (x1p - cx));
1234abb7d134c02ac60091108c491dafb00877093170John Hoford
1235abb7d134c02ac60091108c491dafb00877093170John Hoford            double sweep = (eta1 - eta0);
1236abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isPositiveArc != (sweep >= 0)) {
1237abb7d134c02ac60091108c491dafb00877093170John Hoford                if (sweep > 0) {
1238abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep -= 2 * Math.PI;
1239abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1240abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep += 2 * Math.PI;
1241abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1242abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1243abb7d134c02ac60091108c491dafb00877093170John Hoford
1244abb7d134c02ac60091108c491dafb00877093170John Hoford            cx *= a;
1245abb7d134c02ac60091108c491dafb00877093170John Hoford            cy *= b;
1246abb7d134c02ac60091108c491dafb00877093170John Hoford            double tcx = cx;
1247abb7d134c02ac60091108c491dafb00877093170John Hoford            cx = cx * cosTheta - cy * sinTheta;
1248abb7d134c02ac60091108c491dafb00877093170John Hoford            cy = tcx * sinTheta + cy * cosTheta;
1249abb7d134c02ac60091108c491dafb00877093170John Hoford
1250abb7d134c02ac60091108c491dafb00877093170John Hoford            arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
1251abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1252abb7d134c02ac60091108c491dafb00877093170John Hoford
1253abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1254abb7d134c02ac60091108c491dafb00877093170John Hoford         * Converts an arc to cubic Bezier segments and records them in p.
1255abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1256abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param p The target for the cubic Bezier segments
1257abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cx The x coordinate center of the ellipse
1258abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cy The y coordinate center of the ellipse
1259abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param a The radius of the ellipse in the horizontal direction
1260abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param b The radius of the ellipse in the vertical direction
1261abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1x E(eta1) x coordinate of the starting point of the arc
1262abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1y E(eta2) y coordinate of the starting point of the arc
1263abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane
1264abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start The start angle of the arc on the ellipse
1265abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
1266abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1267abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void arcToBezier(Path p,
1268abb7d134c02ac60091108c491dafb00877093170John Hoford                double cx,
1269abb7d134c02ac60091108c491dafb00877093170John Hoford                double cy,
1270abb7d134c02ac60091108c491dafb00877093170John Hoford                double a,
1271abb7d134c02ac60091108c491dafb00877093170John Hoford                double b,
1272abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1x,
1273abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1y,
1274abb7d134c02ac60091108c491dafb00877093170John Hoford                double theta,
1275abb7d134c02ac60091108c491dafb00877093170John Hoford                double start,
1276abb7d134c02ac60091108c491dafb00877093170John Hoford                double sweep) {
1277abb7d134c02ac60091108c491dafb00877093170John Hoford            // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
1278abb7d134c02ac60091108c491dafb00877093170John Hoford            // and http://www.spaceroots.org/documents/ellipse/node22.html
1279abb7d134c02ac60091108c491dafb00877093170John Hoford
1280abb7d134c02ac60091108c491dafb00877093170John Hoford            // Maximum of 45 degrees per cubic Bezier segment
1281abb7d134c02ac60091108c491dafb00877093170John Hoford            int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI));
1282abb7d134c02ac60091108c491dafb00877093170John Hoford
1283abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = start;
1284abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(theta);
1285abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(theta);
1286abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosEta1 = Math.cos(eta1);
1287abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinEta1 = Math.sin(eta1);
1288abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
1289abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
1290abb7d134c02ac60091108c491dafb00877093170John Hoford
1291abb7d134c02ac60091108c491dafb00877093170John Hoford            double anglePerSegment = sweep / numSegments;
1292abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < numSegments; i++) {
1293abb7d134c02ac60091108c491dafb00877093170John Hoford                double eta2 = eta1 + anglePerSegment;
1294abb7d134c02ac60091108c491dafb00877093170John Hoford                double sinEta2 = Math.sin(eta2);
1295abb7d134c02ac60091108c491dafb00877093170John Hoford                double cosEta2 = Math.cos(eta2);
1296abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2);
1297abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2);
1298abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
1299abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
1300abb7d134c02ac60091108c491dafb00877093170John Hoford                double tanDiff2 = Math.tan((eta2 - eta1) / 2);
1301abb7d134c02ac60091108c491dafb00877093170John Hoford                double alpha =
1302abb7d134c02ac60091108c491dafb00877093170John Hoford                        Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
1303abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1x = e1x + alpha * ep1x;
1304abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1y = e1y + alpha * ep1y;
1305abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2x = e2x - alpha * ep2x;
1306abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2y = e2y - alpha * ep2y;
1307abb7d134c02ac60091108c491dafb00877093170John Hoford
1308abb7d134c02ac60091108c491dafb00877093170John Hoford                p.cubicTo((float) q1x,
1309abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q1y,
1310abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2x,
1311abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2y,
1312abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2x,
1313abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2y);
1314abb7d134c02ac60091108c491dafb00877093170John Hoford                eta1 = eta2;
1315abb7d134c02ac60091108c491dafb00877093170John Hoford                e1x = e2x;
1316abb7d134c02ac60091108c491dafb00877093170John Hoford                e1y = e2y;
1317abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1x = ep2x;
1318abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1y = ep2y;
1319abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1320abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1321abb7d134c02ac60091108c491dafb00877093170John Hoford
1322abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1323abb7d134c02ac60091108c491dafb00877093170John Hoford}
1324