VectorDrawable.java revision 6d9c422de5e0a3890dd723cb1b9264d4507053e9
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.Collection;
43abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.HashMap;
444b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
45abb7d134c02ac60091108c491dafb00877093170John Hoford/**
46d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * This lets you create a drawable based on an XML vector graphic It can be
47d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * defined in an XML file with the <code>&lt;vector></code> element.
48abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
4946e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * The vector drawable has the following elements:
50abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
51abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
52177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui * <dt><code>&lt;vector></code></dt>
53e3c45e7a6b2a7d2176aa46ee482e299b54feeb9fztenghui * <dd>Used to defined a vector drawable</dd>
54abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;size></code></dt>
55abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the intrinsic Width Height size of the drawable using
56d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <code>android:width</code> and <code>android:height</code></dd>
57abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;viewport></code></dt>
58abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the size of the virtual canvas the paths are drawn on.
59d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * The size is defined using the attributes <code>android:viewportHeight</code>
60d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <code>android:viewportWidth</code></dd>
616d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui * <dt><code>&lt;group></code></dt>
626d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui * <dd>Defines a group of paths or subgroups, plus transformation information.</dd>
63abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;path></code></dt>
646d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui * <dd>Defines paths to be drawn.
65abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
66abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:name</code>
67abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the name of the path.</dd></dt>
68abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pathData</code>
6946e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * <dd>Defines path string. This is using exactly same format as "d" attribute
7046e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * in the SVG's path data</dd></dt>
71abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fill</code>
72abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the color to fill the path (none if not present).</dd></dt>
73abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:stroke</code>
74d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <dd>Defines the color to draw the path outline (none if not present).</dd>
75d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * </dt>
76abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeWidth</code>
77abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The width a path stroke</dd></dt>
78abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeOpacity</code>
79abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity of a path stroke</dd></dt>
80abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:rotation</code>
81abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The amount to rotation the path stroke.</dd></dt>
82abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotX</code>
83abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The X coordinate of the center of rotation of a path</dd></dt>
84abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotY</code>
85abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The Y coordinate of the center of rotation of a path</dd></dt>
86abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fillOpacity</code>
87abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity to fill the path with</dd></dt>
88abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathStart</code>
89abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the start from 0 to 1</dd></dt>
90abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathEnd</code>
91abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the end from 0 to 1</dd></dt>
92abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathOffset</code>
93d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <dd>Shift trim region (allows showed region to include the start and end)
94d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * from 0 to 1</dd></dt>
95abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:clipToPath</code>
96abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Path will set the clip path</dd></dt>
97abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineCap</code>
98abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the linecap for a stroked path: butt, round, square</dd></dt>
99abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineJoin</code>
100abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt>
101abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeMiterLimit</code>
102abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the Miter limit for a stroked path</dd></dt>
103abb7d134c02ac60091108c491dafb00877093170John Hoford * </dl>
104abb7d134c02ac60091108c491dafb00877093170John Hoford * </dd>
105abb7d134c02ac60091108c491dafb00877093170John Hoford */
106abb7d134c02ac60091108c491dafb00877093170John Hofordpublic class VectorDrawable extends Drawable {
1079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private static final String LOGTAG = VectorDrawable.class.getSimpleName();
1089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
109abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_SIZE = "size";
110abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VIEWPORT = "viewport";
1116d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui    private static final String SHAPE_GROUP = "group";
112abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_PATH = "path";
113abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VECTOR = "vector";
114abb7d134c02ac60091108c491dafb00877093170John Hoford
115abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_BUTT = 0;
116abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_ROUND = 1;
117abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_SQUARE = 2;
1189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
119abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_MITER = 0;
120abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_ROUND = 1;
121abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_BEVEL = 2;
1229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1234b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette    private final VectorDrawableState mVectorState;
1244b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
125abb7d134c02ac60091108c491dafb00877093170John Hoford    private int mAlpha = 0xFF;
126abb7d134c02ac60091108c491dafb00877093170John Hoford
127abb7d134c02ac60091108c491dafb00877093170John Hoford    public VectorDrawable() {
1289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        mVectorState = new VectorDrawableState(null);
129abb7d134c02ac60091108c491dafb00877093170John Hoford    }
130abb7d134c02ac60091108c491dafb00877093170John Hoford
1319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
132abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState = new VectorDrawableState(state);
1339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (theme != null && canApplyTheme()) {
1359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            applyTheme(theme);
1369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
137abb7d134c02ac60091108c491dafb00877093170John Hoford    }
138abb7d134c02ac60091108c491dafb00877093170John Hoford
139abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
140abb7d134c02ac60091108c491dafb00877093170John Hoford    public ConstantState getConstantState() {
141abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState;
142abb7d134c02ac60091108c491dafb00877093170John Hoford    }
143abb7d134c02ac60091108c491dafb00877093170John Hoford
1444554a6a5137d8e9bdfb623ad84ff344a48b7eb9dAlan Viverette    @Override
145abb7d134c02ac60091108c491dafb00877093170John Hoford    public void draw(Canvas canvas) {
1464b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final int saveCount = canvas.save();
1474b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final Rect bounds = getBounds();
1484b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.translate(bounds.left, bounds.top);
149ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
1504b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.restoreToCount(saveCount);
151abb7d134c02ac60091108c491dafb00877093170John Hoford    }
152abb7d134c02ac60091108c491dafb00877093170John Hoford
153abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
154abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setAlpha(int alpha) {
155abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO correct handling of transparent
156abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mAlpha != alpha) {
157abb7d134c02ac60091108c491dafb00877093170John Hoford            mAlpha = alpha;
158abb7d134c02ac60091108c491dafb00877093170John Hoford            invalidateSelf();
159abb7d134c02ac60091108c491dafb00877093170John Hoford        }
160abb7d134c02ac60091108c491dafb00877093170John Hoford    }
161abb7d134c02ac60091108c491dafb00877093170John Hoford
162abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
163abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setColorFilter(ColorFilter colorFilter) {
164abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO: support color filter
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();
2916d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    pathRenderer.mGroupList.add(currentGroup);
2926d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    noGroupTag = false;
293abb7d134c02ac60091108c491dafb00877093170John Hoford                }
294abb7d134c02ac60091108c491dafb00877093170John Hoford            }
2959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
296abb7d134c02ac60091108c491dafb00877093170John Hoford            eventType = parser.next();
297abb7d134c02ac60091108c491dafb00877093170John Hoford        }
2989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
2996d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui        if (noGroupTag && !noPathTag) {
3006d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui            pathRenderer.mGroupList.add(currentGroup);
3016d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui        }
3026d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui
30346e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui        if (noSizeTag || noViewportTag || noPathTag) {
3049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final StringBuffer tag = new StringBuffer();
3059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
306abb7d134c02ac60091108c491dafb00877093170John Hoford            if (noSizeTag) {
3079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
308abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
310d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette            if (noViewportTag) {
311d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                if (tag.length() > 0) {
312abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
313abb7d134c02ac60091108c491dafb00877093170John Hoford                }
3149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
315abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
317d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette            if (noPathTag) {
318d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                if (tag.length() > 0) {
319abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" or ");
320abb7d134c02ac60091108c491dafb00877093170John Hoford                }
3219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_PATH);
322abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
3249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            throw new XmlPullParserException("no " + tag + " defined");
325abb7d134c02ac60091108c491dafb00877093170John Hoford        }
3269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
327abb7d134c02ac60091108c491dafb00877093170John Hoford        // post parse cleanup
328ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        pathRenderer.parseFinish();
329ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return pathRenderer;
330abb7d134c02ac60091108c491dafb00877093170John Hoford    }
331abb7d134c02ac60091108c491dafb00877093170John Hoford
332ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private void setPathRenderer(VPathRenderer pathRenderer) {
333ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        mVectorState.mVPathRenderer = pathRenderer;
334abb7d134c02ac60091108c491dafb00877093170John Hoford    }
335abb7d134c02ac60091108c491dafb00877093170John Hoford
3365c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    private static class VectorDrawableState extends ConstantState {
3375c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        int mChangingConfigurations;
338ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        VPathRenderer mVPathRenderer;
3395c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        Rect mPadding;
3405c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3415c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public VectorDrawableState(VectorDrawableState copy) {
3425c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            if (copy != null) {
3435c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mChangingConfigurations = copy.mChangingConfigurations;
344ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
3455c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mPadding = new Rect(copy.mPadding);
3465c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            }
3475c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3485c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3495c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3505c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable() {
3515c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, null, null);
3525c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3555c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res) {
3565c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, null);
3575c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3585c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3595c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3605c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res, Theme theme) {
3615c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, theme);
3625c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3635c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3645c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3655c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public int getChangingConfigurations() {
3665c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return mChangingConfigurations;
3675c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3685c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    }
3695c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
370ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private static class VPathRenderer {
3714b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mPath = new Path();
3724b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mRenderPath = new Path();
3734b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Matrix mMatrix = new Matrix();
3744b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
375abb7d134c02ac60091108c491dafb00877093170John Hoford        private VPath[] mCurrentPaths;
3764b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mStrokePaint;
3774b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mFillPaint;
378abb7d134c02ac60091108c491dafb00877093170John Hoford        private PathMeasure mPathMeasure;
3794b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
3806d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui        final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
3819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
382abb7d134c02ac60091108c491dafb00877093170John Hoford        float mBaseWidth = 1;
383abb7d134c02ac60091108c491dafb00877093170John Hoford        float mBaseHeight = 1;
384abb7d134c02ac60091108c491dafb00877093170John Hoford        float mViewportWidth;
385abb7d134c02ac60091108c491dafb00877093170John Hoford        float mViewportHeight;
386abb7d134c02ac60091108c491dafb00877093170John Hoford
387ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        public VPathRenderer() {
388abb7d134c02ac60091108c491dafb00877093170John Hoford        }
3899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
390ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        public VPathRenderer(VPathRenderer copy) {
3916d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui            mGroupList.addAll(copy.mGroupList);
392abb7d134c02ac60091108c491dafb00877093170John Hoford            if (copy.mCurrentPaths != null) {
393abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentPaths = new VPath[copy.mCurrentPaths.length];
394abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < mCurrentPaths.length; i++) {
395abb7d134c02ac60091108c491dafb00877093170John Hoford                    mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]);
396abb7d134c02ac60091108c491dafb00877093170John Hoford                }
397abb7d134c02ac60091108c491dafb00877093170John Hoford            }
398abb7d134c02ac60091108c491dafb00877093170John Hoford
399abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = copy.mBaseWidth;
400abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = copy.mBaseHeight;
401abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = copy.mViewportHeight;
402abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = copy.mViewportHeight;
403abb7d134c02ac60091108c491dafb00877093170John Hoford        }
404abb7d134c02ac60091108c491dafb00877093170John Hoford
4059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
4066d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui            final ArrayList<VGroup> groups = mGroupList;
4076d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui            for (int i = groups.size() - 1; i >= 0; i--) {
4086d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                final ArrayList<VPath> paths = groups.get(i).mVGList;
4096d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                for (int j = paths.size() - 1; j >= 0; j--) {
4106d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    final VPath path = paths.get(j);
4116d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    if (path.canApplyTheme()) {
4126d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                        return true;
4136d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    }
4149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
4159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
4166d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui
4179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return false;
4189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
4199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
4216d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui            final ArrayList<VGroup> groups = mGroupList;
4226d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui            for (int i = groups.size() - 1; i >= 0; i--) {
4236d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                final ArrayList<VPath> paths = groups.get(i).mVGList;
4246d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                for (int j = paths.size() - 1; j >= 0; j--) {
4256d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    final VPath path = paths.get(j);
4266d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    if (path.canApplyTheme()) {
4276d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                        path.applyTheme(t);
4286d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    }
4299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
4309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
4316d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui
432abb7d134c02ac60091108c491dafb00877093170John Hoford        }
433abb7d134c02ac60091108c491dafb00877093170John Hoford
4344b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        public void draw(Canvas canvas, int w, int h) {
435abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentPaths == null) {
436abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"mCurrentPaths == null");
437abb7d134c02ac60091108c491dafb00877093170John Hoford                return;
438abb7d134c02ac60091108c491dafb00877093170John Hoford            }
439abb7d134c02ac60091108c491dafb00877093170John Hoford
440abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mCurrentPaths.length; i++) {
441ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                if (mCurrentPaths[i] != null) {
442abb7d134c02ac60091108c491dafb00877093170John Hoford                    drawPath(mCurrentPaths[i], canvas, w, h);
443abb7d134c02ac60091108c491dafb00877093170John Hoford                }
444abb7d134c02ac60091108c491dafb00877093170John Hoford            }
445abb7d134c02ac60091108c491dafb00877093170John Hoford        }
446abb7d134c02ac60091108c491dafb00877093170John Hoford
447abb7d134c02ac60091108c491dafb00877093170John Hoford        private void drawPath(VPath vPath, Canvas canvas, int w, int h) {
4489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
449abb7d134c02ac60091108c491dafb00877093170John Hoford
450abb7d134c02ac60091108c491dafb00877093170John Hoford            vPath.toPath(mPath);
4514b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final Path path = mPath;
452abb7d134c02ac60091108c491dafb00877093170John Hoford
453abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
454abb7d134c02ac60091108c491dafb00877093170John Hoford                float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
455abb7d134c02ac60091108c491dafb00877093170John Hoford                float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f;
456abb7d134c02ac60091108c491dafb00877093170John Hoford
457abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPathMeasure == null) {
458abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure = new PathMeasure();
459abb7d134c02ac60091108c491dafb00877093170John Hoford                }
460abb7d134c02ac60091108c491dafb00877093170John Hoford                mPathMeasure.setPath(mPath, false);
461abb7d134c02ac60091108c491dafb00877093170John Hoford
462abb7d134c02ac60091108c491dafb00877093170John Hoford                float len = mPathMeasure.getLength();
463abb7d134c02ac60091108c491dafb00877093170John Hoford                start = start * len;
464abb7d134c02ac60091108c491dafb00877093170John Hoford                end = end * len;
465abb7d134c02ac60091108c491dafb00877093170John Hoford                path.reset();
466abb7d134c02ac60091108c491dafb00877093170John Hoford                if (start > end) {
467abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(start, len, path, true);
468abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(0f, end, path, true);
469abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
470abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(start, end, path, true);
471abb7d134c02ac60091108c491dafb00877093170John Hoford                }
472abb7d134c02ac60091108c491dafb00877093170John Hoford                path.rLineTo(0, 0); // fix bug in measure
473abb7d134c02ac60091108c491dafb00877093170John Hoford            }
474abb7d134c02ac60091108c491dafb00877093170John Hoford
475abb7d134c02ac60091108c491dafb00877093170John Hoford            mRenderPath.reset();
476abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.reset();
477abb7d134c02ac60091108c491dafb00877093170John Hoford
478abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postRotate(vPath.mRotate, vPath.mPivotX, vPath.mPivotY);
479abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
480abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
481abb7d134c02ac60091108c491dafb00877093170John Hoford
482abb7d134c02ac60091108c491dafb00877093170John Hoford            mRenderPath.addPath(path, mMatrix);
483abb7d134c02ac60091108c491dafb00877093170John Hoford
484abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mClip) {
485abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.clipPath(mRenderPath, Region.Op.REPLACE);
486abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
488abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mFillColor != 0) {
4894b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                if (mFillPaint == null) {
4904b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint = new Paint();
4914b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint.setStyle(Paint.Style.FILL);
4924b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint.setAntiAlias(true);
4934b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                }
4944b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
495abb7d134c02ac60091108c491dafb00877093170John Hoford                mFillPaint.setColor(vPath.mFillColor);
496abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.drawPath(mRenderPath, mFillPaint);
497abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
499abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mStrokeColor != 0) {
5004b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                if (mStrokePaint == null) {
5014b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint = new Paint();
5024b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint.setStyle(Paint.Style.STROKE);
5034b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint.setAntiAlias(true);
5044b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                }
5054b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
5064b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                final Paint strokePaint = mStrokePaint;
5077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                if (vPath.mStrokeLineJoin != null) {
5084b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
509abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5104b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
5117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                if (vPath.mStrokeLineCap != null) {
5124b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    strokePaint.setStrokeCap(vPath.mStrokeLineCap);
513abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5144b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
5154b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
5164b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setColor(vPath.mStrokeColor);
5174b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
5184b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                canvas.drawPath(mRenderPath, strokePaint);
519abb7d134c02ac60091108c491dafb00877093170John Hoford            }
520abb7d134c02ac60091108c491dafb00877093170John Hoford        }
521abb7d134c02ac60091108c491dafb00877093170John Hoford
522abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
52346e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui         * Build the "current" path based on the current group
524abb7d134c02ac60091108c491dafb00877093170John Hoford         * TODO: improve memory use & performance or move to C++
525abb7d134c02ac60091108c491dafb00877093170John Hoford         */
526abb7d134c02ac60091108c491dafb00877093170John Hoford        public void parseFinish() {
5276d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui            final Collection<VPath> paths = mGroupList.get(0).getPaths();
528abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentPaths = paths.toArray(new VPath[paths.size()]);
529abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mCurrentPaths.length; i++) {
530abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentPaths[i] = new VPath(mCurrentPaths[i]);
531abb7d134c02ac60091108c491dafb00877093170John Hoford            }
532abb7d134c02ac60091108c491dafb00877093170John Hoford        }
533abb7d134c02ac60091108c491dafb00877093170John Hoford
534abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseViewport(Resources r, AttributeSet attrs)
535abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException {
5364b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
537abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, 0);
538abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, 0);
539abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mViewportWidth == 0 || mViewportHeight == 0) {
540abb7d134c02ac60091108c491dafb00877093170John Hoford                throw new XmlPullParserException(a.getPositionDescription()+
541abb7d134c02ac60091108c491dafb00877093170John Hoford                        "<viewport> tag requires viewportWidth & viewportHeight to be set");
542abb7d134c02ac60091108c491dafb00877093170John Hoford            }
543abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
544abb7d134c02ac60091108c491dafb00877093170John Hoford        }
545abb7d134c02ac60091108c491dafb00877093170John Hoford
546abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseSize(Resources r, AttributeSet attrs)
547abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException  {
5484b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
549abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, 0);
550abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, 0);
551abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mBaseWidth == 0 || mBaseHeight == 0) {
552abb7d134c02ac60091108c491dafb00877093170John Hoford                throw new XmlPullParserException(a.getPositionDescription()+
553abb7d134c02ac60091108c491dafb00877093170John Hoford                        "<size> tag requires width & height to be set");
554abb7d134c02ac60091108c491dafb00877093170John Hoford            }
555abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
556abb7d134c02ac60091108c491dafb00877093170John Hoford        }
5574b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
558abb7d134c02ac60091108c491dafb00877093170John Hoford    }
559abb7d134c02ac60091108c491dafb00877093170John Hoford
560abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VGroup {
5619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
5629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final ArrayList<VPath> mVGList = new ArrayList<VPath>();
563abb7d134c02ac60091108c491dafb00877093170John Hoford
564abb7d134c02ac60091108c491dafb00877093170John Hoford        public void add(VPath path) {
565abb7d134c02ac60091108c491dafb00877093170John Hoford            String id = path.getID();
566abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGPathMap.put(id, path);
567abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGList.add(path);
568abb7d134c02ac60091108c491dafb00877093170John Hoford         }
569abb7d134c02ac60091108c491dafb00877093170John Hoford
570abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
571abb7d134c02ac60091108c491dafb00877093170John Hoford         * Must return in order of adding
572abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return ordered list of paths
573abb7d134c02ac60091108c491dafb00877093170John Hoford         */
574abb7d134c02ac60091108c491dafb00877093170John Hoford        public Collection<VPath> getPaths() {
575abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGList;
576abb7d134c02ac60091108c491dafb00877093170John Hoford        }
577abb7d134c02ac60091108c491dafb00877093170John Hoford
578abb7d134c02ac60091108c491dafb00877093170John Hoford    }
579abb7d134c02ac60091108c491dafb00877093170John Hoford
580abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VPath {
581abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int MAX_STATES = 10;
5829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
5839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int[] mThemeAttrs;
5849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
585abb7d134c02ac60091108c491dafb00877093170John Hoford        int mStrokeColor = 0;
586abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeWidth = 0;
587abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeOpacity = Float.NaN;
5889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
589abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillColor = 0;
590abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillRule;
591abb7d134c02ac60091108c491dafb00877093170John Hoford        float mFillOpacity = Float.NaN;
5929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
593abb7d134c02ac60091108c491dafb00877093170John Hoford        float mRotate = 0;
594abb7d134c02ac60091108c491dafb00877093170John Hoford        float mPivotX = 0;
595abb7d134c02ac60091108c491dafb00877093170John Hoford        float mPivotY = 0;
5969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
597abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathStart = 0;
598abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathEnd = 1;
599abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathOffset = 0;
6009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
601abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean mClip = false;
6024b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
6034b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Join mStrokeLineJoin = Paint.Join.MITER;
604abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeMiterlimit = 4;
6059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private VNode[] mNode = null;
6079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private String mId;
608abb7d134c02ac60091108c491dafb00877093170John Hoford        private int[] mCheckState = new int[MAX_STATES];
609abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean[] mCheckValue = new boolean[MAX_STATES];
610abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mNumberOfStates = 0;
611abb7d134c02ac60091108c491dafb00877093170John Hoford
6129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath() {
6139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // Empty constructor.
6149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
6159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath(VPath p) {
6179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            copyFrom(p);
6189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
6199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
620abb7d134c02ac60091108c491dafb00877093170John Hoford        public void toPath(Path path) {
621abb7d134c02ac60091108c491dafb00877093170John Hoford            path.reset();
622abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mNode != null) {
623abb7d134c02ac60091108c491dafb00877093170John Hoford                VNode.createPath(mNode, path);
624abb7d134c02ac60091108c491dafb00877093170John Hoford            }
625abb7d134c02ac60091108c491dafb00877093170John Hoford        }
626abb7d134c02ac60091108c491dafb00877093170John Hoford
6277f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        public String getID() {
628abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
629abb7d134c02ac60091108c491dafb00877093170John Hoford        }
630abb7d134c02ac60091108c491dafb00877093170John Hoford
6317f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
6327f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
6337f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_BUTT:
6347f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.BUTT;
6357f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_ROUND:
6367f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.ROUND;
6377f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_SQUARE:
6387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.SQUARE;
6397f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
6407f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
6417f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
6437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
6457f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
6467f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_MITER:
6477f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.MITER;
6487f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_ROUND:
6497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.ROUND;
6507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_BEVEL:
6517f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.BEVEL;
6527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
6537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
6547f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6557f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
6567f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
6589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
6599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int[] themeAttrs = a.extractThemeAttrs();
6609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mThemeAttrs = themeAttrs;
6619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6627f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // NOTE: The set of attributes loaded here MUST match the
6637f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // set of attributes loaded in applyTheme.
6647f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_clipToPath] == 0) {
6657f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
6667f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6677f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) {
6697f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mId = a.getString(R.styleable.VectorDrawablePath_name);
6707f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6717f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6727f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) {
6737f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
6747f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
675abb7d134c02ac60091108c491dafb00877093170John Hoford
6769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) {
6777f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
6789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6807f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) {
6817f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
682abb7d134c02ac60091108c491dafb00877093170John Hoford            }
6839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_rotation] == 0) {
6857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
6867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotX] == 0) {
6897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
690abb7d134c02ac60091108c491dafb00877093170John Hoford            }
6919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotY] == 0) {
6937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
6947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
6977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) {
6987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineCap = getStrokeLineCap(
6997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
7007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineJoin] == 0) {
7047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineJoin = getStrokeLineJoin(
7057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
706abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeMiterLimit] == 0) {
7107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeMiterlimit = a.getFloat(
7117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
7127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) {
7159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
716abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null
7199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) {
7209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeOpacity = a.getFloat(
7217f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
7229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7247f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeWidth] == 0) {
7257f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
7267f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7277f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7287f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_trimPathEnd] == 0) {
7297f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
7307f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7327f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7337f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathOffset] == 0) {
7347f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathOffset = a.getFloat(
7357f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
7367f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7377f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7397f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathStart] == 0) {
7407f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathStart = a.getFloat(
7417f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
7427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
7459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
746abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
747abb7d134c02ac60091108c491dafb00877093170John Hoford        }
748abb7d134c02ac60091108c491dafb00877093170John Hoford
7499453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
7509453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mThemeAttrs != null;
7519453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
7529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
7549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (mThemeAttrs == null) {
7559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                return;
7569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = t.resolveAttributes(
7590cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette                    mThemeAttrs, R.styleable.VectorDrawablePath);
7609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7617f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
7629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7637f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_name)) {
7647f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mId = a.getString(R.styleable.VectorDrawablePath_name);
7659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7677f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) {
7687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
7699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7717f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
7727f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
7737f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7747f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
7757f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
7767f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
7777f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = getStrokeLineCap(a.getInt(
7797f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
7807f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
7817f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
7827f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeMiterlimit = a.getFloat(
7837f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
7847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
7857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeOpacity = a.getFloat(
7867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
7877f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
7887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
7907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathOffset = a.getFloat(
7917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
7927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathStart = a.getFloat(
7937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
7949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
7969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
7979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private void updateColorAlphas() {
7999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mFillOpacity)) {
8009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor &= 0x00FFFFFF;
8019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor |= ((int) (0xFF * mFillOpacity)) << 24;
8029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
8039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
8049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mStrokeOpacity)) {
8059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor &= 0x00FFFFFF;
8069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor |= ((int) (0xFF * mStrokeOpacity)) << 24;
8079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
8089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
8099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
810abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int nextStart(String s, int end) {
811abb7d134c02ac60091108c491dafb00877093170John Hoford            char c;
812abb7d134c02ac60091108c491dafb00877093170John Hoford
813abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < s.length()) {
814abb7d134c02ac60091108c491dafb00877093170John Hoford                c = s.charAt(end);
815abb7d134c02ac60091108c491dafb00877093170John Hoford                if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) {
816abb7d134c02ac60091108c491dafb00877093170John Hoford                    return end;
817abb7d134c02ac60091108c491dafb00877093170John Hoford                }
818abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
819abb7d134c02ac60091108c491dafb00877093170John Hoford            }
820abb7d134c02ac60091108c491dafb00877093170John Hoford            return end;
821abb7d134c02ac60091108c491dafb00877093170John Hoford        }
822abb7d134c02ac60091108c491dafb00877093170John Hoford
823abb7d134c02ac60091108c491dafb00877093170John Hoford        private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) {
824abb7d134c02ac60091108c491dafb00877093170John Hoford            list.add(new VectorDrawable.VNode(cmd, val));
825abb7d134c02ac60091108c491dafb00877093170John Hoford        }
826abb7d134c02ac60091108c491dafb00877093170John Hoford
827abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
828abb7d134c02ac60091108c491dafb00877093170John Hoford         * parse the floats in the string
829abb7d134c02ac60091108c491dafb00877093170John Hoford         * this is an optimized version of
830abb7d134c02ac60091108c491dafb00877093170John Hoford         * parseFloat(s.split(",|\\s"));
831abb7d134c02ac60091108c491dafb00877093170John Hoford         *
832abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string containing a command and list of floats
833abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return array of floats
834abb7d134c02ac60091108c491dafb00877093170John Hoford         */
835abb7d134c02ac60091108c491dafb00877093170John Hoford        private static float[] getFloats(String s) {
836abb7d134c02ac60091108c491dafb00877093170John Hoford            if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') {
837abb7d134c02ac60091108c491dafb00877093170John Hoford                return new float[0];
838abb7d134c02ac60091108c491dafb00877093170John Hoford            }
839abb7d134c02ac60091108c491dafb00877093170John Hoford            try {
840abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] tmp = new float[s.length()];
841abb7d134c02ac60091108c491dafb00877093170John Hoford                int count = 0;
842abb7d134c02ac60091108c491dafb00877093170John Hoford                int pos = 1, end;
843abb7d134c02ac60091108c491dafb00877093170John Hoford                while ((end = extract(s, pos)) >= 0) {
844abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (pos < end) {
845abb7d134c02ac60091108c491dafb00877093170John Hoford                        tmp[count++] = Float.parseFloat(s.substring(pos, end));
846abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
847abb7d134c02ac60091108c491dafb00877093170John Hoford                    pos = end + 1;
848abb7d134c02ac60091108c491dafb00877093170John Hoford                }
849abb7d134c02ac60091108c491dafb00877093170John Hoford                // handle the final float if there is one
850abb7d134c02ac60091108c491dafb00877093170John Hoford                if (pos < s.length()) {
851abb7d134c02ac60091108c491dafb00877093170John Hoford                    tmp[count++] = Float.parseFloat(s.substring(pos, s.length()));
852abb7d134c02ac60091108c491dafb00877093170John Hoford                }
853abb7d134c02ac60091108c491dafb00877093170John Hoford                return Arrays.copyOf(tmp, count);
854abb7d134c02ac60091108c491dafb00877093170John Hoford            } catch (NumberFormatException e){
855abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"error in parsing \""+s+"\"");
856abb7d134c02ac60091108c491dafb00877093170John Hoford                throw e;
857abb7d134c02ac60091108c491dafb00877093170John Hoford            }
858abb7d134c02ac60091108c491dafb00877093170John Hoford        }
859abb7d134c02ac60091108c491dafb00877093170John Hoford
860abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
861abb7d134c02ac60091108c491dafb00877093170John Hoford         * calculate the position of the next comma or space
862abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string to search
863abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start the position to start searching
864abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the position of the next comma or space or -1 if none found
865abb7d134c02ac60091108c491dafb00877093170John Hoford         */
866abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int extract(String s, int start) {
867abb7d134c02ac60091108c491dafb00877093170John Hoford            int space = s.indexOf(' ', start);
868abb7d134c02ac60091108c491dafb00877093170John Hoford            int comma = s.indexOf(',', start);
869abb7d134c02ac60091108c491dafb00877093170John Hoford            if (space == -1) {
870abb7d134c02ac60091108c491dafb00877093170John Hoford                return comma;
871abb7d134c02ac60091108c491dafb00877093170John Hoford            }
872abb7d134c02ac60091108c491dafb00877093170John Hoford            if (comma == -1) {
873abb7d134c02ac60091108c491dafb00877093170John Hoford                return space;
874abb7d134c02ac60091108c491dafb00877093170John Hoford            }
875abb7d134c02ac60091108c491dafb00877093170John Hoford            return (comma > space) ? space : comma;
876abb7d134c02ac60091108c491dafb00877093170John Hoford        }
877abb7d134c02ac60091108c491dafb00877093170John Hoford
878abb7d134c02ac60091108c491dafb00877093170John Hoford        private VectorDrawable.VNode[] parsePath(String value) {
879abb7d134c02ac60091108c491dafb00877093170John Hoford            int start = 0;
880abb7d134c02ac60091108c491dafb00877093170John Hoford            int end = 1;
881abb7d134c02ac60091108c491dafb00877093170John Hoford
882abb7d134c02ac60091108c491dafb00877093170John Hoford            ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>();
883abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < value.length()) {
884abb7d134c02ac60091108c491dafb00877093170John Hoford                end = nextStart(value, end);
885abb7d134c02ac60091108c491dafb00877093170John Hoford                String s = value.substring(start, end);
886abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] val = getFloats(s);
887abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, s.charAt(0), val);
888abb7d134c02ac60091108c491dafb00877093170John Hoford
889abb7d134c02ac60091108c491dafb00877093170John Hoford                start = end;
890abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
891abb7d134c02ac60091108c491dafb00877093170John Hoford            }
892abb7d134c02ac60091108c491dafb00877093170John Hoford            if ((end - start) == 1 && start < value.length()) {
893abb7d134c02ac60091108c491dafb00877093170John Hoford
894abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, value.charAt(start), new float[0]);
895abb7d134c02ac60091108c491dafb00877093170John Hoford            }
896abb7d134c02ac60091108c491dafb00877093170John Hoford            return list.toArray(new VectorDrawable.VNode[list.size()]);
897abb7d134c02ac60091108c491dafb00877093170John Hoford        }
898abb7d134c02ac60091108c491dafb00877093170John Hoford
899abb7d134c02ac60091108c491dafb00877093170John Hoford        public void copyFrom(VPath p1) {
900abb7d134c02ac60091108c491dafb00877093170John Hoford            mNode = new VNode[p1.mNode.length];
901abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNode.length; i++) {
902abb7d134c02ac60091108c491dafb00877093170John Hoford                mNode[i] = new VNode(p1.mNode[i]);
903abb7d134c02ac60091108c491dafb00877093170John Hoford            }
904abb7d134c02ac60091108c491dafb00877093170John Hoford            mId = p1.mId;
905abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeColor = p1.mStrokeColor;
906abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillColor = p1.mFillColor;
907abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeWidth = p1.mStrokeWidth;
908abb7d134c02ac60091108c491dafb00877093170John Hoford            mRotate = p1.mRotate;
909abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotX = p1.mPivotX;
910abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotY = p1.mPivotY;
911abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathStart = p1.mTrimPathStart;
912abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathEnd = p1.mTrimPathEnd;
913abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathOffset = p1.mTrimPathOffset;
9147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = p1.mStrokeLineCap;
9157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = p1.mStrokeLineJoin;
916abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeMiterlimit = p1.mStrokeMiterlimit;
917abb7d134c02ac60091108c491dafb00877093170John Hoford            mNumberOfStates = p1.mNumberOfStates;
918abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNumberOfStates; i++) {
919abb7d134c02ac60091108c491dafb00877093170John Hoford                mCheckState[i] = p1.mCheckState[i];
920abb7d134c02ac60091108c491dafb00877093170John Hoford                mCheckValue[i] = p1.mCheckValue[i];
921abb7d134c02ac60091108c491dafb00877093170John Hoford            }
922abb7d134c02ac60091108c491dafb00877093170John Hoford
923abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillRule = p1.mFillRule;
924abb7d134c02ac60091108c491dafb00877093170John Hoford        }
925abb7d134c02ac60091108c491dafb00877093170John Hoford    }
926abb7d134c02ac60091108c491dafb00877093170John Hoford
927abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VNode {
9285c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private char mType;
9295c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private float[] mParams;
9309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
931abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(char type, float[] params) {
9325c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = type;
9335c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = params;
934abb7d134c02ac60091108c491dafb00877093170John Hoford        }
935abb7d134c02ac60091108c491dafb00877093170John Hoford
936abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(VNode n) {
9375c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = n.mType;
9385c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = Arrays.copyOf(n.mParams, n.mParams.length);
939abb7d134c02ac60091108c491dafb00877093170John Hoford        }
940abb7d134c02ac60091108c491dafb00877093170John Hoford
941abb7d134c02ac60091108c491dafb00877093170John Hoford        public static void createPath(VNode[] node, Path path) {
9425c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            float[] current = new float[4];
94333ed52eff4b41f88858874e1af7723277a041b56ztenghui            char previousCommand = 'm';
944abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < node.length; i++) {
94533ed52eff4b41f88858874e1af7723277a041b56ztenghui                addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
94633ed52eff4b41f88858874e1af7723277a041b56ztenghui                previousCommand = node[i].mType;
947abb7d134c02ac60091108c491dafb00877093170John Hoford            }
948abb7d134c02ac60091108c491dafb00877093170John Hoford        }
949abb7d134c02ac60091108c491dafb00877093170John Hoford
95033ed52eff4b41f88858874e1af7723277a041b56ztenghui        private static void addCommand(Path path, float[] current,
95133ed52eff4b41f88858874e1af7723277a041b56ztenghui                char previousCmd, char cmd, float[] val) {
952abb7d134c02ac60091108c491dafb00877093170John Hoford
953abb7d134c02ac60091108c491dafb00877093170John Hoford            int incr = 2;
954abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentX = current[0];
955abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentY = current[1];
956abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointX = current[2];
957abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointY = current[3];
95833ed52eff4b41f88858874e1af7723277a041b56ztenghui            float reflectiveCtrlPointX;
95933ed52eff4b41f88858874e1af7723277a041b56ztenghui            float reflectiveCtrlPointY;
960abb7d134c02ac60091108c491dafb00877093170John Hoford
961abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (cmd) {
962abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'z':
963abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Z':
964abb7d134c02ac60091108c491dafb00877093170John Hoford                    path.close();
965abb7d134c02ac60091108c491dafb00877093170John Hoford                    return;
966abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'm':
967abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'M':
968abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'l':
969abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'L':
970abb7d134c02ac60091108c491dafb00877093170John Hoford                case 't':
971abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'T':
972abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 2;
973abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
974abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'h':
975abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'H':
976abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'v':
977abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'V':
978abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 1;
979abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
980abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'c':
981abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'C':
982abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 6;
983abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
984abb7d134c02ac60091108c491dafb00877093170John Hoford                case 's':
985abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'S':
986abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'q':
987abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Q':
988abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 4;
989abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
990abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'a':
991abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'A':
992abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 7;
993abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
994abb7d134c02ac60091108c491dafb00877093170John Hoford            }
995abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int k = 0; k < val.length; k += incr) {
996abb7d134c02ac60091108c491dafb00877093170John Hoford                switch (cmd) {
997abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'm': // moveto - Start a new sub-path (relative)
998abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rMoveTo(val[k + 0], val[k + 1]);
999abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1000abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1001abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1002abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'M': // moveto - Start a new sub-path
1003abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.moveTo(val[k + 0], val[k + 1]);
1004abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1005abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1006abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1007abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'l': // lineto - Draw a line from the current point (relative)
1008abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], val[k + 1]);
1009abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1010abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1011abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1012abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'L': // lineto - Draw a line from the current point
1013abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], val[k + 1]);
1014abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1015abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1016abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1017abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'z': // closepath - Close the current subpath
1018abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Z': // closepath - Close the current subpath
1019abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.close();
1020abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1021abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'h': // horizontal lineto - Draws a horizontal line (relative)
1022abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], 0);
1023abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1024abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1025abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'H': // horizontal lineto - Draws a horizontal line
1026abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], currentY);
1027abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1028abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1029abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'v': // vertical lineto - Draws a vertical line from the current point (r)
1030abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(0, val[k + 0]);
1031abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 0];
1032abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1033abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'V': // vertical lineto - Draws a vertical line from the current point
1034abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(currentX, val[k + 0]);
1035abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 0];
1036abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1037abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'c': // curveto - Draws a cubic Bézier curve (relative)
103833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
103933ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 4], val[k + 5]);
1040abb7d134c02ac60091108c491dafb00877093170John Hoford
1041abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 2];
1042abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 3];
1043abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 4];
1044abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 5];
1045abb7d134c02ac60091108c491dafb00877093170John Hoford
1046abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1047abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'C': // curveto - Draws a cubic Bézier curve
104833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
104933ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 4], val[k + 5]);
1050abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 4];
1051abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 5];
1052abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 2];
1053abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 3];
1054abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1055abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
105633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = 0;
105733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = 0;
105833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'c' || previousCmd == 's'
105933ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'C' || previousCmd == 'S') {
106033ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = currentX - ctrlPointX;
106133ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = currentY - ctrlPointY;
106233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
106333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1064abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1],
1065abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2], val[k + 3]);
1066abb7d134c02ac60091108c491dafb00877093170John Hoford
1067abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 0];
1068abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 1];
1069abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1070abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1071abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1072abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
107333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = currentX;
107433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = currentY;
107533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'c' || previousCmd == 's'
107633ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'C' || previousCmd == 'S') {
107733ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
107833ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
107933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
108033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
108133ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1082abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1083abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
108433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentX = val[k + 2];
108533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 3];
1086abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1087abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'q': // Draws a quadratic Bézier (relative)
1088abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
108933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointX = currentX + val[k + 0];
109033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointY = currentY + val[k + 1];
1091abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1092abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1093abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1094abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Q': // Draws a quadratic Bézier
1095abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1096abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1097abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
109833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentX = val[k + 2];
109933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 3];
1100abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1101abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
110233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = 0;
110333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = 0;
110433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'q' || previousCmd == 't'
110533ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'Q' || previousCmd == 'T') {
110633ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = currentX - ctrlPointX;
110733ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = currentY - ctrlPointY;
110833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
110933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1110abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
1111175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui                        ctrlPointX = currentX + reflectiveCtrlPointX;
1112175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui                        ctrlPointY = currentY + reflectiveCtrlPointY;
1113abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1114abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1115abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1116abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'T': // Draws a quadratic Bézier curve (reflective control point)
111733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = currentX;
111833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = currentY;
111933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'q' || previousCmd == 't'
112033ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'Q' || previousCmd == 'T') {
112133ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
112233ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
112333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
112433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1125abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
112633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointX = reflectiveCtrlPointX;
112733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointY = reflectiveCtrlPointY;
1128abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
112933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 1];
1130abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1131abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'a': // Draws an elliptical arc
1132abb7d134c02ac60091108c491dafb00877093170John Hoford                        // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
1133abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1134abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1135abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1136abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5] + currentX,
1137abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6] + currentY,
1138abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1139abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1140abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1141abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1142abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1143abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 5];
1144abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 6];
1145abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
1146abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
1147abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1148abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'A': // Draws an elliptical arc
1149abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1150abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1151abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1152abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5],
1153abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6],
1154abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1155abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1156abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1157abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1158abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1159abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 5];
1160abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 6];
1161abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
1162abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
1163abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1164abb7d134c02ac60091108c491dafb00877093170John Hoford                }
116533ed52eff4b41f88858874e1af7723277a041b56ztenghui                previousCmd = cmd;
1166abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1167abb7d134c02ac60091108c491dafb00877093170John Hoford            current[0] = currentX;
1168abb7d134c02ac60091108c491dafb00877093170John Hoford            current[1] = currentY;
1169abb7d134c02ac60091108c491dafb00877093170John Hoford            current[2] = ctrlPointX;
1170abb7d134c02ac60091108c491dafb00877093170John Hoford            current[3] = ctrlPointY;
1171abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1172abb7d134c02ac60091108c491dafb00877093170John Hoford
1173abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void drawArc(Path p,
1174abb7d134c02ac60091108c491dafb00877093170John Hoford                float x0,
1175abb7d134c02ac60091108c491dafb00877093170John Hoford                float y0,
1176abb7d134c02ac60091108c491dafb00877093170John Hoford                float x1,
1177abb7d134c02ac60091108c491dafb00877093170John Hoford                float y1,
1178abb7d134c02ac60091108c491dafb00877093170John Hoford                float a,
1179abb7d134c02ac60091108c491dafb00877093170John Hoford                float b,
1180abb7d134c02ac60091108c491dafb00877093170John Hoford                float theta,
1181abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isMoreThanHalf,
1182abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isPositiveArc) {
1183abb7d134c02ac60091108c491dafb00877093170John Hoford
1184abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Convert rotation angle from degrees to radians */
1185abb7d134c02ac60091108c491dafb00877093170John Hoford            double thetaD = Math.toRadians(theta);
1186abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Pre-compute rotation matrix entries */
1187abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(thetaD);
1188abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(thetaD);
1189abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Transform (x0, y0) and (x1, y1) into unit space */
1190abb7d134c02ac60091108c491dafb00877093170John Hoford            /* using (inverse) rotation, followed by (inverse) scale */
1191abb7d134c02ac60091108c491dafb00877093170John Hoford            double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
1192abb7d134c02ac60091108c491dafb00877093170John Hoford            double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
1193abb7d134c02ac60091108c491dafb00877093170John Hoford            double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
1194abb7d134c02ac60091108c491dafb00877093170John Hoford            double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
1195abb7d134c02ac60091108c491dafb00877093170John Hoford
1196abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Compute differences and averages */
1197abb7d134c02ac60091108c491dafb00877093170John Hoford            double dx = x0p - x1p;
1198abb7d134c02ac60091108c491dafb00877093170John Hoford            double dy = y0p - y1p;
1199abb7d134c02ac60091108c491dafb00877093170John Hoford            double xm = (x0p + x1p) / 2;
1200abb7d134c02ac60091108c491dafb00877093170John Hoford            double ym = (y0p + y1p) / 2;
1201abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Solve for intersecting unit circles */
1202abb7d134c02ac60091108c491dafb00877093170John Hoford            double dsq = dx * dx + dy * dy;
1203abb7d134c02ac60091108c491dafb00877093170John Hoford            if (dsq == 0.0) {
1204abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, " Points are coincident");
1205abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are coincident */
1206abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1207abb7d134c02ac60091108c491dafb00877093170John Hoford            double disc = 1.0 / dsq - 1.0 / 4.0;
1208abb7d134c02ac60091108c491dafb00877093170John Hoford            if (disc < 0.0) {
1209abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, "Points are too far apart " + dsq);
1210abb7d134c02ac60091108c491dafb00877093170John Hoford                float adjust = (float) (Math.sqrt(dsq) / 1.99999);
1211abb7d134c02ac60091108c491dafb00877093170John Hoford                drawArc(p, x0, y0, x1, y1, a * adjust,
1212abb7d134c02ac60091108c491dafb00877093170John Hoford                        b * adjust, theta, isMoreThanHalf, isPositiveArc);
1213abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are too far apart */
1214abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1215abb7d134c02ac60091108c491dafb00877093170John Hoford            double s = Math.sqrt(disc);
1216abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdx = s * dx;
1217abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdy = s * dy;
1218abb7d134c02ac60091108c491dafb00877093170John Hoford            double cx;
1219abb7d134c02ac60091108c491dafb00877093170John Hoford            double cy;
1220abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isMoreThanHalf == isPositiveArc) {
1221abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm - sdy;
1222abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym + sdx;
1223abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
1224abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm + sdy;
1225abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym - sdx;
1226abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1227abb7d134c02ac60091108c491dafb00877093170John Hoford
1228abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta0 = Math.atan2((y0p - cy), (x0p - cx));
1229abb7d134c02ac60091108c491dafb00877093170John Hoford
1230abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = Math.atan2((y1p - cy), (x1p - cx));
1231abb7d134c02ac60091108c491dafb00877093170John Hoford
1232abb7d134c02ac60091108c491dafb00877093170John Hoford            double sweep = (eta1 - eta0);
1233abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isPositiveArc != (sweep >= 0)) {
1234abb7d134c02ac60091108c491dafb00877093170John Hoford                if (sweep > 0) {
1235abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep -= 2 * Math.PI;
1236abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1237abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep += 2 * Math.PI;
1238abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1239abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1240abb7d134c02ac60091108c491dafb00877093170John Hoford
1241abb7d134c02ac60091108c491dafb00877093170John Hoford            cx *= a;
1242abb7d134c02ac60091108c491dafb00877093170John Hoford            cy *= b;
1243abb7d134c02ac60091108c491dafb00877093170John Hoford            double tcx = cx;
1244abb7d134c02ac60091108c491dafb00877093170John Hoford            cx = cx * cosTheta - cy * sinTheta;
1245abb7d134c02ac60091108c491dafb00877093170John Hoford            cy = tcx * sinTheta + cy * cosTheta;
1246abb7d134c02ac60091108c491dafb00877093170John Hoford
1247abb7d134c02ac60091108c491dafb00877093170John Hoford            arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
1248abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1249abb7d134c02ac60091108c491dafb00877093170John Hoford
1250abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1251abb7d134c02ac60091108c491dafb00877093170John Hoford         * Converts an arc to cubic Bezier segments and records them in p.
1252abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1253abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param p The target for the cubic Bezier segments
1254abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cx The x coordinate center of the ellipse
1255abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cy The y coordinate center of the ellipse
1256abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param a The radius of the ellipse in the horizontal direction
1257abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param b The radius of the ellipse in the vertical direction
1258abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1x E(eta1) x coordinate of the starting point of the arc
1259abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1y E(eta2) y coordinate of the starting point of the arc
1260abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane
1261abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start The start angle of the arc on the ellipse
1262abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
1263abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1264abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void arcToBezier(Path p,
1265abb7d134c02ac60091108c491dafb00877093170John Hoford                double cx,
1266abb7d134c02ac60091108c491dafb00877093170John Hoford                double cy,
1267abb7d134c02ac60091108c491dafb00877093170John Hoford                double a,
1268abb7d134c02ac60091108c491dafb00877093170John Hoford                double b,
1269abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1x,
1270abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1y,
1271abb7d134c02ac60091108c491dafb00877093170John Hoford                double theta,
1272abb7d134c02ac60091108c491dafb00877093170John Hoford                double start,
1273abb7d134c02ac60091108c491dafb00877093170John Hoford                double sweep) {
1274abb7d134c02ac60091108c491dafb00877093170John Hoford            // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
1275abb7d134c02ac60091108c491dafb00877093170John Hoford            // and http://www.spaceroots.org/documents/ellipse/node22.html
1276abb7d134c02ac60091108c491dafb00877093170John Hoford
1277abb7d134c02ac60091108c491dafb00877093170John Hoford            // Maximum of 45 degrees per cubic Bezier segment
1278abb7d134c02ac60091108c491dafb00877093170John Hoford            int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI));
1279abb7d134c02ac60091108c491dafb00877093170John Hoford
1280abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = start;
1281abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(theta);
1282abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(theta);
1283abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosEta1 = Math.cos(eta1);
1284abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinEta1 = Math.sin(eta1);
1285abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
1286abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
1287abb7d134c02ac60091108c491dafb00877093170John Hoford
1288abb7d134c02ac60091108c491dafb00877093170John Hoford            double anglePerSegment = sweep / numSegments;
1289abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < numSegments; i++) {
1290abb7d134c02ac60091108c491dafb00877093170John Hoford                double eta2 = eta1 + anglePerSegment;
1291abb7d134c02ac60091108c491dafb00877093170John Hoford                double sinEta2 = Math.sin(eta2);
1292abb7d134c02ac60091108c491dafb00877093170John Hoford                double cosEta2 = Math.cos(eta2);
1293abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2);
1294abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2);
1295abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
1296abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
1297abb7d134c02ac60091108c491dafb00877093170John Hoford                double tanDiff2 = Math.tan((eta2 - eta1) / 2);
1298abb7d134c02ac60091108c491dafb00877093170John Hoford                double alpha =
1299abb7d134c02ac60091108c491dafb00877093170John Hoford                        Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
1300abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1x = e1x + alpha * ep1x;
1301abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1y = e1y + alpha * ep1y;
1302abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2x = e2x - alpha * ep2x;
1303abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2y = e2y - alpha * ep2y;
1304abb7d134c02ac60091108c491dafb00877093170John Hoford
1305abb7d134c02ac60091108c491dafb00877093170John Hoford                p.cubicTo((float) q1x,
1306abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q1y,
1307abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2x,
1308abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2y,
1309abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2x,
1310abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2y);
1311abb7d134c02ac60091108c491dafb00877093170John Hoford                eta1 = eta2;
1312abb7d134c02ac60091108c491dafb00877093170John Hoford                e1x = e2x;
1313abb7d134c02ac60091108c491dafb00877093170John Hoford                e1y = e2y;
1314abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1x = ep2x;
1315abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1y = ep2y;
1316abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1317abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1318abb7d134c02ac60091108c491dafb00877093170John Hoford
1319abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1320abb7d134c02ac60091108c491dafb00877093170John Hoford}
1321